写是时序逻辑;读是组合逻辑
`include "defines.v"
module cp0_reg(
input wire clk,
input wire rst,
input wire we_i, //是否要写CP0的寄存器
input wire[4:0] waddr_i, //要写寄存器的地址
input wire[4:0] raddr_i, //要读取寄存器的地址
input wire[`RegBus] data_i, //要写入的数据
input wire[5:0] int_i, //6个外部硬件中断的输入
output reg[`RegBus] data_o, //读出的值
//相关寄存器的值
output reg[`RegBus] count_o,
output reg[`RegBus] compare_o,
output reg[`RegBus] status_o,
output reg[`RegBus] cause_o,
output reg[`RegBus] epc_o,
output reg[`RegBus] config_o,
output reg[`RegBus] prid_o,
//是否有定时中断发生
output reg timer_int_o
);
//第一段:对CP0中寄存器的写操作
always @ (posedge clk) begin
if(rst == `RstEnable) begin
count_o <= `ZeroWord;
compare_o <= `ZeroWord;
//status寄存器的CU为0001,表示协处理器CP0存在
status_o <= 32'b00010000000000000000000000000000;
cause_o <= `ZeroWord;
epc_o <= `ZeroWord;
//config寄存器的BE为1,表示Big-Endian;MT为00,表示没有MMU
config_o <= 32'b00000000000000001000000000000000;
//制作者是L,对应的是0x48,类型是0x1,基本类型,版本号是1.0
prid_o <= 32'b00000000010011000000000100000010;
timer_int_o <= `InterruptNotAssert;
end
else begin
count_o <= count_o + 1 ; //每个时钟周期自加1
cause_o[15:10] <= int_i; //cause[15:11]保存外部中断声明
//当comepare不为0且count值为compare时
//将输出信号timer_int_o置为1,表示时钟中断发生
if(compare_o != `ZeroWord && count_o == compare_o) begin
timer_int_o <= `InterruptAssert;
end
if(we_i == `WriteEnable) begin
case (waddr_i)
`CP0_REG_COUNT: begin //写count寄存器
count_o <= data_i;
end
`CP0_REG_COMPARE: begin //写compare寄存器
compare_o <= data_i;
timer_int_o <= `InterruptNotAssert;
end
`CP0_REG_STATUS: begin //写state寄存器
status_o <= data_i;
end
`CP0_REG_EPC: begin //写EPC寄存器
epc_o <= data_i;
end
`CP0_REG_CAUSE: begin //写cause寄存器
//cause寄存器只有IP[1:0]、IV、WP字段是可写的
cause_o[9:8] <= data_i[9:8];
cause_o[23] <= data_i[23];
cause_o[22] <= data_i[22];
end
endcase
end
end
end
//第二段:对cp0寄存器的读操作
always @ (*) begin
if(rst == `RstEnable) begin
data_o <= `ZeroWord;
end
else begin
case (raddr_i)
`CP0_REG_COUNT: begin
data_o <= count_o ;
end
`CP0_REG_COMPARE: begin
data_o <= compare_o ;
end
`CP0_REG_STATUS: begin
data_o <= status_o ;
end
`CP0_REG_CAUSE: begin
data_o <= cause_o ;
end
`CP0_REG_EPC: begin
data_o <= epc_o ;
end
`CP0_REG_PrId: begin
data_o <= prid_o ;
end
`CP0_REG_CONFIG: begin
data_o <= config_o ;
end
default: begin
end
endcase
end
end
endmodule
if(inst_i[31:21] == 11'b01000000000
&& inst_i[10:0] == 11'b00000000000) begin
aluop_o <= `EXE_MFC0_OP;
alusel_o <= `EXE_RES_MOVE;
wd_o <= inst_i[20:16];
wreg_o <= `WriteEnable;
instvalid <= `InstValid;
reg1_read_o <= 1'b0;
reg2_read_o <= 1'b0;
end
else if(inst_i[31:21] == 11'b01000000100
&& inst_i[10:0] == 11'b00000000000) begin
aluop_o <= `EXE_MTC0_OP;
alusel_o <= `EXE_RES_NOP;
wreg_o <= `WriteDisable;
instvalid <= `InstValid;
reg1_read_o <= 1'b1;
reg1_addr_o <= inst_i[20:16];
reg2_read_o <= 1'b0;
end