command path works, data and dma not

This commit is contained in:
Polprzewodnikowy 2021-02-05 22:38:17 +01:00
parent 22c670ef29
commit d8da4c7f1f
13 changed files with 998 additions and 335 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
/packages /packages
**/.vscode **/.vscode
/sw/test

View File

@ -64,8 +64,15 @@ set_global_assignment -name VERILOG_FILE rtl/memory/memory_sdram.v
set_global_assignment -name VERILOG_FILE rtl/n64/n64_bank_decoder.v set_global_assignment -name VERILOG_FILE rtl/n64/n64_bank_decoder.v
set_global_assignment -name VERILOG_FILE rtl/n64/n64_pi.v set_global_assignment -name VERILOG_FILE rtl/n64/n64_pi.v
set_global_assignment -name VERILOG_FILE rtl/n64/n64_si.v set_global_assignment -name VERILOG_FILE rtl/n64/n64_si.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_clk.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_cmd.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_crc_16.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_crc_7.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_dat.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_dma.v set_global_assignment -name VERILOG_FILE rtl/sd/sd_dma.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_fifo.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_interface.v set_global_assignment -name VERILOG_FILE rtl/sd/sd_interface.v
set_global_assignment -name VERILOG_FILE rtl/sd/sd_regs.v
set_global_assignment -name VERILOG_FILE rtl/top.v set_global_assignment -name VERILOG_FILE rtl/top.v
set_global_assignment -name VERILOG_FILE rtl/usb/usb_ftdi_fsi.v set_global_assignment -name VERILOG_FILE rtl/usb/usb_ftdi_fsi.v
set_global_assignment -name VERILOG_FILE rtl/usb/usb_pc.v set_global_assignment -name VERILOG_FILE rtl/usb/usb_pc.v
@ -91,8 +98,6 @@ set_location_assignment PIN_25 -to i_n64_nmi
set_location_assignment PIN_26 -to i_clk set_location_assignment PIN_26 -to i_clk
set_location_assignment PIN_27 -to i_n64_reset set_location_assignment PIN_27 -to i_n64_reset
set_location_assignment PIN_28 -to i_n64_si_clk set_location_assignment PIN_28 -to i_n64_si_clk
set_location_assignment PIN_29 -to i_n64_cic_clk
set_location_assignment PIN_30 -to io_n64_cic_dq
set_location_assignment PIN_32 -to io_n64_pi_ad[7] set_location_assignment PIN_32 -to io_n64_pi_ad[7]
set_location_assignment PIN_33 -to io_n64_pi_ad[8] set_location_assignment PIN_33 -to io_n64_pi_ad[8]
set_location_assignment PIN_38 -to io_n64_pi_ad[6] set_location_assignment PIN_38 -to io_n64_pi_ad[6]
@ -161,12 +166,6 @@ set_location_assignment PIN_123 -to io_sram_dq[3]
set_location_assignment PIN_124 -to o_sram_cs set_location_assignment PIN_124 -to o_sram_cs
set_location_assignment PIN_126 -to io_sram_dq[1] set_location_assignment PIN_126 -to io_sram_dq[1]
set_location_assignment PIN_127 -to io_sram_dq[2] set_location_assignment PIN_127 -to io_sram_dq[2]
set_location_assignment PIN_130 -to io_flash_dq[0]
set_location_assignment PIN_131 -to o_flash_clk
set_location_assignment PIN_132 -to io_flash_dq[3]
set_location_assignment PIN_134 -to o_flash_cs
set_location_assignment PIN_135 -to io_flash_dq[1]
set_location_assignment PIN_136 -to io_flash_dq[2]
set_location_assignment PIN_138 -to io_pmod[0] set_location_assignment PIN_138 -to io_pmod[0]
set_location_assignment PIN_140 -to io_pmod[1] set_location_assignment PIN_140 -to io_pmod[1]
set_location_assignment PIN_141 -to io_pmod[2] set_location_assignment PIN_141 -to io_pmod[2]
@ -257,7 +256,6 @@ set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -
# Fitter Assignments # Fitter Assignments
# ================== # ==================
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_cic_clk
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_nmi set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_nmi
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_pi_aleh set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_pi_aleh
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_pi_alel set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_pi_alel
@ -265,7 +263,6 @@ set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_pi_write set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_pi_write
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_reset set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_reset
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_si_clk set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to i_n64_si_clk
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to io_n64_cic_dq
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to io_n64_si_dq set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to io_n64_si_dq
set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to i_clk set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to i_clk
set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to "pll:sys_pll|altpll:altpll_component|pll_altpll:auto_generated|wire_pll1_clk[0]" set_instance_assignment -name GLOBAL_SIGNAL GLOBAL_CLOCK -to "pll:sys_pll|altpll:altpll_component|pll_altpll:auto_generated|wire_pll1_clk[0]"

View File

@ -32,21 +32,24 @@ module device_arbiter #(
reg [(NUM_CONTROLLERS - 1):0] r_ack_fifo_mem [0:(ACK_FIFO_LENGTH - 1)]; reg [(NUM_CONTROLLERS - 1):0] r_ack_fifo_mem [0:(ACK_FIFO_LENGTH - 1)];
reg [(FIFO_ADDRESS_WIDTH - 1):0] r_ack_fifo_wrptr; reg [FIFO_ADDRESS_WIDTH:0] r_ack_fifo_wrptr;
reg [(FIFO_ADDRESS_WIDTH - 1):0] r_ack_fifo_rdptr; reg [FIFO_ADDRESS_WIDTH:0] r_ack_fifo_rdptr;
wire w_ack_fifo_wrreq = |(r_request_successful & ~i_write); wire w_ack_fifo_wrreq = |(r_request_successful & ~i_write);
wire w_ack_fifo_rdreq = i_device_ack; wire w_ack_fifo_rdreq = i_device_ack;
wire w_ack_fifo_full = (r_ack_fifo_wrptr + 1'd1) == r_ack_fifo_rdptr; wire w_empty = r_ack_fifo_wrptr[FIFO_ADDRESS_WIDTH] == r_ack_fifo_rdptr[FIFO_ADDRESS_WIDTH];
wire w_full_or_empty = r_ack_fifo_wrptr[(FIFO_ADDRESS_WIDTH - 1):0] == r_ack_fifo_rdptr[(FIFO_ADDRESS_WIDTH - 1):0];
wire w_ack_fifo_full = !w_empty && w_full_or_empty;
always @(posedge i_clk) begin always @(posedge i_clk) begin
if (i_reset) begin if (i_reset) begin
r_ack_fifo_wrptr <= {FIFO_ADDRESS_WIDTH{1'b0}}; r_ack_fifo_wrptr <= {(FIFO_ADDRESS_WIDTH + 1){1'b0}};
r_ack_fifo_rdptr <= {FIFO_ADDRESS_WIDTH{1'b0}}; r_ack_fifo_rdptr <= {(FIFO_ADDRESS_WIDTH + 1){1'b0}};
end else begin end else begin
if (w_ack_fifo_wrreq) begin if (w_ack_fifo_wrreq) begin
r_ack_fifo_mem[r_ack_fifo_wrptr] <= r_request_successful & ~i_write; r_ack_fifo_mem[r_ack_fifo_wrptr[(FIFO_ADDRESS_WIDTH - 1):0]] <= r_request_successful & ~i_write;
r_ack_fifo_wrptr <= r_ack_fifo_wrptr + 1'd1; r_ack_fifo_wrptr <= r_ack_fifo_wrptr + 1'd1;
end end
if (w_ack_fifo_rdreq) begin if (w_ack_fifo_rdreq) begin
@ -66,7 +69,7 @@ module device_arbiter #(
end end
r_request_successful = r_request & ~o_busy; r_request_successful = r_request & ~o_busy;
o_ack = {NUM_CONTROLLERS{i_device_ack}} & r_ack_fifo_mem[r_ack_fifo_rdptr]; o_ack = {NUM_CONTROLLERS{i_device_ack}} & r_ack_fifo_mem[r_ack_fifo_rdptr[(FIFO_ADDRESS_WIDTH - 1):0]];
o_data = {NUM_CONTROLLERS{i_device_data}}; o_data = {NUM_CONTROLLERS{i_device_data}};
end end

107
fw/rtl/sd/sd_clk.v Normal file
View File

@ -0,0 +1,107 @@
module sd_clk (
input i_clk,
input i_reset,
output reg o_sd_clk,
input [1:0] i_sd_clk_config,
output reg o_sd_clk_strobe_rising,
output reg o_sd_clk_strobe_falling
);
// Clock configuration values
localparam [1:0] SD_CLK_CONFIG_STOP = 2'd0;
localparam [1:0] SD_CLK_CONFIG_DIV_256 = 2'd1;
localparam [1:0] SD_CLK_CONFIG_DIV_4 = 2'd2;
localparam [1:0] SD_CLK_CONFIG_DIV_2 = 2'd3;
// Clock configuration change detection
reg [1:0] r_prev_sd_clk_config;
wire w_sd_clk_config_changed = r_prev_sd_clk_config != i_sd_clk_config;
always @(posedge i_clk) begin
if (i_reset) begin
r_prev_sd_clk_config <= SD_CLK_CONFIG_STOP;
end else begin
r_prev_sd_clk_config <= i_sd_clk_config;
end
end
// Clock divider
reg [7:0] r_sd_clk_counter;
always @(posedge i_clk) begin
if (i_reset || w_sd_clk_config_changed) begin
r_sd_clk_counter <= 8'd0;
end else begin
r_sd_clk_counter <= r_sd_clk_counter + 1'd1;
end
end
// Clock divider selector
reg r_selected_sd_clk;
always @(*) begin
case (r_prev_sd_clk_config)
SD_CLK_CONFIG_STOP:
r_selected_sd_clk = 1'b0;
SD_CLK_CONFIG_DIV_256:
r_selected_sd_clk = r_sd_clk_counter[7];
SD_CLK_CONFIG_DIV_4:
r_selected_sd_clk = r_sd_clk_counter[1];
SD_CLK_CONFIG_DIV_2:
r_selected_sd_clk = r_sd_clk_counter[0];
endcase
end
// Clock strobe generation
reg r_prev_selected_sd_clk;
always @(posedge i_clk) begin
o_sd_clk_strobe_rising <= 1'b0;
o_sd_clk_strobe_falling <= 1'b0;
if (i_reset) begin
r_prev_selected_sd_clk <= 1'b0;
end else begin
r_prev_selected_sd_clk <= r_selected_sd_clk;
if (!r_prev_selected_sd_clk && r_selected_sd_clk) begin
o_sd_clk_strobe_rising <= 1'b1;
end
if (r_prev_selected_sd_clk && !r_selected_sd_clk) begin
o_sd_clk_strobe_falling <= 1'b1;
end
end
end
// SD clock generation
always @(posedge i_clk) begin
if (i_reset) begin
o_sd_clk <= 1'b0;
end else begin
if (o_sd_clk_strobe_rising) begin
o_sd_clk <= 1'b1;
end
if (o_sd_clk_strobe_falling) begin
o_sd_clk <= 1'b0;
end
end
end
endmodule

249
fw/rtl/sd/sd_cmd.v Normal file
View File

@ -0,0 +1,249 @@
module sd_cmd (
input i_clk,
input i_reset,
inout io_sd_cmd,
input i_sd_clk_strobe_rising,
input i_sd_clk_strobe_falling,
input [5:0] i_command_index,
input [31:0] i_command_argument,
input i_command_long_response,
input i_command_skip_response,
output reg [5:0] o_command_index,
output reg [31:0] o_command_response,
input i_command_start,
output o_command_busy,
output reg o_command_timeout,
output reg o_command_response_crc_error
);
// Start synchronizer
reg r_pending_start;
wire w_start = r_pending_start && i_sd_clk_strobe_falling;
always @(posedge i_clk) begin
if (i_reset) begin
r_pending_start <= 1'b0;
end else begin
if (i_command_start) begin
r_pending_start <= 1'b1;
end else if (i_sd_clk_strobe_falling) begin
r_pending_start <= 1'b0;
end
end
end
// Module state
localparam STATE_IDLE = 0;
localparam STATE_SENDING = 1;
localparam STATE_RESP_WAIT = 2;
localparam STATE_RECEIVING = 3;
localparam STATE_HIZ_WAIT = 4;
reg [4:0] r_state;
// Bit counter logic
reg [8:0] r_bit_counter;
reg r_bit_done;
wire w_command_start = w_start && r_state[STATE_IDLE];
wire w_command_end = r_bit_done && r_state[STATE_SENDING];
wire w_response_timeout = r_bit_done && r_state[STATE_RESP_WAIT];
wire w_response_start = !io_sd_cmd && i_sd_clk_strobe_rising && r_state[STATE_RESP_WAIT];
wire w_response_end = r_bit_done && r_state[STATE_RECEIVING];
wire w_hiz_end = r_bit_done && r_state[STATE_HIZ_WAIT];
localparam [8:0] COMMAND_BIT_LENGTH = (9'd48 - 1'd1);
localparam [8:0] RESPONSE_WAIT_BIT_LENGTH = (9'd64 - 1'd1);
localparam [8:0] RESPONSE_SHORT_BIT_LENGTH = (9'd48 - 1'd1);
localparam [8:0] RESPONSE_LONG_BIT_LENGTH = (9'd136 - 1'd1);
localparam [8:0] HIZ_WAIT_BIT_LENGTH = (9'd8 - 1'd1);
always @(posedge i_clk) begin
if (w_command_start) begin
r_bit_counter <= COMMAND_BIT_LENGTH;
r_bit_done <= 1'b0;
end else if (w_command_end) begin
r_bit_counter <= RESPONSE_WAIT_BIT_LENGTH;
r_bit_done <= 1'b0;
end else if (w_response_start) begin
r_bit_counter <= i_command_long_response ? RESPONSE_LONG_BIT_LENGTH : RESPONSE_SHORT_BIT_LENGTH;
r_bit_done <= 1'b0;
end else if (w_response_end) begin
r_bit_counter <= HIZ_WAIT_BIT_LENGTH;
r_bit_done <= 1'b0;
end else if (i_sd_clk_strobe_rising) begin
if (r_bit_counter > 9'd0) begin
r_bit_counter <= r_bit_counter - 1'd1;
end else begin
r_bit_done <= 1'b1;
end
end
end
// CRC7 generator
reg [6:0] r_crc_7_received;
wire w_crc_shift_reset = !(r_state[STATE_SENDING] || r_state[STATE_RECEIVING]);
wire w_crc_shift_enabled = (r_bit_counter <= 9'd127) && (r_bit_counter > (r_state[STATE_SENDING] ? 9'd7 : 9'd8));
wire w_crc_shift = w_crc_shift_enabled && i_sd_clk_strobe_rising;
wire [6:0] w_crc_7_calculated;
sd_crc_7 sd_crc_7_inst (
.i_clk(i_clk),
.i_crc_reset(w_crc_shift_reset),
.i_crc_shift(w_crc_shift),
.i_crc_input(io_sd_cmd),
.o_crc_output(w_crc_7_calculated)
);
// Control signals
assign o_command_busy = r_pending_start || (!r_state[STATE_IDLE]);
always @(posedge i_clk) begin
if (i_reset) begin
o_command_timeout <= 1'b0;
o_command_response_crc_error <= 1'b0;
end else begin
if (w_command_start) begin
o_command_timeout <= 1'b0;
end
if (w_response_timeout) begin
o_command_timeout <= 1'b1;
end
if (w_response_end) begin
o_command_response_crc_error <= (w_crc_7_calculated != r_crc_7_received);
end
end
end
// State machine
always @(posedge i_clk) begin
if (i_reset) begin
r_state <= (1'b1 << STATE_IDLE);
end else begin
r_state <= 5'b00000;
unique case (1'b1)
r_state[STATE_IDLE]: begin
if (w_start) begin
r_state[STATE_SENDING] <= 1'b1;
end else begin
r_state[STATE_IDLE] <= 1'b1;
end
end
r_state[STATE_SENDING]: begin
if (w_command_end) begin
if (i_command_skip_response) begin
r_state[STATE_HIZ_WAIT] <= 1'b1;
end else begin
r_state[STATE_RESP_WAIT] <= 1'b1;
end
end else begin
r_state[STATE_SENDING] <= 1'b1;
end
end
r_state[STATE_RESP_WAIT]: begin
if (w_response_timeout) begin
r_state[STATE_IDLE] <= 1'b1;
end else if (w_response_start) begin
r_state[STATE_RECEIVING] <= 1'b1;
end else begin
r_state[STATE_RESP_WAIT] <= 1'b1;
end
end
r_state[STATE_RECEIVING]: begin
if (w_response_end) begin
r_state[STATE_HIZ_WAIT] <= 1'b1;
end else begin
r_state[STATE_RECEIVING] <= 1'b1;
end
end
r_state[STATE_HIZ_WAIT]: begin
if (w_hiz_end) begin
r_state[STATE_IDLE] <= 1'b1;
end else begin
r_state[STATE_HIZ_WAIT] <= 1'b1;
end
end
endcase
end
end
// Shifting operation
reg [7:0] r_shift;
wire w_shift = (r_state[STATE_SENDING] && i_sd_clk_strobe_falling) || (r_state[STATE_RECEIVING] && i_sd_clk_strobe_rising);
assign io_sd_cmd = r_state[STATE_SENDING] ? r_shift[7] : 1'bZ;
always @(posedge i_clk) begin
if (w_command_start) begin
o_command_response <= 32'h0000_0000;
r_shift <= {2'b01, i_command_index};
end else if (w_response_start) begin
r_shift <= 8'h00;
end else begin
if (w_shift) begin
r_shift <= {r_shift[6:0], io_sd_cmd};
end
if (i_sd_clk_strobe_falling && r_state[STATE_SENDING]) begin
if (r_bit_counter == 9'd39) begin
r_shift <= i_command_argument[31:24];
end
if (r_bit_counter == 9'd31) begin
r_shift <= i_command_argument[23:16];
end
if (r_bit_counter == 9'd23) begin
r_shift <= i_command_argument[15:8];
end
if (r_bit_counter == 9'd15) begin
r_shift <= i_command_argument[7:0];
end
if (r_bit_counter == 9'd7) begin
r_shift <= {w_crc_7_calculated, 1'b1};
end
end
if (i_sd_clk_strobe_rising && r_state[STATE_RECEIVING]) begin
if (r_bit_counter == (i_command_long_response ? 9'd128 : 9'd40)) begin
o_command_index <= r_shift[5:0];
end else if (r_bit_counter[2:0] == 3'd0) begin
if (r_bit_counter > 9'd7) begin
o_command_response <= {o_command_response[23:0], r_shift};
end else begin
r_crc_7_received <= r_shift[7:1];
end
end
end
end
end
endmodule

26
fw/rtl/sd/sd_crc_16.v Normal file
View File

@ -0,0 +1,26 @@
module sd_crc_16 (
input i_clk,
input i_crc_reset,
input i_crc_shift,
input i_crc_input,
output reg [15:0] o_crc_output
);
wire w_crc_inv = o_crc_output[15] ^ i_crc_input;
always @(posedge i_clk) begin
if (i_crc_reset) begin
o_crc_output <= 16'd0;
end else if (i_crc_shift) begin
o_crc_output <= {
o_crc_output[14:12],
o_crc_output[11] ^ w_crc_inv,
o_crc_output[10:5],
o_crc_output[4] ^ w_crc_inv,
o_crc_output[3:0],
w_crc_inv
};
end
end
endmodule

24
fw/rtl/sd/sd_crc_7.v Normal file
View File

@ -0,0 +1,24 @@
module sd_crc_7 (
input i_clk,
input i_crc_reset,
input i_crc_shift,
input i_crc_input,
output reg [6:0] o_crc_output
);
wire w_crc_inv = o_crc_output[6] ^ i_crc_input;
always @(posedge i_clk) begin
if (i_crc_reset) begin
o_crc_output <= 7'd0;
end else if (i_crc_shift) begin
o_crc_output <= {
o_crc_output[5:3],
o_crc_output[2] ^ w_crc_inv,
o_crc_output[1:0],
w_crc_inv
};
end
end
endmodule

28
fw/rtl/sd/sd_dat.v Normal file
View File

@ -0,0 +1,28 @@
module sd_dat (
input i_clk,
input i_reset,
inout reg [3:0] io_sd_dat,
input i_sd_clk_strobe_rising,
input i_sd_clk_strobe_falling,
input i_dat_width,
input i_dat_direction,
input [6:0] i_dat_block_size,
input [10:0] i_dat_num_blocks,
input i_dat_start,
input i_dat_stop,
output o_dat_busy,
output o_dat_crc_error,
output reg o_rx_fifo_push,
input i_rx_fifo_overrun,
output [31:0] o_rx_fifo_data,
input i_tx_fifo_full,
output reg o_tx_fifo_pop,
input [31:0] i_tx_fifo_data
);
endmodule

View File

@ -2,61 +2,33 @@ module sd_dma (
input i_clk, input i_clk,
input i_reset, input i_reset,
input i_fifo_flush, input [3:0] i_dma_bank,
input i_fifo_push, input [23:0] i_dma_address,
output o_fifo_full, input [14:0] i_dma_length,
output o_fifo_empty, output reg [14:0] o_dma_left,
input [31:0] i_fifo_data, input i_dma_load_bank_address,
input i_dma_load_length,
input i_dma_direction,
input i_dma_start,
input i_dma_stop,
output reg o_dma_busy,
output reg o_rx_fifo_pop,
input i_rx_fifo_empty,
input [31:0] i_rx_fifo_data,
output reg o_tx_fifo_push,
input i_tx_fifo_full,
output reg [31:0] o_tx_fifo_data,
output reg o_request, output reg o_request,
output reg o_write, output reg o_write,
input i_busy, input i_busy,
input i_ack,
output reg [3:0] o_bank,
output reg [23:0] o_address,
input [31:0] i_data,
output reg [31:0] o_data output reg [31:0] o_data
); );
reg [31:0] r_dma_fifo_mem [0:127];
reg [6:0] r_dma_fifo_wrptr;
reg [6:0] r_dma_fifo_rdptr;
assign o_fifo_full = (r_dma_fifo_wrptr + 1'd1) == r_dma_fifo_rdptr;
assign o_fifo_empty = r_dma_fifo_wrptr == r_dma_fifo_rdptr;
wire [31:0] w_rddata = r_dma_fifo_mem[r_dma_fifo_rdptr];
wire w_request_successful = o_request && !i_busy;
always @(posedge i_clk) begin
if (i_reset || i_fifo_flush) begin
r_dma_fifo_wrptr <= 7'd0;
end else begin
if (i_fifo_push) begin
r_dma_fifo_wrptr <= r_dma_fifo_wrptr + 1'd1;
r_dma_fifo_mem[r_dma_fifo_wrptr] <= i_fifo_data;
end
end
end
always @(posedge i_clk) begin
if (i_reset || i_fifo_flush) begin
o_request <= 1'b0;
o_write <= 1'b1;
r_dma_fifo_rdptr <= 7'd0;
end else begin
if (!o_request && !o_fifo_empty) begin
o_request <= 1'b1;
o_data <= w_rddata;
r_dma_fifo_rdptr <= r_dma_fifo_rdptr + 1'd1;
end
if (w_request_successful) begin
if (o_fifo_empty) begin
o_request <= 1'b0;
end else begin
r_dma_fifo_rdptr <= r_dma_fifo_rdptr + 1'd1;
o_data <= w_rddata;
end
end
end
end
endmodule endmodule

56
fw/rtl/sd/sd_fifo.v Normal file
View File

@ -0,0 +1,56 @@
module sd_fifo (
input i_clk,
input i_reset,
input i_fifo_flush,
input i_fifo_push,
input i_fifo_pop,
output o_fifo_empty,
output o_fifo_full,
output [7:0] o_fifo_items,
output reg o_fifo_underrun,
output reg o_fifo_overrun,
input [31:0] i_fifo_data,
output [31:0] o_fifo_data
);
reg [31:0] r_fifo_mem [0:127];
reg [7:0] r_fifo_wrptr;
reg [7:0] r_fifo_rdptr;
assign o_fifo_data = r_fifo_mem[r_fifo_rdptr[6:0]];
wire w_empty = r_fifo_wrptr[7] == r_fifo_rdptr[7];
wire w_full_or_empty = r_fifo_wrptr[6:0] == r_fifo_rdptr[6:0];
assign o_fifo_empty = w_empty && w_full_or_empty;
assign o_fifo_full = !w_empty && w_full_or_empty;
assign o_fifo_items = r_fifo_wrptr - r_fifo_rdptr;
always @(posedge i_clk) begin
if (i_reset) begin
r_fifo_wrptr <= 8'd0;
r_fifo_rdptr <= 8'd0;
o_fifo_underrun <= 1'b0;
o_fifo_overrun <= 1'b0;
end else begin
if (i_fifo_flush) begin
r_fifo_wrptr <= 8'd0;
r_fifo_rdptr <= 8'd0;
o_fifo_underrun <= 1'b0;
o_fifo_overrun <= 1'b0;
end
if (i_fifo_push) begin
o_fifo_overrun <= o_fifo_overrun ? 1'b1 : o_fifo_full;
r_fifo_mem[r_fifo_wrptr[6:0]] <= i_fifo_data;
r_fifo_wrptr <= r_fifo_wrptr + 1'd1;
end
if (i_fifo_pop) begin
o_fifo_underrun <= o_fifo_underrun ? 1'b1 : o_fifo_empty;
r_fifo_rdptr <= r_fifo_rdptr + 1'd1;
end
end
end
endmodule

View File

@ -1,19 +1,16 @@
`include "../constants.vh"
module sd_interface ( module sd_interface (
input i_clk, input i_clk,
input i_reset, input i_reset,
output reg o_sd_clk, output o_sd_clk,
output reg o_sd_cs, inout io_sd_cmd,
output reg o_sd_mosi, inout [3:0] io_sd_dat,
input i_sd_miso,
input i_request, input i_request,
input i_write, input i_write,
output o_busy, output o_busy,
output reg o_ack, output o_ack,
input [7:0] i_address, input [3:0] i_address,
output [31:0] o_data, output [31:0] o_data,
input [31:0] i_data, input [31:0] i_data,
@ -21,277 +18,278 @@ module sd_interface (
output o_dma_write, output o_dma_write,
input i_dma_busy, input i_dma_busy,
input i_dma_ack, input i_dma_ack,
output reg [3:0] o_dma_bank, output [3:0] o_dma_bank,
output reg [23:0] o_dma_address, output [23:0] o_dma_address,
input [31:0] i_dma_data, input [31:0] i_dma_data,
output [31:0] o_dma_data output [31:0] o_dma_data
); );
// Register offsets // Clock generator
localparam [2:0] REG_SD_SCR = 3'd0; wire [1:0] w_sd_clk_config;
localparam [2:0] REG_SD_CS = 3'd1; wire w_sd_clk_strobe_rising;
localparam [2:0] REG_SD_DR = 3'd2; wire w_sd_clk_strobe_falling;
localparam [2:0] REG_SD_MULTI = 3'd3;
localparam [2:0] REG_SD_DMA_SCR = 3'd4;
localparam [2:0] REG_SD_DMA_ADDR = 3'd5;
localparam [7:0] MEM_SD_BUFFER_BASE = 8'h80; sd_clk sd_clk_inst (
.i_clk(i_clk),
.i_reset(i_reset),
.i_sd_clk_config(w_sd_clk_config),
.o_sd_clk_strobe_rising(w_sd_clk_strobe_rising),
.o_sd_clk_strobe_falling(w_sd_clk_strobe_falling),
.o_sd_clk(o_sd_clk)
);
// Bus controller // Command path
reg [8:0] r_o_data; wire [5:0] w_command_index;
wire [31:0] w_command_argument;
wire w_command_skip_response;
wire w_command_long_response;
wire [5:0] w_command_response_index;
wire [31:0] w_command_response;
wire w_command_start;
wire w_command_busy;
wire w_command_timeout;
wire w_command_response_crc_error;
wire w_address_in_buffers = i_address >= MEM_SD_BUFFER_BASE; sd_cmd sd_cmd_inst (
wire [31:0] w_sd_buffer_rx_o_data; .i_clk(i_clk),
.i_reset(i_reset),
assign o_busy = 1'b0; .io_sd_cmd(io_sd_cmd),
assign o_data = w_address_in_buffers ? w_sd_buffer_rx_o_data : {23'd0, r_o_data};
always @(posedge i_clk) begin .i_sd_clk_strobe_rising(w_sd_clk_strobe_rising),
o_ack <= !i_reset && i_request && !i_write && !o_busy; .i_sd_clk_strobe_falling(w_sd_clk_strobe_falling),
.i_command_index(w_command_index),
.i_command_argument(w_command_argument),
.i_command_long_response(w_command_long_response),
.i_command_skip_response(w_command_skip_response),
.o_command_index(w_command_response_index),
.o_command_response(w_command_response),
.i_command_start(w_command_start),
.o_command_busy(w_command_busy),
.o_command_timeout(w_command_timeout),
.o_command_response_crc_error(w_command_response_crc_error)
);
// SD to FPGA (RX) data path FIFO
wire w_rx_fifo_flush;
wire w_rx_fifo_push;
wire w_rx_fifo_regs_pop;
wire w_rx_fifo_dma_pop;
wire w_rx_fifo_empty;
wire [7:0] w_rx_fifo_items;
wire w_rx_fifo_overrun;
wire [31:0] w_rx_fifo_i_data;
wire [31:0] w_rx_fifo_o_data;
sd_fifo sd_fifo_rx_inst (
.i_clk(i_clk),
.i_reset(i_reset),
.i_fifo_flush(w_rx_fifo_flush),
.i_fifo_push(w_rx_fifo_push),
.i_fifo_pop(w_rx_fifo_regs_pop || w_rx_fifo_dma_pop),
.o_fifo_empty(w_rx_fifo_empty),
// .o_fifo_full(),
.o_fifo_items(w_rx_fifo_items),
// .o_fifo_underrun(),
.o_fifo_overrun(w_rx_fifo_overrun),
.i_fifo_data(w_rx_fifo_i_data),
.o_fifo_data(w_rx_fifo_o_data)
);
// FPGA to SD (TX) data path FIFO
wire w_tx_fifo_flush;
wire w_tx_fifo_regs_push;
wire w_tx_fifo_dma_push;
wire w_tx_fifo_pop;
wire w_tx_fifo_empty;
wire w_tx_fifo_full;
reg [31:0] r_tx_fifo_i_data;
wire [31:0] w_tx_fifo_o_data;
wire [31:0] w_tx_fifo_i_data_regs;
wire [31:0] w_tx_fifo_i_data_dma;
always @(*) begin
r_tx_fifo_i_data = 32'h0000_0000;
if (w_tx_fifo_regs_push) r_tx_fifo_i_data = w_tx_fifo_i_data_regs;
if (w_tx_fifo_dma_push) r_tx_fifo_i_data = w_tx_fifo_i_data_dma;
end end
sd_fifo sd_fifo_tx_inst (
.i_clk(i_clk),
.i_reset(i_reset),
// DMA controller .i_fifo_flush(w_tx_fifo_flush),
.i_fifo_push(w_tx_fifo_regs_push || w_tx_fifo_dma_push),
.i_fifo_pop(w_tx_fifo_pop),
.o_fifo_empty(w_tx_fifo_empty),
.o_fifo_full(w_tx_fifo_full),
// .o_fifo_items(),
// .o_fifo_underrun(),
// .o_fifo_overrun(),
.i_fifo_data(r_tx_fifo_i_data),
.o_fifo_data(w_tx_fifo_o_data)
);
reg r_dma_fifo_flush;
reg r_dma_fifo_push;
reg [31:0] r_dma_fifo_data;
wire w_dma_fifo_full; // Data path
wire w_dma_fifo_empty;
wire w_dat_width;
wire w_dat_direction;
wire [6:0] w_dat_block_size;
wire [10:0] w_dat_num_blocks;
wire w_dat_start;
wire w_dat_stop;
wire w_dat_busy;
wire w_dat_crc_error;
sd_dat sd_dat_inst (
.i_clk(i_clk),
.i_reset(i_reset),
.io_sd_dat(io_sd_dat),
.i_sd_clk_strobe_rising(w_sd_clk_strobe_rising),
.i_sd_clk_strobe_falling(w_sd_clk_strobe_falling),
.i_dat_width(w_dat_width),
.i_dat_direction(w_dat_direction),
.i_dat_block_size(w_dat_block_size),
.i_dat_num_blocks(w_dat_num_blocks),
.i_dat_start(w_dat_start),
.i_dat_stop(w_dat_stop),
.o_dat_busy(w_dat_busy),
.o_dat_crc_error(w_dat_crc_error),
.o_rx_fifo_push(w_rx_fifo_push),
.i_rx_fifo_overrun(w_rx_fifo_overrun),
.o_rx_fifo_data(w_rx_fifo_i_data),
.i_tx_fifo_full(w_tx_fifo_full),
.o_tx_fifo_pop(w_tx_fifo_pop),
.i_tx_fifo_data(w_tx_fifo_o_data)
);
// DMA
wire [3:0] w_dma_bank;
wire [23:0] w_dma_address;
wire [14:0] w_dma_length;
wire [14:0] w_dma_left;
wire w_dma_load_bank_address;
wire w_dma_load_length;
wire w_dma_direction;
wire w_dma_start;
wire w_dma_stop;
wire w_dma_busy;
sd_dma sd_dma_inst ( sd_dma sd_dma_inst (
.i_clk(i_clk), .i_clk(i_clk),
.i_reset(i_reset), .i_reset(i_reset),
.i_fifo_flush(r_dma_fifo_flush), .i_dma_bank(w_dma_bank),
.i_fifo_push(r_dma_fifo_push), .i_dma_address(w_dma_address),
.o_fifo_full(w_dma_fifo_full), .i_dma_length(w_dma_length),
.o_fifo_empty(w_dma_fifo_empty), .o_dma_left(w_dma_left),
.i_fifo_data(r_dma_fifo_data), .i_dma_load_bank_address(w_dma_load_bank_address),
.i_dma_load_length(w_dma_load_length),
.i_dma_direction(w_dma_direction),
.i_dma_start(w_dma_start),
.i_dma_stop(w_dma_stop),
.o_dma_busy(w_dma_busy),
.o_rx_fifo_pop(w_rx_fifo_dma_pop),
.i_rx_fifo_empty(w_rx_fifo_empty),
.i_rx_fifo_data(w_rx_fifo_o_data),
.o_tx_fifo_push(w_tx_fifo_dma_push),
.i_tx_fifo_full(w_tx_fifo_full),
.o_tx_fifo_data(w_tx_fifo_i_data_dma),
.o_request(o_dma_request), .o_request(o_dma_request),
.o_write(o_dma_write), .o_write(o_dma_write),
.i_busy(i_dma_busy), .i_busy(i_dma_busy),
.i_ack(i_dma_ack),
.o_bank(o_dma_bank),
.o_address(o_dma_address),
.i_data(i_dma_data),
.o_data(o_dma_data) .o_data(o_dma_data)
); );
// Bus <-> peripheral interface registers // Peripheral registers
reg r_spi_busy; sd_regs sd_regs_inst (
.i_clk(i_clk),
.i_reset(i_reset),
reg [2:0] r_spi_clk_div; .o_sd_clk_config(w_sd_clk_config),
reg r_spi_start;
reg [7:0] r_spi_tx_data;
reg [7:0] r_spi_rx_data;
reg r_spi_rx_only; .o_command_index(w_command_index),
.o_command_argument(w_command_argument),
.o_command_long_response(w_command_long_response),
.o_command_skip_response(w_command_skip_response),
.i_command_index(w_command_response_index),
.i_command_response(w_command_response),
.o_command_start(w_command_start),
.i_command_busy(w_command_busy),
.i_command_timeout(w_command_timeout),
.i_command_response_crc_error(w_command_response_crc_error),
reg r_spi_start_multi; .o_dat_width(w_dat_width),
reg [8:0] r_spi_multi_length; .o_dat_direction(w_dat_direction),
reg r_spi_multi_dma; .o_dat_block_size(w_dat_block_size),
.o_dat_num_blocks(w_dat_num_blocks),
.o_dat_start(w_dat_start),
.o_dat_stop(w_dat_stop),
.i_dat_busy(w_dat_busy),
.i_dat_crc_error(w_dat_crc_error),
.o_rx_fifo_flush(w_rx_fifo_flush),
.o_rx_fifo_pop(w_rx_fifo_regs_pop),
.i_rx_fifo_items(w_rx_fifo_items),
.i_rx_fifo_overrun(w_rx_fifo_overrun),
.i_rx_fifo_data(w_rx_fifo_o_data),
// Write logic .o_tx_fifo_flush(w_tx_fifo_flush),
.o_tx_fifo_push(w_tx_fifo_regs_push),
.i_tx_fifo_empty(w_tx_fifo_empty),
.i_tx_fifo_full(w_tx_fifo_full),
.o_tx_fifo_data(w_tx_fifo_i_data_regs),
wire w_dma_request_successful = o_dma_request && !i_dma_busy; .o_dma_bank(w_dma_bank),
.o_dma_address(w_dma_address),
.o_dma_length(w_dma_length),
.i_dma_bank(o_dma_bank),
.i_dma_address(o_dma_address),
.i_dma_left(w_dma_left),
.o_dma_load_bank_address(w_dma_load_bank_address),
.o_dma_load_length(w_dma_load_length),
.o_dma_direction(w_dma_direction),
.o_dma_start(w_dma_start),
.o_dma_stop(w_dma_stop),
.i_dma_busy(w_dma_busy),
always @(posedge i_clk) begin .i_request(i_request),
r_spi_start <= 1'b0; .i_write(i_write),
r_spi_start_multi <= 1'b0; .o_busy(o_busy),
r_dma_fifo_flush <= 1'b0; .o_ack(o_ack),
.i_address(i_address),
if (i_reset) begin .o_data(o_data),
o_sd_cs <= 1'b1; .i_data(i_data)
o_dma_bank <= 4'd0;
o_dma_address <= 24'd0;
r_spi_clk_div <= 3'b111;
end else if (i_request && i_write && !o_busy && !w_address_in_buffers) begin
case (i_address[2:0])
REG_SD_SCR: begin
r_spi_clk_div <= i_data[3:1];
end
REG_SD_CS: if (!r_spi_busy) begin
o_sd_cs <= i_data[0];
end
REG_SD_DR: if (!r_spi_busy) begin
r_spi_start <= 1'b1;
r_spi_tx_data <= i_data[7:0];
r_spi_rx_only <= 1'b0;
r_spi_multi_length <= 9'd0;
r_spi_multi_dma <= 1'b0;
end
REG_SD_MULTI: if (!r_spi_busy) begin
r_spi_start_multi <= 1'b1;
{r_spi_multi_dma, r_spi_rx_only, r_spi_multi_length} <= i_data[10:0];
end
REG_SD_DMA_SCR: begin
{r_dma_fifo_flush} <= i_data[0];
end
REG_SD_DMA_ADDR: begin
{o_dma_bank, o_dma_address} <= {i_data[31:28], i_data[25:2]};
end
default: begin
end
endcase
end
if (w_dma_request_successful) begin
o_dma_address <= o_dma_address + 1'd1;
end
end
// Read logic
always @(posedge i_clk) begin
if (!i_reset && i_request && !i_write && !o_busy) begin
if (!w_address_in_buffers) begin
case (i_address[2:0])
REG_SD_SCR: begin
r_o_data[3:0] <= {r_spi_clk_div, r_spi_busy};
end
REG_SD_DR: begin
r_o_data[8:0] <= {r_spi_busy, r_spi_rx_data};
end
REG_SD_DMA_SCR: begin
r_o_data[1:0] <= {w_dma_fifo_full, w_dma_fifo_empty};
end
default: begin
end
endcase
end
end
end
// Clock divider
reg [7:0] r_spi_clk_div_counter;
reg r_spi_clk_prev_value;
reg r_spi_clk_strobe;
wire w_spi_clk_div_selected = r_spi_clk_div_counter[r_spi_clk_div];
always @(posedge i_clk) begin
r_spi_clk_div_counter <= r_spi_clk_div_counter + 1'd1;
r_spi_clk_prev_value <= w_spi_clk_div_selected;
r_spi_clk_strobe <= (w_spi_clk_div_selected != r_spi_clk_prev_value) && !w_dma_fifo_full;
end
// Buffers
reg [8:0] r_spi_multi_tx_address;
wire [7:0] w_spi_multi_tx_data;
ram_sd_buffer ram_sd_buffer_tx_inst (
.clock(i_clk),
.address_a(r_spi_multi_tx_address),
.q_a(w_spi_multi_tx_data),
.wren_b(!i_reset && i_request && i_write && !o_busy && w_address_in_buffers),
.address_b(i_address[6:0]),
.data_b({i_data[7:0], i_data[15:8], i_data[23:16], i_data[31:24]})
); );
reg r_spi_multi_rx_byte_write;
reg [8:0] r_spi_multi_rx_address;
ram_sd_buffer ram_sd_buffer_rx_inst (
.clock(i_clk),
.wren_a(r_spi_multi_rx_byte_write),
.address_a(r_spi_multi_rx_address),
.data_a(r_spi_rx_data),
.address_b(i_address[6:0]),
.q_b({w_sd_buffer_rx_o_data[7:0], w_sd_buffer_rx_o_data[15:8], w_sd_buffer_rx_o_data[23:16], w_sd_buffer_rx_o_data[31:24]})
);
// Shifting operation
reg r_spi_multi;
reg r_spi_first_bit;
reg [3:0] r_spi_bit_clk;
reg [6:0] r_spi_tx_shift;
wire [7:0] w_next_spi_tx_data = r_spi_rx_only ? 8'hFF : (r_spi_multi ? w_spi_multi_tx_data : r_spi_tx_data);
always @(posedge i_clk) begin
r_spi_multi_rx_byte_write <= 1'b0;
if (i_reset) begin
o_sd_clk <= 1'b0;
r_spi_bit_clk <= 4'd8;
r_spi_multi_tx_address <= 9'd0;
r_spi_multi_rx_address <= 9'd0;
end else begin
if (!r_spi_busy && (r_spi_start || r_spi_start_multi)) begin
r_spi_busy <= 1'b1;
r_spi_multi <= r_spi_start_multi;
r_spi_first_bit <= 1'b1;
end else if (r_spi_busy && r_spi_clk_strobe) begin
if (r_spi_first_bit) begin
r_spi_first_bit <= 1'b0;
{o_sd_mosi, r_spi_tx_shift} <= w_next_spi_tx_data;
r_spi_multi_tx_address <= r_spi_multi_tx_address + 1'd1;
end else if (!o_sd_clk) begin
o_sd_clk <= 1'b1;
r_spi_rx_data <= {r_spi_rx_data[6:0], i_sd_miso};
r_spi_bit_clk <= r_spi_bit_clk - 1'd1;
if (r_spi_bit_clk == 4'd1) begin
r_spi_multi_rx_byte_write <= 1'b1;
end
end else begin
o_sd_clk <= 1'b0;
if (r_spi_bit_clk == 4'd0) begin
{o_sd_mosi, r_spi_tx_shift} <= w_next_spi_tx_data;
r_spi_bit_clk <= 4'd8;
r_spi_multi_tx_address <= r_spi_multi_tx_address + 1'd1;
r_spi_multi_rx_address <= r_spi_multi_rx_address + 1'd1;
if (r_spi_multi_rx_address == r_spi_multi_length) begin
r_spi_busy <= 1'b0;
r_spi_multi_tx_address <= 9'd0;
r_spi_multi_rx_address <= 9'd0;
end
end else begin
{o_sd_mosi, r_spi_tx_shift} <= {r_spi_tx_shift, 1'b0};
end
end
end
end
end
// DMA RX FIFO controller
reg [1:0] r_dma_byte_counter;
always @(posedge i_clk) begin
r_dma_fifo_push <= 1'b0;
if (i_reset) begin
r_dma_byte_counter <= 2'd0;
end else begin
if (!r_spi_busy || (r_spi_busy && !r_spi_multi_dma)) begin
if (r_dma_fifo_flush) begin
r_dma_byte_counter <= 2'd0;
end
end else if (r_spi_multi_rx_byte_write && r_spi_multi_dma) begin
r_dma_byte_counter <= r_dma_byte_counter + 1'd1;
r_dma_fifo_data <= {r_dma_fifo_data[23:0], r_spi_rx_data};
if (r_dma_byte_counter == 2'd3) begin
r_dma_fifo_push <= 1'b1;
end
end
end
end
endmodule endmodule

222
fw/rtl/sd/sd_regs.v Normal file
View File

@ -0,0 +1,222 @@
module sd_regs (
input i_clk,
input i_reset,
output reg [1:0] o_sd_clk_config,
output reg [5:0] o_command_index,
output reg [31:0] o_command_argument,
output reg o_command_long_response,
output reg o_command_skip_response,
input [5:0] i_command_index,
input [31:0] i_command_response,
output reg o_command_start,
input i_command_busy,
input i_command_timeout,
input i_command_response_crc_error,
output reg o_dat_width,
output reg o_dat_direction,
output reg [6:0] o_dat_block_size,
output reg [10:0] o_dat_num_blocks,
output reg o_dat_start,
output reg o_dat_stop,
input i_dat_busy,
input i_dat_crc_error,
output reg o_rx_fifo_flush,
output reg o_rx_fifo_pop,
input [7:0] i_rx_fifo_items,
input i_rx_fifo_overrun,
input [31:0] i_rx_fifo_data,
output reg o_tx_fifo_flush,
output reg o_tx_fifo_push,
input i_tx_fifo_empty,
input i_tx_fifo_full,
output reg [31:0] o_tx_fifo_data,
output reg [3:0] o_dma_bank,
output reg [23:0] o_dma_address,
output reg [14:0] o_dma_length,
input [3:0] i_dma_bank,
input [23:0] i_dma_address,
input [14:0] i_dma_left,
output reg o_dma_load_bank_address,
output reg o_dma_load_length,
output reg o_dma_direction,
output reg o_dma_start,
output reg o_dma_stop,
input i_dma_busy,
input i_request,
input i_write,
output o_busy,
output reg o_ack,
input [3:0] i_address,
output reg [31:0] o_data,
input [31:0] i_data
);
localparam [2:0] SD_REG_SCR = 3'd0;
localparam [2:0] SD_REG_ARG = 3'd1;
localparam [2:0] SD_REG_CMD = 3'd2;
localparam [2:0] SD_REG_RSP = 3'd3;
localparam [2:0] SD_REG_DAT = 3'd4;
localparam [2:0] SD_REG_DMA_SCR = 3'd5;
localparam [2:0] SD_REG_DMA_ADDR = 3'd6;
localparam [2:0] SD_REG_DMA_LENGTH = 3'd7;
wire w_write_request = i_request && i_write && !o_busy;
wire w_read_request = i_request && !i_write && !o_busy;
always @(*) begin
o_dma_bank = i_data[31:28];
o_dma_address = i_data[25:2];
o_dma_length = i_data[14:0];
o_dma_load_bank_address = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_ADDR);
o_dma_load_length = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_LENGTH);
o_busy = 1'b0;
end
always @(posedge i_clk) begin
o_command_start <= 1'b0;
o_dat_start <= 1'b0;
o_rx_fifo_flush <= 1'b0;
o_tx_fifo_flush <= 1'b0;
o_tx_fifo_push <= 1'b0;
o_dma_start <= 1'b0;
o_dat_stop <= 1'b0;
o_dma_stop <= 1'b0;
if (i_reset) begin
o_sd_clk_config <= 2'd0;
o_dat_width <= 1'b0;
o_dat_direction <= 1'b0;
o_dat_block_size <= 7'd0;
o_dat_num_blocks <= 11'd0;
o_dma_direction <= 1'b0;
end else if (w_write_request) begin
if (!i_address[3]) begin
case (i_address[2:0])
SD_REG_SCR: begin
{o_dat_width, o_sd_clk_config} <= i_data[2:0];
end
SD_REG_ARG: begin
o_command_argument <= i_data;
end
SD_REG_CMD: begin
{
o_command_skip_response,
o_command_long_response,
o_command_start,
o_command_index
} <= i_data[8:0];
end
SD_REG_RSP: begin
end
SD_REG_DAT: begin
{
o_tx_fifo_flush,
o_rx_fifo_flush,
o_dat_num_blocks,
o_dat_block_size,
o_dat_direction,
o_dat_stop,
o_dat_start
} <= i_data[22:0];
end
SD_REG_DMA_SCR: begin
{
o_dma_direction,
o_dma_stop,
o_dma_start
} <= i_data[2:0];
end
SD_REG_DMA_ADDR: begin
end
SD_REG_DMA_LENGTH: begin
end
endcase
end else begin
o_tx_fifo_push <= 1'b1;
o_tx_fifo_data <= i_data;
end
end
end
always @(posedge i_clk) begin
o_rx_fifo_pop <= 1'b0;
o_ack <= 1'b0;
if (i_reset) begin
o_data <= 32'h0000_0000;
end else if (w_read_request) begin
o_ack <= 1'b1;
if (!i_address[3]) begin
case (i_address[2:0])
SD_REG_SCR: begin
o_data <= {30'd0, o_sd_clk_config};
end
SD_REG_ARG: begin
o_data <= o_command_argument;
end
SD_REG_CMD: begin
o_data <= {
21'd0,
i_command_response_crc_error,
i_command_timeout,
2'b00,
i_command_busy,
i_command_index
};
end
SD_REG_RSP: begin
o_data <= i_command_response;
end
SD_REG_DAT: begin
o_data <= {
i_rx_fifo_items,
i_tx_fifo_full,
i_tx_fifo_empty,
i_rx_fifo_overrun,
o_dat_num_blocks,
o_dat_block_size,
o_dat_direction,
i_dat_crc_error,
i_dat_busy
};
end
SD_REG_DMA_SCR: begin
o_data <= {29'd0, o_dma_direction, 1'b0, i_dma_busy};
end
SD_REG_DMA_ADDR: begin
o_data <= {i_dma_bank, 2'd0, i_dma_address, 2'b00};
end
SD_REG_DMA_LENGTH: begin
o_data <= {17'd0, i_dma_left};
end
endcase
end else begin
o_rx_fifo_pop <= 1'b1;
o_data <= i_rx_fifo_data;
end
end
end
endmodule

View File

@ -20,9 +20,6 @@ module top (
input i_n64_si_clk, input i_n64_si_clk,
inout io_n64_si_dq, inout io_n64_si_dq,
input i_n64_cic_clk, // TODO: to be removed
inout io_n64_cic_dq, // TODO: to be removed
output o_sdram_clk, output o_sdram_clk,
output o_sdram_cs, output o_sdram_cs,
output o_sdram_ras, output o_sdram_ras,
@ -36,10 +33,6 @@ module top (
inout io_sd_cmd, inout io_sd_cmd,
inout [3:0] io_sd_dat, inout [3:0] io_sd_dat,
output o_flash_clk, // TODO: to be removed
output o_flash_cs, // TODO: to be removed
inout [3:0] io_flash_dq, // TODO: to be removed
output o_sram_clk, output o_sram_clk,
output o_sram_cs, output o_sram_cs,
inout [3:0] io_sram_dq, inout [3:0] io_sram_dq,
@ -49,7 +42,7 @@ module top (
output o_led, output o_led,
inout [7:0] io_pmod // TODO: to be removed inout [7:0] io_pmod
); );
// Clock and reset signals // Clock and reset signals
@ -64,8 +57,6 @@ module top (
wire w_n64_reset_btn; wire w_n64_reset_btn;
assign io_n64_cic_dq = 1'bZ;
assign {o_flash_clk, o_flash_cs, io_flash_dq} = 6'bZZZZZZ;
assign {o_sram_clk, o_sram_cs, io_sram_dq} = 6'bZZZZZZ; assign {o_sram_clk, o_sram_cs, io_sram_dq} = 6'bZZZZZZ;
assign {o_rtc_scl, io_rtc_sda} = 2'bZZ; assign {o_rtc_scl, io_rtc_sda} = 2'bZZ;
assign io_pmod[3] = w_n64_reset_btn ? 1'bZ : 1'b0; assign io_pmod[3] = w_n64_reset_btn ? 1'bZ : 1'b0;
@ -363,16 +354,6 @@ module top (
// SD card // SD card
wire w_sd_clk;
wire w_sd_cs;
wire w_sd_mosi;
wire w_sd_miso;
assign o_sd_clk = w_sd_clk;
assign io_sd_dat = {w_sd_cs, 3'bZZZ};
assign io_sd_cmd = w_sd_mosi;
assign w_sd_miso = io_sd_dat[0];
wire w_n64_request_sd = w_n64_request && w_n64_bank == `BANK_SD; wire w_n64_request_sd = w_n64_request && w_n64_bank == `BANK_SD;
wire w_sd_dma_request; wire w_sd_dma_request;
@ -404,16 +385,15 @@ module top (
.i_clk(w_sys_clk), .i_clk(w_sys_clk),
.i_reset(w_sys_reset), .i_reset(w_sys_reset),
.o_sd_clk(w_sd_clk), .o_sd_clk(o_sd_clk),
.o_sd_cs(w_sd_cs), .io_sd_cmd(io_sd_cmd),
.o_sd_mosi(w_sd_mosi), .io_sd_dat(io_sd_dat),
.i_sd_miso(w_sd_miso),
.i_request(w_n64_request_sd), .i_request(w_n64_request_sd),
.i_write(w_n64_write), .i_write(w_n64_write),
.o_busy(w_n64_busy_sd), .o_busy(w_n64_busy_sd),
.o_ack(w_n64_ack_sd), .o_ack(w_n64_ack_sd),
.i_address(w_n64_address[9:2]), .i_address({w_n64_address[9], w_n64_address[4:2]}),
.o_data(w_n64_i_data_sd), .o_data(w_n64_i_data_sd),
.i_data(w_n64_o_data), .i_data(w_n64_o_data),