E203 itcm是64Kb,所以地址总线为16位,2^16=64Kb, 数据线宽度为64 bits(8 bytes),所以address width是16-3=13bit,ram depth 是2^16/8=2^13。
itcm的基地址默认是0x8000_0000。
在目录e200_opensource/riscv-tools/riscv-tests/isa/generated,这儿有很多生成好的test文件。比如test rv32ui-p-andi
文件rv32ui-p-andi是riscv的可执行elf文件, rv32ui-p-andi.dump是对应的汇编文件,rv32ui-p-andi.verilog是对于的机器码文件,可以在verilog中用下面的代码把要执行的机器码装入itcm中。
//default itcm size is 64Kb, so E203_ITCM_RAM_DP=13 reg [7:0] itcm_mem [0:(`E203_ITCM_RAM_DP*8)-1]; initial begin $readmemh({testcase, ".verilog"}, itcm_mem); for (i=0;i<(`E203_ITCM_RAM_DP);i=i+1) begin `ITCM.mem_r[i][00+7:00] = itcm_mem[i*8+0]; `ITCM.mem_r[i][08+7:08] = itcm_mem[i*8+1]; `ITCM.mem_r[i][16+7:16] = itcm_mem[i*8+2]; `ITCM.mem_r[i][24+7:24] = itcm_mem[i*8+3]; `ITCM.mem_r[i][32+7:32] = itcm_mem[i*8+4]; `ITCM.mem_r[i][40+7:40] = itcm_mem[i*8+5]; `ITCM.mem_r[i][48+7:48] = itcm_mem[i*8+6]; `ITCM.mem_r[i][56+7:56] = itcm_mem[i*8+7]; end
itcm实际上就是一块sram,对itcm的读写如下,读写数据宽度都是按32bit进行的,对于写可以通过write mask只写某个byte。
module sirv_sim_ram #(parameter DP = 512, parameter FORCE_X2ZERO = 0, parameter DW = 32, parameter MW = 4, parameter AW = 32 ) ( input clk, input [DW-1 :0] din,//input data input [AW-1 :0] addr,//input address input cs, //chip select input we, //write enable input [MW-1:0] wem,//write enable mask output [DW-1:0] dout //write data out ); reg [DW-1:0] mem_r [0:DP-1]; reg [AW-1:0] addr_r; wire [MW-1:0] wen; wire ren; assign ren = cs & (~we); //it is 4 bits, and every bit mask a byte write assign wen = ({MW{cs & we}} & wem); genvar i; always @(posedge clk) begin if (ren) begin addr_r <= addr; end end generate for (i = 0; i < MW; i = i+1) begin :mem if((8*i+8) > DW ) begin: last always @(posedge clk) begin if (wen[i]) begin mem_r[addr][DW-1:8*i] <= din[DW-1:8*i]; end end end else begin: non_last always @(posedge clk) begin if (wen[i]) begin mem_r[addr][8*i+7:8*i] <= din[8*i+7:8*i]; end end end end endgenerate wire [DW-1:0] dout_pre; assign dout_pre = mem_r[addr_r]; generate if(FORCE_X2ZERO == 1) begin: force_x_to_zero for (i = 0; i < DW; i = i+1) begin:force_x_gen `ifndef SYNTHESIS//{ assign dout[i] = (dout_pre[i] === 1'bx) ? 1'b0 : dout_pre[i]; `else//}{ assign dout[i] = dout_pre[i]; `endif//} end end else begin:no_force_x_to_zero assign dout = dout_pre; end endgenerate endmodule
testbench文件
module sirv_sim_ram_tb; reg clk=0; reg cs=1; reg we=1; reg[3:0] wem=4'b1111; reg[31:0] addr; reg[31:0] din; wire[31:0] dout; integer i,j; sirv_sim_ram #( .FORCE_X2ZERO (1), .DP (64), .AW (6), .MW (4), .DW (32) )u_sirv_sim_ram ( .clk (clk), .din (din), .addr (addr), .cs (cs), .we (we), .wem (wem), .dout (dout) ); always #10 clk = ~clk; initial begin for(i=0; i<16; i=i+1) #20 addr=i; #20 #20 we = 0; addr = 0; #20 addr = 1; #20 addr = 2; #20 addr = 3; #20 addr = 4; #20 addr = 5; #20 addr = 6; end initial begin for(j=0; j<16; j=j+1) #20 din=j; end initial begin //$dumpfile("dump.vcd"); //$dumpvars; $fsdbDumpfile("dump.fsdb"); $fsdbDumpvars("+all"); end initial begin $monitor($time,,,"%d,%d,%d,%d,%d,%d)",cs,din,addr,we,wem,dout); #1000 $finish; end endmodule