-- TOC --
本文假设了一个简易的memory decoder结构,用verilog将其实现,并仿真测试。
假设有一块64位的CPU,它的RAM的寻址能力为 \(2^{40}\) 字节,即1T(terabyte),40位RAM地址线。用它配置一个低版本的电脑,只提供4G内存,即32线的RAM访问能力,\(2^{32}\) 字节。这4G内存由4块1G内存组合而成,每一块1G的内存提供 \(2^{30}\) 个字节。
原理图如下:
40条地址线,高8位固定为0,这样才能够选择1T空间中的低4G部分。上图中用一个8输入的NOR门连接地址线的高8位,产生EN_MEM信号,注意图中画的是8-input的not-and(不是NAND),等同于NOR。紧接着是2位的选片信号,选择4块1G内存中的哪一块,这就是一个带EN信号的2to4 decoder。再后面的27位信号连接全部的4块1G内存,用来选择一个longword,即8byte。最后8位信号用来选择8byte中的具体哪一个byte,这是一个3to8 decoder。
另外,图中还有2位额外的SIZE信号输入给3to8 decoder,用来指示其操作的宽度,比如00表示1byte,01表示2byte,10表示4byte,11表示8byte。当这两个信号不等于00的时候,这个3to8 decoder的部分输入会无效。比如当SIZE等于01的时候,每次选2个byte,INPUT每增加2时,其输入有效,如下表,NA表示无效输入:
SIZE | INPUT | OUTPUT |
---|---|---|
01 | 000 | BE0,BE1 |
01 | 001 | NA |
01 | 010 | BE2,BE3 |
01 | 011 | NA |
01 | 100 | BE4,BE5 |
01 | 101 | NA |
01 | 110 | BE6,BE7 |
01 | 111 | NA |
module mem_decoder(HADDR, LADDR, SIZE, EN_L, BE_L);
input [39:30] HADDR;
input [2:0] LADDR;
input [1:0] SIZE;
output reg [3:0] EN_L;
output reg [7:0] BE_L;
reg EN_MEM;
parameter BYTE = 2'b00,
HWORD = 2'b01,
WORD = 2'b10,
LWORD = 2'b11;
always @ (*) begin
EN_L = 4'b1111; BE_L = 8'hFF;
EN_MEM = (HADDR[39:32] == 8'h00);
if (EN_MEM) begin
EN_L[HADDR[31:30]] = 1'b0;
if (SIZE == BYTE)
BE_L[LADDR] = 1'b0;
else if (SIZE == HWORD)
case (LADDR)
3'b000: BE_L = 8'b11111100;
3'b010: BE_L = 8'b11110011;
3'b100: BE_L = 8'b11001111;
3'b110: BE_L = 8'b00111111;
endcase
else if (SIZE == WORD)
case (LADDR)
3'b000: BE_L = 8'hF0;
3'b100: BE_L = 8'h0F;
endcase
else // LWORD
if (LADDR == 3'b000) BE_L = 8'h00;
else BE_L = 8'hFF;
end
end
endmodule
代码说明:
EN_L[HADDR[31:30]] = 1'b0;
和 BE_L[LADDR] = 1'b0;
;module test_mem_decoder();
integer size, haddr, laddr;
reg [39:30] HADDR;
reg [2:0] LADDR;
reg [1:0] SIZE;
wire [3:0] EN_L;
wire [7:0] BE_L;
reg [3:0] expectEN;
reg [7:0] expectBE;
parameter BYTE = 2'b00,
HWORD = 2'b01,
WORD = 2'b10,
LWORD = 2'b11;
task showerror;
$display("HADDR=%10b, LADDR=%3b, SIZE=%2b, EN_L=%4b, BE_L=%8b",
HADDR, LADDR, SIZE, EN_L, BE_L);
endtask
mem_decoder UUT(HADDR, LADDR, SIZE, EN_L, BE_L);
initial begin
for (haddr=0; haddr<1024; haddr=haddr+1)
for (size=0; size<4; size=size+1)
for (laddr=0; laddr<8; laddr=laddr+1) begin
// set input and wait 10ns
HADDR = haddr; LADDR = laddr; SIZE = size;
#10;
//
expectEN = 4'b0000;
expectBE = 8'h00;
// check enable
if (HADDR[39:32] != 8'h00)
if ((EN_L==~expectEN) && (BE_L==~expectBE)) ;
else showerror;
else begin
// check EN_L
expectEN[HADDR[31:30]] = 1'b1;
if (EN_L != ~expectEN) showerror;
// check BE_L
if (SIZE == BYTE) begin
expectBE[LADDR] = 1'b1;
if (BE_L != ~expectBE) showerror;
end
else if (SIZE == HWORD)
case (LADDR)
3'b000: if (BE_L!=8'b11111100) showerror;
3'b010: if (BE_L!=8'b11110011) showerror;
3'b100: if (BE_L!=8'b11001111) showerror;
3'b110: if (BE_L!=8'b00111111) showerror;
default if (BE_L!=8'b11111111) showerror;
endcase
else if (SIZE == WORD)
case (LADDR)
3'b000: if (BE_L!=8'b11110000) showerror;
3'b100: if (BE_L!=8'b00001111) showerror;
default if (BE_L!=8'b11111111) showerror;
endcase
else // LWORD
case (LADDR)
3'b000: if (BE_L!=8'b00000000) showerror;
default if (BE_L!=8'b11111111) showerror;
endcase
end
end
$display("Test Done!");
end
endmodule
测试代码说明:
本文以上代码测试OK,仿真过程没有任何error信息打印出来。
下面是wave图,看起来稍微有些费劲:
红线右边的部分,是HADDR不为0的部分,符合预期,BE_L和EB_L都一直保持全0状态。红线左边可以仔细看看,在SIZE不断变化之下,BE_L呈现有规律的变化;而EN_L和HADDR[31:30]的变化保持同步。花了半天时间编写调试代码,成功了!:)
本文链接:https://cs.pynote.net/hd/verilog/202109275/
-- EOF --
-- MORE --