mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-22 05:59:15 +01:00
[SC64][FW] Verilator tests + many bugfixes in the FPGA code (#75)
This commit is contained in:
parent
5e33e516a2
commit
1b71b4a333
@ -3,6 +3,9 @@
|
|||||||
<Options/>
|
<Options/>
|
||||||
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="synplify" default_strategy="release">
|
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="synplify" default_strategy="release">
|
||||||
<Options VerilogStandard="System Verilog" def_top="top" top="top"/>
|
<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">
|
<Source name="../../rtl/memory/mem_bus.sv" type="Verilog" type_short="Verilog">
|
||||||
<Options VerilogStandard="System Verilog"/>
|
<Options VerilogStandard="System Verilog"/>
|
||||||
</Source>
|
</Source>
|
||||||
@ -12,6 +15,9 @@
|
|||||||
<Source name="../../rtl/sd/sd_scb.sv" type="Verilog" type_short="Verilog">
|
<Source name="../../rtl/sd/sd_scb.sv" type="Verilog" type_short="Verilog">
|
||||||
<Options VerilogStandard="System Verilog"/>
|
<Options VerilogStandard="System Verilog"/>
|
||||||
</Source>
|
</Source>
|
||||||
|
<Source name="../../rtl/usb/usb_scb.sv" type="Verilog" type_short="Verilog">
|
||||||
|
<Options VerilogStandard="System Verilog"/>
|
||||||
|
</Source>
|
||||||
<Source name="../../rtl/fifo/fifo_bus.sv" type="Verilog" type_short="Verilog">
|
<Source name="../../rtl/fifo/fifo_bus.sv" type="Verilog" type_short="Verilog">
|
||||||
<Options VerilogStandard="System Verilog"/>
|
<Options VerilogStandard="System Verilog"/>
|
||||||
</Source>
|
</Source>
|
||||||
|
@ -214,7 +214,7 @@ LOCATE COMP "usb_miso" SITE "10" ;
|
|||||||
LOCATE COMP "usb_pwrsav" SITE "2" ;
|
LOCATE COMP "usb_pwrsav" SITE "2" ;
|
||||||
SYSCONFIG SDM_PORT=DISABLE I2C_PORT=ENABLE ;
|
SYSCONFIG SDM_PORT=DISABLE I2C_PORT=ENABLE ;
|
||||||
VOLTAGE 3.300 V;
|
VOLTAGE 3.300 V;
|
||||||
FREQUENCY NET "clk" 100.000000 MHz PAR_ADJ 10.000000 ;
|
FREQUENCY NET "clk" 100.000000 MHz ;
|
||||||
BLOCK PATH TO PORT "mcu_int" ;
|
BLOCK PATH TO PORT "mcu_int" ;
|
||||||
BLOCK PATH TO PORT "n64_irq" ;
|
BLOCK PATH TO PORT "n64_irq" ;
|
||||||
BLOCK PATH FROM PORT "usb_pwrsav" ;
|
BLOCK PATH FROM PORT "usb_pwrsav" ;
|
||||||
|
@ -1,35 +1,29 @@
|
|||||||
interface fifo_bus ();
|
interface fifo_bus ();
|
||||||
|
|
||||||
logic rx_empty;
|
logic rx_empty;
|
||||||
logic rx_almost_empty;
|
|
||||||
logic rx_read;
|
logic rx_read;
|
||||||
logic [7:0] rx_rdata;
|
logic [7:0] rx_rdata;
|
||||||
|
|
||||||
logic tx_full;
|
logic tx_full;
|
||||||
logic tx_almost_full;
|
|
||||||
logic tx_write;
|
logic tx_write;
|
||||||
logic [7:0] tx_wdata;
|
logic [7:0] tx_wdata;
|
||||||
|
|
||||||
modport controller (
|
modport controller (
|
||||||
input rx_empty,
|
input rx_empty,
|
||||||
input rx_almost_empty,
|
|
||||||
output rx_read,
|
output rx_read,
|
||||||
input rx_rdata,
|
input rx_rdata,
|
||||||
|
|
||||||
input tx_full,
|
input tx_full,
|
||||||
input tx_almost_full,
|
|
||||||
output tx_write,
|
output tx_write,
|
||||||
output tx_wdata
|
output tx_wdata
|
||||||
);
|
);
|
||||||
|
|
||||||
modport fifo (
|
modport fifo (
|
||||||
output rx_empty,
|
output rx_empty,
|
||||||
output rx_almost_empty,
|
|
||||||
input rx_read,
|
input rx_read,
|
||||||
output rx_rdata,
|
output rx_rdata,
|
||||||
|
|
||||||
output tx_full,
|
output tx_full,
|
||||||
output tx_almost_full,
|
|
||||||
input tx_write,
|
input tx_write,
|
||||||
input tx_wdata
|
input tx_wdata
|
||||||
);
|
);
|
||||||
|
@ -11,16 +11,12 @@ module fifo_junction (
|
|||||||
dev_bus.tx_wdata = cfg_bus.tx_write ? cfg_bus.tx_wdata : dma_bus.tx_wdata;
|
dev_bus.tx_wdata = cfg_bus.tx_write ? cfg_bus.tx_wdata : dma_bus.tx_wdata;
|
||||||
|
|
||||||
cfg_bus.rx_empty = dev_bus.rx_empty;
|
cfg_bus.rx_empty = dev_bus.rx_empty;
|
||||||
cfg_bus.rx_almost_empty = dev_bus.rx_almost_empty;
|
|
||||||
cfg_bus.rx_rdata = dev_bus.rx_rdata;
|
cfg_bus.rx_rdata = dev_bus.rx_rdata;
|
||||||
cfg_bus.tx_full = dev_bus.tx_full;
|
cfg_bus.tx_full = dev_bus.tx_full;
|
||||||
cfg_bus.tx_almost_full = dev_bus.tx_almost_full;
|
|
||||||
|
|
||||||
dma_bus.rx_empty = dev_bus.rx_empty;
|
dma_bus.rx_empty = dev_bus.rx_empty;
|
||||||
dma_bus.rx_almost_empty = dev_bus.rx_almost_empty;
|
|
||||||
dma_bus.rx_rdata = dev_bus.rx_rdata;
|
dma_bus.rx_rdata = dev_bus.rx_rdata;
|
||||||
dma_bus.tx_full = dev_bus.tx_full;
|
dma_bus.tx_full = dev_bus.tx_full;
|
||||||
dma_bus.tx_almost_full = dev_bus.tx_almost_full;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
31
fw/rtl/memory/dma_scb.sv
Normal file
31
fw/rtl/memory/dma_scb.sv
Normal 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
|
@ -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 (
|
module memory_dma (
|
||||||
input clk,
|
input clk,
|
||||||
input reset,
|
input reset,
|
||||||
@ -41,227 +8,403 @@ module memory_dma (
|
|||||||
mem_bus.controller mem_bus
|
mem_bus.controller mem_bus
|
||||||
);
|
);
|
||||||
|
|
||||||
// DMA start/stop control
|
// Start/stop logic
|
||||||
|
|
||||||
logic dma_start;
|
logic dma_start;
|
||||||
logic dma_stop;
|
logic dma_stop;
|
||||||
logic dma_stop_requested;
|
|
||||||
|
|
||||||
always_comb begin
|
|
||||||
dma_start = dma_scb.start && !dma_scb.stop && !dma_scb.busy;
|
|
||||||
dma_stop = dma_scb.stop;
|
|
||||||
end
|
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
if (reset) begin
|
dma_start <= 1'b0;
|
||||||
dma_stop_requested <= 1'b0;
|
if (dma_scb.stop) begin
|
||||||
end else begin
|
dma_stop <= 1'b1;
|
||||||
if (dma_stop) begin
|
end else if (dma_scb.start) begin
|
||||||
dma_stop_requested <= 1'b1;
|
dma_start <= 1'b1;
|
||||||
end
|
dma_stop <= 1'b0;
|
||||||
if (dma_start) begin
|
|
||||||
dma_stop_requested <= 1'b0;
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
// Remaining counter and FIFO enable
|
// Memory bus controller
|
||||||
|
|
||||||
logic [26:0] remaining;
|
typedef enum bit [1:0] {
|
||||||
logic trx_enabled;
|
MEM_BUS_STATE_IDLE,
|
||||||
|
MEM_BUS_STATE_WAIT,
|
||||||
|
MEM_BUS_STATE_TRANSFER
|
||||||
|
} e_mem_bus_state;
|
||||||
|
|
||||||
|
e_mem_bus_state mem_bus_state;
|
||||||
|
e_mem_bus_state next_mem_bus_state;
|
||||||
|
|
||||||
|
logic mem_bus_wdata_ready;
|
||||||
|
logic mem_bus_wdata_empty;
|
||||||
|
logic mem_bus_wdata_end;
|
||||||
|
logic [1:0] mem_bus_wdata_valid;
|
||||||
|
logic [15:0] mem_bus_wdata_buffer;
|
||||||
|
|
||||||
|
logic mem_bus_rdata_ready;
|
||||||
|
logic mem_bus_rdata_ack;
|
||||||
|
logic mem_bus_rdata_end;
|
||||||
|
logic [1:0] mem_bus_rdata_valid;
|
||||||
|
logic [15:0] mem_bus_rdata_buffer;
|
||||||
|
|
||||||
|
logic [26:0] mem_bus_remaining_bytes;
|
||||||
|
logic mem_bus_last_transfer;
|
||||||
|
logic mem_bus_almost_last_transfer;
|
||||||
|
logic mem_bus_unaligned_start;
|
||||||
|
logic mem_bus_unaligned_end;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (reset) begin
|
||||||
|
mem_bus_state <= MEM_BUS_STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
mem_bus_state <= next_mem_bus_state;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
trx_enabled = remaining > 27'd0;
|
next_mem_bus_state = mem_bus_state;
|
||||||
|
|
||||||
|
mem_bus_last_transfer = (mem_bus_remaining_bytes == 27'd0);
|
||||||
|
mem_bus_almost_last_transfer = (mem_bus_remaining_bytes <= 27'd2);
|
||||||
|
|
||||||
|
mem_bus_wdata_end = mem_bus_last_transfer;
|
||||||
|
mem_bus_wdata_valid = (mem_bus_unaligned_end && mem_bus_almost_last_transfer) ? 2'b10 :
|
||||||
|
mem_bus_unaligned_start ? 2'b01 :
|
||||||
|
2'b11;
|
||||||
|
|
||||||
|
case (mem_bus_state)
|
||||||
|
MEM_BUS_STATE_IDLE: begin
|
||||||
|
if (dma_start) begin
|
||||||
|
next_mem_bus_state = MEM_BUS_STATE_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MEM_BUS_STATE_WAIT: begin
|
||||||
|
if (dma_stop || mem_bus_last_transfer) begin
|
||||||
|
next_mem_bus_state = MEM_BUS_STATE_IDLE;
|
||||||
|
end else if (mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready) begin
|
||||||
|
next_mem_bus_state = MEM_BUS_STATE_TRANSFER;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MEM_BUS_STATE_TRANSFER: begin
|
||||||
|
if (mem_bus.ack) begin
|
||||||
|
if (dma_stop || mem_bus_last_transfer) begin
|
||||||
|
next_mem_bus_state = MEM_BUS_STATE_IDLE;
|
||||||
|
end else if (!(mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready)) begin
|
||||||
|
next_mem_bus_state = MEM_BUS_STATE_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin
|
||||||
|
next_mem_bus_state = MEM_BUS_STATE_IDLE;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
mem_bus_rdata_ack <= 1'b0;
|
||||||
|
|
||||||
|
if (mem_bus.ack) begin
|
||||||
|
mem_bus.request <= 1'b0;
|
||||||
|
mem_bus.address <= (mem_bus.address + 26'd2);
|
||||||
|
mem_bus_rdata_ack <= 1'b1;
|
||||||
|
mem_bus_rdata_end <= mem_bus_last_transfer;
|
||||||
|
mem_bus_rdata_valid <= mem_bus.wmask;
|
||||||
|
mem_bus_rdata_buffer <= mem_bus.rdata;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (mem_bus_wdata_ready) begin
|
||||||
|
mem_bus_wdata_empty <= 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
case (mem_bus_state)
|
||||||
|
MEM_BUS_STATE_IDLE: begin
|
||||||
|
mem_bus.request <= 1'b0;
|
||||||
|
mem_bus_rdata_end <= 1'b1;
|
||||||
|
if (dma_start) begin
|
||||||
|
mem_bus.write <= dma_scb.direction;
|
||||||
|
mem_bus.address <= {dma_scb.starting_address[26:1], 1'b0};
|
||||||
|
mem_bus_remaining_bytes <= dma_scb.transfer_length;
|
||||||
|
mem_bus_unaligned_start <= dma_scb.starting_address[0];
|
||||||
|
mem_bus_unaligned_end <= (dma_scb.starting_address[0] ^ dma_scb.transfer_length[0]);
|
||||||
|
mem_bus_rdata_end <= 1'b0;
|
||||||
|
mem_bus_wdata_empty <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MEM_BUS_STATE_WAIT: begin
|
||||||
|
if (!dma_stop && !mem_bus_last_transfer) begin
|
||||||
|
if (mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready) begin
|
||||||
|
mem_bus.request <= 1'b1;
|
||||||
|
mem_bus_unaligned_start <= 1'b0;
|
||||||
|
mem_bus.wdata <= (dma_scb.byte_swap ? {mem_bus_wdata_buffer[7:0], mem_bus_wdata_buffer[15:8]} : mem_bus_wdata_buffer);
|
||||||
|
mem_bus.wmask <= 2'b11;
|
||||||
|
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd2);
|
||||||
|
if (mem_bus_unaligned_end && mem_bus_almost_last_transfer) begin
|
||||||
|
mem_bus.wmask <= 2'b10;
|
||||||
|
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd1);
|
||||||
|
end
|
||||||
|
if (mem_bus_unaligned_start) begin
|
||||||
|
mem_bus.wmask <= 2'b01;
|
||||||
|
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd1);
|
||||||
|
end
|
||||||
|
mem_bus_wdata_empty <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
MEM_BUS_STATE_TRANSFER: begin
|
||||||
|
if (!dma_stop && !mem_bus_last_transfer) begin
|
||||||
|
if (mem_bus.ack && (mem_bus_wdata_ready || !mem_bus_wdata_empty || mem_bus_rdata_ready)) begin
|
||||||
|
mem_bus.request <= 1'b1;
|
||||||
|
mem_bus.wdata <= (dma_scb.byte_swap ? {mem_bus_wdata_buffer[7:0], mem_bus_wdata_buffer[15:8]} : mem_bus_wdata_buffer);
|
||||||
|
mem_bus.wmask <= 2'b11;
|
||||||
|
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd2);
|
||||||
|
if (mem_bus_unaligned_end && mem_bus_almost_last_transfer) begin
|
||||||
|
mem_bus.wmask <= 2'b10;
|
||||||
|
mem_bus_remaining_bytes <= (mem_bus_remaining_bytes - 27'd1);
|
||||||
|
end
|
||||||
|
mem_bus_wdata_empty <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin end
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
// RX FIFO controller
|
// RX FIFO controller
|
||||||
|
|
||||||
logic [1:0] rx_wmask;
|
typedef enum bit [2:0] {
|
||||||
logic rx_rdata_pop;
|
RX_FIFO_BUS_STATE_IDLE,
|
||||||
logic rx_rdata_shift;
|
RX_FIFO_BUS_STATE_WAIT,
|
||||||
logic rx_rdata_valid;
|
RX_FIFO_BUS_STATE_TRANSFER_1,
|
||||||
logic [15:0] rx_buffer;
|
RX_FIFO_BUS_STATE_TRANSFER_2,
|
||||||
logic rx_buffer_valid;
|
RX_FIFO_BUS_STATE_ACK
|
||||||
logic [1:0] rx_buffer_counter;
|
} e_rx_fifo_bus_state;
|
||||||
logic [1:0] rx_buffer_valid_counter;
|
|
||||||
|
e_rx_fifo_bus_state rx_fifo_bus_state;
|
||||||
|
e_rx_fifo_bus_state next_rx_fifo_bus_state;
|
||||||
|
|
||||||
|
logic rx_fifo_shift;
|
||||||
|
logic rx_fifo_shift_delayed;
|
||||||
|
logic [1:0] rx_fifo_valid;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (reset || dma_stop) begin
|
||||||
|
rx_fifo_bus_state <= RX_FIFO_BUS_STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
rx_fifo_bus_state <= next_rx_fifo_bus_state;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
rx_buffer_valid = rx_buffer_valid_counter == 2'd2;
|
next_rx_fifo_bus_state = rx_fifo_bus_state;
|
||||||
|
|
||||||
|
rx_fifo_shift = 1'b0;
|
||||||
|
|
||||||
|
fifo_bus.rx_read = 1'b0;
|
||||||
|
|
||||||
|
case (rx_fifo_bus_state)
|
||||||
|
RX_FIFO_BUS_STATE_IDLE: begin
|
||||||
|
if (dma_start && dma_scb.direction) begin
|
||||||
|
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RX_FIFO_BUS_STATE_WAIT: begin
|
||||||
|
if (mem_bus_wdata_end) begin
|
||||||
|
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_IDLE;
|
||||||
|
end else if (mem_bus_wdata_empty) begin
|
||||||
|
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_TRANSFER_1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RX_FIFO_BUS_STATE_TRANSFER_1: begin
|
||||||
|
fifo_bus.rx_read = (!fifo_bus.rx_empty && rx_fifo_valid[1]);
|
||||||
|
if (!fifo_bus.rx_empty || !rx_fifo_valid[1]) begin
|
||||||
|
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_TRANSFER_2;
|
||||||
|
rx_fifo_shift = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RX_FIFO_BUS_STATE_TRANSFER_2: begin
|
||||||
|
fifo_bus.rx_read = (!fifo_bus.rx_empty && rx_fifo_valid[1]);
|
||||||
|
if (!fifo_bus.rx_empty || !rx_fifo_valid[1]) begin
|
||||||
|
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_ACK;
|
||||||
|
rx_fifo_shift = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RX_FIFO_BUS_STATE_ACK: begin
|
||||||
|
if (mem_bus_wdata_ready) begin
|
||||||
|
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_WAIT;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin
|
||||||
|
next_rx_fifo_bus_state = RX_FIFO_BUS_STATE_IDLE;
|
||||||
|
end
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
rx_rdata_pop <= (
|
mem_bus_wdata_ready <= 1'b0;
|
||||||
!rx_rdata_pop &&
|
rx_fifo_shift_delayed <= rx_fifo_shift;
|
||||||
!fifo_bus.rx_read &&
|
|
||||||
trx_enabled &&
|
|
||||||
rx_buffer_counter < 2'd2 &&
|
|
||||||
!fifo_bus.rx_empty &&
|
|
||||||
mem_bus.write
|
|
||||||
);
|
|
||||||
rx_rdata_shift <= 1'b0;
|
|
||||||
fifo_bus.rx_read <= rx_rdata_pop;
|
|
||||||
rx_rdata_valid <= fifo_bus.rx_read;
|
|
||||||
|
|
||||||
if (dma_start) begin
|
if (rx_fifo_shift) begin
|
||||||
if (dma_scb.starting_address[0]) begin
|
rx_fifo_valid <= {rx_fifo_valid[0], 1'bX};
|
||||||
rx_wmask <= 2'b01;
|
end
|
||||||
rx_buffer_counter <= 2'd1;
|
|
||||||
rx_buffer_valid_counter <= 2'd1;
|
if (rx_fifo_shift_delayed) begin
|
||||||
end else begin
|
if (rx_fifo_bus_state == RX_FIFO_BUS_STATE_ACK) begin
|
||||||
rx_wmask <= 2'b11;
|
mem_bus_wdata_ready <= 1'b1;
|
||||||
rx_buffer_counter <= 2'd0;
|
|
||||||
rx_buffer_valid_counter <= 2'd0;
|
|
||||||
end
|
end
|
||||||
|
mem_bus_wdata_buffer <= {mem_bus_wdata_buffer[7:0], fifo_bus.rx_rdata};
|
||||||
end
|
end
|
||||||
|
|
||||||
if (rx_rdata_pop) begin
|
case (rx_fifo_bus_state)
|
||||||
rx_buffer_counter <= rx_buffer_counter + 1'd1;
|
RX_FIFO_BUS_STATE_WAIT: begin
|
||||||
end
|
if (mem_bus_wdata_empty) begin
|
||||||
|
rx_fifo_valid <= mem_bus_wdata_valid;
|
||||||
if (rx_rdata_shift || rx_rdata_valid) begin
|
end
|
||||||
if (dma_scb.byte_swap) begin
|
|
||||||
rx_buffer <= {fifo_bus.rx_rdata, rx_buffer[15:8]};
|
|
||||||
end else begin
|
|
||||||
rx_buffer <= {rx_buffer[7:0], fifo_bus.rx_rdata};
|
|
||||||
end
|
end
|
||||||
rx_buffer_valid_counter <= rx_buffer_valid_counter + 1'd1;
|
|
||||||
if (remaining == 27'd0 && rx_buffer_counter == 2'd1) begin
|
|
||||||
rx_wmask <= 2'b10;
|
|
||||||
rx_rdata_shift <= 1'b1;
|
|
||||||
rx_buffer_counter <= rx_buffer_counter + 1'd1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (rx_buffer_valid && !mem_bus.request) begin
|
default: begin end
|
||||||
rx_wmask <= 2'b11;
|
endcase
|
||||||
rx_buffer_counter <= 2'd0;
|
|
||||||
rx_buffer_valid_counter <= 2'd0;
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
// TX FIFO controller
|
// TX FIFO controller
|
||||||
|
|
||||||
logic tx_wdata_push;
|
typedef enum bit [1:0] {
|
||||||
logic tx_wdata_first_push;
|
TX_FIFO_BUS_STATE_IDLE,
|
||||||
logic [7:0] tx_buffer;
|
TX_FIFO_BUS_STATE_WAIT,
|
||||||
logic tx_buffer_counter;
|
TX_FIFO_BUS_STATE_TRANSFER_1,
|
||||||
logic tx_buffer_ready;
|
TX_FIFO_BUS_STATE_TRANSFER_2
|
||||||
logic tx_buffer_valid;
|
} e_tx_fifo_bus_state;
|
||||||
|
|
||||||
|
e_tx_fifo_bus_state tx_fifo_bus_state;
|
||||||
|
e_tx_fifo_bus_state next_tx_fifo_bus_state;
|
||||||
|
|
||||||
|
logic tx_fifo_shift;
|
||||||
|
logic tx_fifo_waiting;
|
||||||
|
logic [1:0] tx_fifo_valid;
|
||||||
|
logic [15:0] tx_fifo_buffer;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (reset || dma_stop) begin
|
||||||
|
tx_fifo_bus_state <= TX_FIFO_BUS_STATE_IDLE;
|
||||||
|
end else begin
|
||||||
|
tx_fifo_bus_state <= next_tx_fifo_bus_state;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
always_comb begin
|
always_comb begin
|
||||||
fifo_bus.tx_write = tx_wdata_push;
|
next_tx_fifo_bus_state = tx_fifo_bus_state;
|
||||||
end
|
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
tx_fifo_shift = 1'b0;
|
||||||
tx_wdata_push <= (
|
|
||||||
!tx_wdata_push &&
|
|
||||||
trx_enabled &&
|
|
||||||
tx_buffer_valid &&
|
|
||||||
!fifo_bus.tx_full &&
|
|
||||||
!mem_bus.write
|
|
||||||
);
|
|
||||||
|
|
||||||
if (reset || dma_stop) begin
|
fifo_bus.tx_write = 1'b0;
|
||||||
tx_buffer_ready <= 1'b0;
|
fifo_bus.tx_wdata = tx_fifo_buffer[15:8];
|
||||||
tx_buffer_valid <= 1'b0;
|
|
||||||
end
|
|
||||||
|
|
||||||
if (dma_start) begin
|
case (tx_fifo_bus_state)
|
||||||
tx_wdata_first_push <= 1'b1;
|
TX_FIFO_BUS_STATE_IDLE: begin
|
||||||
tx_buffer_ready <= 1'b1;
|
if (dma_start && !dma_scb.direction) begin
|
||||||
tx_buffer_valid <= 1'b0;
|
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_WAIT;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (tx_buffer_ready && mem_bus.request) begin
|
|
||||||
tx_buffer_ready <= 1'b0;
|
|
||||||
end
|
|
||||||
|
|
||||||
if (mem_bus.ack) begin
|
|
||||||
tx_wdata_first_push <= 1'b0;
|
|
||||||
tx_buffer_counter <= 1'd1;
|
|
||||||
tx_buffer_valid <= 1'b1;
|
|
||||||
{fifo_bus.tx_wdata, tx_buffer} <= mem_bus.rdata;
|
|
||||||
if (tx_wdata_first_push && dma_scb.starting_address[0]) begin
|
|
||||||
fifo_bus.tx_wdata <= mem_bus.rdata[7:0];
|
|
||||||
tx_buffer_counter <= 1'd0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (tx_wdata_push) begin
|
|
||||||
tx_buffer_counter <= tx_buffer_counter - 1'd1;
|
|
||||||
fifo_bus.tx_wdata <= tx_buffer;
|
|
||||||
if (tx_buffer_counter == 1'd0) begin
|
|
||||||
tx_buffer_ready <= 1'b1;
|
|
||||||
tx_buffer_valid <= 1'b0;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
// Remaining counter controller
|
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
|
||||||
if (reset || dma_stop) begin
|
|
||||||
remaining <= 27'd0;
|
|
||||||
end else begin
|
|
||||||
if (dma_start) begin
|
|
||||||
remaining <= dma_scb.transfer_length;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if (!dma_stop_requested && ((mem_bus.write && rx_rdata_pop) || (!mem_bus.write && tx_wdata_push))) begin
|
TX_FIFO_BUS_STATE_WAIT: begin
|
||||||
remaining <= remaining - 1'd1;
|
if (mem_bus_rdata_ack || tx_fifo_waiting) begin
|
||||||
|
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_TRANSFER_1;
|
||||||
|
end else if (mem_bus_rdata_end) begin
|
||||||
|
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_IDLE;
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
TX_FIFO_BUS_STATE_TRANSFER_1: begin
|
||||||
|
fifo_bus.tx_write = (!fifo_bus.tx_full && tx_fifo_valid[1]);
|
||||||
|
if (!fifo_bus.tx_full || !tx_fifo_valid[1]) begin
|
||||||
|
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_TRANSFER_2;
|
||||||
|
tx_fifo_shift = 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
// Mem bus controller
|
TX_FIFO_BUS_STATE_TRANSFER_2: begin
|
||||||
|
fifo_bus.tx_write = (!fifo_bus.tx_full && tx_fifo_valid[1]);
|
||||||
always_ff @(posedge clk) begin
|
if (!fifo_bus.tx_full || !tx_fifo_valid[1]) begin
|
||||||
dma_scb.busy <= mem_bus.request || trx_enabled;
|
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_WAIT;
|
||||||
end
|
tx_fifo_shift = 1'b1;
|
||||||
|
if (!mem_bus_rdata_ack && !tx_fifo_waiting && mem_bus_rdata_end) begin
|
||||||
always_ff @(posedge clk) begin
|
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_IDLE;
|
||||||
if (reset) begin
|
|
||||||
mem_bus.request <= 1'b0;
|
|
||||||
end else begin
|
|
||||||
if (!mem_bus.request) begin
|
|
||||||
if (mem_bus.write) begin
|
|
||||||
if (rx_buffer_valid) begin
|
|
||||||
mem_bus.request <= 1'b1;
|
|
||||||
mem_bus.wmask <= rx_wmask;
|
|
||||||
mem_bus.wdata <= rx_buffer;
|
|
||||||
end
|
|
||||||
end else begin
|
|
||||||
if (tx_buffer_ready) begin
|
|
||||||
mem_bus.request <= 1'b1;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
if (mem_bus.ack) begin
|
default: begin
|
||||||
mem_bus.request <= 1'b0;
|
next_tx_fifo_bus_state = TX_FIFO_BUS_STATE_IDLE;
|
||||||
end
|
end
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
if (dma_start) begin
|
if (tx_fifo_shift) begin
|
||||||
mem_bus.write <= dma_scb.direction;
|
tx_fifo_valid <= {tx_fifo_valid[0], 1'bX};
|
||||||
|
tx_fifo_buffer <= {tx_fifo_buffer[7:0], 8'hXX};
|
||||||
end
|
end
|
||||||
|
|
||||||
|
case (tx_fifo_bus_state)
|
||||||
|
TX_FIFO_BUS_STATE_IDLE: begin
|
||||||
|
mem_bus_rdata_ready <= 1'b0;
|
||||||
|
tx_fifo_waiting <= 1'b0;
|
||||||
|
if (dma_start) begin
|
||||||
|
mem_bus_rdata_ready <= !dma_scb.direction;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
TX_FIFO_BUS_STATE_WAIT: begin
|
||||||
|
if (mem_bus_rdata_ack || tx_fifo_waiting) begin
|
||||||
|
mem_bus_rdata_ready <= 1'b0;
|
||||||
|
tx_fifo_waiting <= 1'b0;
|
||||||
|
tx_fifo_valid <= mem_bus_rdata_valid;
|
||||||
|
tx_fifo_buffer <= mem_bus_rdata_buffer;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
TX_FIFO_BUS_STATE_TRANSFER_1: begin
|
||||||
|
if (mem_bus_rdata_ack) begin
|
||||||
|
tx_fifo_waiting <= 1'b1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
TX_FIFO_BUS_STATE_TRANSFER_2: begin
|
||||||
|
if (mem_bus_rdata_ack) begin
|
||||||
|
tx_fifo_waiting <= 1'b1;
|
||||||
|
end
|
||||||
|
if (fifo_bus.tx_write || !tx_fifo_valid[1]) begin
|
||||||
|
mem_bus_rdata_ready <= !mem_bus_rdata_end;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
default: begin end
|
||||||
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
|
||||||
if (dma_start) begin
|
|
||||||
mem_bus.address <= {dma_scb.starting_address[26:1], 1'b0};
|
|
||||||
end
|
|
||||||
|
|
||||||
if (mem_bus.ack) begin
|
// DMA busy indicator
|
||||||
mem_bus.address <= mem_bus.address + 2'd2;
|
|
||||||
end
|
always_ff @(posedge clk) begin
|
||||||
|
dma_scb.busy <= (
|
||||||
|
(dma_scb.start && !dma_scb.stop) ||
|
||||||
|
dma_start ||
|
||||||
|
(mem_bus_state != MEM_BUS_STATE_IDLE) ||
|
||||||
|
(rx_fifo_bus_state != RX_FIFO_BUS_STATE_IDLE) ||
|
||||||
|
(tx_fifo_bus_state != TX_FIFO_BUS_STATE_IDLE)
|
||||||
|
);
|
||||||
end
|
end
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -14,29 +14,38 @@ module memory_sdram (
|
|||||||
inout [15:0] sdram_dq
|
inout [15:0] sdram_dq
|
||||||
);
|
);
|
||||||
|
|
||||||
localparam [2:0] CAS_LATENCY = 3'd2;
|
// in Hz
|
||||||
|
localparam real FREQUENCY = 100_000_000.0;
|
||||||
|
|
||||||
localparam real T_INIT = 100_000.0;
|
// in clocks
|
||||||
localparam real T_RC = 60.0;
|
localparam bit [2:0] CAS_LATENCY = 3'd2;
|
||||||
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_CLK = (1.0 / 100_000_000) * 1_000_000_000.0;
|
// in nanoseconds
|
||||||
localparam int C_INIT = int'((T_INIT + T_CLK - 1) / T_CLK);
|
localparam real T_INIT = 100_000.0;
|
||||||
localparam int C_RC = int'((T_RC + T_CLK - 1) / T_CLK);
|
localparam real T_MRD = 14.0;
|
||||||
localparam int C_RP = int'((T_RP + T_CLK - 1) / T_CLK);
|
localparam real T_RAS = 37.0;
|
||||||
localparam int C_RCD = int'((T_RCD + T_CLK - 1) / T_CLK);
|
localparam real T_RC = 60.0;
|
||||||
localparam int C_MRD = int'((T_MRD + T_CLK - 1) / T_CLK);
|
localparam real T_RCD = 15.0;
|
||||||
localparam int C_REF = int'((T_REF + T_CLK - 1) / T_CLK);
|
localparam real T_REF = 7_812.5;
|
||||||
|
localparam real T_RP = 15.0;
|
||||||
|
|
||||||
localparam INIT_PRECHARGE = 4'd0;
|
localparam real T_CLK = (1.0 / FREQUENCY) * 1_000_000_000.0;
|
||||||
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_MRD = 5'(int'($ceil(T_MRD / T_CLK)));
|
||||||
|
const bit [2:0] C_RAS = 3'(int'($ceil(T_RAS / T_CLK)));
|
||||||
|
const bit [4:0] C_RC = 5'(int'($ceil(T_RC / T_CLK)));
|
||||||
|
const bit [4:0] C_RCD = 5'(int'($ceil(T_RCD / T_CLK)));
|
||||||
|
const bit [13:0] C_REF = 14'(int'($ceil(T_REF / T_CLK)));
|
||||||
|
const bit [4:0] C_RP = 5'(int'($ceil(T_RP / 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] {
|
typedef enum bit [3:0] {
|
||||||
CMD_DESL = 4'b1111,
|
CMD_DESL = 4'b1111,
|
||||||
CMD_NOP = 4'b0111,
|
CMD_NOP = 4'b0111,
|
||||||
@ -58,13 +67,10 @@ module memory_sdram (
|
|||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
{sdram_cs, sdram_ras, sdram_cas, sdram_we} <= 4'(sdram_next_cmd);
|
{sdram_cs, sdram_ras, sdram_cas, sdram_we} <= 4'(sdram_next_cmd);
|
||||||
|
|
||||||
{sdram_ba, sdram_a} <= 15'd0;
|
{sdram_ba, sdram_a} <= 15'd0;
|
||||||
sdram_dqm <= 2'b00;
|
sdram_dqm <= 2'b00;
|
||||||
|
|
||||||
sdram_dq_input <= sdram_dq;
|
sdram_dq_input <= sdram_dq;
|
||||||
sdram_dq_output <= mem_bus.wdata;
|
sdram_dq_output <= mem_bus.wdata;
|
||||||
|
|
||||||
sdram_dq_output_enable <= 1'b0;
|
sdram_dq_output_enable <= 1'b0;
|
||||||
|
|
||||||
case (sdram_next_cmd)
|
case (sdram_next_cmd)
|
||||||
@ -76,19 +82,31 @@ module memory_sdram (
|
|||||||
|
|
||||||
CMD_ACT: begin
|
CMD_ACT: begin
|
||||||
{sdram_ba, sdram_a} <= mem_bus.address[25:11];
|
{sdram_ba, sdram_a} <= mem_bus.address[25:11];
|
||||||
sdram_dqm <= 2'b00;
|
|
||||||
current_active_bank_row <= mem_bus.address[25:11];
|
current_active_bank_row <= mem_bus.address[25:11];
|
||||||
end
|
end
|
||||||
|
|
||||||
CMD_PRE: begin
|
CMD_PRE: begin
|
||||||
{sdram_ba, sdram_a} <= {2'b00, 2'b00, 1'b1, 10'd0};
|
{sdram_ba, sdram_a} <= {
|
||||||
sdram_dqm <= 2'b00;
|
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
|
end
|
||||||
|
|
||||||
CMD_MRS: begin
|
CMD_MRS: begin
|
||||||
{sdram_ba, sdram_a} <= {2'b00, 1'b0, 1'b0, 2'b00, CAS_LATENCY, 1'b0, 3'b000};
|
{sdram_ba, sdram_a} <= {
|
||||||
sdram_dqm <= 2'b00;
|
2'b00, // [BA1:BA0] Reserved = 0
|
||||||
|
3'b000, // [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
|
end
|
||||||
|
|
||||||
|
default: begin end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -121,35 +139,51 @@ module memory_sdram (
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
logic [13:0] powerup_coutner;
|
logic [13:0] refresh_counter;
|
||||||
logic powerup_done;
|
|
||||||
logic [4:0] wait_counter;
|
logic [4:0] wait_counter;
|
||||||
logic [9:0] refresh_counter;
|
logic [2:0] precharge_counter;
|
||||||
|
logic powerup_done;
|
||||||
logic pending_refresh;
|
logic pending_refresh;
|
||||||
|
logic precharge_valid;
|
||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
if (reset) begin
|
refresh_counter <= refresh_counter + 1'd1;
|
||||||
powerup_coutner <= 14'd0;
|
|
||||||
powerup_done <= 1'b0;
|
if (refresh_counter == C_INIT) begin
|
||||||
end else if (powerup_coutner < C_INIT) begin
|
refresh_counter <= 14'd0;
|
||||||
powerup_coutner <= powerup_coutner + 1'd1;
|
|
||||||
end else begin
|
|
||||||
powerup_done <= 1'b1;
|
powerup_done <= 1'b1;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (reset || state != next_state) begin
|
if (powerup_done && refresh_counter == C_REF - 14'd1) begin
|
||||||
wait_counter <= 5'd0;
|
refresh_counter <= 14'd0;
|
||||||
end else begin
|
pending_refresh <= 1'b1;
|
||||||
wait_counter <= wait_counter + 1'd1;
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if (sdram_next_cmd == CMD_REF) begin
|
if (sdram_next_cmd == CMD_REF) begin
|
||||||
refresh_counter <= 10'd0;
|
|
||||||
pending_refresh <= 1'b0;
|
pending_refresh <= 1'b0;
|
||||||
end else if (refresh_counter < C_REF) begin
|
end
|
||||||
refresh_counter <= refresh_counter + 1'd1;
|
|
||||||
end else begin
|
if (reset) begin
|
||||||
pending_refresh <= 1'b1;
|
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
|
||||||
|
|
||||||
|
precharge_counter <= precharge_counter + 1'd1;
|
||||||
|
|
||||||
|
if (precharge_counter >= C_RAS - 2'd2) begin
|
||||||
|
precharge_valid <= 1'b1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if (sdram_next_cmd == CMD_ACT) begin
|
||||||
|
precharge_counter <= 3'd0;
|
||||||
|
precharge_valid <= 1'b0;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -157,6 +191,7 @@ module memory_sdram (
|
|||||||
|
|
||||||
always_ff @(posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
mem_bus.ack <= 1'b0;
|
mem_bus.ack <= 1'b0;
|
||||||
|
|
||||||
read_cmd_ack_delay <= {sdram_next_cmd == CMD_READ, read_cmd_ack_delay[(CAS_LATENCY):1]};
|
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
|
if (sdram_next_cmd == CMD_WRITE || read_cmd_ack_delay[0]) begin
|
||||||
@ -202,20 +237,20 @@ module memory_sdram (
|
|||||||
end
|
end
|
||||||
|
|
||||||
S_ACTIVATING: begin
|
S_ACTIVATING: begin
|
||||||
if (wait_counter == C_RCD) begin
|
if (wait_counter == C_RCD - 5'd2) begin
|
||||||
next_state = S_ACTIVE;
|
next_state = S_ACTIVE;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
S_ACTIVE: begin
|
S_ACTIVE: begin
|
||||||
if (pending_refresh) begin
|
if (pending_refresh && precharge_valid) begin
|
||||||
next_state = S_PRECHARGE;
|
next_state = S_PRECHARGE;
|
||||||
sdram_next_cmd = CMD_PRE;
|
sdram_next_cmd = CMD_PRE;
|
||||||
end else if (mem_bus.request) begin
|
end else if (mem_bus.request) begin
|
||||||
if (request_in_current_active_bank_row) begin
|
if (request_in_current_active_bank_row) begin
|
||||||
next_state = S_BUSY;
|
next_state = S_BUSY;
|
||||||
sdram_next_cmd = mem_bus.write ? CMD_WRITE : CMD_READ;
|
sdram_next_cmd = mem_bus.write ? CMD_WRITE : CMD_READ;
|
||||||
end else begin
|
end else if (precharge_valid) begin
|
||||||
next_state = S_PRECHARGE;
|
next_state = S_PRECHARGE;
|
||||||
sdram_next_cmd = CMD_PRE;
|
sdram_next_cmd = CMD_PRE;
|
||||||
end
|
end
|
||||||
@ -229,18 +264,13 @@ module memory_sdram (
|
|||||||
end
|
end
|
||||||
|
|
||||||
S_PRECHARGE: begin
|
S_PRECHARGE: begin
|
||||||
if (wait_counter == C_RP) begin
|
if (wait_counter == C_RP - 5'd2) begin
|
||||||
if (pending_refresh) begin
|
next_state = S_IDLE;
|
||||||
next_state = S_REFRESH;
|
|
||||||
sdram_next_cmd = CMD_REF;
|
|
||||||
end else begin
|
|
||||||
next_state = S_IDLE;
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
S_REFRESH: begin
|
S_REFRESH: begin
|
||||||
if (wait_counter == C_RC) begin
|
if (wait_counter == C_RC - 5'd2) begin
|
||||||
next_state = S_IDLE;
|
next_state = S_IDLE;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -36,12 +36,10 @@ module sd_dat (
|
|||||||
// FIFO
|
// FIFO
|
||||||
|
|
||||||
logic rx_full;
|
logic rx_full;
|
||||||
logic rx_almost_full;
|
|
||||||
logic rx_write;
|
logic rx_write;
|
||||||
logic [7:0] rx_wdata;
|
logic [7:0] rx_wdata;
|
||||||
|
|
||||||
logic tx_empty;
|
logic tx_empty;
|
||||||
logic tx_almost_empty;
|
|
||||||
logic tx_read;
|
logic tx_read;
|
||||||
logic [7:0] tx_rdata;
|
logic [7:0] tx_rdata;
|
||||||
|
|
||||||
@ -50,12 +48,10 @@ module sd_dat (
|
|||||||
.reset(reset || sd_scb.dat_fifo_flush),
|
.reset(reset || sd_scb.dat_fifo_flush),
|
||||||
|
|
||||||
.empty(fifo_bus.rx_empty),
|
.empty(fifo_bus.rx_empty),
|
||||||
.almost_empty(fifo_bus.rx_almost_empty),
|
|
||||||
.read(fifo_bus.rx_read),
|
.read(fifo_bus.rx_read),
|
||||||
.rdata(fifo_bus.rx_rdata),
|
.rdata(fifo_bus.rx_rdata),
|
||||||
|
|
||||||
.full(rx_full),
|
.full(rx_full),
|
||||||
.almost_full(rx_almost_full),
|
|
||||||
.write(rx_write),
|
.write(rx_write),
|
||||||
.wdata(rx_wdata),
|
.wdata(rx_wdata),
|
||||||
|
|
||||||
@ -67,12 +63,10 @@ module sd_dat (
|
|||||||
.reset(reset || sd_scb.dat_fifo_flush),
|
.reset(reset || sd_scb.dat_fifo_flush),
|
||||||
|
|
||||||
.empty(tx_empty),
|
.empty(tx_empty),
|
||||||
.almost_empty(tx_almost_empty),
|
|
||||||
.read(tx_read),
|
.read(tx_read),
|
||||||
.rdata(tx_rdata),
|
.rdata(tx_rdata),
|
||||||
|
|
||||||
.full(fifo_bus.tx_full),
|
.full(fifo_bus.tx_full),
|
||||||
.almost_full(fifo_bus.tx_almost_full),
|
|
||||||
.write(fifo_bus.tx_write),
|
.write(fifo_bus.tx_write),
|
||||||
.wdata(fifo_bus.tx_wdata),
|
.wdata(fifo_bus.tx_wdata),
|
||||||
|
|
||||||
|
@ -1,42 +1,3 @@
|
|||||||
interface usb_scb ();
|
|
||||||
|
|
||||||
logic fifo_flush;
|
|
||||||
logic fifo_flush_busy;
|
|
||||||
logic write_buffer_flush;
|
|
||||||
logic [10:0] rx_count;
|
|
||||||
logic [10:0] tx_count;
|
|
||||||
logic pwrsav;
|
|
||||||
logic reset_state;
|
|
||||||
logic reset_on_ack;
|
|
||||||
logic reset_off_ack;
|
|
||||||
|
|
||||||
modport controller (
|
|
||||||
output fifo_flush,
|
|
||||||
input fifo_flush_busy,
|
|
||||||
output write_buffer_flush,
|
|
||||||
input rx_count,
|
|
||||||
input tx_count,
|
|
||||||
input pwrsav,
|
|
||||||
input reset_state,
|
|
||||||
output reset_on_ack,
|
|
||||||
output reset_off_ack
|
|
||||||
);
|
|
||||||
|
|
||||||
modport usb (
|
|
||||||
input fifo_flush,
|
|
||||||
output fifo_flush_busy,
|
|
||||||
input write_buffer_flush,
|
|
||||||
output rx_count,
|
|
||||||
output tx_count,
|
|
||||||
output pwrsav,
|
|
||||||
output reset_state,
|
|
||||||
input reset_on_ack,
|
|
||||||
input reset_off_ack
|
|
||||||
);
|
|
||||||
|
|
||||||
endinterface
|
|
||||||
|
|
||||||
|
|
||||||
module usb_ft1248 (
|
module usb_ft1248 (
|
||||||
input clk,
|
input clk,
|
||||||
input reset,
|
input reset,
|
||||||
@ -53,12 +14,10 @@ module usb_ft1248 (
|
|||||||
);
|
);
|
||||||
|
|
||||||
logic rx_full;
|
logic rx_full;
|
||||||
logic rx_almost_full;
|
logic rx_write_delayed;
|
||||||
logic rx_write;
|
|
||||||
logic [7:0] rx_wdata;
|
logic [7:0] rx_wdata;
|
||||||
|
|
||||||
logic tx_empty;
|
logic tx_empty;
|
||||||
logic tx_almost_empty;
|
|
||||||
logic tx_read;
|
logic tx_read;
|
||||||
logic [7:0] tx_rdata;
|
logic [7:0] tx_rdata;
|
||||||
|
|
||||||
@ -66,16 +25,14 @@ module usb_ft1248 (
|
|||||||
|
|
||||||
fifo_8kb fifo_8kb_rx_inst (
|
fifo_8kb fifo_8kb_rx_inst (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset(reset || fifo_flush),
|
.reset(fifo_flush),
|
||||||
|
|
||||||
.empty(fifo_bus.rx_empty),
|
.empty(fifo_bus.rx_empty),
|
||||||
.almost_empty(fifo_bus.rx_almost_empty),
|
|
||||||
.read(fifo_bus.rx_read),
|
.read(fifo_bus.rx_read),
|
||||||
.rdata(fifo_bus.rx_rdata),
|
.rdata(fifo_bus.rx_rdata),
|
||||||
|
|
||||||
.full(rx_full),
|
.full(rx_full),
|
||||||
.almost_full(rx_almost_full),
|
.write(rx_write_delayed),
|
||||||
.write(rx_write),
|
|
||||||
.wdata(rx_wdata),
|
.wdata(rx_wdata),
|
||||||
|
|
||||||
.count(usb_scb.rx_count)
|
.count(usb_scb.rx_count)
|
||||||
@ -83,15 +40,13 @@ module usb_ft1248 (
|
|||||||
|
|
||||||
fifo_8kb fifo_8kb_tx_inst (
|
fifo_8kb fifo_8kb_tx_inst (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset(reset || fifo_flush),
|
.reset(fifo_flush),
|
||||||
|
|
||||||
.empty(tx_empty),
|
.empty(tx_empty),
|
||||||
.almost_empty(tx_almost_empty),
|
|
||||||
.read(tx_read),
|
.read(tx_read),
|
||||||
.rdata(tx_rdata),
|
.rdata(tx_rdata),
|
||||||
|
|
||||||
.full(fifo_bus.tx_full),
|
.full(fifo_bus.tx_full),
|
||||||
.almost_full(fifo_bus.tx_almost_full),
|
|
||||||
.write(fifo_bus.tx_write),
|
.write(fifo_bus.tx_write),
|
||||||
.wdata(fifo_bus.tx_wdata),
|
.wdata(fifo_bus.tx_wdata),
|
||||||
|
|
||||||
@ -145,6 +100,8 @@ module usb_ft1248 (
|
|||||||
e_cmd cmd;
|
e_cmd cmd;
|
||||||
e_cmd next_cmd;
|
e_cmd next_cmd;
|
||||||
logic [3:0] phase;
|
logic [3:0] phase;
|
||||||
|
logic rx_write;
|
||||||
|
logic last_rx_failed;
|
||||||
logic last_tx_failed;
|
logic last_tx_failed;
|
||||||
logic reset_reply;
|
logic reset_reply;
|
||||||
logic [4:0] modem_status_counter;
|
logic [4:0] modem_status_counter;
|
||||||
@ -158,6 +115,8 @@ module usb_ft1248 (
|
|||||||
usb_scb.pwrsav <= !ft_pwrsav;
|
usb_scb.pwrsav <= !ft_pwrsav;
|
||||||
fifo_flush <= 1'b0;
|
fifo_flush <= 1'b0;
|
||||||
|
|
||||||
|
rx_write_delayed <= rx_write;
|
||||||
|
|
||||||
phase <= {phase[2:0], phase[3]};
|
phase <= {phase[2:0], phase[3]};
|
||||||
if (state == STATE_IDLE) begin
|
if (state == STATE_IDLE) begin
|
||||||
phase <= 4'b0100;
|
phase <= 4'b0100;
|
||||||
@ -166,6 +125,7 @@ module usb_ft1248 (
|
|||||||
if (reset) begin
|
if (reset) begin
|
||||||
usb_scb.fifo_flush_busy <= 1'b0;
|
usb_scb.fifo_flush_busy <= 1'b0;
|
||||||
usb_scb.reset_state <= 1'b0;
|
usb_scb.reset_state <= 1'b0;
|
||||||
|
last_rx_failed <= 1'b0;
|
||||||
last_tx_failed <= 1'b0;
|
last_tx_failed <= 1'b0;
|
||||||
reset_reply <= 1'b0;
|
reset_reply <= 1'b0;
|
||||||
modem_status_counter <= 5'd0;
|
modem_status_counter <= 5'd0;
|
||||||
@ -195,9 +155,19 @@ module usb_ft1248 (
|
|||||||
if (usb_scb.fifo_flush_busy) begin
|
if (usb_scb.fifo_flush_busy) begin
|
||||||
usb_scb.fifo_flush_busy <= 1'b0;
|
usb_scb.fifo_flush_busy <= 1'b0;
|
||||||
fifo_flush <= 1'b1;
|
fifo_flush <= 1'b1;
|
||||||
|
last_rx_failed <= 1'b0;
|
||||||
|
last_tx_failed <= 1'b0;
|
||||||
|
end else if (last_rx_failed && !rx_full) begin
|
||||||
|
last_rx_failed <= 1'b0;
|
||||||
|
rx_write_delayed <= 1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if ((state == STATE_DATA) && (cmd == CMD_READ) && phase[3]) begin
|
||||||
|
rx_wdata <= ft_miosi_in;
|
||||||
|
last_rx_failed <= !ft_miso && rx_full;
|
||||||
|
end
|
||||||
|
|
||||||
if ((state == STATE_DATA) && (cmd == CMD_WRITE) && phase[3]) begin
|
if ((state == STATE_DATA) && (cmd == CMD_WRITE) && phase[3]) begin
|
||||||
last_tx_failed <= ft_miso;
|
last_tx_failed <= ft_miso;
|
||||||
end
|
end
|
||||||
@ -262,8 +232,6 @@ module usb_ft1248 (
|
|||||||
rx_write = 1'b0;
|
rx_write = 1'b0;
|
||||||
tx_read = 1'b0;
|
tx_read = 1'b0;
|
||||||
|
|
||||||
rx_wdata = ft_miosi_in;
|
|
||||||
|
|
||||||
if (!ft_miso && phase[3]) begin
|
if (!ft_miso && phase[3]) begin
|
||||||
case (state)
|
case (state)
|
||||||
STATE_STATUS: begin
|
STATE_STATUS: begin
|
||||||
@ -273,13 +241,15 @@ module usb_ft1248 (
|
|||||||
end
|
end
|
||||||
|
|
||||||
STATE_DATA: begin
|
STATE_DATA: begin
|
||||||
if (cmd == CMD_READ) begin
|
if (cmd == CMD_READ && !rx_full) begin
|
||||||
rx_write = 1'b1;
|
rx_write = 1'b1;
|
||||||
end
|
end
|
||||||
if (cmd == CMD_WRITE && !tx_empty) begin
|
if (cmd == CMD_WRITE && !tx_empty) begin
|
||||||
tx_read = 1'b1;
|
tx_read = 1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
default: begin end
|
||||||
endcase
|
endcase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -340,7 +310,7 @@ module usb_ft1248 (
|
|||||||
if (ft_miso) begin
|
if (ft_miso) begin
|
||||||
next_state = STATE_DESELECT;
|
next_state = STATE_DESELECT;
|
||||||
end else if (cmd == CMD_READ) begin
|
end else if (cmd == CMD_READ) begin
|
||||||
if (rx_almost_full) begin
|
if (rx_full) begin
|
||||||
next_state = STATE_DESELECT;
|
next_state = STATE_DESELECT;
|
||||||
end
|
end
|
||||||
end else if (cmd == CMD_WRITE) begin
|
end else if (cmd == CMD_WRITE) begin
|
||||||
|
37
fw/rtl/usb/usb_scb.sv
Normal file
37
fw/rtl/usb/usb_scb.sv
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
interface usb_scb ();
|
||||||
|
|
||||||
|
logic fifo_flush;
|
||||||
|
logic fifo_flush_busy;
|
||||||
|
logic write_buffer_flush;
|
||||||
|
logic [10:0] rx_count;
|
||||||
|
logic [10:0] tx_count;
|
||||||
|
logic pwrsav;
|
||||||
|
logic reset_state;
|
||||||
|
logic reset_on_ack;
|
||||||
|
logic reset_off_ack;
|
||||||
|
|
||||||
|
modport controller (
|
||||||
|
output fifo_flush,
|
||||||
|
input fifo_flush_busy,
|
||||||
|
output write_buffer_flush,
|
||||||
|
input rx_count,
|
||||||
|
input tx_count,
|
||||||
|
input pwrsav,
|
||||||
|
input reset_state,
|
||||||
|
output reset_on_ack,
|
||||||
|
output reset_off_ack
|
||||||
|
);
|
||||||
|
|
||||||
|
modport usb (
|
||||||
|
input fifo_flush,
|
||||||
|
output fifo_flush_busy,
|
||||||
|
input write_buffer_flush,
|
||||||
|
output rx_count,
|
||||||
|
output tx_count,
|
||||||
|
output pwrsav,
|
||||||
|
output reset_state,
|
||||||
|
input reset_on_ack,
|
||||||
|
input reset_off_ack
|
||||||
|
);
|
||||||
|
|
||||||
|
endinterface
|
@ -3,18 +3,19 @@ module fifo_8kb (
|
|||||||
input reset,
|
input reset,
|
||||||
|
|
||||||
output empty,
|
output empty,
|
||||||
output almost_empty,
|
|
||||||
input read,
|
input read,
|
||||||
output [7:0] rdata,
|
output [7:0] rdata,
|
||||||
|
|
||||||
output full,
|
output full,
|
||||||
output almost_full,
|
|
||||||
input write,
|
input write,
|
||||||
input [7:0] wdata,
|
input [7:0] wdata,
|
||||||
|
|
||||||
output logic [10:0] count
|
output logic [10:0] count
|
||||||
);
|
);
|
||||||
|
|
||||||
|
logic almost_empty;
|
||||||
|
logic almost_full;
|
||||||
|
|
||||||
fifo_8kb_lattice_generated fifo_8kb_lattice_generated_inst (
|
fifo_8kb_lattice_generated fifo_8kb_lattice_generated_inst (
|
||||||
.Data(wdata),
|
.Data(wdata),
|
||||||
.WrClock(clk),
|
.WrClock(clk),
|
||||||
|
1
fw/tests/.gitignore
vendored
Normal file
1
fw/tests/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
35
fw/tests/Makefile
Normal file
35
fw/tests/Makefile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
RTL_DIR = ../rtl
|
||||||
|
BENCHES_DIR = benches
|
||||||
|
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)/vendor \
|
||||||
|
$(MOCKS_DIR)
|
||||||
|
|
||||||
|
INC_DIRS = $(addprefix -I, $(SRC_DIRS))
|
||||||
|
TEST_FILES = $(shell find "./$(BENCHES_DIR)" -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
|
126
fw/tests/benches/memory_dma_tb.sv
Normal file
126
fw/tests/benches/memory_dma_tb.sv
Normal 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_fifo_mock #(
|
||||||
|
.DEPTH(8),
|
||||||
|
.FILL_RATE(3),
|
||||||
|
.DRAIN_RATE(3)
|
||||||
|
) fifo_bus_fifo_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'hFFF1;
|
||||||
|
transfer_length = 27'd64;
|
||||||
|
#1;
|
||||||
|
start = 1'b0;
|
||||||
|
|
||||||
|
#9;
|
||||||
|
tx_drain_enabled = 1'b1;
|
||||||
|
|
||||||
|
#490;
|
||||||
|
stop = 1'b1;
|
||||||
|
#1;
|
||||||
|
stop = 1'b0;
|
||||||
|
|
||||||
|
#165;
|
||||||
|
|
||||||
|
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
|
119
fw/tests/benches/usb_ft1248_tb.sv
Normal file
119
fw/tests/benches/usb_ft1248_tb.sv
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
module usb_ft1248_tb;
|
||||||
|
|
||||||
|
logic clk;
|
||||||
|
logic reset;
|
||||||
|
|
||||||
|
usb_scb usb_scb ();
|
||||||
|
fifo_bus fifo_bus ();
|
||||||
|
|
||||||
|
logic usb_pwrsav;
|
||||||
|
logic usb_clk;
|
||||||
|
logic usb_cs;
|
||||||
|
logic usb_miso;
|
||||||
|
logic [7:0] usb_miosi;
|
||||||
|
|
||||||
|
usb_ft1248 usb_ft1248 (
|
||||||
|
.clk(clk),
|
||||||
|
.reset(reset),
|
||||||
|
.usb_scb(usb_scb),
|
||||||
|
.fifo_bus(fifo_bus),
|
||||||
|
.usb_pwrsav(usb_pwrsav),
|
||||||
|
.usb_clk(usb_clk),
|
||||||
|
.usb_cs(usb_cs),
|
||||||
|
.usb_miso(usb_miso),
|
||||||
|
.usb_miosi(usb_miosi)
|
||||||
|
);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
clk = 1'b0;
|
||||||
|
forever begin
|
||||||
|
clk = ~clk; #0.5;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
reset = 1'b1;
|
||||||
|
#10;
|
||||||
|
reset = 1'b0;
|
||||||
|
end
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$dumpfile("traces/usb_ft1248_tb.vcd");
|
||||||
|
|
||||||
|
$dumpvars();
|
||||||
|
|
||||||
|
usb_pwrsav = 1'b1;
|
||||||
|
usb_miso = 1'b1;
|
||||||
|
|
||||||
|
#100;
|
||||||
|
|
||||||
|
fifo_bus.tx_write = 1'b1;
|
||||||
|
#100;
|
||||||
|
fifo_bus.tx_write = 1'b0;
|
||||||
|
|
||||||
|
#103;
|
||||||
|
|
||||||
|
usb_miso = 1'b0;
|
||||||
|
#80;
|
||||||
|
usb_scb.write_buffer_flush = 1'b1;
|
||||||
|
#1;
|
||||||
|
usb_scb.write_buffer_flush = 1'b0;
|
||||||
|
#20;
|
||||||
|
usb_miso = 1'b1;
|
||||||
|
#26;
|
||||||
|
usb_miso = 1'b0;
|
||||||
|
|
||||||
|
#4430;
|
||||||
|
|
||||||
|
usb_miso = 1'b1;
|
||||||
|
#13;
|
||||||
|
usb_miso = 1'b0;
|
||||||
|
|
||||||
|
#79;
|
||||||
|
|
||||||
|
fifo_bus.rx_read = 1'b1;
|
||||||
|
#1;
|
||||||
|
fifo_bus.rx_read = 1'b0;
|
||||||
|
|
||||||
|
#10;
|
||||||
|
|
||||||
|
fifo_bus.rx_read = 1'b1;
|
||||||
|
#1;
|
||||||
|
fifo_bus.rx_read = 1'b0;
|
||||||
|
|
||||||
|
#80;
|
||||||
|
|
||||||
|
fifo_bus.rx_read = 1'b1;
|
||||||
|
#1;
|
||||||
|
fifo_bus.rx_read = 1'b0;
|
||||||
|
|
||||||
|
#200;
|
||||||
|
|
||||||
|
usb_scb.reset_on_ack = 1'b1;
|
||||||
|
#1;
|
||||||
|
usb_scb.reset_on_ack = 1'b0;
|
||||||
|
|
||||||
|
#200;
|
||||||
|
|
||||||
|
usb_scb.reset_off_ack = 1'b1;
|
||||||
|
#1;
|
||||||
|
usb_scb.reset_off_ack = 1'b0;
|
||||||
|
|
||||||
|
#200;
|
||||||
|
|
||||||
|
usb_scb.fifo_flush = 1'b1;
|
||||||
|
#1;
|
||||||
|
usb_scb.fifo_flush = 1'b0;
|
||||||
|
|
||||||
|
#3000;
|
||||||
|
|
||||||
|
usb_scb.fifo_flush = 1'b1;
|
||||||
|
#1;
|
||||||
|
usb_scb.fifo_flush = 1'b0;
|
||||||
|
|
||||||
|
#6000;
|
||||||
|
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
22
fw/tests/docker_run.sh
Executable file
22
fw/tests/docker_run.sh
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
pushd $(dirname $0) > /dev/null
|
||||||
|
|
||||||
|
docker run \
|
||||||
|
-it \
|
||||||
|
--rm \
|
||||||
|
--user $(id -u):$(id -g) \
|
||||||
|
-v "$(pwd)":/work \
|
||||||
|
-v "$(pwd)/../rtl":/rtl \
|
||||||
|
-e CCACHE_DIR=/tmp/ccache \
|
||||||
|
--entrypoint /bin/bash \
|
||||||
|
verilator/verilator:latest \
|
||||||
|
-c "make -j"
|
||||||
|
|
||||||
|
BUILD_ERROR=$?
|
||||||
|
|
||||||
|
popd > /dev/null
|
||||||
|
|
||||||
|
if [ $BUILD_ERROR -ne 0 ]; then
|
||||||
|
exit -1
|
||||||
|
fi
|
39
fw/tests/mocks/dma_controller_mock.sv
Normal file
39
fw/tests/mocks/dma_controller_mock.sv
Normal 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
|
145
fw/tests/mocks/fifo_bus_fifo_mock.sv
Normal file
145
fw/tests/mocks/fifo_bus_fifo_mock.sv
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
module fifo_bus_fifo_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 rx_full;
|
||||||
|
logic rx_write;
|
||||||
|
logic [7:0] rx_wdata;
|
||||||
|
|
||||||
|
logic [PTR_BITS:0] rx_count;
|
||||||
|
|
||||||
|
fifo_mock #(
|
||||||
|
.DEPTH(DEPTH)
|
||||||
|
) fifo_rx (
|
||||||
|
.clk(clk),
|
||||||
|
.reset(reset),
|
||||||
|
|
||||||
|
.empty(fifo_bus.rx_empty),
|
||||||
|
.read(fifo_bus.rx_read),
|
||||||
|
.rdata(fifo_bus.rx_rdata),
|
||||||
|
|
||||||
|
.full(rx_full),
|
||||||
|
.write(rx_write),
|
||||||
|
.wdata(rx_wdata),
|
||||||
|
|
||||||
|
.count(rx_count)
|
||||||
|
);
|
||||||
|
|
||||||
|
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_full;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
always_comb begin
|
||||||
|
rx_write = rx_fill && !rx_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 tx_empty;
|
||||||
|
logic tx_read;
|
||||||
|
logic [7:0] tx_rdata;
|
||||||
|
|
||||||
|
logic [PTR_BITS:0] tx_count;
|
||||||
|
|
||||||
|
fifo_mock #(
|
||||||
|
.DEPTH(DEPTH)
|
||||||
|
) fifo_tx (
|
||||||
|
.clk(clk),
|
||||||
|
.reset(reset),
|
||||||
|
|
||||||
|
.empty(tx_empty),
|
||||||
|
.read(tx_read),
|
||||||
|
.rdata(tx_rdata),
|
||||||
|
|
||||||
|
.full(fifo_bus.tx_full),
|
||||||
|
.write(fifo_bus.tx_write),
|
||||||
|
.wdata(fifo_bus.tx_wdata),
|
||||||
|
|
||||||
|
.count(tx_count)
|
||||||
|
);
|
||||||
|
|
||||||
|
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_empty;
|
||||||
|
end
|
||||||
|
end else begin
|
||||||
|
always_comb begin
|
||||||
|
tx_read = tx_drain && !tx_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
|
49
fw/tests/mocks/fifo_mock.sv
Normal file
49
fw/tests/mocks/fifo_mock.sv
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
module fifo_mock #(
|
||||||
|
parameter int DEPTH = 1024,
|
||||||
|
localparam int PTR_BITS = $clog2(DEPTH)
|
||||||
|
) (
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
|
||||||
|
output logic empty,
|
||||||
|
input read,
|
||||||
|
output [7:0] rdata,
|
||||||
|
|
||||||
|
output logic full,
|
||||||
|
input write,
|
||||||
|
input [7:0] wdata,
|
||||||
|
|
||||||
|
output logic [PTR_BITS:0] count
|
||||||
|
);
|
||||||
|
|
||||||
|
logic [7:0] fifo_mem [0:(DEPTH - 1)];
|
||||||
|
logic [(PTR_BITS - 1):0] fifo_rptr;
|
||||||
|
logic [(PTR_BITS - 1):0] fifo_wptr;
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
full = count >= (PTR_BITS + 1)'(DEPTH);
|
||||||
|
empty = count == (PTR_BITS + 1)'('d0);
|
||||||
|
end
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (read) begin
|
||||||
|
rdata <= fifo_mem[fifo_rptr];
|
||||||
|
fifo_rptr <= fifo_rptr + PTR_BITS'('d1);
|
||||||
|
count <= count - (PTR_BITS + 1)'('d1);
|
||||||
|
end
|
||||||
|
if (write) begin
|
||||||
|
fifo_mem[fifo_wptr] <= wdata;
|
||||||
|
fifo_wptr <= fifo_wptr + PTR_BITS'('d1);
|
||||||
|
count <= count + (PTR_BITS + 1)'('d1);
|
||||||
|
end
|
||||||
|
if (read && write) begin
|
||||||
|
count <= count;
|
||||||
|
end
|
||||||
|
if (reset) begin
|
||||||
|
count <= (PTR_BITS + 1)'('d0);
|
||||||
|
fifo_rptr <= PTR_BITS'('d0);
|
||||||
|
fifo_wptr <= PTR_BITS'('d0);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
70
fw/tests/mocks/memory_sdram_mock.sv
Normal file
70
fw/tests/mocks/memory_sdram_mock.sv
Normal 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;
|
||||||
|
|
||||||
|
always_ff @(posedge clk) begin
|
||||||
|
if (reset) begin
|
||||||
|
cas_delay <= 2'b00;
|
||||||
|
data_from_sdram <= 16'h0102;
|
||||||
|
data_to_sdram <= 16'hFFFF;
|
||||||
|
end else 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
|
||||||
|
end
|
||||||
|
|
||||||
|
always_comb begin
|
||||||
|
sdram_dq_driven = 16'hXXXX;
|
||||||
|
if (cas_delay[1]) begin
|
||||||
|
sdram_dq_driven = data_from_sdram;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
33
fw/tests/mocks/vendor/fifo_8kb.sv
vendored
Normal file
33
fw/tests/mocks/vendor/fifo_8kb.sv
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
module fifo_8kb (
|
||||||
|
input clk,
|
||||||
|
input reset,
|
||||||
|
|
||||||
|
output empty,
|
||||||
|
input read,
|
||||||
|
output [7:0] rdata,
|
||||||
|
|
||||||
|
output full,
|
||||||
|
input write,
|
||||||
|
input [7:0] wdata,
|
||||||
|
|
||||||
|
output logic [10:0] count
|
||||||
|
);
|
||||||
|
|
||||||
|
fifo_mock #(
|
||||||
|
.DEPTH(1024)
|
||||||
|
) fifo_8kb (
|
||||||
|
.clk(clk),
|
||||||
|
.reset(reset),
|
||||||
|
|
||||||
|
.empty(empty),
|
||||||
|
.read(read),
|
||||||
|
.rdata(rdata),
|
||||||
|
|
||||||
|
.full(full),
|
||||||
|
.write(write),
|
||||||
|
.wdata(wdata),
|
||||||
|
|
||||||
|
.count(count)
|
||||||
|
);
|
||||||
|
|
||||||
|
endmodule
|
2
fw/tests/traces/.gitignore
vendored
Normal file
2
fw/tests/traces/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.vcd
|
||||||
|
*.gtkw
|
@ -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) {
|
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)) {
|
if ((address >= MEMORY_LENGTH) || (length > MEMORY_LENGTH)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -486,7 +486,7 @@ impl FtdiDevice {
|
|||||||
wrapper.set_module_detach_mode(ModuleDetachMode::AutoDetachReattach);
|
wrapper.set_module_detach_mode(ModuleDetachMode::AutoDetachReattach);
|
||||||
wrapper.set_interface(InterfaceIndex::A)?;
|
wrapper.set_interface(InterfaceIndex::A)?;
|
||||||
|
|
||||||
const CHUNK_SIZE: usize = 16 * 1024;
|
const CHUNK_SIZE: usize = 2 * 1024 * 1024;
|
||||||
|
|
||||||
wrapper.read_data_set_chunksize(CHUNK_SIZE)?;
|
wrapper.read_data_set_chunksize(CHUNK_SIZE)?;
|
||||||
wrapper.write_data_set_chunksize(CHUNK_SIZE)?;
|
wrapper.write_data_set_chunksize(CHUNK_SIZE)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user