单周期MIPS处理器中Store Byte/Store Half-Word实现合理性与常规方案咨询
嘿,这个问题问得特别好,看得出来你是真的在深入琢磨MIPS处理器的细节~咱们先直接说结论:你当前的实现不符合实际硬件逻辑,有几个关键的问题,我给你拆解清楚,再说说常规的正确实现方式。
你当前代码的核心问题
RAM索引错误
你定义的RAM是64个32位字的数组,正确的索引应该是字地址,也就是a[31:2](因为每个字占4字节,低两位是字节偏移)。但你在sh和sb的代码里用了RAM[a[31:0]],这会导致当地址不是字对齐时,索引超出RAM的范围(毕竟RAM只有64个单元,索引只需要6位),直接指向错误的存储单元。非法的部分赋值操作
Verilog里,你直接写RAM[...]][15:0] <= wd[15:0]这种部分赋值是不可综合的(大部分工具不支持),而且逻辑上也有问题:你没有保留原有字中不需要修改的高位部分,相当于把整个字的高位清零了,这完全不符合MIPS的存储语义(sh/sb只修改指定的半字/字节,其余位保持不变)。未考虑地址偏移
MIPS的sh要求地址半字对齐(低两位是00或10),sb可以是任意字节地址,但你的代码没有根据地址的低两位来选择要修改的半字/字节位置,比如地址0x02的sb应该修改对应字的第1个字节,而你的代码会错误地修改低字节。
常规的两种实现方式
方式1:基于字寻址RAM(适合教学/简化实现)
如果还是沿用Harris教授原有的字寻址RAM结构,我们需要根据地址的低两位来定位要修改的半字/字节,同时保留原有字的其他部分。代码示例如下:
module dmem( input logic clk, input logic [1:0] we, // 00:无操作, 01:sw, 10:sh, 11:sb input logic [31:0] a, wd, output logic [31:0] rd ); // 64个32位字,对应字节地址0x00 ~ 0xFC logic [31:0] RAM[63:0]; // 读操作:按字读取,忽略地址低两位(MIPS的lw指令会自行处理符号扩展) assign rd = RAM[a[31:2]]; always_ff @(posedge clk) begin case(we) 2'b01: // sw:写入整个字(控制单元需保证地址字对齐) RAM[a[31:2]] <= wd; 2'b10: begin // sh:根据地址第1位选择高/低半字 case(a[1]) 1'b0: // 地址低两位00 → 写入低16位 RAM[a[31:2]] <= {RAM[a[31:2]][31:16], wd[15:0]}; 1'b1: // 地址低两位10 → 写入高16位 RAM[a[31:2]] <= {wd[15:0], RAM[a[31:2]][15:0]}; endcase end 2'b11: begin // sb:根据地址低两位选择对应字节 case(a[1:0]) 2'b00: RAM[a[31:2]] <= {RAM[a[31:2]][31:8], wd[7:0]}; 2'b01: RAM[a[31:2]] <= {RAM[a[31:2]][31:16], wd[7:0], RAM[a[31:2]][7:0]}; 2'b10: RAM[a[31:2]] <= {RAM[a[31:2]][31:24], wd[7:0], RAM[a[31:2]][15:0]}; 2'b11: RAM[a[31:2]] <= {wd[7:0], RAM[a[31:2]][23:0]}; endcase end default: ; // 无操作 endcase end endmodule
方式2:基于字节寻址RAM(更贴近实际硬件)
真实的计算机存储器都是字节寻址的,所以这种实现方式更符合实际情况。我们把RAM定义为字节宽度的数组,直接按字节地址操作:
module dmem( input logic clk, input logic [1:0] we, // 00:无操作, 01:sw, 10:sh, 11:sb input logic [31:0] a, wd, output logic [31:0] rd ); // 256个字节,对应原64个32位字(字节地址0x00 ~ 0xFF) logic [7:0] RAM[255:0]; // 读操作:拼接4个连续字节为32位字(这里采用小端模式,符合多数MIPS实现) assign rd = {RAM[a+3], RAM[a+2], RAM[a+1], RAM[a]}; always_ff @(posedge clk) begin case(we) 2'b01: begin // sw:写入4个连续字节 RAM[a] <= wd[7:0]; RAM[a+1] <= wd[15:8]; RAM[a+2] <= wd[23:16]; RAM[a+3] <= wd[31:24]; end 2'b10: begin // sh:写入2个连续字节(控制单元需保证半字对齐) RAM[a] <= wd[7:0]; RAM[a+1] <= wd[15:8]; end 2'b11: begin // sb:写入单个字节 RAM[a] <= wd[7:0]; end default: ; // 无操作 endcase end endmodule
额外提示
- 控制单元需要配合存储器做地址对齐检查:
sw要求地址字对齐(a[1:0] == 2'b00),sh要求半字对齐(a[0] == 1'b0),如果违反对齐要求,MIPS会触发地址异常(不过教学用的单周期处理器通常可以忽略异常处理)。 - 字节顺序(大端/小端):上面的字节寻址示例用了小端模式,你可以根据需求调整拼接顺序。
内容的提问来源于stack exchange,提问作者Abdullah Khalid

