verilator init

This commit is contained in:
Mateusz Faderewski 2024-07-07 00:09:03 +02:00
parent ab5b02251f
commit 24f04ae916
13 changed files with 772 additions and 89 deletions

View File

@ -3,6 +3,9 @@
<Options/>
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="synplify" default_strategy="release">
<Options VerilogStandard="System Verilog" def_top="top" top="top"/>
<Source name="../../rtl/memory/dma_scb.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>
<Source name="../../rtl/memory/mem_bus.sv" type="Verilog" type_short="Verilog">
<Options VerilogStandard="System Verilog"/>
</Source>

View File

@ -214,7 +214,7 @@ LOCATE COMP "usb_miso" SITE "10" ;
LOCATE COMP "usb_pwrsav" SITE "2" ;
SYSCONFIG SDM_PORT=DISABLE I2C_PORT=ENABLE ;
VOLTAGE 3.300 V;
FREQUENCY NET "clk" 100.000000 MHz PAR_ADJ 10.000000 ;
FREQUENCY NET "clk" 100.000000 MHz PAR_ADJ 20.000000 ;
BLOCK PATH TO PORT "mcu_int" ;
BLOCK PATH TO PORT "n64_irq" ;
BLOCK PATH FROM PORT "usb_pwrsav" ;

31
fw/rtl/memory/dma_scb.sv Normal file
View File

@ -0,0 +1,31 @@
interface dma_scb ();
logic start;
logic stop;
logic busy;
logic direction;
logic byte_swap;
logic [26:0] starting_address;
logic [26:0] transfer_length;
modport controller (
output start,
output stop,
input busy,
output direction,
output byte_swap,
output starting_address,
output transfer_length
);
modport dma (
input start,
input stop,
output busy,
input direction,
input byte_swap,
input starting_address,
input transfer_length
);
endinterface

View File

@ -1,36 +1,3 @@
interface dma_scb ();
logic start;
logic stop;
logic busy;
logic direction;
logic byte_swap;
logic [26:0] starting_address;
logic [26:0] transfer_length;
modport controller (
output start,
output stop,
input busy,
output direction,
output byte_swap,
output starting_address,
output transfer_length
);
modport dma (
input start,
input stop,
output busy,
input direction,
input byte_swap,
input starting_address,
input transfer_length
);
endinterface
module memory_dma (
input clk,
input reset,
@ -41,6 +8,228 @@ module memory_dma (
mem_bus.controller mem_bus
);
// logic stop_requested;
// logic dma_done;
// always_ff @(posedge clk) begin
// if (reset) begin
// dma_scb.busy <= 1'b0;
// stop_requested <= 1'b0;
// end else begin
// if (dma_scb.start) begin
// dma_scb.busy <= 1'b1;
// end
// if (dma_scb.busy && dma_scb.stop) begin
// stop_requested <= 1'b1;
// end
// if (dma_done) begin
// dma_scb.busy <= 1'b0;
// stop_requested <= 1'b0;
// end
// end
// end
// logic unaligned_start;
// logic unaligned_end;
// always_ff @(posedge clk) begin
// if (dma_scb.start) begin
// unaligned_start <= dma_scb.starting_address[0];
// // unaligned_end <= ;
// end
// end
// logic [26:0] bytes_remaining;
// always_ff @(posedge clk) begin
// bytes_remaining <= bytes_remaining - 27'd1;
// if (dma_scb.start) begin
// bytes_remaining <= dma_scb.transfer_length;
// end
// end
// logic mem_transfer_request;
// logic mem_wdata_buffer_ready;
// logic mem_rdata_buffer_ready;
// logic [15:0] mem_wdata_buffer;
// logic [15:0] mem_rdata_buffer;
// logic [1:0] mem_wdata_buffer_valid_bytes;
// logic mem_rdata_buffer_valid;
// always_comb begin
// mem_transfer_request = (
// !mem_bus.request || mem_bus.ack
// ) && (
// mem_wdata_buffer_ready || mem_rdata_buffer_ready
// );
// end
// always_ff @(posedge clk) begin
// if (dma_scb.start) begin
// mem_bus.write <= dma_scb.direction;
// mem_bus.address <= {dma_scb.starting_address[26:1], 1'b0};
// mem_rdata_buffer_valid <= 1'b0;
// end
// if (mem_bus.ack) begin
// mem_bus.request <= 1'b0;
// mem_bus.address <= mem_bus.address + 27'd2;
// mem_rdata_buffer <= mem_bus.rdata;
// mem_rdata_buffer_valid <= 1'b1;
// end
// if (reset) begin
// mem_bus.request <= 1'b0;
// end else if (mem_transfer_request) begin
// mem_bus.request <= 1'b1;
// mem_bus.wmask <= mem_wdata_buffer_valid_bytes;
// end
// if (!mem_bus.request || mem_bus.ack) begin
// if (mem_wdata_buffer_ready) begin
// if (dma_scb.byte_swap) begin
// mem_bus.wdata[15:8] <= mem_wdata_buffer[7:0];
// mem_bus.wdata[7:0] <= mem_wdata_buffer[15:8];
// end else begin
// mem_bus.wdata <= mem_wdata_buffer;
// end
// end
// end
// end
// // always_ff @(posedge clk) begin
// // mem_wdata_buffer_ready <= dma_scb.busy;
// // mem_wdata_buffer_valid_bytes <= 2'b10;
// // end
// logic [1:0] rx_fifo_bytes_available;
// logic [1:0] tx_fifo_bytes_available;
// always_comb begin
// rx_fifo_bytes_available = 2'd2;
// if (fifo_bus.rx_almost_empty) begin
// rx_fifo_bytes_available = 2'd1;
// end
// if (fifo_bus.rx_empty) begin
// rx_fifo_bytes_available = 2'd0;
// end
// tx_fifo_bytes_available = 2'd2;
// if (fifo_bus.tx_almost_full) begin
// tx_fifo_bytes_available = 2'd1;
// end
// if (fifo_bus.tx_full) begin
// tx_fifo_bytes_available = 2'd0;
// end
// end
// always_ff @(posedge clk) begin
// if (dma_scb.busy) begin
// if (!dma_scb.direction) begin
// // RX FIFO handling
// end
// end
// end
// always_ff @(posedge clk) begin
// if (dma_scb.busy) begin
// if (dma_scb.direction) begin
// // TX FIFO handling
// end
// end
// end
//XDDDAWDWD
// always_ff @(posedge clk) begin
// dma_done <= 1'b0;
// if (dma_scb.busy && bytes_remaining == 27'd0) begin
// // dma_done <= 1'b1;
// end
// end
// typedef enum bit [1:0] {
// } e_rx_fifo_state;
// typedef enum bit [1:0] {
// } e_tx_fifo_state;
// typedef enum bit [1:0] {
// MEM_BUS_IDLE = 2'b00,
// MEM_BUS_WAIT = 2'b01,
// MEM_BUS_TRANSFERRING = 2'b10,
// } e_mem_bus_state;
// e_mem_bus_state mem_bus_state;
// e_mem_bus_state next_mem_bus_state;
// always_ff @(posedge clk) begin
// mem_bus_state <= next_mem_bus_state;
// if (reset) begin
// mem_bus_state <= MEM_BUS_IDLE;
// end
// end
// always_comb begin
// next_mem_bus_state = mem_bus_state;
// case (mem_bus_state)
// MEM_BUS_IDLE: begin
// if (dma_scb.start) begin
// next_mem_bus_state = MEM_BUS_WAIT;
// end
// end
// MEM_BUS_WAIT: begin
// i
// end
// MEM_BUS_TRANSFERRING: begin
// end
// endcase
// end
// DMA start/stop control
logic dma_start;
@ -260,7 +449,7 @@ module memory_dma (
end
if (mem_bus.ack) begin
mem_bus.address <= mem_bus.address + 2'd2;
mem_bus.address <= mem_bus.address + 27'd2;
end
end

View File

@ -14,29 +14,36 @@ module memory_sdram (
inout [15:0] sdram_dq
);
localparam [2:0] CAS_LATENCY = 3'd2;
// in Hz
localparam real FREQUENCY = 100_000_000.0;
// in clocks
localparam bit [2:0] CAS_LATENCY = 3'd2;
// in nanoseconds
localparam real T_INIT = 100_000.0;
localparam real T_RC = 60.0;
localparam real T_RP = 15.0;
localparam real T_RCD = 15.0;
localparam real T_MRD = 14.0;
localparam real T_REF = 7_800.0;
localparam real T_REF = 7_812.5;
localparam real T_CLK = (1.0 / 100_000_000) * 1_000_000_000.0;
localparam int C_INIT = int'((T_INIT + T_CLK - 1) / T_CLK);
localparam int C_RC = int'((T_RC + T_CLK - 1) / T_CLK);
localparam int C_RP = int'((T_RP + T_CLK - 1) / T_CLK);
localparam int C_RCD = int'((T_RCD + T_CLK - 1) / T_CLK);
localparam int C_MRD = int'((T_MRD + T_CLK - 1) / T_CLK);
localparam int C_REF = int'((T_REF + T_CLK - 1) / T_CLK);
localparam real T_CLK = (1.0 / FREQUENCY) * 1_000_000_000.0;
localparam INIT_PRECHARGE = 4'd0;
localparam INIT_REFRESH_1 = C_RP;
localparam INIT_REFRESH_2 = C_RP + C_RC;
localparam INIT_MODE_REG = C_RP + (2 * C_RC);
localparam INIT_DONE = C_RP + (2 * C_RC) + C_MRD;
const bit [13:0] C_INIT = 14'(int'($ceil(T_INIT / T_CLK)));
const bit [4:0] C_RC = 5'(int'($ceil(T_RC / T_CLK)));
const bit [4:0] C_RP = 5'(int'($ceil(T_RP / T_CLK)));
const bit [4:0] C_RCD = 5'(int'($ceil(T_RCD / T_CLK)));
const bit [4:0] C_MRD = 5'(int'($ceil(T_MRD / T_CLK)));
const bit [13:0] C_REF = 14'(int'($ceil(T_REF / T_CLK)));
const bit [4:0] INIT_PRECHARGE = 5'd0;
const bit [4:0] INIT_REFRESH_1 = INIT_PRECHARGE + C_RP;
const bit [4:0] INIT_REFRESH_2 = INIT_REFRESH_1 + C_RC;
const bit [4:0] INIT_MODE_REG = INIT_REFRESH_2 + C_RC;
const bit [4:0] INIT_DONE = INIT_MODE_REG + C_MRD;
// /CS, /RAS, /CAS, /WE
typedef enum bit [3:0] {
CMD_DESL = 4'b1111,
CMD_NOP = 4'b0111,
@ -58,13 +65,10 @@ module memory_sdram (
always_ff @(posedge clk) begin
{sdram_cs, sdram_ras, sdram_cas, sdram_we} <= 4'(sdram_next_cmd);
{sdram_ba, sdram_a} <= 15'd0;
sdram_dqm <= 2'b00;
sdram_dq_input <= sdram_dq;
sdram_dq_output <= mem_bus.wdata;
sdram_dq_output_enable <= 1'b0;
case (sdram_next_cmd)
@ -76,19 +80,31 @@ module memory_sdram (
CMD_ACT: begin
{sdram_ba, sdram_a} <= mem_bus.address[25:11];
sdram_dqm <= 2'b00;
current_active_bank_row <= mem_bus.address[25:11];
end
CMD_PRE: begin
{sdram_ba, sdram_a} <= {2'b00, 2'b00, 1'b1, 10'd0};
sdram_dqm <= 2'b00;
{sdram_ba, sdram_a} <= {
2'b00, // [BA1:BA0] Don't care
2'b00, // [A12:A11] Don't care
1'b1, // [A10] Precharge all banks
10'd0 // [A9:A0] Don't care
};
end
CMD_MRS: begin
{sdram_ba, sdram_a} <= {2'b00, 1'b0, 1'b0, 2'b00, CAS_LATENCY, 1'b0, 3'b000};
sdram_dqm <= 2'b00;
{sdram_ba, sdram_a} <= {
2'b00, // [BA1:BA0] Reserved = 0
3'b00, // [A12:A10] Reserved = 0
1'b0, // [A9] Write Burst Mode = Programmed Burst Length
2'b00, // [A8:A7] Operating Mode = Standard Operation
CAS_LATENCY, // [A6:A4] Latency Mode = 2
1'b0, // [A3] Burst Type = Sequential
3'b000 // [A2:A0] Burst Length = 1
};
end
default: begin end
endcase
end
@ -121,35 +137,38 @@ module memory_sdram (
end
end
logic [13:0] powerup_coutner;
logic powerup_done;
logic [13:0] refresh_counter;
logic [4:0] wait_counter;
logic [9:0] refresh_counter;
logic powerup_done;
logic pending_refresh;
always_ff @(posedge clk) begin
if (reset) begin
powerup_coutner <= 14'd0;
powerup_done <= 1'b0;
end else if (powerup_coutner < C_INIT) begin
powerup_coutner <= powerup_coutner + 1'd1;
end else begin
refresh_counter <= refresh_counter + 1'd1;
if (refresh_counter == C_INIT) begin
refresh_counter <= 14'd0;
powerup_done <= 1'b1;
end
if (reset || state != next_state) begin
wait_counter <= 5'd0;
end else begin
wait_counter <= wait_counter + 1'd1;
if (powerup_done && refresh_counter == C_REF - 14'd1) begin
refresh_counter <= 14'd0;
pending_refresh <= 1'b1;
end
if (sdram_next_cmd == CMD_REF) begin
refresh_counter <= 10'd0;
pending_refresh <= 1'b0;
end else if (refresh_counter < C_REF) begin
refresh_counter <= refresh_counter + 1'd1;
end else begin
pending_refresh <= 1'b1;
end
if (reset) begin
refresh_counter <= 14'd0;
powerup_done <= 1'b0;
pending_refresh <= 1'b0;
end
wait_counter <= wait_counter + 1'd1;
if (state != next_state) begin
wait_counter <= 5'd0;
end
end
@ -157,6 +176,7 @@ module memory_sdram (
always_ff @(posedge clk) begin
mem_bus.ack <= 1'b0;
read_cmd_ack_delay <= {sdram_next_cmd == CMD_READ, read_cmd_ack_delay[(CAS_LATENCY):1]};
if (sdram_next_cmd == CMD_WRITE || read_cmd_ack_delay[0]) begin
@ -202,7 +222,7 @@ module memory_sdram (
end
S_ACTIVATING: begin
if (wait_counter == C_RCD) begin
if (wait_counter == C_RCD - 5'd2) begin
next_state = S_ACTIVE;
end
end
@ -229,18 +249,13 @@ module memory_sdram (
end
S_PRECHARGE: begin
if (wait_counter == C_RP) begin
if (pending_refresh) begin
next_state = S_REFRESH;
sdram_next_cmd = CMD_REF;
end else begin
if (wait_counter == C_RP - 5'd2) begin
next_state = S_IDLE;
end
end
end
S_REFRESH: begin
if (wait_counter == C_RC) begin
if (wait_counter == C_RC - 5'd2) begin
next_state = S_IDLE;
end
end

2
fw/tests/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/build
*.vcd

33
fw/tests/Makefile Normal file
View File

@ -0,0 +1,33 @@
RTL_DIR = ../rtl
MOCKS_DIR = mocks
BUILD_DIR = build
SRC_DIRS = \
$(RTL_DIR)/fifo \
$(RTL_DIR)/mcu \
$(RTL_DIR)/memory \
$(RTL_DIR)/n64 \
$(RTL_DIR)/sd \
$(RTL_DIR)/serv \
$(RTL_DIR)/usb \
$(RTL_DIR)/vendor \
$(RTL_DIR) \
$(MOCKS_DIR)
INC_DIRS = $(addprefix -I, $(SRC_DIRS))
TEST_FILES = $(shell find "./" -not -path "$(BUILD_DIR)/*" -type f -name "*_tb.sv")
TESTS = $(addprefix $(BUILD_DIR)/, $(basename $(TEST_FILES)))
VERILATOR_FLAGS = --binary --trace --timescale 10ns/1ns -j --quiet $(INC_DIRS)
$(BUILD_DIR)/%: %.sv
@echo "[VERILATOR] $<"
@mkdir -p $@.obj
@verilator $(VERILATOR_FLAGS) -Mdir $@.obj $< > /dev/null
@$@.obj/V$(notdir $@)
tests: $(TESTS)
clean:
@rm -rf ./$(BUILD_DIR)
.PHONY: tests

View File

@ -0,0 +1,126 @@
module memory_dma_tb;
logic clk;
logic reset;
dma_scb dma_scb ();
fifo_bus fifo_bus ();
mem_bus mem_bus ();
logic start;
logic stop;
logic direction;
logic byte_swap;
logic [26:0] starting_address;
logic [26:0] transfer_length;
logic flush;
logic rx_fill_enabled;
logic tx_drain_enabled;
memory_dma memory_dma (
.clk(clk),
.reset(reset),
.dma_scb(dma_scb),
.fifo_bus(fifo_bus),
.mem_bus(mem_bus)
);
dma_controller_mock dma_controller_mock (
.clk(clk),
.reset(reset),
.dma_scb(dma_scb),
.start(start),
.stop(stop),
.direction(direction),
.byte_swap(byte_swap),
.starting_address(starting_address),
.transfer_length(transfer_length)
);
fifo_bus_mock #(
.DEPTH(16),
.FILL_RATE(16),
.DRAIN_RATE(16)
) fifo_bus_mock (
.clk(clk),
.reset(reset),
.fifo_bus(fifo_bus),
.flush(flush),
.rx_fill_enabled(rx_fill_enabled),
.tx_drain_enabled(tx_drain_enabled)
);
memory_sdram_mock memory_sdram_mock (
.clk(clk),
.reset(reset),
.mem_bus(mem_bus)
);
initial begin
clk = 1'b0;
forever begin
clk = ~clk; #0.5;
end
end
initial begin
reset = 1'b0;
#10;
reset = 1'b1;
#10;
reset = 1'b0;
end
initial begin
$dumpfile("traces/memory_dma_tb.vcd");
#10000;
$dumpvars();
#100;
start = 1'b1;
direction = 1'b0;
byte_swap = 1'b0;
starting_address = 27'hFFF0;
transfer_length = 27'd32;
#1;
start = 1'b0;
#9;
tx_drain_enabled = 1'b1;
#490;
stop = 1'b1;
#1;
stop = 1'b0;
#99;
start = 1'b1;
direction = 1'b1;
#1;
start = 1'b0;
#9;
rx_fill_enabled = 1'b1;
#490;
stop = 1'b1;
#1;
stop = 1'b0;
#99;
$finish;
end
endmodule

View File

@ -0,0 +1,39 @@
module dma_controller_mock (
input clk,
input reset,
dma_scb.controller dma_scb,
input start,
input stop,
input direction,
input byte_swap,
input [26:0] starting_address,
input [26:0] transfer_length
);
always_ff @(posedge clk) begin
dma_scb.start <= 1'b0;
dma_scb.stop <= 1'b0;
if (reset) begin
dma_scb.direction <= 1'b0;
dma_scb.byte_swap <= 1'b0;
dma_scb.starting_address <= 27'd0;
dma_scb.transfer_length <= 27'd0;
end else begin
if (start) begin
dma_scb.start <= 1'b1;
dma_scb.direction <= direction;
dma_scb.byte_swap <= byte_swap;
dma_scb.starting_address <= starting_address;
dma_scb.transfer_length <= transfer_length;
end
if (stop) begin
dma_scb.stop <= 1'b1;
end
end
end
endmodule

View File

@ -0,0 +1,172 @@
module fifo_bus_mock #(
parameter int DEPTH = 1024,
parameter int FILL_RATE = 3,
parameter int DRAIN_RATE = 3
) (
input clk,
input reset,
fifo_bus.fifo fifo_bus,
input flush,
input rx_fill_enabled,
input tx_drain_enabled
);
localparam int PTR_BITS = $clog2(DEPTH);
// RX FIFO mock
logic [7:0] rx_fifo_mem [0:(DEPTH - 1)];
logic [(PTR_BITS - 1):0] rx_fifo_rptr;
logic [(PTR_BITS - 1):0] rx_fifo_wptr;
logic [PTR_BITS:0] rx_available;
logic rx_fifo_full;
logic rx_fifo_almost_full;
logic rx_write;
logic [7:0] rx_wdata;
always_comb begin
rx_fifo_full = rx_available >= (PTR_BITS + 1)'(DEPTH);
rx_fifo_almost_full = rx_available >= (PTR_BITS + 1)'(DEPTH - 1);
fifo_bus.rx_empty = rx_available == (PTR_BITS + 1)'('d0);
fifo_bus.rx_almost_empty = rx_available <= (PTR_BITS + 1)'('d1);
end
always_ff @(posedge clk) begin
if (fifo_bus.rx_read) begin
fifo_bus.rx_rdata <= rx_fifo_mem[rx_fifo_rptr];
rx_fifo_rptr <= rx_fifo_rptr + PTR_BITS'('d1);
rx_available <= rx_available - (PTR_BITS + 1)'('d1);
end
if (rx_write) begin
rx_fifo_mem[rx_fifo_wptr] <= rx_wdata;
rx_fifo_wptr <= rx_fifo_wptr + PTR_BITS'('d1);
rx_available <= rx_available + (PTR_BITS + 1)'('d1);
end
if (fifo_bus.rx_read && rx_write) begin
rx_available <= rx_available;
end
if (reset || flush) begin
rx_available <= (PTR_BITS + 1)'('d0);
rx_fifo_rptr <= PTR_BITS'('d0);
rx_fifo_wptr <= PTR_BITS'('d0);
end
end
localparam int FILL_BITS = $clog2(FILL_RATE);
logic [FILL_BITS:0] fill_counter;
logic rx_fill;
always_ff @(posedge clk) begin
rx_fill <= rx_fill_enabled;
end
generate;
if (FILL_RATE == 0) begin
always_comb begin
rx_write = rx_fill && !rx_fifo_full;
end
end else begin
always_comb begin
rx_write = rx_fill && !rx_fifo_full && (fill_counter == (FILL_BITS + 1)'(FILL_RATE));
end
always_ff @(posedge clk) begin
if (fill_counter < (FILL_BITS + 1)'(FILL_RATE)) begin
fill_counter <= fill_counter + (FILL_BITS + 1)'('d1);
end
if (reset) begin
fill_counter <= (FILL_BITS + 1)'('d0);
end else begin
if (rx_write) begin
fill_counter <= (FILL_BITS + 1)'('d0);
end
end
end
end
endgenerate
always_ff @(posedge clk) begin
if (reset) begin
rx_wdata <= 8'h01;
end else begin
if (rx_write) begin
rx_wdata <= rx_wdata + 8'h01;
end
end
end
// TX FIFO mock
logic [7:0] tx_fifo_mem [0:(DEPTH - 1)];
logic [(PTR_BITS - 1):0] tx_fifo_rptr;
logic [(PTR_BITS - 1):0] tx_fifo_wptr;
logic [PTR_BITS:0] tx_available;
logic tx_fifo_empty;
logic tx_fifo_almost_empty;
logic tx_read;
logic [7:0] tx_rdata;
always_comb begin
tx_fifo_empty = tx_available == (PTR_BITS + 1)'('d0);
tx_fifo_almost_empty = tx_available <= (PTR_BITS + 1)'('d1);
fifo_bus.tx_full = tx_available >= (PTR_BITS + 1)'(DEPTH);
fifo_bus.tx_almost_full = tx_available >= (PTR_BITS + 1)'(DEPTH - 1);
end
always_ff @(posedge clk) begin
if (fifo_bus.tx_write) begin
tx_fifo_mem[tx_fifo_wptr] <= fifo_bus.tx_wdata;
tx_fifo_wptr <= tx_fifo_wptr + PTR_BITS'('d1);
tx_available <= tx_available + (PTR_BITS + 1)'('d1);
end
if (tx_read) begin
tx_rdata <= tx_fifo_mem[tx_fifo_rptr];
tx_fifo_rptr <= tx_fifo_rptr + PTR_BITS'('d1);
tx_available <= tx_available - (PTR_BITS + 1)'('d1);
end
if (fifo_bus.tx_write && tx_read) begin
tx_available <= tx_available;
end
if (reset || flush) begin
tx_available <= (PTR_BITS + 1)'('d0);
tx_fifo_rptr <= PTR_BITS'('d0);
tx_fifo_wptr <= PTR_BITS'('d0);
end
end
localparam int DRAIN_BITS = $clog2(DRAIN_RATE);
logic [DRAIN_BITS:0] drain_counter;
logic tx_drain;
always_ff @(posedge clk) begin
tx_drain <= tx_drain_enabled;
end
generate;
if (DRAIN_RATE == 0) begin
always_comb begin
tx_read = tx_drain && !tx_fifo_empty;
end
end else begin
always_comb begin
tx_read = tx_drain && !tx_fifo_empty && (drain_counter == (DRAIN_BITS + 1)'(DRAIN_RATE));
end
always_ff @(posedge clk) begin
if (drain_counter < (DRAIN_BITS + 1)'(DRAIN_RATE)) begin
drain_counter <= drain_counter + (DRAIN_BITS + 1)'('d1);
end
if (reset) begin
drain_counter <= (DRAIN_BITS + 1)'('d0);
end else begin
if (tx_read) begin
drain_counter <= (DRAIN_BITS + 1)'('d0);
end
end
end
end
endgenerate
endmodule

View File

@ -0,0 +1,70 @@
module memory_sdram_mock (
input clk,
input reset,
mem_bus.memory mem_bus
);
logic sdram_cs;
logic sdram_ras;
logic sdram_cas;
logic sdram_we;
logic [1:0] sdram_ba;
logic [12:0] sdram_a;
logic [1:0] sdram_dqm;
logic [15:0] sdram_dq;
memory_sdram memory_sdram_inst (
.clk(clk),
.reset(reset),
.mem_bus(mem_bus),
.sdram_cs(sdram_cs),
.sdram_ras(sdram_ras),
.sdram_cas(sdram_cas),
.sdram_we(sdram_we),
.sdram_ba(sdram_ba),
.sdram_a(sdram_a),
.sdram_dqm(sdram_dqm),
.sdram_dq(sdram_dq)
);
logic [1:0] cas_delay;
logic [15:0] data_from_sdram;
logic [15:0] data_to_sdram;
logic [15:0] sdram_dq_driven;
assign sdram_dq = sdram_dq_driven;
initial begin
cas_delay = 2'b00;
data_from_sdram = 16'h0102;
data_to_sdram = 16'hFFFF;
end
always_ff @(posedge clk) begin
cas_delay <= {cas_delay[0], 1'b0};
if ({sdram_cs, sdram_ras, sdram_cas, sdram_we} == 4'b0101) begin
cas_delay[0] <= 1'b1;
end
if (cas_delay[1]) begin
data_from_sdram <= data_from_sdram + 16'h0202;
end
if ({sdram_cs, sdram_ras, sdram_cas, sdram_we} == 4'b0100) begin
if (!sdram_dqm[0]) data_to_sdram[7:0] <= sdram_dq[7:0];
if (!sdram_dqm[1]) data_to_sdram[15:8] <= sdram_dq[15:8];
end
end
always_comb begin
sdram_dq_driven = 16'hXXXX;
if (cas_delay[1]) begin
sdram_dq_driven = data_from_sdram;
end
end
endmodule

0
fw/tests/traces/.gitkeep Normal file
View File

View File

@ -201,6 +201,9 @@ static bool usb_dma_ready (void) {
}
static bool usb_validate_address_length (uint32_t address, uint32_t length, bool exclude_bootloader) {
if (length == 0) {
return true;
}
if ((address >= MEMORY_LENGTH) || (length > MEMORY_LENGTH)) {
return true;
}