working with memory

This commit is contained in:
2026-09-02 13:09:20 +02:00
parent d4ae2417a4
commit 16769eaa4b
40 changed files with 1263404 additions and 3560 deletions
+954
View File
@@ -0,0 +1,954 @@
$date
Wed Sep 2 12:39:25 2026
$end
$version
Icarus Verilog
$end
$timescale
1ps
$end
$scope module tb $end
$var wire 16 ! mem_rdata [15:0] $end
$var wire 1 " mem_ready $end
$var wire 1 # ready $end
$var wire 8 $ rdata [7:0] $end
$var wire 1 % mem_wr $end
$var wire 16 & mem_wdata [15:0] $end
$var wire 1 ' mem_ub_n $end
$var wire 1 ( mem_req $end
$var wire 1 ) mem_lb_n $end
$var wire 22 * mem_addr [21:0] $end
$var parameter 32 + ADDR_WIDTH $end
$var real 1 , CLK_PERIOD $end
$var reg 22 - addr [21:0] $end
$var reg 1 . clk $end
$var reg 16 / model_rdata [15:0] $end
$var reg 1 0 model_ready $end
$var reg 1 1 req $end
$var reg 1 2 rst $end
$var reg 8 3 wdata [7:0] $end
$var reg 1 4 wr $end
$var integer 32 5 i [31:0] $end
$scope module dut $end
$var wire 22 6 addr [21:0] $end
$var wire 1 . clk $end
$var wire 16 7 mem_rdata [15:0] $end
$var wire 1 " mem_ready $end
$var wire 1 1 req $end
$var wire 1 2 rst $end
$var wire 8 8 wdata [7:0] $end
$var wire 1 4 wr $end
$var parameter 32 9 ADDR_WIDTH $end
$var parameter 2 : STATE_IDLE $end
$var parameter 2 ; STATE_WAIT $end
$var reg 22 < addr_reg [21:0] $end
$var reg 22 = mem_addr [21:0] $end
$var reg 1 ) mem_lb_n $end
$var reg 1 ( mem_req $end
$var reg 1 ' mem_ub_n $end
$var reg 16 > mem_wdata [15:0] $end
$var reg 1 % mem_wr $end
$var reg 8 ? rdata [7:0] $end
$var reg 1 # ready $end
$var reg 2 @ state [1:0] $end
$upscope $end
$scope task read_byte $end
$var reg 22 A byte_addr [21:0] $end
$var reg 8 B expected [7:0] $end
$upscope $end
$scope task write_byte $end
$var reg 22 C byte_addr [21:0] $end
$var reg 8 D data [7:0] $end
$upscope $end
$upscope $end
$enddefinitions $end
$comment Show the parameter values. $end
$dumpall
b1 ;
b0 :
b10110 9
r12.5 ,
b10110 +
$end
#0
$dumpvars
bx D
bx C
bx B
bx A
bx @
bx ?
bx >
bx =
bx <
b0 8
b0 7
b0 6
b10000000000 5
04
b0 3
12
01
00
b0 /
0.
b0 -
bx *
x)
x(
x'
bx &
x%
bx $
x#
0"
b0 !
$end
#6250
1'
1)
b0 &
b0 >
b0 *
b0 =
0%
0(
0#
b0 $
b0 ?
b0 <
b0 @
1.
#12500
0.
#18750
1.
#25000
0.
#31250
1.
#37500
0.
#43750
1.
#50000
0.
#56250
b10010 D
b0 C
02
1.
#62500
0.
#68750
11
14
b10010 3
b10010 8
1.
#75000
0.
#81250
01
b1 @
b10010 &
b10010 >
0)
1%
1(
1.
#87500
0.
#93750
1"
10
0(
1.
#100000
0.
#106250
b0 @
1#
0"
00
1.
#112500
0.
#118750
0#
b110100 D
b1 C
1.
#125000
0.
#131250
11
b110100 3
b110100 8
b1 -
b1 6
1.
#137500
0.
#143750
01
b1 @
b11010000000000 &
b11010000000000 >
0'
1)
1(
b1 <
1.
#150000
0.
#156250
0(
1"
10
1.
#162500
0.
#168750
0"
00
b0 @
1#
1.
#175000
0.
#181250
0#
b1010110 D
b10 C
1.
#187500
0.
#193750
11
b1010110 3
b1010110 8
b10 -
b10 6
1.
#200000
0.
#206250
01
b1 @
b1010110 &
b1010110 >
1'
0)
b1 *
b1 =
1(
b10 <
1.
#212500
0.
#218750
1"
10
0(
1.
#225000
0.
#231250
b0 @
1#
0"
00
1.
#237500
0.
#243750
0#
b1111000 D
b11 C
1.
#250000
0.
#256250
11
b1111000 3
b1111000 8
b11 -
b11 6
1.
#262500
0.
#268750
01
b1 @
b111100000000000 &
b111100000000000 >
0'
1)
1(
b11 <
1.
#275000
0.
#281250
0(
1"
10
1.
#287500
0.
#293750
0"
00
b0 @
1#
1.
#300000
0.
#306250
0#
b10010 B
b0 A
1.
#312500
0.
#318750
11
04
b0 -
b0 6
1.
#325000
0.
#331250
01
b1 @
b1111000 &
b1111000 >
1'
0)
b0 *
b0 =
0%
1(
b0 <
1.
#337500
0.
#343750
1"
10
b11010000010010 !
b11010000010010 7
b11010000010010 /
0(
1.
#350000
0.
#356250
b0 @
1#
b10010 $
b10010 ?
0"
00
1.
#362500
0.
#368750
0#
b110100 B
b1 A
1.
#375000
0.
#381250
11
b1 -
b1 6
1.
#387500
0.
#393750
01
b1 @
b111100000000000 &
b111100000000000 >
0'
1)
1(
b1 <
1.
#400000
0.
#406250
0(
1"
10
1.
#412500
0.
#418750
0"
00
b0 @
1#
b110100 $
b110100 ?
1.
#425000
0.
#431250
0#
b1010110 B
b10 A
1.
#437500
0.
#443750
11
b10 -
b10 6
1.
#450000
0.
#456250
01
b1 @
b1111000 &
b1111000 >
1'
0)
b1 *
b1 =
1(
b10 <
1.
#462500
0.
#468750
1"
10
b111100001010110 !
b111100001010110 7
b111100001010110 /
0(
1.
#475000
0.
#481250
b0 @
1#
b1010110 $
b1010110 ?
0"
00
1.
#487500
0.
#493750
0#
b1111000 B
b11 A
1.
#500000
0.
#506250
11
b11 -
b11 6
1.
#512500
0.
#518750
01
b1 @
b111100000000000 &
b111100000000000 >
0'
1)
1(
b11 <
1.
#525000
0.
#531250
0(
1"
10
1.
#537500
0.
#543750
0"
00
b0 @
1#
b1111000 $
b1111000 ?
1.
#550000
0.
#556250
0#
b110100 D
b10000 C
1.
#562500
0.
#568750
11
14
b110100 3
b110100 8
b10000 -
b10000 6
1.
#575000
0.
#581250
01
b1 @
b110100 &
b110100 >
1'
0)
b1000 *
b1000 =
1%
1(
b10000 <
1.
#587500
0.
#593750
1"
10
0(
1.
#600000
0.
#606250
b0 @
1#
b1010110 $
b1010110 ?
0"
00
1.
#612500
0.
#618750
0#
b10010 D
b10001 C
1.
#625000
0.
#631250
11
b10010 3
b10010 8
b10001 -
b10001 6
1.
#637500
0.
#643750
01
b1 @
b1001000000000 &
b1001000000000 >
0'
1)
1(
b10001 <
1.
#650000
0.
#656250
0(
1"
10
1.
#662500
0.
#668750
0"
00
b0 @
1#
b1111000 $
b1111000 ?
1.
#675000
0.
#681250
0#
b10101010 D
b10000 C
1.
#687500
0.
#693750
11
b10101010 3
b10101010 8
b10000 -
b10000 6
1.
#700000
0.
#706250
01
b1 @
b10101010 &
b10101010 >
1'
0)
1(
b10000 <
1.
#712500
0.
#718750
1"
10
0(
1.
#725000
0.
#731250
b0 @
1#
b1010110 $
b1010110 ?
0"
00
1.
#737500
0.
#743750
0#
b10111011 D
b10001 C
1.
#750000
0.
#756250
11
b10111011 3
b10111011 8
b10001 -
b10001 6
1.
#762500
0.
#768750
01
b1 @
b1011101100000000 &
b1011101100000000 >
0'
1)
1(
b10001 <
1.
#775000
0.
#781250
0(
1"
10
1.
#787500
0.
#793750
0"
00
b0 @
1#
b1111000 $
b1111000 ?
1.
#800000
0.
#806250
0#
b11111111 D
b100000 C
1.
#812500
0.
#818750
11
b11111111 3
b11111111 8
b100000 -
b100000 6
1.
#825000
0.
#831250
01
b1 @
b11111111 &
b11111111 >
1'
0)
b10000 *
b10000 =
1(
b100000 <
1.
#837500
0.
#843750
1"
10
0(
1.
#850000
0.
#856250
b0 @
1#
b1010110 $
b1010110 ?
0"
00
1.
#862500
0.
#868750
0#
b10000000 D
b100001 C
1.
#875000
0.
#881250
11
b10000000 3
b10000000 8
b100001 -
b100001 6
1.
#887500
0.
#893750
01
b1 @
b1000000000000000 &
b1000000000000000 >
0'
1)
1(
b100001 <
1.
#900000
0.
#906250
0(
1"
10
1.
#912500
0.
#918750
0"
00
b0 @
1#
b1111000 $
b1111000 ?
1.
#925000
0.
#931250
0#
b1111111 D
b100010 C
1.
#937500
0.
#943750
11
b1111111 3
b1111111 8
b100010 -
b100010 6
1.
#950000
0.
#956250
01
b1 @
b1111111 &
b1111111 >
1'
0)
b10001 *
b10001 =
1(
b100010 <
1.
#962500
0.
#968750
1"
10
0(
1.
#975000
0.
#981250
b0 @
1#
b1010110 $
b1010110 ?
0"
00
1.
#987500
0.
#993750
0#
b11111111 B
b100000 A
1.
#1000000
0.
#1006250
11
04
b100000 -
b100000 6
1.
#1012500
0.
#1018750
01
b1 @
b10000 *
b10000 =
0%
1(
b100000 <
1.
#1025000
0.
#1031250
0(
1"
10
b1000000011111111 !
b1000000011111111 7
b1000000011111111 /
1.
#1037500
0.
#1043750
0"
00
b0 @
1#
b11111111 $
b11111111 ?
1.
#1050000
0.
#1056250
0#
b10000000 B
b100001 A
1.
#1062500
0.
#1068750
11
b100001 -
b100001 6
1.
#1075000
0.
#1081250
01
b1 @
b111111100000000 &
b111111100000000 >
0'
1)
1(
b100001 <
1.
#1087500
0.
#1093750
1"
10
0(
1.
#1100000
0.
#1106250
b0 @
1#
b10000000 $
b10000000 ?
0"
00
1.
#1112500
0.
#1118750
0#
b1111111 B
b100010 A
1.
#1125000
0.
#1131250
11
b100010 -
b100010 6
1.
#1137500
0.
#1143750
01
b1 @
b1111111 &
b1111111 >
1'
0)
b10001 *
b10001 =
1(
b100010 <
1.
#1150000
0.
#1156250
0(
1"
10
b1111111 !
b1111111 7
b1111111 /
1.
#1162500
0.
#1168750
0"
00
b0 @
1#
b1111111 $
b1111111 ?
1.
#1175000
0.
#1181250
0#
1.
+550
View File
@@ -0,0 +1,550 @@
#! /opt/homebrew/Cellar/icarus-verilog/13.0/bin/vvp
:ivl_version "13.0 (stable)" "(v13_0)";
:ivl_delay_selection "TYPICAL";
:vpi_time_precision - 12;
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/system.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/vhdl_sys.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/vhdl_textio.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/v2005_math.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/va_math.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/v2009.vpi";
S_0x102cce1c0 .scope package, "$unit" "$unit" 2 1;
.timescale 0 0;
S_0x102cc09e0 .scope module, "tb" "tb" 3 3;
.timescale -9 -12;
P_0x102ccf000 .param/l "ADDR_WIDTH" 1 3 5, +C4<00000000000000000000000000010110>;
P_0x102ccf040 .param/real "CLK_PERIOD" 1 3 6, Cr<m6400000000000000gfc5>; value=12.5000
L_0x102ccff60 .functor BUFZ 16, v0x74b08cdc0_0, C4<0000000000000000>, C4<0000000000000000>, C4<0000000000000000>;
L_0x102ccf620 .functor BUFZ 1, v0x74b08ce60_0, C4<0>, C4<0>, C4<0>;
v0x74b08c640_0 .var "addr", 21 0;
v0x74b08c6e0_0 .var "clk", 0 0;
v0x74b08c780_0 .var/i "i", 31 0;
v0x74b08c820_0 .net "mem_addr", 21 0, v0x102ccd820_0; 1 drivers
v0x74b08c8c0_0 .net "mem_lb_n", 0 0, v0x102ccf580_0; 1 drivers
v0x74b08c960_0 .net "mem_rdata", 15 0, L_0x102ccff60; 1 drivers
v0x74b08ca00_0 .net "mem_ready", 0 0, L_0x102ccf620; 1 drivers
v0x74b08caa0_0 .net "mem_req", 0 0, v0x102ccfb40_0; 1 drivers
v0x74b08cb40_0 .net "mem_ub_n", 0 0, v0x102ccfbe0_0; 1 drivers
v0x74b08cbe0_0 .net "mem_wdata", 15 0, v0x102ccfc80_0; 1 drivers
v0x74b08cc80_0 .net "mem_wr", 0 0, v0x102ccfd20_0; 1 drivers
v0x74b08cd20 .array "memory", 1023 0, 15 0;
v0x74b08cdc0_0 .var "model_rdata", 15 0;
v0x74b08ce60_0 .var "model_ready", 0 0;
v0x74b08cf00_0 .net/s "rdata", 7 0, v0x102ccfdc0_0; 1 drivers
v0x74b08cfa0_0 .net "ready", 0 0, v0x74b08c000_0; 1 drivers
v0x74b08d040_0 .var "req", 0 0;
v0x74b08d0e0_0 .var "rst", 0 0;
v0x74b08d180_0 .var/s "wdata", 7 0;
v0x74b08d220_0 .var "wr", 0 0;
S_0x102cc0b60 .scope module, "dut" "int8_memory_access" 3 43, 4 1 0, S_0x102cc09e0;
.timescale -9 -12;
.port_info 0 /INPUT 1 "clk";
.port_info 1 /INPUT 1 "rst";
.port_info 2 /INPUT 1 "req";
.port_info 3 /INPUT 1 "wr";
.port_info 4 /INPUT 22 "addr";
.port_info 5 /INPUT 8 "wdata";
.port_info 6 /OUTPUT 8 "rdata";
.port_info 7 /OUTPUT 1 "ready";
.port_info 8 /OUTPUT 1 "mem_req";
.port_info 9 /OUTPUT 1 "mem_wr";
.port_info 10 /OUTPUT 22 "mem_addr";
.port_info 11 /OUTPUT 16 "mem_wdata";
.port_info 12 /OUTPUT 1 "mem_lb_n";
.port_info 13 /OUTPUT 1 "mem_ub_n";
.port_info 14 /INPUT 16 "mem_rdata";
.port_info 15 /INPUT 1 "mem_ready";
P_0x102cce340 .param/l "ADDR_WIDTH" 0 4 2, +C4<00000000000000000000000000010110>;
P_0x102cce380 .param/l "STATE_IDLE" 1 4 40, C4<00>;
P_0x102cce3c0 .param/l "STATE_WAIT" 1 4 41, C4<01>;
v0x102ccb170_0 .net "addr", 21 0, v0x74b08c640_0; 1 drivers
v0x102ccd070_0 .var "addr_reg", 21 0;
v0x102ccebc0_0 .net "clk", 0 0, v0x74b08c6e0_0; 1 drivers
v0x102ccd820_0 .var "mem_addr", 21 0;
v0x102ccf580_0 .var "mem_lb_n", 0 0;
v0x102ccfa00_0 .net "mem_rdata", 15 0, L_0x102ccff60; alias, 1 drivers
v0x102ccfaa0_0 .net "mem_ready", 0 0, L_0x102ccf620; alias, 1 drivers
v0x102ccfb40_0 .var "mem_req", 0 0;
v0x102ccfbe0_0 .var "mem_ub_n", 0 0;
v0x102ccfc80_0 .var "mem_wdata", 15 0;
v0x102ccfd20_0 .var "mem_wr", 0 0;
v0x102ccfdc0_0 .var/s "rdata", 7 0;
v0x74b08c000_0 .var "ready", 0 0;
v0x74b08c0a0_0 .net "req", 0 0, v0x74b08d040_0; 1 drivers
v0x74b08c140_0 .net "rst", 0 0, v0x74b08d0e0_0; 1 drivers
v0x74b08c1e0_0 .var "state", 1 0;
v0x74b08c280_0 .net/s "wdata", 7 0, v0x74b08d180_0; 1 drivers
v0x74b08c320_0 .net "wr", 0 0, v0x74b08d220_0; 1 drivers
E_0x74ac1b040 .event posedge, v0x102ccebc0_0;
S_0x102cd1180 .scope task, "read_byte" "read_byte" 3 174, 3 174 0, S_0x102cc09e0;
.timescale -9 -12;
v0x74b08c3c0_0 .var "byte_addr", 21 0;
v0x74b08c460_0 .var/s "expected", 7 0;
E_0x74ac1b080 .event anyedge, v0x74b08c000_0;
TD_tb.read_byte ;
%wait E_0x74ac1b040;
%load/vec4 v0x74b08c3c0_0;
%assign/vec4 v0x74b08c640_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x74b08d220_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x74b08d040_0, 0;
%wait E_0x74ac1b040;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x74b08d040_0, 0;
T_0.0 ;
%load/vec4 v0x74b08cfa0_0;
%cmpi/ne 1, 0, 1;
%jmp/0xz T_0.1, 6;
%wait E_0x74ac1b080;
%jmp T_0.0;
T_0.1 ;
%load/vec4 v0x74b08cf00_0;
%load/vec4 v0x74b08c460_0;
%cmp/ne;
%jmp/0xz T_0.2, 6;
%vpi_call/w 3 195 "$display", "READ BYTE addr=0x%08x FAIL got=0x%02x expected=0x%02x", v0x74b08c3c0_0, v0x74b08cf00_0, v0x74b08c460_0 {0 0 0};
%vpi_call/w 3 202 "$fatal" {0 0 0};
%jmp T_0.3;
T_0.2 ;
%vpi_call/w 3 206 "$display", "READ BYTE addr=0x%08x data=0x%02x PASS", v0x74b08c3c0_0, v0x74b08cf00_0 {0 0 0};
T_0.3 ;
%wait E_0x74ac1b040;
%end;
S_0x102cd1300 .scope task, "write_byte" "write_byte" 3 138, 3 138 0, S_0x102cc09e0;
.timescale -9 -12;
v0x74b08c500_0 .var "byte_addr", 21 0;
v0x74b08c5a0_0 .var/s "data", 7 0;
TD_tb.write_byte ;
%wait E_0x74ac1b040;
%load/vec4 v0x74b08c500_0;
%assign/vec4 v0x74b08c640_0, 0;
%load/vec4 v0x74b08c5a0_0;
%assign/vec4 v0x74b08d180_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x74b08d220_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x74b08d040_0, 0;
%wait E_0x74ac1b040;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x74b08d040_0, 0;
T_1.4 ;
%load/vec4 v0x74b08cfa0_0;
%cmpi/ne 1, 0, 1;
%jmp/0xz T_1.5, 6;
%wait E_0x74ac1b080;
%jmp T_1.4;
T_1.5 ;
%vpi_call/w 3 158 "$display", "WRITE BYTE addr=0x%08x data=0x%02x PASS", v0x74b08c500_0, v0x74b08c5a0_0 {0 0 0};
%wait E_0x74ac1b040;
%end;
.scope S_0x102cc0b60;
T_2 ;
%wait E_0x74ac1b040;
%load/vec4 v0x74b08c140_0;
%flag_set/vec4 8;
%jmp/0xz T_2.0, 8;
%pushi/vec4 0, 0, 2;
%assign/vec4 v0x74b08c1e0_0, 0;
%pushi/vec4 0, 0, 22;
%assign/vec4 v0x102ccd070_0, 0;
%pushi/vec4 0, 0, 8;
%assign/vec4 v0x102ccfdc0_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x74b08c000_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x102ccfb40_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x102ccfd20_0, 0;
%pushi/vec4 0, 0, 22;
%assign/vec4 v0x102ccd820_0, 0;
%pushi/vec4 0, 0, 16;
%assign/vec4 v0x102ccfc80_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x102ccf580_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x102ccfbe0_0, 0;
%jmp T_2.1;
T_2.0 ;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x74b08c000_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x102ccfb40_0, 0;
%load/vec4 v0x74b08c1e0_0;
%dup/vec4;
%pushi/vec4 0, 0, 2;
%cmp/u;
%jmp/1 T_2.2, 6;
%dup/vec4;
%pushi/vec4 1, 0, 2;
%cmp/u;
%jmp/1 T_2.3, 6;
%pushi/vec4 0, 0, 2;
%assign/vec4 v0x74b08c1e0_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x102ccfb40_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x102ccf580_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x102ccfbe0_0, 0;
%jmp T_2.5;
T_2.2 ;
%load/vec4 v0x74b08c0a0_0;
%flag_set/vec4 8;
%jmp/0xz T_2.6, 8;
%load/vec4 v0x102ccb170_0;
%assign/vec4 v0x102ccd070_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x102ccfb40_0, 0;
%load/vec4 v0x74b08c320_0;
%assign/vec4 v0x102ccfd20_0, 0;
%load/vec4 v0x102ccb170_0;
%ix/load 4, 1, 0;
%flag_set/imm 4, 0;
%shiftr 4;
%assign/vec4 v0x102ccd820_0, 0;
%load/vec4 v0x102ccb170_0;
%parti/s 1, 0, 2;
%cmpi/e 0, 0, 1;
%jmp/0xz T_2.8, 4;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x102ccf580_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x102ccfbe0_0, 0;
%pushi/vec4 0, 0, 8;
%load/vec4 v0x74b08c280_0;
%concat/vec4; draw_concat_vec4
%assign/vec4 v0x102ccfc80_0, 0;
%jmp T_2.9;
T_2.8 ;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x102ccf580_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x102ccfbe0_0, 0;
%load/vec4 v0x74b08c280_0;
%concati/vec4 0, 0, 8;
%assign/vec4 v0x102ccfc80_0, 0;
T_2.9 ;
%pushi/vec4 1, 0, 2;
%assign/vec4 v0x74b08c1e0_0, 0;
T_2.6 ;
%jmp T_2.5;
T_2.3 ;
%load/vec4 v0x102ccfaa0_0;
%flag_set/vec4 8;
%jmp/0xz T_2.10, 8;
%load/vec4 v0x102ccd070_0;
%parti/s 1, 0, 2;
%cmpi/e 0, 0, 1;
%jmp/0xz T_2.12, 4;
%load/vec4 v0x102ccfa00_0;
%parti/s 8, 0, 2;
%assign/vec4 v0x102ccfdc0_0, 0;
%jmp T_2.13;
T_2.12 ;
%load/vec4 v0x102ccfa00_0;
%parti/s 8, 8, 5;
%assign/vec4 v0x102ccfdc0_0, 0;
T_2.13 ;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x74b08c000_0, 0;
%pushi/vec4 0, 0, 2;
%assign/vec4 v0x74b08c1e0_0, 0;
T_2.10 ;
%jmp T_2.5;
T_2.5 ;
%pop/vec4 1;
T_2.1 ;
%jmp T_2;
.thread T_2;
.scope S_0x102cc09e0;
T_3 ;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x74b08c6e0_0, 0, 1;
T_3.0 ;
%delay 6250, 0;
%load/vec4 v0x74b08c6e0_0;
%inv;
%store/vec4 v0x74b08c6e0_0, 0, 1;
%jmp T_3.0;
T_3.1 ;
%end;
.thread T_3;
.scope S_0x102cc09e0;
T_4 ;
%vpi_call/w 3 99 "$dumpfile", "sim/int8_memory_access.vcd" {0 0 0};
%vpi_call/w 3 100 "$dumpvars", 32'sb00000000000000000000000000000000, S_0x102cc09e0 {0 0 0};
%end;
.thread T_4;
.scope S_0x102cc09e0;
T_5 ;
%wait E_0x74ac1b040;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x74b08ce60_0, 0;
%load/vec4 v0x74b08caa0_0;
%flag_set/vec4 8;
%jmp/0xz T_5.0, 8;
%load/vec4 v0x74b08cc80_0;
%flag_set/vec4 8;
%jmp/0xz T_5.2, 8;
%load/vec4 v0x74b08c8c0_0;
%nor/r;
%flag_set/vec4 8;
%jmp/0xz T_5.4, 8;
%load/vec4 v0x74b08cbe0_0;
%parti/s 8, 0, 2;
%ix/getv 3, v0x74b08c820_0;
%ix/load 4, 0, 0; Constant delay
%assign/vec4/a/d v0x74b08cd20, 0, 4;
T_5.4 ;
%load/vec4 v0x74b08cb40_0;
%nor/r;
%flag_set/vec4 8;
%jmp/0xz T_5.6, 8;
%load/vec4 v0x74b08cbe0_0;
%parti/s 8, 8, 5;
%ix/getv 3, v0x74b08c820_0;
%ix/load 4, 8, 0; part off
%ix/load 5, 0, 0; Constant delay
%assign/vec4/a/d v0x74b08cd20, 4, 5;
T_5.6 ;
%jmp T_5.3;
T_5.2 ;
%ix/getv 4, v0x74b08c820_0;
%load/vec4a v0x74b08cd20, 4;
%assign/vec4 v0x74b08cdc0_0, 0;
T_5.3 ;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x74b08ce60_0, 0;
T_5.0 ;
%jmp T_5;
.thread T_5;
.scope S_0x102cc09e0;
T_6 ;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x74b08d040_0, 0, 1;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x74b08d220_0, 0, 1;
%pushi/vec4 0, 0, 22;
%store/vec4 v0x74b08c640_0, 0, 22;
%pushi/vec4 0, 0, 8;
%store/vec4 v0x74b08d180_0, 0, 8;
%pushi/vec4 0, 0, 16;
%store/vec4 v0x74b08cdc0_0, 0, 16;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x74b08ce60_0, 0, 1;
%pushi/vec4 0, 0, 32;
%store/vec4 v0x74b08c780_0, 0, 32;
T_6.0 ; Top of for-loop
%load/vec4 v0x74b08c780_0;
%cmpi/s 1024, 0, 32;
%jmp/0xz T_6.1, 5;
%pushi/vec4 0, 0, 16;
%ix/getv/s 4, v0x74b08c780_0;
%store/vec4a v0x74b08cd20, 4, 0;
T_6.2 ; for-loop step statement
%load/vec4 v0x74b08c780_0;
%addi 1, 0, 32;
%store/vec4 v0x74b08c780_0, 0, 32;
%jmp T_6.0;
T_6.1 ; for-loop exit label
%pushi/vec4 1, 0, 1;
%store/vec4 v0x74b08d0e0_0, 0, 1;
%pushi/vec4 5, 0, 32;
T_6.3 %dup/vec4;
%cmpi/s 0, 0, 32;
%jmp/1xz T_6.4, 5;
%jmp/1 T_6.4, 4;
%subi 1, 0, 32;
%wait E_0x74ac1b040;
%jmp T_6.3;
T_6.4 ;
%pop/vec4 1;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x74b08d0e0_0, 0, 1;
%vpi_call/w 3 244 "$display", "\000" {0 0 0};
%vpi_call/w 3 245 "$display", "========================================" {0 0 0};
%vpi_call/w 3 246 "$display", "INT8 MEMORY ACCESS TEST" {0 0 0};
%vpi_call/w 3 247 "$display", "========================================" {0 0 0};
%vpi_call/w 3 248 "$display", "\000" {0 0 0};
%pushi/vec4 0, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 18, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 1, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 52, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 2, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 86, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 3, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 120, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 0, 0, 22;
%store/vec4 v0x74b08c3c0_0, 0, 22;
%pushi/vec4 18, 0, 8;
%store/vec4 v0x74b08c460_0, 0, 8;
%fork TD_tb.read_byte, S_0x102cd1180;
%join;
%pushi/vec4 1, 0, 22;
%store/vec4 v0x74b08c3c0_0, 0, 22;
%pushi/vec4 52, 0, 8;
%store/vec4 v0x74b08c460_0, 0, 8;
%fork TD_tb.read_byte, S_0x102cd1180;
%join;
%pushi/vec4 2, 0, 22;
%store/vec4 v0x74b08c3c0_0, 0, 22;
%pushi/vec4 86, 0, 8;
%store/vec4 v0x74b08c460_0, 0, 8;
%fork TD_tb.read_byte, S_0x102cd1180;
%join;
%pushi/vec4 3, 0, 22;
%store/vec4 v0x74b08c3c0_0, 0, 22;
%pushi/vec4 120, 0, 8;
%store/vec4 v0x74b08c460_0, 0, 8;
%fork TD_tb.read_byte, S_0x102cd1180;
%join;
%ix/load 4, 0, 0;
%flag_set/imm 4, 0;
%load/vec4a v0x74b08cd20, 4;
%cmpi/ne 13330, 0, 16;
%jmp/0xz T_6.5, 6;
%vpi_call/w 3 276 "$display", "PACKING ERROR word[0]=0x%04x expected=0x3412", &A<v0x74b08cd20, 0> {0 0 0};
%vpi_call/w 3 281 "$fatal" {0 0 0};
%jmp T_6.6;
T_6.5 ;
%vpi_call/w 3 285 "$display", "PACKING word[0] = 0x%04x PASS", &A<v0x74b08cd20, 0> {0 0 0};
T_6.6 ;
%ix/load 4, 1, 0;
%flag_set/imm 4, 0;
%load/vec4a v0x74b08cd20, 4;
%cmpi/ne 30806, 0, 16;
%jmp/0xz T_6.7, 6;
%vpi_call/w 3 294 "$display", "PACKING ERROR word[1]=0x%04x expected=0x7856", &A<v0x74b08cd20, 1> {0 0 0};
%vpi_call/w 3 299 "$fatal" {0 0 0};
%jmp T_6.8;
T_6.7 ;
%vpi_call/w 3 303 "$display", "PACKING word[1] = 0x%04x PASS", &A<v0x74b08cd20, 1> {0 0 0};
T_6.8 ;
%pushi/vec4 16, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 52, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 17, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 18, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%ix/load 4, 8, 0;
%flag_set/imm 4, 0;
%load/vec4a v0x74b08cd20, 4;
%cmpi/ne 4660, 0, 16;
%jmp/0xz T_6.9, 6;
%vpi_call/w 3 320 "$display", "INITIAL WORD ERROR = 0x%04x", &A<v0x74b08cd20, 8> {0 0 0};
%vpi_call/w 3 325 "$fatal" {0 0 0};
T_6.9 ;
%pushi/vec4 16, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 170, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%ix/load 4, 8, 0;
%flag_set/imm 4, 0;
%load/vec4a v0x74b08cd20, 4;
%cmpi/ne 4778, 0, 16;
%jmp/0xz T_6.11, 6;
%vpi_call/w 3 336 "$display", "LOW BYTE PRESERVE ERROR = 0x%04x expected=0x12AA", &A<v0x74b08cd20, 8> {0 0 0};
%vpi_call/w 3 341 "$fatal" {0 0 0};
%jmp T_6.12;
T_6.11 ;
%vpi_call/w 3 345 "$display", "LOW BYTE PRESERVE 0x1234 -> 0x12AA PASS" {0 0 0};
T_6.12 ;
%pushi/vec4 17, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 187, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%ix/load 4, 8, 0;
%flag_set/imm 4, 0;
%load/vec4a v0x74b08cd20, 4;
%cmpi/ne 48042, 0, 16;
%jmp/0xz T_6.13, 6;
%vpi_call/w 3 358 "$display", "HIGH BYTE PRESERVE ERROR = 0x%04x expected=0xBBAA", &A<v0x74b08cd20, 8> {0 0 0};
%vpi_call/w 3 363 "$fatal" {0 0 0};
%jmp T_6.14;
T_6.13 ;
%vpi_call/w 3 367 "$display", "HIGH BYTE PRESERVE 0x12AA -> 0xBBAA PASS" {0 0 0};
T_6.14 ;
%pushi/vec4 32, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 255, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 33, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 128, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 34, 0, 22;
%store/vec4 v0x74b08c500_0, 0, 22;
%pushi/vec4 127, 0, 8;
%store/vec4 v0x74b08c5a0_0, 0, 8;
%fork TD_tb.write_byte, S_0x102cd1300;
%join;
%pushi/vec4 32, 0, 22;
%store/vec4 v0x74b08c3c0_0, 0, 22;
%pushi/vec4 255, 0, 8;
%store/vec4 v0x74b08c460_0, 0, 8;
%fork TD_tb.read_byte, S_0x102cd1180;
%join;
%pushi/vec4 33, 0, 22;
%store/vec4 v0x74b08c3c0_0, 0, 22;
%pushi/vec4 128, 0, 8;
%store/vec4 v0x74b08c460_0, 0, 8;
%fork TD_tb.read_byte, S_0x102cd1180;
%join;
%pushi/vec4 34, 0, 22;
%store/vec4 v0x74b08c3c0_0, 0, 22;
%pushi/vec4 127, 0, 8;
%store/vec4 v0x74b08c460_0, 0, 8;
%fork TD_tb.read_byte, S_0x102cd1180;
%join;
%vpi_call/w 3 389 "$display", "\000" {0 0 0};
%vpi_call/w 3 390 "$display", "========================================" {0 0 0};
%vpi_call/w 3 391 "$display", "INT8 MEMORY ACCESS TEST PASSED" {0 0 0};
%vpi_call/w 3 392 "$display", "BYTE ADDRESSING : PASS" {0 0 0};
%vpi_call/w 3 393 "$display", "LOW BYTE : PASS" {0 0 0};
%vpi_call/w 3 394 "$display", "HIGH BYTE : PASS" {0 0 0};
%vpi_call/w 3 395 "$display", "INT8 PACKING : PASS" {0 0 0};
%vpi_call/w 3 396 "$display", "BYTE PRESERVATION : PASS" {0 0 0};
%vpi_call/w 3 397 "$display", "SIGNED INT8 : PASS" {0 0 0};
%vpi_call/w 3 398 "$display", "========================================" {0 0 0};
%vpi_call/w 3 399 "$display", "\000" {0 0 0};
%vpi_call/w 3 401 "$finish" {0 0 0};
%end;
.thread T_6;
# The file index is used to find the file name in the following table.
:file_names 5;
"N/A";
"<interactive>";
"-";
"sim/int8_memory_access_tb.v";
"rtl/int8_memory_access.v";
+405
View File
@@ -0,0 +1,405 @@
`timescale 1ns/1ps
module tb;
localparam ADDR_WIDTH = 22;
localparam CLK_PERIOD = 12.5;
reg clk;
reg rst;
// ============================================================
// INT8 interface
// ============================================================
reg req;
reg wr;
reg [ADDR_WIDTH-1:0] addr;
reg signed [7:0] wdata;
wire signed [7:0] rdata;
wire ready;
// ============================================================
// Memory interface
// ============================================================
wire mem_req;
wire mem_wr;
wire [ADDR_WIDTH-1:0] mem_addr;
wire [15:0] mem_wdata;
wire mem_lb_n;
wire mem_ub_n;
wire [15:0] mem_rdata;
wire mem_ready;
// ============================================================
// DUT
// ============================================================
int8_memory_access #(
.ADDR_WIDTH(ADDR_WIDTH)
) dut (
.clk (clk),
.rst (rst),
.req (req),
.wr (wr),
.addr (addr),
.wdata (wdata),
.rdata (rdata),
.ready (ready),
.mem_req (mem_req),
.mem_wr (mem_wr),
.mem_addr (mem_addr),
.mem_wdata (mem_wdata),
.mem_lb_n (mem_lb_n),
.mem_ub_n (mem_ub_n),
.mem_rdata (mem_rdata),
.mem_ready (mem_ready)
);
// ============================================================
// Simple memory model
// ============================================================
reg [15:0] memory [0:1023];
reg [15:0] model_rdata;
reg model_ready;
integer i;
assign mem_rdata = model_rdata;
assign mem_ready = model_ready;
// ============================================================
// Clock
// ============================================================
initial begin
clk = 1'b0;
forever #(CLK_PERIOD / 2.0)
clk = ~clk;
end
// ============================================================
// VCD
// ============================================================
initial begin
$dumpfile("sim/int8_memory_access.vcd");
$dumpvars(0, tb);
end
// ============================================================
// Memory model
// ============================================================
always @(posedge clk) begin
model_ready <= 1'b0;
if (mem_req) begin
if (mem_wr) begin
if (!mem_lb_n)
memory[mem_addr][7:0] <= mem_wdata[7:0];
if (!mem_ub_n)
memory[mem_addr][15:8] <= mem_wdata[15:8];
end else begin
model_rdata <= memory[mem_addr];
end
model_ready <= 1'b1;
end
end
// ============================================================
// Write helper
// ============================================================
task write_byte;
input [ADDR_WIDTH-1:0] byte_addr;
input signed [7:0] data;
begin
@(posedge clk);
addr <= byte_addr;
wdata <= data;
wr <= 1'b1;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
$display(
"WRITE BYTE addr=0x%08x data=0x%02x PASS",
byte_addr,
data
);
@(posedge clk);
end
endtask
// ============================================================
// Read helper
// ============================================================
task read_byte;
input [ADDR_WIDTH-1:0] byte_addr;
input signed [7:0] expected;
begin
@(posedge clk);
addr <= byte_addr;
wr <= 1'b0;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
if (rdata !== expected) begin
$display(
"READ BYTE addr=0x%08x FAIL got=0x%02x expected=0x%02x",
byte_addr,
rdata,
expected
);
$fatal;
end else begin
$display(
"READ BYTE addr=0x%08x data=0x%02x PASS",
byte_addr,
rdata
);
end
@(posedge clk);
end
endtask
// ============================================================
// Test
// ============================================================
initial begin
req = 1'b0;
wr = 1'b0;
addr = 0;
wdata = 0;
model_rdata = 16'h0000;
model_ready = 1'b0;
for (i = 0; i < 1024; i = i + 1)
memory[i] = 16'h0000;
rst = 1'b1;
repeat (5)
@(posedge clk);
rst = 1'b0;
$display("");
$display("========================================");
$display("INT8 MEMORY ACCESS TEST");
$display("========================================");
$display("");
// ========================================================
// Basic byte writes
// ========================================================
write_byte(22'h000000, 8'h12);
write_byte(22'h000001, 8'h34);
write_byte(22'h000002, 8'h56);
write_byte(22'h000003, 8'h78);
// ========================================================
// Reads
// ========================================================
read_byte(22'h000000, 8'h12);
read_byte(22'h000001, 8'h34);
read_byte(22'h000002, 8'h56);
read_byte(22'h000003, 8'h78);
// ========================================================
// Verify physical packing
// ========================================================
if (memory[0] !== 16'h3412) begin
$display(
"PACKING ERROR word[0]=0x%04x expected=0x3412",
memory[0]
);
$fatal;
end else begin
$display(
"PACKING word[0] = 0x%04x PASS",
memory[0]
);
end
if (memory[1] !== 16'h7856) begin
$display(
"PACKING ERROR word[1]=0x%04x expected=0x7856",
memory[1]
);
$fatal;
end else begin
$display(
"PACKING word[1] = 0x%04x PASS",
memory[1]
);
end
// ========================================================
// Byte preservation test
// ========================================================
// Start with 0x1234
write_byte(22'h000010, 8'h34);
write_byte(22'h000011, 8'h12);
if (memory[8] !== 16'h1234) begin
$display(
"INITIAL WORD ERROR = 0x%04x",
memory[8]
);
$fatal;
end
// Change low byte only:
// 0x1234 -> 0x12AA
write_byte(22'h000010, 8'hAA);
if (memory[8] !== 16'h12AA) begin
$display(
"LOW BYTE PRESERVE ERROR = 0x%04x expected=0x12AA",
memory[8]
);
$fatal;
end else begin
$display(
"LOW BYTE PRESERVE 0x1234 -> 0x12AA PASS"
);
end
// Change high byte only:
// 0x12AA -> 0xBBAA
write_byte(22'h000011, 8'hBB);
if (memory[8] !== 16'hBBAA) begin
$display(
"HIGH BYTE PRESERVE ERROR = 0x%04x expected=0xBBAA",
memory[8]
);
$fatal;
end else begin
$display(
"HIGH BYTE PRESERVE 0x12AA -> 0xBBAA PASS"
);
end
// ========================================================
// Signed INT8 values
// ========================================================
write_byte(22'h000020, -8'sd1);
write_byte(22'h000021, -8'sd128);
write_byte(22'h000022, 8'sd127);
read_byte(22'h000020, -8'sd1);
read_byte(22'h000021, -8'sd128);
read_byte(22'h000022, 8'sd127);
// ========================================================
// Final result
// ========================================================
$display("");
$display("========================================");
$display("INT8 MEMORY ACCESS TEST PASSED");
$display("BYTE ADDRESSING : PASS");
$display("LOW BYTE : PASS");
$display("HIGH BYTE : PASS");
$display("INT8 PACKING : PASS");
$display("BYTE PRESERVATION : PASS");
$display("SIGNED INT8 : PASS");
$display("========================================");
$display("");
$finish;
end
endmodule
File diff suppressed because it is too large Load Diff
+22197
View File
File diff suppressed because one or more lines are too long
+455
View File
@@ -0,0 +1,455 @@
`timescale 1ns/1ps
module tb;
localparam ADDR_WIDTH = 22;
localparam DATA_WIDTH = 16;
localparam CLK_PERIOD = 12.5; // 80 MHz
// ============================================================
// Clock / Reset
// ============================================================
reg clk;
reg rst;
// ============================================================
// INT8 interface
// ============================================================
reg req;
reg wr;
reg [ADDR_WIDTH-1:0] addr;
reg signed [7:0] wdata;
wire signed [7:0] rdata;
wire ready;
// ============================================================
// memory_interface
// ============================================================
wire mem_req;
wire mem_wr;
wire [ADDR_WIDTH-1:0] mem_addr;
wire [DATA_WIDTH-1:0] mem_wdata;
wire mem_lb_n;
wire mem_ub_n;
wire [DATA_WIDTH-1:0] mem_rdata;
wire mem_ready;
// ============================================================
// Memory interface -> PSRAM controller
// ============================================================
wire psram_mem_req;
wire psram_mem_wr;
wire [ADDR_WIDTH-1:0] psram_mem_addr;
wire [DATA_WIDTH-1:0] psram_mem_wdata;
wire psram_mem_lb_n;
wire psram_mem_ub_n;
wire [DATA_WIDTH-1:0] psram_mem_rdata;
wire psram_mem_ready;
// ============================================================
// PSRAM physical interface
// ============================================================
wire [ADDR_WIDTH-1:0] psram_a;
wire [DATA_WIDTH-1:0] psram_dq;
wire psram_ce_n;
wire psram_oe_n;
wire psram_we_n;
wire psram_lb_n;
wire psram_ub_n;
wire psram_zz_n;
// ============================================================
// INT8 MEMORY ACCESS
// ============================================================
int8_memory_access #(
.ADDR_WIDTH(ADDR_WIDTH)
) int8_access (
.clk (clk),
.rst (rst),
.req (req),
.wr (wr),
.addr (addr),
.wdata (wdata),
.rdata (rdata),
.ready (ready),
.mem_req (mem_req),
.mem_wr (mem_wr),
.mem_addr (mem_addr),
.mem_wdata (mem_wdata),
.mem_lb_n (mem_lb_n),
.mem_ub_n (mem_ub_n),
.mem_rdata (mem_rdata),
.mem_ready (mem_ready)
);
// ============================================================
// MEMORY INTERFACE
// ============================================================
memory_interface #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH)
) memory_if (
.clk (clk),
.rst (rst),
.req (mem_req),
.wr (mem_wr),
.addr (mem_addr),
.wdata (mem_wdata),
.lb_n (mem_lb_n),
.ub_n (mem_ub_n),
.rdata (mem_rdata),
.ready (mem_ready),
.mem_req (psram_mem_req),
.mem_wr (psram_mem_wr),
.mem_addr (psram_mem_addr),
.mem_wdata (psram_mem_wdata),
.mem_lb_n (psram_mem_lb_n),
.mem_ub_n (psram_mem_ub_n),
.mem_rdata (psram_mem_rdata),
.mem_ready (psram_mem_ready)
);
// ============================================================
// PSRAM CONTROLLER
// ============================================================
psram_controller #(
.ADDR_WIDTH (ADDR_WIDTH),
.DATA_WIDTH (DATA_WIDTH),
.CLK_FREQ_MHZ (80)
) psram_ctrl (
.clk (clk),
.rst (rst),
.mem_req (psram_mem_req),
.mem_wr (psram_mem_wr),
.mem_addr (psram_mem_addr),
.mem_wdata (psram_mem_wdata),
.mem_lb_n (psram_mem_lb_n),
.mem_ub_n (psram_mem_ub_n),
.mem_rdata (psram_mem_rdata),
.mem_ready (psram_mem_ready),
.psram_a (psram_a),
.psram_dq (psram_dq),
.psram_ce_n(psram_ce_n),
.psram_oe_n(psram_oe_n),
.psram_we_n(psram_we_n),
.psram_lb_n(psram_lb_n),
.psram_ub_n(psram_ub_n),
.psram_zz_n(psram_zz_n)
);
// ============================================================
// PSRAM MODEL
// ============================================================
psram_model #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(16384)
) psram (
.clk (clk),
.a (psram_a),
.dq (psram_dq),
.ce_n (psram_ce_n),
.oe_n (psram_oe_n),
.we_n (psram_we_n),
.lb_n (psram_lb_n),
.ub_n (psram_ub_n),
.zz_n (psram_zz_n)
);
// ============================================================
// Clock
// ============================================================
initial begin
clk = 1'b0;
forever #(CLK_PERIOD / 2.0)
clk = ~clk;
end
// ============================================================
// VCD
// ============================================================
initial begin
$dumpfile("sim/int8_psram_integration.vcd");
$dumpvars(0, tb);
end
// ============================================================
// Write INT8
// ============================================================
task write_byte;
input [ADDR_WIDTH-1:0] byte_addr;
input signed [7:0] data;
begin
@(posedge clk);
addr <= byte_addr;
wdata <= data;
wr <= 1'b1;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
$display(
"WRITE BYTE addr=0x%08x data=0x%02x PASS",
byte_addr,
data
);
@(posedge clk);
end
endtask
// ============================================================
// Read INT8
// ============================================================
task read_byte;
input [ADDR_WIDTH-1:0] byte_addr;
input signed [7:0] expected;
begin
@(posedge clk);
addr <= byte_addr;
wr <= 1'b0;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
if (rdata !== expected) begin
$display(
"READ BYTE addr=0x%08x FAIL got=0x%02x expected=0x%02x",
byte_addr,
rdata,
expected
);
$fatal;
end else begin
$display(
"READ BYTE addr=0x%08x data=0x%02x PASS",
byte_addr,
rdata
);
end
@(posedge clk);
end
endtask
// ============================================================
// Test
// ============================================================
integer i;
integer test_addr;
reg signed [7:0] test_data;
initial begin
req = 1'b0;
wr = 1'b0;
addr = 0;
wdata = 0;
rst = 1'b1;
repeat (5)
@(posedge clk);
rst = 1'b0;
$display("");
$display("========================================");
$display("INT8 + PSRAM FULL INTEGRATION TEST");
$display("========================================");
$display("");
// --------------------------------------------------------
// Wait for PSRAM initialization
// --------------------------------------------------------
wait (psram_ctrl.state == psram_ctrl.STATE_IDLE);
$display("PSRAM initialization complete");
$display("");
// ========================================================
// BASIC INT8 PACKING
// ========================================================
write_byte(22'h000000, 8'h12);
write_byte(22'h000001, 8'h34);
write_byte(22'h000002, 8'h56);
write_byte(22'h000003, 8'h78);
read_byte(22'h000000, 8'h12);
read_byte(22'h000001, 8'h34);
read_byte(22'h000002, 8'h56);
read_byte(22'h000003, 8'h78);
// ========================================================
// BYTE PRESERVATION
// ========================================================
write_byte(22'h000010, 8'h34);
write_byte(22'h000011, 8'h12);
write_byte(22'h000010, 8'hAA);
read_byte(22'h000010, 8'hAA);
read_byte(22'h000011, 8'h12);
write_byte(22'h000011, 8'hBB);
read_byte(22'h000010, 8'hAA);
read_byte(22'h000011, 8'hBB);
// ========================================================
// SIGNED INT8
// ========================================================
write_byte(22'h000020, -8'sd1);
write_byte(22'h000021, -8'sd128);
write_byte(22'h000022, 8'sd127);
read_byte(22'h000020, -8'sd1);
read_byte(22'h000021, -8'sd128);
read_byte(22'h000022, 8'sd127);
// ========================================================
// SPARSE ADDRESSES
// ========================================================
write_byte(22'h000100, 8'h11);
write_byte(22'h000101, 8'h22);
write_byte(22'h001000, 8'h33);
write_byte(22'h001001, 8'h44);
write_byte(22'h003FFE, 8'h55);
write_byte(22'h003FFF, 8'h66);
read_byte(22'h000100, 8'h11);
read_byte(22'h000101, 8'h22);
read_byte(22'h001000, 8'h33);
read_byte(22'h001001, 8'h44);
read_byte(22'h003FFE, 8'h55);
read_byte(22'h003FFF, 8'h66);
// ========================================================
// STRESS TEST
// ========================================================
$display("");
$display("========================================");
$display("INT8 PSRAM STRESS TEST");
$display("2048 WRITE + READ BYTE TRANSACTIONS");
$display("========================================");
$display("");
for (i = 0; i < 2048; i = i + 1) begin
test_addr =
((i * 7919) ^ (i << 5)) & 16'h7FFF;
test_data =
((i * 1237) ^ 8'hA5);
write_byte(
test_addr,
test_data
);
read_byte(
test_addr,
test_data
);
if ((i % 128) == 0)
$display(
"STRESS %0d / 2048 PASS",
i
);
end
// ========================================================
// Final result
// ========================================================
$display("");
$display("========================================");
$display("INT8 + PSRAM INTEGRATION TEST PASSED");
$display("BYTE ADDRESSING : PASS");
$display("LB# / UB# : PASS");
$display("INT8 PACKING : PASS");
$display("BYTE PRESERVATION : PASS");
$display("SIGNED INT8 : PASS");
$display("SPARSE ADDRESSES : PASS");
$display("2048 STRESS : PASS");
$display("========================================");
$display("");
$finish;
end
endmodule
File diff suppressed because it is too large Load Diff
+504
View File
@@ -0,0 +1,504 @@
#! /opt/homebrew/Cellar/icarus-verilog/13.0/bin/vvp
:ivl_version "13.0 (stable)" "(v13_0)";
:ivl_delay_selection "TYPICAL";
:vpi_time_precision - 12;
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/system.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/vhdl_sys.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/vhdl_textio.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/v2005_math.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/va_math.vpi";
:vpi_module "/opt/homebrew/Cellar/icarus-verilog/13.0/lib/ivl/v2009.vpi";
S_0x1008dc9a0 .scope package, "$unit" "$unit" 2 1;
.timescale 0 0;
S_0x1008dbb60 .scope module, "memory_interface_tb" "memory_interface_tb" 3 3;
.timescale -9 -12;
P_0x1008dbce0 .param/l "ADDR_WIDTH" 0 3 5, +C4<00000000000000000000000000010110>;
P_0x1008dbd20 .param/l "DATA_WIDTH" 0 3 6, +C4<00000000000000000000000000010000>;
v0x83f094e60_0 .var "addr", 21 0;
v0x83f094f00_0 .var "clk", 0 0;
v0x83f094fa0_0 .net "mem_addr", 21 0, v0x1008cea80_0; 1 drivers
v0x83f095040_0 .net "mem_rdata", 15 0, v0x83f094780_0; 1 drivers
v0x83f0950e0_0 .net "mem_ready", 0 0, v0x83f094820_0; 1 drivers
v0x83f095180_0 .net "mem_req", 0 0, v0x1008d8580_0; 1 drivers
v0x83f095220_0 .net "mem_wdata", 15 0, v0x1008d8620_0; 1 drivers
v0x83f0952c0_0 .net "mem_wr", 0 0, v0x1008d86c0_0; 1 drivers
v0x83f095360_0 .net "rdata", 15 0, v0x1008d8760_0; 1 drivers
v0x83f095400_0 .net "ready", 0 0, v0x1008d8800_0; 1 drivers
v0x83f0954a0_0 .var "req", 0 0;
v0x83f095540_0 .var "rst", 0 0;
v0x83f0955e0_0 .var "wdata", 15 0;
v0x83f095680_0 .var "wr", 0 0;
S_0x1008d97e0 .scope module, "dut" "memory_interface" 3 46, 4 1 0, S_0x1008dbb60;
.timescale -9 -12;
.port_info 0 /INPUT 1 "clk";
.port_info 1 /INPUT 1 "rst";
.port_info 2 /INPUT 1 "req";
.port_info 3 /INPUT 1 "wr";
.port_info 4 /INPUT 22 "addr";
.port_info 5 /INPUT 16 "wdata";
.port_info 6 /OUTPUT 16 "rdata";
.port_info 7 /OUTPUT 1 "ready";
.port_info 8 /OUTPUT 1 "mem_req";
.port_info 9 /OUTPUT 1 "mem_wr";
.port_info 10 /OUTPUT 22 "mem_addr";
.port_info 11 /OUTPUT 16 "mem_wdata";
.port_info 12 /INPUT 16 "mem_rdata";
.port_info 13 /INPUT 1 "mem_ready";
P_0x1008dcb20 .param/l "ADDR_WIDTH" 0 4 2, +C4<00000000000000000000000000010110>;
P_0x1008dcb60 .param/l "DATA_WIDTH" 0 4 3, +C4<00000000000000000000000000010000>;
P_0x1008dcba0 .param/l "STATE_IDLE" 1 4 27, C4<00>;
P_0x1008dcbe0 .param/l "STATE_WAIT" 1 4 28, C4<01>;
v0x1008ce940_0 .net "addr", 21 0, v0x83f094e60_0; 1 drivers
v0x1008ce9e0_0 .net "clk", 0 0, v0x83f094f00_0; 1 drivers
v0x1008cea80_0 .var "mem_addr", 21 0;
v0x1008ceb20_0 .net "mem_rdata", 15 0, v0x83f094780_0; alias, 1 drivers
v0x1008cebc0_0 .net "mem_ready", 0 0, v0x83f094820_0; alias, 1 drivers
v0x1008d8580_0 .var "mem_req", 0 0;
v0x1008d8620_0 .var "mem_wdata", 15 0;
v0x1008d86c0_0 .var "mem_wr", 0 0;
v0x1008d8760_0 .var "rdata", 15 0;
v0x1008d8800_0 .var "ready", 0 0;
v0x1008de100_0 .net "req", 0 0, v0x83f0954a0_0; 1 drivers
v0x1008de1a0_0 .net "rst", 0 0, v0x83f095540_0; 1 drivers
v0x83f094000_0 .var "state", 1 0;
v0x83f0940a0_0 .net "wdata", 15 0, v0x83f0955e0_0; 1 drivers
v0x83f094140_0 .net "wr", 0 0, v0x83f095680_0; 1 drivers
E_0x83ec14080 .event posedge, v0x1008ce9e0_0;
S_0x1008de240 .scope module, "memory" "memory_model" 3 76, 5 1 0, S_0x1008dbb60;
.timescale -9 -12;
.port_info 0 /INPUT 1 "clk";
.port_info 1 /INPUT 1 "rst";
.port_info 2 /INPUT 1 "req";
.port_info 3 /INPUT 1 "wr";
.port_info 4 /INPUT 22 "addr";
.port_info 5 /INPUT 16 "wdata";
.port_info 6 /OUTPUT 16 "rdata";
.port_info 7 /OUTPUT 1 "ready";
P_0x1008de3c0 .param/l "ADDR_WIDTH" 0 5 2, +C4<00000000000000000000000000010110>;
P_0x1008de400 .param/l "DATA_WIDTH" 0 5 3, +C4<00000000000000000000000000010000>;
P_0x1008de440 .param/l "DEPTH" 0 5 4, +C4<00000000000000000001000000000000>;
P_0x1008de480 .param/l "READ_LATENCY" 0 5 5, +C4<00000000000000000000000000000010>;
v0x83f0941e0_0 .net "addr", 21 0, v0x1008cea80_0; alias, 1 drivers
v0x83f094280_0 .var "busy", 0 0;
v0x83f094320_0 .net "clk", 0 0, v0x83f094f00_0; alias, 1 drivers
v0x83f0943c0_0 .var/i "delay_count", 31 0;
v0x83f094460_0 .var/i "i", 31 0;
v0x83f094500 .array "mem", 4095 0, 15 0;
v0x83f0945a0_0 .var "pending_addr", 21 0;
v0x83f094640_0 .var "pending_wdata", 15 0;
v0x83f0946e0_0 .var "pending_wr", 0 0;
v0x83f094780_0 .var "rdata", 15 0;
v0x83f094820_0 .var "ready", 0 0;
v0x83f0948c0_0 .net "req", 0 0, v0x1008d8580_0; alias, 1 drivers
v0x83f094960_0 .net "rst", 0 0, v0x83f095540_0; alias, 1 drivers
v0x83f094a00_0 .net "wdata", 15 0, v0x1008d8620_0; alias, 1 drivers
v0x83f094aa0_0 .net "wr", 0 0, v0x1008d86c0_0; alias, 1 drivers
S_0x1008ded00 .scope task, "read_mem" "read_mem" 3 120, 3 120 0, S_0x1008dbb60;
.timescale -9 -12;
v0x83f094b40_0 .var "address", 21 0;
v0x83f094be0_0 .var "expected", 15 0;
v0x83f094c80_0 .var "received", 15 0;
E_0x83ec17000 .event anyedge, v0x1008d8800_0;
TD_memory_interface_tb.read_mem ;
%wait E_0x83ec14080;
%load/vec4 v0x83f094b40_0;
%assign/vec4 v0x83f094e60_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f095680_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x83f0954a0_0, 0;
%wait E_0x83ec14080;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f0954a0_0, 0;
T_0.0 ;
%load/vec4 v0x83f095400_0;
%cmpi/ne 1, 0, 1;
%jmp/0xz T_0.1, 6;
%wait E_0x83ec17000;
%jmp T_0.0;
T_0.1 ;
%load/vec4 v0x83f095360_0;
%store/vec4 v0x83f094c80_0, 0, 16;
%wait E_0x83ec14080;
%load/vec4 v0x83f094c80_0;
%load/vec4 v0x83f094be0_0;
%cmp/e;
%jmp/0xz T_0.2, 6;
%vpi_call/w 3 144 "$display", "READ addr=0x%08h data=0x%04h PASS", v0x83f094b40_0, v0x83f094c80_0 {0 0 0};
%jmp T_0.3;
T_0.2 ;
%vpi_call/w 3 150 "$display", "READ addr=0x%08h got=0x%04h expected=0x%04h FAIL", v0x83f094b40_0, v0x83f094c80_0, v0x83f094be0_0 {0 0 0};
%vpi_call/w 3 157 "$fatal" {0 0 0};
T_0.3 ;
%end;
S_0x1008dee80 .scope task, "write_mem" "write_mem" 3 93, 3 93 0, S_0x1008dbb60;
.timescale -9 -12;
v0x83f094d20_0 .var "address", 21 0;
v0x83f094dc0_0 .var "data", 15 0;
TD_memory_interface_tb.write_mem ;
%wait E_0x83ec14080;
%load/vec4 v0x83f094d20_0;
%assign/vec4 v0x83f094e60_0, 0;
%load/vec4 v0x83f094dc0_0;
%assign/vec4 v0x83f0955e0_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x83f095680_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x83f0954a0_0, 0;
%wait E_0x83ec14080;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f0954a0_0, 0;
T_1.4 ;
%load/vec4 v0x83f095400_0;
%cmpi/ne 1, 0, 1;
%jmp/0xz T_1.5, 6;
%wait E_0x83ec17000;
%jmp T_1.4;
T_1.5 ;
%wait E_0x83ec14080;
%vpi_call/w 3 112 "$display", "WRITE addr=0x%08h data=0x%04h PASS", v0x83f094d20_0, v0x83f094dc0_0 {0 0 0};
%end;
.scope S_0x1008d97e0;
T_2 ;
%wait E_0x83ec14080;
%load/vec4 v0x1008de1a0_0;
%flag_set/vec4 8;
%jmp/0xz T_2.0, 8;
%pushi/vec4 0, 0, 2;
%assign/vec4 v0x83f094000_0, 0;
%pushi/vec4 0, 0, 16;
%assign/vec4 v0x1008d8760_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x1008d8800_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x1008d8580_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x1008d86c0_0, 0;
%pushi/vec4 0, 0, 22;
%assign/vec4 v0x1008cea80_0, 0;
%pushi/vec4 0, 0, 16;
%assign/vec4 v0x1008d8620_0, 0;
%jmp T_2.1;
T_2.0 ;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x1008d8800_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x1008d8580_0, 0;
%load/vec4 v0x83f094000_0;
%dup/vec4;
%pushi/vec4 0, 0, 2;
%cmp/u;
%jmp/1 T_2.2, 6;
%dup/vec4;
%pushi/vec4 1, 0, 2;
%cmp/u;
%jmp/1 T_2.3, 6;
%pushi/vec4 0, 0, 2;
%assign/vec4 v0x83f094000_0, 0;
%jmp T_2.5;
T_2.2 ;
%load/vec4 v0x1008de100_0;
%flag_set/vec4 8;
%jmp/0xz T_2.6, 8;
%load/vec4 v0x83f094140_0;
%assign/vec4 v0x1008d86c0_0, 0;
%load/vec4 v0x1008ce940_0;
%assign/vec4 v0x1008cea80_0, 0;
%load/vec4 v0x83f0940a0_0;
%assign/vec4 v0x1008d8620_0, 0;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x1008d8580_0, 0;
%pushi/vec4 1, 0, 2;
%assign/vec4 v0x83f094000_0, 0;
T_2.6 ;
%jmp T_2.5;
T_2.3 ;
%load/vec4 v0x1008cebc0_0;
%flag_set/vec4 8;
%jmp/0xz T_2.8, 8;
%load/vec4 v0x1008d86c0_0;
%nor/r;
%flag_set/vec4 8;
%jmp/0xz T_2.10, 8;
%load/vec4 v0x1008ceb20_0;
%assign/vec4 v0x1008d8760_0, 0;
T_2.10 ;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x1008d8800_0, 0;
%pushi/vec4 0, 0, 2;
%assign/vec4 v0x83f094000_0, 0;
T_2.8 ;
%jmp T_2.5;
T_2.5 ;
%pop/vec4 1;
T_2.1 ;
%jmp T_2;
.thread T_2;
.scope S_0x1008de240;
T_3 ;
%wait E_0x83ec14080;
%load/vec4 v0x83f094960_0;
%flag_set/vec4 8;
%jmp/0xz T_3.0, 8;
%pushi/vec4 0, 0, 16;
%assign/vec4 v0x83f094780_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f094820_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f094280_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f0946e0_0, 0;
%pushi/vec4 0, 0, 22;
%assign/vec4 v0x83f0945a0_0, 0;
%pushi/vec4 0, 0, 16;
%assign/vec4 v0x83f094640_0, 0;
%pushi/vec4 0, 0, 32;
%assign/vec4 v0x83f0943c0_0, 0;
%pushi/vec4 0, 0, 32;
%store/vec4 v0x83f094460_0, 0, 32;
T_3.2 ; Top of for-loop
%load/vec4 v0x83f094460_0;
%cmpi/s 4096, 0, 32;
%jmp/0xz T_3.3, 5;
%pushi/vec4 0, 0, 16;
%ix/getv/s 3, v0x83f094460_0;
%ix/load 4, 0, 0; Constant delay
%assign/vec4/a/d v0x83f094500, 0, 4;
T_3.4 ; for-loop step statement
%load/vec4 v0x83f094460_0;
%addi 1, 0, 32;
%store/vec4 v0x83f094460_0, 0, 32;
%jmp T_3.2;
T_3.3 ; for-loop exit label
%jmp T_3.1;
T_3.0 ;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f094820_0, 0;
%load/vec4 v0x83f094280_0;
%nor/r;
%flag_set/vec4 8;
%jmp/0xz T_3.5, 8;
%load/vec4 v0x83f0948c0_0;
%flag_set/vec4 8;
%jmp/0xz T_3.7, 8;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x83f094280_0, 0;
%load/vec4 v0x83f094aa0_0;
%assign/vec4 v0x83f0946e0_0, 0;
%load/vec4 v0x83f0941e0_0;
%assign/vec4 v0x83f0945a0_0, 0;
%load/vec4 v0x83f094a00_0;
%assign/vec4 v0x83f094640_0, 0;
%pushi/vec4 2, 0, 32;
%assign/vec4 v0x83f0943c0_0, 0;
T_3.7 ;
%jmp T_3.6;
T_3.5 ;
%load/vec4 v0x83f0943c0_0;
%cmpi/s 0, 0, 32;
%flag_or 5, 4; GT is !LE
%flag_inv 5;
%jmp/0xz T_3.9, 5;
%load/vec4 v0x83f0943c0_0;
%subi 1, 0, 32;
%assign/vec4 v0x83f0943c0_0, 0;
%jmp T_3.10;
T_3.9 ;
%load/vec4 v0x83f0946e0_0;
%flag_set/vec4 8;
%jmp/0xz T_3.11, 8;
%load/vec4 v0x83f0945a0_0;
%pad/u 32;
%cmpi/u 4096, 0, 32;
%jmp/0xz T_3.13, 5;
%load/vec4 v0x83f094640_0;
%ix/getv 3, v0x83f0945a0_0;
%ix/load 4, 0, 0; Constant delay
%assign/vec4/a/d v0x83f094500, 0, 4;
T_3.13 ;
%jmp T_3.12;
T_3.11 ;
%load/vec4 v0x83f0945a0_0;
%pad/u 32;
%cmpi/u 4096, 0, 32;
%jmp/0xz T_3.15, 5;
%ix/getv 4, v0x83f0945a0_0;
%load/vec4a v0x83f094500, 4;
%assign/vec4 v0x83f094780_0, 0;
%jmp T_3.16;
T_3.15 ;
%pushi/vec4 0, 0, 16;
%assign/vec4 v0x83f094780_0, 0;
T_3.16 ;
T_3.12 ;
%pushi/vec4 1, 0, 1;
%assign/vec4 v0x83f094820_0, 0;
%pushi/vec4 0, 0, 1;
%assign/vec4 v0x83f094280_0, 0;
T_3.10 ;
T_3.6 ;
T_3.1 ;
%jmp T_3;
.thread T_3;
.scope S_0x1008dbb60;
T_4 ;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x83f094f00_0, 0, 1;
T_4.0 ;
%delay 5000, 0;
%load/vec4 v0x83f094f00_0;
%inv;
%store/vec4 v0x83f094f00_0, 0, 1;
%jmp T_4.0;
T_4.1 ;
%end;
.thread T_4;
.scope S_0x1008dbb60;
T_5 ;
%pushi/vec4 1, 0, 1;
%store/vec4 v0x83f095540_0, 0, 1;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x83f0954a0_0, 0, 1;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x83f095680_0, 0, 1;
%pushi/vec4 0, 0, 22;
%store/vec4 v0x83f094e60_0, 0, 22;
%pushi/vec4 0, 0, 16;
%store/vec4 v0x83f0955e0_0, 0, 16;
%pushi/vec4 3, 0, 32;
T_5.0 %dup/vec4;
%cmpi/s 0, 0, 32;
%jmp/1xz T_5.1, 5;
%jmp/1 T_5.1, 4;
%subi 1, 0, 32;
%wait E_0x83ec14080;
%jmp T_5.0;
T_5.1 ;
%pop/vec4 1;
%pushi/vec4 0, 0, 1;
%store/vec4 v0x83f095540_0, 0, 1;
%vpi_call/w 3 182 "$display", "\000" {0 0 0};
%vpi_call/w 3 183 "$display", "========================================" {0 0 0};
%vpi_call/w 3 184 "$display", "MEMORY INTERFACE V1 TEST" {0 0 0};
%vpi_call/w 3 185 "$display", "ADDR_WIDTH = %0d", P_0x1008dbce0 {0 0 0};
%vpi_call/w 3 186 "$display", "DATA_WIDTH = %0d", P_0x1008dbd20 {0 0 0};
%vpi_call/w 3 187 "$display", "========================================" {0 0 0};
%vpi_call/w 3 188 "$display", "\000" {0 0 0};
%pushi/vec4 1, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 4660, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 1, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 4660, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%pushi/vec4 16, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 43981, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 16, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 43981, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%pushi/vec4 256, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 21930, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 256, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 21930, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%pushi/vec4 512, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 1, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 513, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 2, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 514, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 3, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 512, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 1, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%pushi/vec4 513, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 2, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%pushi/vec4 514, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 3, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%pushi/vec4 768, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 0, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 768, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 0, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%pushi/vec4 769, 0, 22;
%store/vec4 v0x83f094d20_0, 0, 22;
%pushi/vec4 65535, 0, 16;
%store/vec4 v0x83f094dc0_0, 0, 16;
%fork TD_memory_interface_tb.write_mem, S_0x1008dee80;
%join;
%pushi/vec4 769, 0, 22;
%store/vec4 v0x83f094b40_0, 0, 22;
%pushi/vec4 65535, 0, 16;
%store/vec4 v0x83f094be0_0, 0, 16;
%fork TD_memory_interface_tb.read_mem, S_0x1008ded00;
%join;
%vpi_call/w 3 301 "$display", "\000" {0 0 0};
%vpi_call/w 3 302 "$display", "========================================" {0 0 0};
%vpi_call/w 3 303 "$display", "MEMORY INTERFACE V1 TEST PASSED" {0 0 0};
%vpi_call/w 3 304 "$display", "========================================" {0 0 0};
%vpi_call/w 3 305 "$display", "\000" {0 0 0};
%vpi_call/w 3 307 "$finish" {0 0 0};
%end;
.thread T_5;
.scope S_0x1008dbb60;
T_6 ;
%vpi_call/w 3 315 "$dumpfile", "sim/memory_interface.vcd" {0 0 0};
%vpi_call/w 3 316 "$dumpvars", 32'sb00000000000000000000000000000000, S_0x1008dbb60 {0 0 0};
%end;
.thread T_6;
# The file index is used to find the file name in the following table.
:file_names 6;
"N/A";
"<interactive>";
"-";
"sim/memory_interface_tb.v";
"rtl/memory_interface.v";
"rtl/memory_model.v";
+319
View File
@@ -0,0 +1,319 @@
`timescale 1ns/1ps
module memory_interface_tb;
parameter ADDR_WIDTH = 22;
parameter DATA_WIDTH = 16;
reg clk;
reg rst;
// Host side
reg req;
reg wr;
reg [ADDR_WIDTH-1:0] addr;
reg [DATA_WIDTH-1:0] wdata;
wire [DATA_WIDTH-1:0] rdata;
wire ready;
// Memory side
wire mem_req;
wire mem_wr;
wire [ADDR_WIDTH-1:0] mem_addr;
wire [DATA_WIDTH-1:0] mem_wdata;
wire [DATA_WIDTH-1:0] mem_rdata;
wire mem_ready;
// ------------------------------------------------------------
// Clock
// ------------------------------------------------------------
initial begin
clk = 1'b0;
forever #5 clk = ~clk;
end
// ------------------------------------------------------------
// DUT: Memory Interface
// ------------------------------------------------------------
memory_interface #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH)
) dut (
.clk(clk),
.rst(rst),
.req(req),
.wr(wr),
.addr(addr),
.wdata(wdata),
.rdata(rdata),
.ready(ready),
.mem_req(mem_req),
.mem_wr(mem_wr),
.mem_addr(mem_addr),
.mem_wdata(mem_wdata),
.mem_rdata(mem_rdata),
.mem_ready(mem_ready)
);
// ------------------------------------------------------------
// Memory model
// ------------------------------------------------------------
memory_model #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(4096),
.READ_LATENCY(2)
) memory (
.clk(clk),
.rst(rst),
.req(mem_req),
.wr(mem_wr),
.addr(mem_addr),
.wdata(mem_wdata),
.rdata(mem_rdata),
.ready(mem_ready)
);
// ------------------------------------------------------------
// Test utilities
// ------------------------------------------------------------
task write_mem;
input [ADDR_WIDTH-1:0] address;
input [DATA_WIDTH-1:0] data;
begin
@(posedge clk);
addr <= address;
wdata <= data;
wr <= 1'b1;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
@(posedge clk);
$display(
"WRITE addr=0x%08h data=0x%04h PASS",
address,
data
);
end
endtask
task read_mem;
input [ADDR_WIDTH-1:0] address;
input [DATA_WIDTH-1:0] expected;
reg [DATA_WIDTH-1:0] received;
begin
@(posedge clk);
addr <= address;
wr <= 1'b0;
req <= 1'b1;
@(posedge clk);
req <= 1'b0;
wait (ready);
received = rdata;
@(posedge clk);
if (received === expected) begin
$display(
"READ addr=0x%08h data=0x%04h PASS",
address,
received
);
end else begin
$display(
"READ addr=0x%08h got=0x%04h expected=0x%04h FAIL",
address,
received,
expected
);
$fatal;
end
end
endtask
// ------------------------------------------------------------
// Test sequence
// ------------------------------------------------------------
initial begin
// Defaults
rst = 1'b1;
req = 1'b0;
wr = 1'b0;
addr = {ADDR_WIDTH{1'b0}};
wdata = {DATA_WIDTH{1'b0}};
// Reset
repeat (3)
@(posedge clk);
rst = 1'b0;
$display("");
$display("========================================");
$display("MEMORY INTERFACE V1 TEST");
$display("ADDR_WIDTH = %0d", ADDR_WIDTH);
$display("DATA_WIDTH = %0d", DATA_WIDTH);
$display("========================================");
$display("");
// --------------------------------------------------------
// Test 1
// --------------------------------------------------------
write_mem(
22'h000001,
16'h1234
);
read_mem(
22'h000001,
16'h1234
);
// --------------------------------------------------------
// Test 2
// --------------------------------------------------------
write_mem(
22'h000010,
16'hABCD
);
read_mem(
22'h000010,
16'hABCD
);
// --------------------------------------------------------
// Test 3
// --------------------------------------------------------
write_mem(
22'h000100,
16'h55AA
);
read_mem(
22'h000100,
16'h55AA
);
// --------------------------------------------------------
// Test 4
// --------------------------------------------------------
// Consecutive different addresses
write_mem(
22'h000200,
16'h0001
);
write_mem(
22'h000201,
16'h0002
);
write_mem(
22'h000202,
16'h0003
);
read_mem(
22'h000200,
16'h0001
);
read_mem(
22'h000201,
16'h0002
);
read_mem(
22'h000202,
16'h0003
);
// --------------------------------------------------------
// Test 5
// --------------------------------------------------------
// Zero value
write_mem(
22'h000300,
16'h0000
);
read_mem(
22'h000300,
16'h0000
);
// --------------------------------------------------------
// Test 6
// --------------------------------------------------------
// Full 16-bit value
write_mem(
22'h000301,
16'hFFFF
);
read_mem(
22'h000301,
16'hFFFF
);
// --------------------------------------------------------
// Finished
// --------------------------------------------------------
$display("");
$display("========================================");
$display("MEMORY INTERFACE V1 TEST PASSED");
$display("========================================");
$display("");
$finish;
end
// ------------------------------------------------------------
// VCD
// ------------------------------------------------------------
initial begin
$dumpfile("sim/memory_interface.vcd");
$dumpvars(0, memory_interface_tb);
end
endmodule
+73405
View File
File diff suppressed because it is too large Load Diff
+23299
View File
File diff suppressed because one or more lines are too long
+625
View File
@@ -0,0 +1,625 @@
`timescale 1ns/1ps
module tb;
localparam ADDR_WIDTH = 22;
localparam DATA_WIDTH = 16;
localparam CLK_PERIOD = 12.5; // 80 MHz
// ============================================================
// CLOCK / RESET
// ============================================================
reg clk;
reg rst;
initial begin
clk = 1'b0;
forever #(CLK_PERIOD / 2.0) clk = ~clk;
end
// ============================================================
// NEURON MEMORY
// ============================================================
reg start;
reg [ADDR_WIDTH-1:0] x_base;
reg [ADDR_WIDTH-1:0] w_base;
reg [ADDR_WIDTH-1:0] bias_addr;
wire signed [7:0] y;
wire busy;
wire done;
// neuron_memory -> memory_interface
wire neuron_mem_req;
wire neuron_mem_wr;
wire [ADDR_WIDTH-1:0] neuron_mem_addr;
wire signed [7:0] neuron_mem_wdata;
wire signed [7:0] neuron_mem_rdata;
wire neuron_mem_ready;
// ============================================================
// TB PRELOAD MASTER
//
// Direct 16-bit master.
// Used only before starting neuron_memory.
// ============================================================
reg tb_mem_req;
reg tb_mem_wr;
reg [ADDR_WIDTH-1:0] tb_mem_addr;
reg [DATA_WIDTH-1:0] tb_mem_wdata;
reg tb_mem_lb_n;
reg tb_mem_ub_n;
wire [DATA_WIDTH-1:0] tb_mem_rdata;
wire tb_mem_ready;
// ============================================================
// SINGLE MASTER MUX
//
// 0 = TB preload master
// 1 = neuron_memory master
// ============================================================
reg use_neuron_master;
wire master_req;
wire master_wr;
wire [ADDR_WIDTH-1:0] master_addr;
wire [DATA_WIDTH-1:0] master_wdata;
wire master_lb_n;
wire master_ub_n;
// ============================================================
// MEMORY INTERFACE
// ============================================================
wire [DATA_WIDTH-1:0] memory_rdata;
wire memory_ready;
wire memory_mem_req;
wire memory_mem_wr;
wire [ADDR_WIDTH-1:0] memory_mem_addr;
wire [DATA_WIDTH-1:0] memory_mem_wdata;
wire memory_mem_lb_n;
wire memory_mem_ub_n;
wire [DATA_WIDTH-1:0] psram_mem_rdata;
wire psram_mem_ready;
assign master_req =
use_neuron_master ? neuron_mem_req : tb_mem_req;
assign master_wr =
use_neuron_master ? neuron_mem_wr : tb_mem_wr;
assign master_addr =
use_neuron_master ? (neuron_mem_addr >> 1) : tb_mem_addr;
assign master_wdata =
use_neuron_master
? (neuron_mem_addr[0]
? {neuron_mem_wdata, 8'h00}
: {8'h00, neuron_mem_wdata})
: tb_mem_wdata;
assign master_lb_n =
use_neuron_master
? (neuron_mem_addr[0] ? 1'b1 : 1'b0)
: tb_mem_lb_n;
assign master_ub_n =
use_neuron_master
? (neuron_mem_addr[0] ? 1'b0 : 1'b1)
: tb_mem_ub_n;
// Return path
assign tb_mem_rdata = memory_rdata;
assign tb_mem_ready = memory_ready;
assign neuron_mem_rdata =
neuron_mem_addr[0]
? memory_rdata[15:8]
: memory_rdata[7:0];
assign neuron_mem_ready = memory_ready;
memory_interface #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH)
) u_memory_if (
.clk(clk),
.rst(rst),
.req(master_req),
.wr(master_wr),
.addr(master_addr),
.wdata(master_wdata),
.lb_n(master_lb_n),
.ub_n(master_ub_n),
.rdata(memory_rdata),
.ready(memory_ready),
.mem_req(memory_mem_req),
.mem_wr(memory_mem_wr),
.mem_addr(memory_mem_addr),
.mem_wdata(memory_mem_wdata),
.mem_lb_n(memory_mem_lb_n),
.mem_ub_n(memory_mem_ub_n),
.mem_rdata(psram_mem_rdata),
.mem_ready(psram_mem_ready)
);
// ============================================================
// PSRAM PHYSICAL INTERFACE
// ============================================================
wire [ADDR_WIDTH-1:0] psram_a;
wire [DATA_WIDTH-1:0] psram_dq;
wire psram_ce_n;
wire psram_oe_n;
wire psram_we_n;
wire psram_lb_n;
wire psram_ub_n;
wire psram_zz_n;
// ============================================================
// PSRAM CONTROLLER
// ============================================================
psram_controller #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.CLK_FREQ_MHZ(80)
) u_psram_ctrl (
.clk(clk),
.rst(rst),
.mem_req(memory_mem_req),
.mem_wr(memory_mem_wr),
.mem_addr(memory_mem_addr),
.mem_wdata(memory_mem_wdata),
.mem_lb_n(memory_mem_lb_n),
.mem_ub_n(memory_mem_ub_n),
.mem_rdata(psram_mem_rdata),
.mem_ready(psram_mem_ready),
.psram_a(psram_a),
.psram_dq(psram_dq),
.psram_ce_n(psram_ce_n),
.psram_oe_n(psram_oe_n),
.psram_we_n(psram_we_n),
.psram_lb_n(psram_lb_n),
.psram_ub_n(psram_ub_n),
.psram_zz_n(psram_zz_n)
);
// ============================================================
// PSRAM MODEL
// ============================================================
psram_model #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(16384)
) u_psram (
.clk(clk),
.a(psram_a),
.dq(psram_dq),
.ce_n(psram_ce_n),
.oe_n(psram_oe_n),
.we_n(psram_we_n),
.lb_n(psram_lb_n),
.ub_n(psram_ub_n),
.zz_n(psram_zz_n)
);
// ============================================================
// NEURON MEMORY
// ============================================================
neuron_memory #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(8),
.N_INPUTS(32),
.PARALLEL(8),
.ACC_WIDTH(32)
) u_neuron (
.clk(clk),
.rst(rst),
.start(start),
.mem_req(neuron_mem_req),
.mem_wr(neuron_mem_wr),
.mem_addr(neuron_mem_addr),
.mem_wdata(neuron_mem_wdata),
.mem_rdata(neuron_mem_rdata),
.mem_ready(neuron_mem_ready),
.x_base(x_base),
.w_base(w_base),
.bias_addr(bias_addr),
.y(y),
.busy(busy),
.done(done)
);
// ============================================================
// TB WORD WRITE
//
// Directly through:
//
// TB -> memory_interface -> psram_controller -> PSRAM
//
// No force.
// ============================================================
task tb_write_word;
input [ADDR_WIDTH-1:0] addr_i;
input [15:0] data_i;
begin
@(posedge clk);
tb_mem_addr <= addr_i;
tb_mem_wdata <= data_i;
tb_mem_wr <= 1'b1;
tb_mem_lb_n <= 1'b0;
tb_mem_ub_n <= 1'b0;
tb_mem_req <= 1'b1;
@(posedge clk);
tb_mem_req <= 1'b0;
wait (tb_mem_ready);
@(posedge clk);
end
endtask
// ============================================================
// PRELOAD 32 INT8 VALUES
//
// Two INT8 values per PSRAM word.
// ============================================================
task preload_vector;
input [ADDR_WIDTH-1:0] base;
input signed [7:0] value;
integer k;
begin
for (k = 0; k < 32; k = k + 2) begin
tb_write_word(
base + (k >> 1),
{value, value}
);
end
end
endtask
// ============================================================
// PRELOAD WEIGHTS
// ============================================================
task preload_weights;
input [ADDR_WIDTH-1:0] base;
input signed [7:0] value;
integer k;
begin
for (k = 0; k < 32; k = k + 2) begin
tb_write_word(
base + (k >> 1),
{value, value}
);
end
end
endtask
// ============================================================
// PRELOAD BIAS
// ============================================================
task preload_bias;
input [ADDR_WIDTH-1:0] addr_i;
input signed [7:0] value;
begin
// Bias address is a BYTE address.
// Write a full word containing bias in low byte.
tb_write_word(
addr_i >> 1,
{8'h00, value}
);
end
endtask
// ============================================================
// RUN NEURON
// ============================================================
task run_neuron;
input signed [7:0] expected;
input [127:0] test_name;
begin
@(posedge clk);
start <= 1'b1;
@(posedge clk);
start <= 1'b0;
wait (done);
if (y !== expected) begin
$display("");
$display("FAIL %s", test_name);
$display(
" got = %0d (0x%02x)",
y,
y
);
$display(
" expected = %0d (0x%02x)",
expected,
expected
);
$fatal;
end else begin
$display(
"PASS %-16s y=%0d (0x%02x)",
test_name,
y,
y
);
end
@(posedge clk);
end
endtask
// ============================================================
// TEST
// ============================================================
integer i;
initial begin
// --------------------------------------------------------
// Initial values
// --------------------------------------------------------
start = 1'b0;
x_base = 22'h000000;
w_base = 22'h000100;
bias_addr = 22'h000200;
tb_mem_req = 1'b0;
tb_mem_wr = 1'b0;
tb_mem_addr = 0;
tb_mem_wdata = 0;
tb_mem_lb_n = 1'b1;
tb_mem_ub_n = 1'b1;
use_neuron_master = 1'b0;
rst = 1'b1;
// --------------------------------------------------------
// VCD
// --------------------------------------------------------
$dumpfile("sim/neuron_memory.vcd");
$dumpvars(0, tb);
repeat (5)
@(posedge clk);
rst = 1'b0;
// --------------------------------------------------------
// Wait PSRAM initialization
// --------------------------------------------------------
wait (u_psram_ctrl.state == u_psram_ctrl.STATE_IDLE);
$display("");
$display("========================================");
$display("NEURON MEMORY END-TO-END TEST");
$display("========================================");
$display("");
// ========================================================
// PRELOAD PHASE
//
// TB is the ONLY memory master.
// ========================================================
$display("PRELOAD: X = 1");
preload_vector(
x_base,
8'sd1
);
$display("PRELOAD: W = 1");
preload_weights(
w_base,
8'sd1
);
$display("PRELOAD: BIAS = 0");
preload_bias(
bias_addr,
8'sd0
);
// ========================================================
// HAND OVER MEMORY BUS
//
// From this point neuron_memory is the only master.
// ========================================================
use_neuron_master = 1'b1;
$display("");
$display("MEMORY MASTER -> neuron_memory");
$display("");
// ========================================================
// TEST 1
//
// 32 * 1 * 1 + 0 = 32
// ========================================================
run_neuron(
8'sd32,
"SUM=32"
);
// ========================================================
// TEST 2
//
// 32 * 1 * 4 = 128
// Saturated to 127.
//
// We must return control to TB to modify weights.
// ========================================================
use_neuron_master = 1'b0;
preload_weights(
w_base,
8'sd4
);
preload_bias(
bias_addr,
8'sd0
);
use_neuron_master = 1'b1;
run_neuron(
8'sd127,
"SATURATION"
);
// ========================================================
// TEST 3
//
// 32 * 1 * (-1) = -32
// ReLU -> 0
// ========================================================
use_neuron_master = 1'b0;
preload_weights(
w_base,
-8'sd1
);
preload_bias(
bias_addr,
8'sd0
);
use_neuron_master = 1'b1;
run_neuron(
8'sd0,
"RELU"
);
// ========================================================
// TEST 4
//
// 32 * 1 * 1 + 10 = 42
// ========================================================
use_neuron_master = 1'b0;
preload_weights(
w_base,
8'sd1
);
preload_bias(
bias_addr,
8'sd10
);
use_neuron_master = 1'b1;
run_neuron(
8'sd42,
"BIAS=10"
);
// ========================================================
// FINAL
// ========================================================
$display("");
$display("========================================");
$display("NEURON MEMORY TEST PASSED");
$display("========================================");
$display("PSRAM -> INT8 -> NEURON : PASS");
$display("SUM : PASS");
$display("BIAS : PASS");
$display("ReLU : PASS");
$display("SATURATION : PASS");
$display("========================================");
$display("");
$finish;
end
endmodule
+3292 -1609
View File
File diff suppressed because one or more lines are too long
+5430
View File
File diff suppressed because it is too large Load Diff
+4242
View File
File diff suppressed because it is too large Load Diff
+2238
View File
File diff suppressed because it is too large Load Diff
+1801 -1633
View File
File diff suppressed because it is too large Load Diff
+5404
View File
File diff suppressed because it is too large Load Diff
+3350
View File
File diff suppressed because it is too large Load Diff
+5478
View File
File diff suppressed because it is too large Load Diff
+99 -193
View File
@@ -2,12 +2,11 @@
module tb;
parameter DATA_WIDTH = 16;
parameter FRAC_BITS = 8;
parameter N_INPUTS = 32;
parameter DATA_WIDTH = 8;
parameter N_INPUTS = 256;
parameter N_NEURONS = 4;
parameter PARALLEL = 8;
parameter ACC_WIDTH = 40;
parameter PARALLEL = 32;
parameter ACC_WIDTH = 32;
reg clk;
reg rst;
@@ -21,20 +20,17 @@ module tb;
reg signed [DATA_WIDTH*N_NEURONS-1:0]
bias_bus;
wire signed [DATA_WIDTH*N_NEURONS-1:0]
y_bus;
wire signed [DATA_WIDTH*N_NEURONS-1:0] y_bus;
wire busy;
wire done;
integer i;
integer n;
integer errors;
integer expected;
layer #(
.DATA_WIDTH(DATA_WIDTH),
.FRAC_BITS(FRAC_BITS),
.N_INPUTS(N_INPUTS),
.N_NEURONS(N_NEURONS),
.PARALLEL(PARALLEL),
@@ -56,13 +52,6 @@ module tb;
forever #5 clk = ~clk;
end
function signed [15:0] q8_8;
input real value;
begin
q8_8 = $rtoi(value * 256.0);
end
endfunction
task run_layer;
begin
@(posedge clk);
@@ -94,107 +83,81 @@ module tb;
rst = 0;
/*
* All inputs = 1.0
*/
for (i = 0; i < N_INPUTS; i = i + 1)
x_bus[i*DATA_WIDTH +: DATA_WIDTH] = q8_8(1.0);
* Tutti gli input = 1
*/
for (i = 0; i < N_INPUTS; i = i + 1)
x_bus[i*DATA_WIDTH +: DATA_WIDTH] = 8'sd1;
/*
* Neuron 0: weight = 1.0
* result = N_INPUTS
*/
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
0*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = q8_8(1.0);
/*
* N0:
* primi 32 pesi = 1
* restanti 224 = 0
*
* Risultato = 32
*
* Questo verifica che l'accumulatore
* attraversi correttamente tutti gli 8 gruppi.
*/
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
0*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = (i < 32) ? 8'sd1 : 8'sd0;
/*
* Neuron 1: weight = 0.5
* result = N_INPUTS / 2
*/
if (N_NEURONS > 1)
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
1*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = q8_8(0.5);
/*
* N1:
* tutti i 256 pesi = 0
* bias = 10
*
* Risultato = 10
*/
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
1*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = 8'sd0;
/*
* Neuron 2: weight = -0.5
* ReLU -> 0
*/
if (N_NEURONS > 2)
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
2*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = q8_8(-0.5);
bias_bus[1*DATA_WIDTH +: DATA_WIDTH] = 8'sd10;
/*
* Neuron 3: weight = 2.0
* Large positive result -> saturation
*/
if (N_NEURONS > 3)
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
3*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = q8_8(2.0);
/*
* N2:
* tutti i pesi = -1
*
* Risultato = -256
* ReLU -> 0
*/
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
2*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = -8'sd1;
/*
* Neuron 4: zero weights + bias +1
*/
if (N_NEURONS > 4)
bias_bus[4*DATA_WIDTH +: DATA_WIDTH] = q8_8(1.0);
/*
* Neuron 5: zero weights + bias -1
* ReLU -> 0
*/
if (N_NEURONS > 5)
bias_bus[5*DATA_WIDTH +: DATA_WIDTH] = q8_8(-1.0);
/*
* Neuron 6: weight 1.0 + bias -1.0
* result = N_INPUTS - 1
*/
if (N_NEURONS > 6) begin
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
6*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = q8_8(1.0);
bias_bus[6*DATA_WIDTH +: DATA_WIDTH] = q8_8(-1.0);
end
/*
* Neuron 7: weight 0.25 + bias 1
* result = N_INPUTS/4 + 1
*/
if (N_NEURONS > 7) begin
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
7*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = q8_8(0.25);
bias_bus[7*DATA_WIDTH +: DATA_WIDTH] = q8_8(1.0);
end
/*
* N3:
* primi 32 pesi = 4
* restanti = 0
*
* Risultato = 128
* Saturazione INT8 -> 127
*/
for (i = 0; i < N_INPUTS; i = i + 1)
weights_bus[
3*N_INPUTS*DATA_WIDTH +
i*DATA_WIDTH +:
DATA_WIDTH
] = (i < 32) ? 8'sd4 : 8'sd0;
$display("");
$display("========================================");
$display("PARAMETRIC LAYER TEST");
$display("INT8 / INT32 PARAMETRIC LAYER TEST");
$display("N_INPUTS = %0d", N_INPUTS);
$display("N_NEURONS = %0d", N_NEURONS);
$display("PARALLEL = %0d", PARALLEL);
$display("DATA_WIDTH = %0d", DATA_WIDTH);
$display("ACC_WIDTH = %0d", ACC_WIDTH);
$display("========================================");
run_layer;
@@ -202,40 +165,45 @@ module tb;
/*
* Neuron 0
*/
expected = N_INPUTS * 256;
expected = 32;
if (y_bus[0*16 +: 16] !== expected[15:0]) begin
if ($signed(y_bus[0*DATA_WIDTH +: DATA_WIDTH]) !== expected) begin
$display("FAIL N0: got %0d expected %0d",
y_bus[0*16 +: 16], expected);
$signed(y_bus[0*DATA_WIDTH +: DATA_WIDTH]),
expected);
errors = errors + 1;
end
else
$display("PASS N0: %0d", y_bus[0*16 +: 16]);
$display("PASS N0: %0d", $signed(y_bus[0*DATA_WIDTH +: DATA_WIDTH]));
/*
* Neuron 1
*/
if (N_NEURONS > 1) begin
expected = (N_INPUTS * 128);
if (y_bus[1*16 +: 16] !== expected[15:0]) begin
expected = 10;
if ($signed(y_bus[1*DATA_WIDTH +: DATA_WIDTH]) !== expected) begin
$display("FAIL N1: got %0d expected %0d",
y_bus[1*16 +: 16], expected);
$signed(y_bus[1*DATA_WIDTH +: DATA_WIDTH]),
expected);
errors = errors + 1;
end
else
$display("PASS N1: %0d", y_bus[1*16 +: 16]);
$display("PASS N1: %0d",
$signed(y_bus[1*DATA_WIDTH +: DATA_WIDTH]));
end
/*
* Neuron 2
*/
if (N_NEURONS > 2) begin
expected = 0;
if (y_bus[2*16 +: 16] !== 16'sd0) begin
if ($signed(y_bus[2*DATA_WIDTH +: DATA_WIDTH]) !== 0) begin
$display("FAIL N2: got %0d expected 0",
y_bus[2*16 +: 16]);
$signed(y_bus[2*DATA_WIDTH +: DATA_WIDTH]));
errors = errors + 1;
end
else
@@ -243,86 +211,24 @@ module tb;
end
/*
* Neuron 3:
* weight = 2.0
* result = N_INPUTS * 2.0
*
* Saturation only occurs when result > 127.996...
*/
* Neuron 3
*
* 32 * 4 = 128
* INT8 positive saturation -> 127
*/
if (N_NEURONS > 3) begin
expected = N_INPUTS * 2 * 256;
expected = 127;
if (expected > 32767)
expected = 32767;
if (y_bus[3*16 +: 16] !== expected[15:0]) begin
$display("FAIL N3: got %0d expected %0d",
y_bus[3*16 +: 16], expected);
errors = errors + 1;
end
else begin
if (expected == 32767)
$display("PASS N3: %0d (saturation)", y_bus[3*16 +: 16]);
else
$display("PASS N3: %0d", y_bus[3*16 +: 16]);
end
end
/*
* Neuron 4
*/
if (N_NEURONS > 4) begin
if (y_bus[4*16 +: 16] !== 16'sd256) begin
$display("FAIL N4: got %0d expected 256",
y_bus[4*16 +: 16]);
if ($signed(y_bus[3*DATA_WIDTH +: DATA_WIDTH]) !== expected) begin
$display("FAIL N3: got %0d expected %0d",
$signed(y_bus[3*DATA_WIDTH +: DATA_WIDTH]),
expected);
errors = errors + 1;
end
else
$display("PASS N4: 256 (bias)");
end
/*
* Neuron 5
*/
if (N_NEURONS > 5) begin
if (y_bus[5*16 +: 16] !== 16'sd0) begin
$display("FAIL N5: got %0d expected 0",
y_bus[5*16 +: 16]);
errors = errors + 1;
end
else
$display("PASS N5: 0 (negative bias + ReLU)");
end
/*
* Neuron 6
*/
if (N_NEURONS > 6) begin
expected = (N_INPUTS - 1) * 256;
if (y_bus[6*16 +: 16] !== expected[15:0]) begin
$display("FAIL N6: got %0d expected %0d",
y_bus[6*16 +: 16], expected);
errors = errors + 1;
end
else
$display("PASS N6: %0d", y_bus[6*16 +: 16]);
end
/*
* Neuron 7
*/
if (N_NEURONS > 7) begin
expected = (N_INPUTS / 4 + 1) * 256;
if (y_bus[7*16 +: 16] !== expected[15:0]) begin
$display("FAIL N7: got %0d expected %0d",
y_bus[7*16 +: 16], expected);
errors = errors + 1;
end
else
$display("PASS N7: %0d", y_bus[7*16 +: 16]);
$display("PASS N3: %0d (saturation)",
$signed(y_bus[3*DATA_WIDTH +: DATA_WIDTH]));
end
if (busy !== 0) begin
@@ -339,9 +245,9 @@ module tb;
$display("========================================");
if (errors == 0)
$display("PARAMETRIC TEST PASSED");
$display("INT8 PARAMETRIC TEST PASSED");
else
$display("PARAMETRIC TEST FAILED: %0d errors", errors);
$display("INT8 PARAMETRIC TEST FAILED: %0d errors", errors);
$display("========================================");
$display("");
@@ -349,4 +255,4 @@ module tb;
$finish;
end
endmodule
endmodule
File diff suppressed because it is too large Load Diff
+21957
View File
File diff suppressed because one or more lines are too long
+498
View File
@@ -0,0 +1,498 @@
`timescale 1ns/1ps
module tb;
localparam ADDR_WIDTH = 22;
localparam DATA_WIDTH = 16;
localparam CLK_PERIOD = 12.5; // 80 MHz
reg clk;
reg rst;
// ============================================================
// Memory Interface
// ============================================================
reg mem_req;
reg mem_wr;
reg [ADDR_WIDTH-1:0] mem_addr;
reg [DATA_WIDTH-1:0] mem_wdata;
reg mem_lb_n;
reg mem_ub_n;
wire [DATA_WIDTH-1:0] mem_rdata;
wire mem_ready;
// ============================================================
// PSRAM
// ============================================================
wire [ADDR_WIDTH-1:0] psram_a;
wire [DATA_WIDTH-1:0] psram_dq;
wire psram_ce_n;
wire psram_oe_n;
wire psram_we_n;
wire psram_lb_n;
wire psram_ub_n;
wire psram_zz_n;
// ============================================================
// Stress-test variables
// ============================================================
integer stress_i;
integer stress_addr;
reg [15:0] stress_data;
// ============================================================
// DUT
// ============================================================
psram_controller #(
.ADDR_WIDTH (ADDR_WIDTH),
.DATA_WIDTH (DATA_WIDTH),
.CLK_FREQ_MHZ (80)
) dut (
.clk (clk),
.rst (rst),
.mem_req (mem_req),
.mem_wr (mem_wr),
.mem_addr (mem_addr),
.mem_wdata (mem_wdata),
.mem_lb_n (mem_lb_n),
.mem_ub_n (mem_ub_n),
.mem_rdata (mem_rdata),
.mem_ready (mem_ready),
.psram_a (psram_a),
.psram_dq (psram_dq),
.psram_ce_n(psram_ce_n),
.psram_oe_n(psram_oe_n),
.psram_we_n(psram_we_n),
.psram_lb_n(psram_lb_n),
.psram_ub_n(psram_ub_n),
.psram_zz_n(psram_zz_n)
);
// ============================================================
// PSRAM model
// ============================================================
psram_model #(
.ADDR_WIDTH(ADDR_WIDTH),
.DATA_WIDTH(DATA_WIDTH),
.DEPTH(16384)
) memory (
.clk (clk),
.a (psram_a),
.dq (psram_dq),
.ce_n (psram_ce_n),
.oe_n (psram_oe_n),
.we_n (psram_we_n),
.lb_n (psram_lb_n),
.ub_n (psram_ub_n),
.zz_n (psram_zz_n)
);
// ============================================================
// Clock
// ============================================================
initial begin
clk = 1'b0;
forever #(CLK_PERIOD / 2.0)
clk = ~clk;
end
// ============================================================
// VCD
// ============================================================
initial begin
$dumpfile("sim/psram_controller.vcd");
$dumpvars(0, tb);
end
// ============================================================
// Helper: write word with byte enables
//
// lb_n = 0 -> low byte enabled
// ub_n = 0 -> high byte enabled
// ============================================================
task write_word;
input [ADDR_WIDTH-1:0] addr;
input [DATA_WIDTH-1:0] data;
input lb;
input ub;
begin
@(posedge clk);
mem_addr <= addr;
mem_wdata <= data;
mem_wr <= 1'b1;
mem_lb_n <= lb;
mem_ub_n <= ub;
mem_req <= 1'b1;
@(posedge clk);
mem_req <= 1'b0;
wait (mem_ready);
$display(
"WRITE addr=0x%08x data=0x%04x LB#=%b UB#=%b PASS",
addr,
data,
lb,
ub
);
@(posedge clk);
end
endtask
// ============================================================
// Helper: read full word
//
// For normal word reads both bytes are enabled.
// ============================================================
task read_word;
input [ADDR_WIDTH-1:0] addr;
input [DATA_WIDTH-1:0] expected;
begin
@(posedge clk);
mem_addr <= addr;
mem_wr <= 1'b0;
mem_lb_n <= 1'b0;
mem_ub_n <= 1'b0;
mem_req <= 1'b1;
@(posedge clk);
mem_req <= 1'b0;
wait (mem_ready);
if (mem_rdata !== expected) begin
$display(
"READ addr=0x%08x FAIL got=0x%04x expected=0x%04x",
addr,
mem_rdata,
expected
);
$fatal;
end else begin
$display(
"READ addr=0x%08x data=0x%04x PASS",
addr,
mem_rdata
);
end
@(posedge clk);
end
endtask
// ============================================================
// Test
// ============================================================
initial begin
mem_req = 1'b0;
mem_wr = 1'b0;
mem_addr = 0;
mem_wdata = 0;
// Both bytes disabled while idle
mem_lb_n = 1'b1;
mem_ub_n = 1'b1;
rst = 1'b1;
repeat (5)
@(posedge clk);
rst = 1'b0;
$display("");
$display("========================================");
$display("PSRAM CONTROLLER V1 TEST");
$display("80 MHz");
$display("4M x 16 PSRAM");
$display("70 ns asynchronous timing");
$display("========================================");
$display("");
wait (dut.state == dut.STATE_IDLE);
$display("PSRAM initialization complete");
$display("");
// ========================================================
// Basic writes / reads
// ========================================================
write_word(22'h000001, 16'h1234, 1'b0, 1'b0);
read_word (22'h000001, 16'h1234);
write_word(22'h000010, 16'hABCD, 1'b0, 1'b0);
read_word (22'h000010, 16'hABCD);
write_word(22'h000100, 16'h55AA, 1'b0, 1'b0);
read_word (22'h000100, 16'h55AA);
// ========================================================
// Consecutive words
// ========================================================
write_word(22'h000200, 16'h0001, 1'b0, 1'b0);
write_word(22'h000201, 16'h0002, 1'b0, 1'b0);
write_word(22'h000202, 16'h0003, 1'b0, 1'b0);
read_word(22'h000200, 16'h0001);
read_word(22'h000201, 16'h0002);
read_word(22'h000202, 16'h0003);
// ========================================================
// Edge values
// ========================================================
write_word(22'h000300, 16'h0000, 1'b0, 1'b0);
read_word (22'h000300, 16'h0000);
write_word(22'h000301, 16'hFFFF, 1'b0, 1'b0);
read_word (22'h000301, 16'hFFFF);
// ========================================================
// High address
// ========================================================
write_word(22'h003FFF, 16'hCAFE, 1'b0, 1'b0);
read_word (22'h003FFF, 16'hCAFE);
// ========================================================
// Basic test passed
// ========================================================
$display("");
$display("========================================");
$display("PSRAM CONTROLLER BASIC TEST PASSED");
$display("========================================");
$display("");
// ========================================================
// BYTE ENABLE TEST
// ========================================================
$display("");
$display("========================================");
$display("PSRAM BYTE ENABLE TEST");
$display("LB# / UB#");
$display("========================================");
$display("");
// --------------------------------------------------------
// Start from known value
// --------------------------------------------------------
write_word(
22'h000400,
16'h1234,
1'b0,
1'b0
);
read_word(
22'h000400,
16'h1234
);
// --------------------------------------------------------
// LOW BYTE ONLY
//
// Initial: 0x1234
// Write: 0x00AA
//
// LB# = 0 -> low byte written
// UB# = 1 -> high byte preserved
//
// Expected: 0x12AA
// --------------------------------------------------------
$display("");
$display("LOW BYTE ONLY");
$display("Initial = 0x1234");
$display("Write = 0x00AA");
$display("LB#=0 UB#=1");
$display("Expected= 0x12AA");
$display("");
write_word(
22'h000400,
16'h00AA,
1'b0,
1'b1
);
read_word(
22'h000400,
16'h12AA
);
// --------------------------------------------------------
// HIGH BYTE ONLY
//
// Current: 0x12AA
// Write: 0xBB00
//
// LB# = 1 -> low byte preserved
// UB# = 0 -> high byte written
//
// Expected: 0xBBAA
// --------------------------------------------------------
$display("");
$display("HIGH BYTE ONLY");
$display("Initial = 0x12AA");
$display("Write = 0xBB00");
$display("LB#=1 UB#=0");
$display("Expected= 0xBBAA");
$display("");
write_word(
22'h000400,
16'hBB00,
1'b1,
1'b0
);
read_word(
22'h000400,
16'hBBAA
);
// --------------------------------------------------------
// FULL WORD
//
// Current: 0xBBAA
// Write: 0xCCDD
//
// LB# = 0 -> low byte written
// UB# = 0 -> high byte written
//
// Expected: 0xCCDD
// --------------------------------------------------------
$display("");
$display("FULL WORD");
$display("Initial = 0xBBAA");
$display("Write = 0xCCDD");
$display("LB#=0 UB#=0");
$display("Expected= 0xCCDD");
$display("");
write_word(
22'h000400,
16'hCCDD,
1'b0,
1'b0
);
read_word(
22'h000400,
16'hCCDD
);
// ========================================================
// BYTE ENABLE TEST PASSED
// ========================================================
$display("");
$display("========================================");
$display("PSRAM BYTE ENABLE TEST PASSED");
$display("LOW BYTE : PASS");
$display("HIGH BYTE : PASS");
$display("FULL WORD : PASS");
$display("PRESERVE : PASS");
$display("========================================");
$display("");
// ========================================================
// STRESS TEST
// ========================================================
$display("");
$display("========================================");
$display("PSRAM STRESS TEST");
$display("2048 WRITE + READ transactions");
$display("========================================");
$display("");
for (stress_i = 0;
stress_i < 2048;
stress_i = stress_i + 1) begin
stress_addr =
((stress_i * 7919) ^ (stress_i << 5)) & 16'h3FFF;
stress_data =
((stress_i * 1237) ^ 16'hA5A5);
write_word(
stress_addr,
stress_data,
1'b0,
1'b0
);
read_word(
stress_addr,
stress_data
);
if ((stress_i % 128) == 0)
$display(
"STRESS %0d / 2048 PASS",
stress_i
);
end
// ========================================================
// Final result
// ========================================================
$display("");
$display("========================================");
$display("PSRAM CONTROLLER V1 TEST PASSED");
$display("2048 WRITE + READ stress transactions");
$display("BYTE ENABLE TEST PASSED");
$display("========================================");
$display("");
$finish;
end
endmodule
+502
View File
@@ -0,0 +1,502 @@
`timescale 1ns/1ps
module psram_model #(
parameter ADDR_WIDTH = 22,
parameter DATA_WIDTH = 16,
parameter DEPTH = 16384
)(
input wire clk,
input wire [ADDR_WIDTH-1:0] a,
inout wire [DATA_WIDTH-1:0] dq,
input wire ce_n,
input wire oe_n,
input wire we_n,
input wire lb_n,
input wire ub_n,
input wire zz_n
);
// ============================================================
// IS66WVE4M16EBLL-70BLI - Rev. D3
// ============================================================
localparam realtime TAA_NS = 70.0;
localparam realtime TRC_NS = 70.0;
localparam realtime TOE_NS = 20.0;
localparam realtime TOH_NS = 5.0;
localparam realtime TLZ_NS = 10.0;
localparam realtime THZ_NS = 8.0;
localparam realtime TWC_NS = 70.0;
localparam realtime TAW_NS = 70.0;
localparam realtime TCW_NS = 70.0;
localparam realtime TWP_NS = 46.0;
localparam realtime TDW_NS = 23.0;
localparam realtime TDH_NS = 0.0;
localparam realtime TWR_NS = 0.0;
localparam realtime TWPH_NS = 10.0;
localparam realtime TPU_NS = 150000.0;
// ============================================================
// Memory
// ============================================================
reg [DATA_WIDTH-1:0] mem [0:DEPTH-1];
reg [DATA_WIDTH-1:0] dq_out;
reg dq_oe;
integer i;
assign dq = dq_oe ? dq_out : {DATA_WIDTH{1'bz}};
// ============================================================
// Timing state
// ============================================================
realtime powerup_time;
realtime ce_low_time;
realtime ce_high_time;
realtime oe_low_time;
realtime oe_high_time;
realtime we_low_time;
realtime we_high_time;
realtime last_read_start;
realtime last_write_start;
realtime addr_valid_time;
realtime data_valid_time;
reg read_active;
reg write_active;
reg [ADDR_WIDTH-1:0] active_addr;
reg [DATA_WIDTH-1:0] active_wdata;
// ============================================================
// Initialization
// ============================================================
initial begin
for (i = 0; i < DEPTH; i = i + 1)
mem[i] = 16'h0000;
dq_out = 16'h0000;
dq_oe = 1'b0;
powerup_time = $realtime;
ce_low_time = 0.0;
ce_high_time = 0.0;
oe_low_time = 0.0;
oe_high_time = 0.0;
we_low_time = 0.0;
we_high_time = 0.0;
last_read_start = -1.0;
last_write_start = -1.0;
addr_valid_time = 0.0;
data_valid_time = 0.0;
read_active = 1'b0;
write_active = 1'b0;
active_addr = 0;
active_wdata = 0;
end
// ============================================================
// FUNCTIONAL READ MODEL
// ============================================================
always @(*) begin
dq_oe = 1'b0;
dq_out = 16'h0000;
if (zz_n &&
!ce_n &&
!oe_n &&
we_n) begin
if (a < DEPTH) begin
dq_oe = 1'b1;
if (!lb_n && !ub_n)
dq_out = mem[a];
else if (!lb_n)
dq_out = {
8'h00,
mem[a][7:0]
};
else if (!ub_n)
dq_out = {
mem[a][15:8],
8'h00
};
end
end
end
// ============================================================
// CE# FALLING
// ============================================================
always @(negedge ce_n) begin
if (!zz_n) begin
$display("ERROR: CE# LOW while ZZ# LOW");
$fatal;
end
ce_low_time = $realtime;
addr_valid_time = $realtime;
active_addr = a;
// --------------------------------------------------------
// READ START
// --------------------------------------------------------
if (!oe_n && we_n) begin
if (($realtime - powerup_time) < TPU_NS) begin
$display("ERROR: READ before tPU");
$fatal;
end
if (last_read_start >= 0.0) begin
if (($realtime - last_read_start) < TRC_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tRC violation");
$display("required = %0.2f ns", TRC_NS);
$display("actual = %0.2f ns",
$realtime - last_read_start);
$display("========================================");
$fatal;
end
end
last_read_start = $realtime;
read_active = 1'b1;
end
// --------------------------------------------------------
// WRITE START
// --------------------------------------------------------
if (oe_n && !we_n) begin
if (($realtime - powerup_time) < TPU_NS) begin
$display("ERROR: WRITE before tPU");
$fatal;
end
if (last_write_start >= 0.0) begin
if (($realtime - last_write_start) < TWC_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tWC violation");
$display("required = %0.2f ns", TWC_NS);
$display("actual = %0.2f ns",
$realtime - last_write_start);
$display("========================================");
$fatal;
end
end
last_write_start = $realtime;
write_active = 1'b1;
end
end
// ============================================================
// CE# RISING
// ============================================================
always @(posedge ce_n) begin
realtime access_time;
ce_high_time = $realtime;
access_time = $realtime - ce_low_time;
// --------------------------------------------------------
// READ END
// --------------------------------------------------------
if (read_active) begin
// tAA
if (access_time < TAA_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tAA violation");
$display("required = %0.2f ns", TAA_NS);
$display("actual = %0.2f ns", access_time);
$display("========================================");
$fatal;
end
// tOE
if (($realtime - oe_low_time) < TOE_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tOE violation");
$display("required = %0.2f ns", TOE_NS);
$display("actual = %0.2f ns",
$realtime - oe_low_time);
$display("========================================");
$fatal;
end
read_active = 1'b0;
end
end
// ============================================================
// OE# FALLING
// ============================================================
always @(negedge oe_n) begin
if (!zz_n) begin
$display("ERROR: OE# LOW while ZZ# LOW");
$fatal;
end
if (!ce_n && we_n)
oe_low_time = $realtime;
// Illegal combination
if (!ce_n && !we_n) begin
$display("");
$display("========================================");
$display("PSRAM PROTOCOL ERROR");
$display("OE# and WE# LOW simultaneously");
$display("========================================");
$fatal;
end
end
// ============================================================
// OE# RISING
// ============================================================
always @(posedge oe_n) begin
oe_high_time = $realtime;
// Output must remain valid long enough for tOH
// after address changes. This is checked by the
// controller access window rather than by forcing
// an artificial delay into the functional model.
end
// ============================================================
// WE# FALLING
// ============================================================
always @(negedge we_n) begin
if (!zz_n) begin
$display("ERROR: WE# LOW while ZZ# LOW");
$fatal;
end
if (!ce_n && oe_n) begin
we_low_time = $realtime;
active_addr = a;
active_wdata = dq;
write_active = 1'b1;
end
// Illegal combination
if (!ce_n && !oe_n) begin
$display("");
$display("========================================");
$display("PSRAM PROTOCOL ERROR");
$display("OE# and WE# LOW simultaneously");
$display("========================================");
$fatal;
end
end
// ============================================================
// WE# RISING
// ============================================================
always @(posedge we_n) begin
realtime write_width;
realtime data_setup;
we_high_time = $realtime;
if (write_active) begin
write_width = $realtime - we_low_time;
// ----------------------------------------------------
// tWP
// ----------------------------------------------------
if (write_width < TWP_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tWP violation");
$display("required = %0.2f ns", TWP_NS);
$display("actual = %0.2f ns", write_width);
$display("========================================");
$fatal;
end
// ----------------------------------------------------
// tAW
// ----------------------------------------------------
if (($realtime - addr_valid_time) < TAW_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tAW violation");
$display("required = %0.2f ns", TAW_NS);
$display("actual = %0.2f ns",
$realtime - addr_valid_time);
$display("========================================");
$fatal;
end
// ----------------------------------------------------
// tCW
// ----------------------------------------------------
if (($realtime - ce_low_time) < TCW_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tCW violation");
$display("required = %0.2f ns", TCW_NS);
$display("actual = %0.2f ns",
$realtime - ce_low_time);
$display("========================================");
$fatal;
end
// ----------------------------------------------------
// tDW
//
// Data must be valid before WE# rises.
// Our controller drives DQ from WE# falling,
// therefore setup is much larger than 23 ns.
// ----------------------------------------------------
data_setup = $realtime - we_low_time;
if (data_setup < TDW_NS) begin
$display("");
$display("========================================");
$display("PSRAM TIMING ERROR");
$display("tDW violation");
$display("required = %0.2f ns", TDW_NS);
$display("actual = %0.2f ns", data_setup);
$display("========================================");
$fatal;
end
// ----------------------------------------------------
// tDH = 0 ns
// ----------------------------------------------------
// No additional hold time is required.
// ----------------------------------------------------
// Store data
// ----------------------------------------------------
if (a !== active_addr) begin
$display("");
$display("========================================");
$display("PSRAM PROTOCOL ERROR");
$display("ADDRESS CHANGED DURING WRITE");
$display("========================================");
$fatal;
end
if (a < DEPTH) begin
if (!lb_n)
mem[a][7:0] <= dq[7:0];
if (!ub_n)
mem[a][15:8] <= dq[15:8];
end
write_active = 1'b0;
end
end
// ============================================================
// ZZ#
// ============================================================
always @(negedge zz_n) begin
if (!ce_n) begin
$display("");
$display("========================================");
$display("PSRAM PROTOCOL ERROR");
$display("ZZ# LOW while CE# LOW");
$display("========================================");
$fatal;
end
end
endmodule