mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
preliminary sd card support
This commit is contained in:
parent
2cc618b268
commit
321f3d37aa
1
fw/project/lcmxo2/.gitignore
vendored
1
fw/project/lcmxo2/.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
.recovery
|
||||
*.dir/
|
||||
*.ccl
|
||||
*.dmp
|
||||
*.html
|
||||
*.ini
|
||||
*.rva
|
||||
|
@ -66,7 +66,13 @@
|
||||
<Source name="../../rtl/sd/sd_cmd.sv" type="Verilog" type_short="Verilog">
|
||||
<Options VerilogStandard="System Verilog"/>
|
||||
</Source>
|
||||
<Source name="../../rtl/sd/sd_crc_7.sv" type="Verilog" type_short="Verilog" excluded="TRUE">
|
||||
<Source name="../../rtl/sd/sd_crc_7.sv" type="Verilog" type_short="Verilog">
|
||||
<Options VerilogStandard="System Verilog"/>
|
||||
</Source>
|
||||
<Source name="../../rtl/sd/sd_crc_16.sv" type="Verilog" type_short="Verilog">
|
||||
<Options VerilogStandard="System Verilog"/>
|
||||
</Source>
|
||||
<Source name="../../rtl/sd/sd_dat.sv" type="Verilog" type_short="Verilog">
|
||||
<Options VerilogStandard="System Verilog"/>
|
||||
</Source>
|
||||
<Source name="../../rtl/sd/sd_scb.sv" type="Verilog" type_short="Verilog">
|
||||
|
@ -322,7 +322,6 @@ module mcu_top (
|
||||
// Register list
|
||||
|
||||
typedef enum bit [7:0] {
|
||||
REG_STATUS,
|
||||
REG_MEM_ADDRESS,
|
||||
REG_MEM_SCR,
|
||||
REG_USB_SCR,
|
||||
@ -373,15 +372,6 @@ module mcu_top (
|
||||
reg_rdata <= 32'd0;
|
||||
|
||||
case (address)
|
||||
REG_STATUS: begin
|
||||
reg_rdata <= {
|
||||
29'd0,
|
||||
n64_scb.cfg_pending,
|
||||
~sd_det_ff[2],
|
||||
~button_ff[2]
|
||||
};
|
||||
end
|
||||
|
||||
REG_MEM_ADDRESS: begin
|
||||
reg_rdata <= mem_address;
|
||||
end
|
||||
@ -396,7 +386,10 @@ module mcu_top (
|
||||
|
||||
REG_USB_SCR: begin
|
||||
reg_rdata <= {
|
||||
28'd0,
|
||||
4'd0,
|
||||
usb_scb.tx_count,
|
||||
usb_scb.rx_count,
|
||||
2'b00,
|
||||
usb_scb.reset_pending,
|
||||
~fifo_bus.tx_full,
|
||||
~fifo_bus.rx_empty,
|
||||
@ -429,7 +422,8 @@ module mcu_top (
|
||||
|
||||
REG_CFG_SCR: begin
|
||||
reg_rdata <= {
|
||||
20'd0,
|
||||
~button_ff[2],
|
||||
19'd0,
|
||||
n64_scb.rom_extended_enabled,
|
||||
n64_scb.eeprom_16k_mode,
|
||||
n64_scb.eeprom_enabled,
|
||||
@ -455,7 +449,8 @@ module mcu_top (
|
||||
|
||||
REG_CFG_CMD: begin
|
||||
reg_rdata <= {
|
||||
24'd0,
|
||||
23'd0,
|
||||
n64_scb.cfg_pending,
|
||||
n64_scb.cfg_cmd
|
||||
};
|
||||
end
|
||||
@ -510,11 +505,57 @@ module mcu_top (
|
||||
|
||||
REG_SD_SCR: begin
|
||||
reg_rdata <= {
|
||||
30'd0,
|
||||
4'd0,
|
||||
sd_scb.tx_count,
|
||||
sd_scb.rx_count,
|
||||
~sd_det_ff[2],
|
||||
sd_scb.card_busy,
|
||||
sd_scb.cmd_error,
|
||||
sd_scb.cmd_busy,
|
||||
sd_scb.clock_mode
|
||||
};
|
||||
end
|
||||
|
||||
REG_SD_ARG: begin
|
||||
reg_rdata <= sd_scb.cmd_arg;
|
||||
end
|
||||
|
||||
REG_SD_CMD: begin
|
||||
reg_rdata <= {
|
||||
22'd0,
|
||||
sd_scb.cmd_ignore_crc,
|
||||
sd_scb.cmd_long_response,
|
||||
sd_scb.cmd_reserved_response,
|
||||
sd_scb.cmd_skip_response,
|
||||
sd_scb.cmd_index
|
||||
};
|
||||
end
|
||||
|
||||
REG_SD_RSP_0: begin
|
||||
reg_rdata <= sd_scb.cmd_rsp[31:0];
|
||||
end
|
||||
|
||||
REG_SD_RSP_1: begin
|
||||
reg_rdata <= sd_scb.cmd_rsp[63:32];
|
||||
end
|
||||
|
||||
REG_SD_RSP_2: begin
|
||||
reg_rdata <= sd_scb.cmd_rsp[95:64];
|
||||
end
|
||||
|
||||
REG_SD_RSP_3: begin
|
||||
reg_rdata <= sd_scb.cmd_rsp[127:96];
|
||||
end
|
||||
|
||||
REG_SD_DAT: begin
|
||||
reg_rdata <= {
|
||||
18'd0,
|
||||
sd_scb.dat_error,
|
||||
sd_scb.dat_busy,
|
||||
12'd0
|
||||
};
|
||||
end
|
||||
|
||||
REG_SD_DMA_ADDRESS: begin
|
||||
reg_rdata <= {
|
||||
5'd0,
|
||||
@ -604,6 +645,12 @@ module mcu_top (
|
||||
usb_dma_scb.start <= 1'b0;
|
||||
usb_dma_scb.stop <= 1'b0;
|
||||
|
||||
sd_scb.cmd_start <= 1'b0;
|
||||
sd_scb.dat_fifo_flush <= 1'b0;
|
||||
sd_scb.dat_start_write <= 1'b0;
|
||||
sd_scb.dat_start_read <= 1'b0;
|
||||
sd_scb.dat_stop <= 1'b0;
|
||||
|
||||
sd_dma_scb.start <= 1'b0;
|
||||
sd_dma_scb.stop <= 1'b0;
|
||||
|
||||
@ -656,8 +703,6 @@ module mcu_top (
|
||||
n64_scb.rtc_wdata_valid <= 1'b0;
|
||||
end else if (reg_write) begin
|
||||
case (address)
|
||||
REG_STATUS: begin end
|
||||
|
||||
REG_MEM_ADDRESS: begin
|
||||
mem_address <= reg_wdata;
|
||||
end
|
||||
@ -725,7 +770,7 @@ module mcu_top (
|
||||
n64_scb.cfg_irq,
|
||||
n64_scb.cfg_error,
|
||||
n64_scb.cfg_done
|
||||
} <= reg_wdata[2:0];
|
||||
} <= reg_wdata[11:9];
|
||||
end
|
||||
|
||||
REG_FLASHRAM_SCR: begin
|
||||
@ -760,6 +805,27 @@ module mcu_top (
|
||||
sd_scb.clock_mode <= reg_wdata[1:0];
|
||||
end
|
||||
|
||||
REG_SD_ARG: begin
|
||||
sd_scb.cmd_arg <= reg_wdata;
|
||||
end
|
||||
|
||||
REG_SD_CMD: begin
|
||||
sd_scb.cmd_start <= 1'b1;
|
||||
sd_scb.cmd_ignore_crc <= reg_wdata[9];
|
||||
sd_scb.cmd_long_response <= reg_wdata[8];
|
||||
sd_scb.cmd_reserved_response <= reg_wdata[7];
|
||||
sd_scb.cmd_skip_response <= reg_wdata[6];
|
||||
sd_scb.cmd_index <= reg_wdata[5:0];
|
||||
end
|
||||
|
||||
REG_SD_DAT: begin
|
||||
sd_scb.dat_blocks <= reg_wdata[11:4];
|
||||
sd_scb.dat_stop <= reg_wdata[3];
|
||||
sd_scb.dat_start_read <= reg_wdata[2];
|
||||
sd_scb.dat_start_write <= reg_wdata[1];
|
||||
sd_scb.dat_fifo_flush <= reg_wdata[0];
|
||||
end
|
||||
|
||||
REG_SD_DMA_ADDRESS: begin
|
||||
sd_dma_scb.starting_address <= reg_wdata[26:0];
|
||||
end
|
||||
|
@ -76,6 +76,7 @@ module memory_dma (
|
||||
always_ff @(posedge clk) begin
|
||||
rx_rdata_pop <= (
|
||||
!rx_rdata_pop &&
|
||||
!fifo_bus.rx_read &&
|
||||
trx_enabled &&
|
||||
rx_buffer_counter < 2'd2 &&
|
||||
!fifo_bus.rx_empty &&
|
||||
|
@ -31,7 +31,8 @@ module n64_cfg (
|
||||
REG_STATUS: reg_bus.rdata = {
|
||||
n64_scb.cfg_pending,
|
||||
cfg_error,
|
||||
14'd0
|
||||
irq,
|
||||
13'd0
|
||||
};
|
||||
REG_COMMAND: reg_bus.rdata = {8'd0, n64_scb.cfg_cmd};
|
||||
REG_DATA_0_H: reg_bus.rdata = n64_scb.cfg_wdata[0][31:16];
|
||||
|
@ -23,8 +23,13 @@ module n64_top (
|
||||
|
||||
logic n64_dd_irq;
|
||||
logic n64_cfg_irq;
|
||||
logic n64_irq_oe;
|
||||
|
||||
assign n64_irq = (n64_dd_irq || n64_cfg_irq) ? 1'b0 : 1'bZ;
|
||||
always @(posedge clk) begin
|
||||
n64_irq_oe <= (n64_dd_irq || n64_cfg_irq);
|
||||
end
|
||||
|
||||
assign n64_irq = n64_irq_oe ? 1'b0 : 1'bZ;
|
||||
|
||||
n64_reg_bus reg_bus ();
|
||||
|
||||
|
@ -10,6 +10,222 @@ module sd_cmd (
|
||||
inout sd_cmd
|
||||
);
|
||||
|
||||
assign sd_cmd = 1'bZ;
|
||||
// Input and output data sampling
|
||||
|
||||
logic sd_cmd_oe;
|
||||
logic sd_cmd_out;
|
||||
logic sd_cmd_in;
|
||||
logic sd_cmd_oe_data;
|
||||
logic sd_cmd_data;
|
||||
|
||||
assign sd_cmd = sd_cmd_oe ? sd_cmd_out : 1'bZ;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
sd_cmd_oe <= sd_cmd_oe_data;
|
||||
sd_cmd_out <= sd_cmd_data;
|
||||
sd_cmd_in <= sd_cmd;
|
||||
end
|
||||
|
||||
|
||||
// CMD state
|
||||
|
||||
typedef enum bit [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_TX,
|
||||
STATE_WAIT,
|
||||
STATE_RX
|
||||
} e_state;
|
||||
|
||||
e_state state;
|
||||
e_state next_state;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset) begin
|
||||
state <= STATE_IDLE;
|
||||
end else begin
|
||||
state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
assign sd_scb.cmd_busy = (state != STATE_IDLE);
|
||||
|
||||
logic [7:0] counter;
|
||||
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
if (sd_scb.cmd_start) begin
|
||||
next_state = STATE_TX;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_TX: begin
|
||||
if (sd_clk_falling) begin
|
||||
if (counter == 8'd48) begin
|
||||
if (sd_scb.cmd_skip_response) begin
|
||||
next_state = STATE_IDLE;
|
||||
end else begin
|
||||
next_state = STATE_WAIT;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
STATE_WAIT: begin
|
||||
if (sd_clk_rising) begin
|
||||
if (counter == 8'd64) begin
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
if (!sd_cmd_in) begin
|
||||
next_state = STATE_RX;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX: begin
|
||||
if (sd_clk_rising) begin
|
||||
if (sd_scb.cmd_long_response) begin
|
||||
if (counter == 8'd136) begin
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
end else begin
|
||||
if (counter == 8'd48) begin
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
default: begin
|
||||
next_state = STATE_IDLE;
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// CRC7 unit
|
||||
|
||||
logic crc_reset;
|
||||
logic crc_enable;
|
||||
logic crc_data;
|
||||
logic [6:0] crc_result;
|
||||
|
||||
sd_crc_7 sd_crc_7_inst (
|
||||
.clk(clk),
|
||||
.reset(crc_reset),
|
||||
.enable(crc_enable),
|
||||
.data(crc_data),
|
||||
.result(crc_result)
|
||||
);
|
||||
|
||||
|
||||
// Data shifting
|
||||
|
||||
logic [7:0] data_shift;
|
||||
|
||||
assign crc_data = (state == STATE_RX) ? data_shift[0] : data_shift[7];
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
crc_reset <= 1'b0;
|
||||
crc_enable <= 1'b0;
|
||||
|
||||
if (reset) begin
|
||||
sd_cmd_oe_data <= 1'b0;
|
||||
sd_cmd_data <= 1'b1;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
if (sd_scb.cmd_start) begin
|
||||
sd_scb.cmd_error <= 1'b0;
|
||||
crc_reset <= 1'b1;
|
||||
data_shift <= {2'b01, sd_scb.cmd_index};
|
||||
counter <= 8'd0;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_TX: begin
|
||||
if (sd_clk_falling) begin
|
||||
sd_cmd_oe_data <= 1'b1;
|
||||
sd_cmd_data <= data_shift[7];
|
||||
counter <= counter + 1'd1;
|
||||
crc_enable <= 1'b1;
|
||||
data_shift <= {data_shift[6:0], 1'bX};
|
||||
if (counter == 8'd7) begin
|
||||
data_shift <= sd_scb.cmd_arg[31:24];
|
||||
end
|
||||
if (counter == 8'd15) begin
|
||||
data_shift <= sd_scb.cmd_arg[23:16];
|
||||
end
|
||||
if (counter == 8'd23) begin
|
||||
data_shift <= sd_scb.cmd_arg[15:8];
|
||||
end
|
||||
if (counter == 8'd31) begin
|
||||
data_shift <= sd_scb.cmd_arg[7:0];
|
||||
end
|
||||
if (counter == 8'd39) begin
|
||||
data_shift <= {crc_result, 1'b1};
|
||||
end
|
||||
if (counter == 8'd48) begin
|
||||
sd_cmd_oe_data <= 1'b0;
|
||||
counter <= 8'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
STATE_WAIT: begin
|
||||
if (sd_clk_rising) begin
|
||||
counter <= counter + 1'd1;
|
||||
if (counter == 8'd64) begin
|
||||
sd_scb.cmd_error <= 1'b1;
|
||||
end
|
||||
if (!sd_cmd_in) begin
|
||||
counter <= 8'd1;
|
||||
crc_reset <= 1'b1;
|
||||
data_shift <= 8'h00;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX: begin
|
||||
if (sd_clk_rising) begin
|
||||
counter <= counter + 1'd1;
|
||||
data_shift <= {data_shift[6:0], sd_cmd_in};
|
||||
if (counter == 8'd8) begin
|
||||
if (data_shift[6:0] != (sd_scb.cmd_reserved_response ? 7'h3F : {1'b0, sd_scb.cmd_index})) begin
|
||||
sd_scb.cmd_error <= 1'b1;
|
||||
end
|
||||
end
|
||||
if (sd_scb.cmd_long_response) begin
|
||||
if (counter >= 8'd8 && counter < 8'd128) begin
|
||||
crc_enable <= 1'b1;
|
||||
end
|
||||
if (counter[2:0] == 3'd0) begin
|
||||
sd_scb.cmd_rsp <= {sd_scb.cmd_rsp[119:0], data_shift};
|
||||
end
|
||||
if (!sd_scb.cmd_ignore_crc && counter == 8'd136) begin
|
||||
if (data_shift[7:1] != crc_result) begin
|
||||
sd_scb.cmd_error <= 1'b1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
if (counter < 8'd40) begin
|
||||
crc_enable <= 1'b1;
|
||||
end
|
||||
if (counter <= 8'd40 && counter[2:0] == 3'd0) begin
|
||||
sd_scb.cmd_rsp <= {sd_scb.cmd_rsp[119:0], data_shift};
|
||||
end
|
||||
if (!sd_scb.cmd_ignore_crc && counter == 8'd48) begin
|
||||
if (data_shift[7:1] != crc_result) begin
|
||||
sd_scb.cmd_error <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
33
fw/rtl/sd/sd_crc_16.sv
Normal file
33
fw/rtl/sd/sd_crc_16.sv
Normal file
@ -0,0 +1,33 @@
|
||||
module sd_crc_16 (
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
input enable,
|
||||
input shift,
|
||||
input data,
|
||||
|
||||
output logic [15:0] result
|
||||
);
|
||||
|
||||
logic crc_inv;
|
||||
|
||||
assign crc_inv = result[15] ^ data;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset) begin
|
||||
result <= 16'd0;
|
||||
end else if (enable) begin
|
||||
result <= {
|
||||
result[14:12],
|
||||
result[11] ^ crc_inv,
|
||||
result[10:5],
|
||||
result[4] ^ crc_inv,
|
||||
result[3:0],
|
||||
crc_inv
|
||||
};
|
||||
end else if (shift) begin
|
||||
result <= {result[14:0], 1'b1};
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
246
fw/rtl/sd/sd_dat.sv
Normal file
246
fw/rtl/sd/sd_dat.sv
Normal file
@ -0,0 +1,246 @@
|
||||
module sd_dat (
|
||||
input clk,
|
||||
input reset,
|
||||
|
||||
sd_scb.dat sd_scb,
|
||||
|
||||
fifo_bus.fifo fifo_bus,
|
||||
|
||||
input sd_clk_rising,
|
||||
input sd_clk_falling,
|
||||
|
||||
inout [3:0] sd_dat
|
||||
);
|
||||
|
||||
// Input and output data sampling
|
||||
|
||||
logic sd_dat_oe;
|
||||
logic sd_dat_out;
|
||||
logic [3:0] sd_dat_in;
|
||||
logic sd_dat_oe_data;
|
||||
logic [3:0] sd_dat_data;
|
||||
|
||||
assign sd_dat = sd_dat_oe ? sd_dat_out : 4'hZ;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
sd_dat_oe <= sd_dat_oe_data;
|
||||
sd_dat_out <= sd_dat_data;
|
||||
sd_dat_in <= sd_dat;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
sd_scb.card_busy <= !sd_dat_in[0];
|
||||
end
|
||||
|
||||
|
||||
// FIFO
|
||||
|
||||
logic rx_full;
|
||||
logic rx_almost_full;
|
||||
logic rx_write;
|
||||
logic [7:0] rx_wdata;
|
||||
|
||||
logic tx_empty;
|
||||
logic tx_almost_empty;
|
||||
logic tx_read;
|
||||
logic [7:0] tx_rdata;
|
||||
|
||||
fifo_8kb fifo_8kb_rx_inst (
|
||||
.clk(clk),
|
||||
.reset(reset || sd_scb.dat_fifo_flush),
|
||||
|
||||
.empty(fifo_bus.rx_empty),
|
||||
.almost_empty(fifo_bus.rx_almost_empty),
|
||||
.read(fifo_bus.rx_read),
|
||||
.rdata(fifo_bus.rx_rdata),
|
||||
|
||||
.full(rx_full),
|
||||
.almost_full(rx_almost_full),
|
||||
.write(rx_write),
|
||||
.wdata(rx_wdata),
|
||||
|
||||
.count(sd_scb.rx_count)
|
||||
);
|
||||
|
||||
fifo_8kb fifo_8kb_tx_inst (
|
||||
.clk(clk),
|
||||
.reset(reset || sd_scb.dat_fifo_flush),
|
||||
|
||||
.empty(tx_empty),
|
||||
.almost_empty(tx_almost_empty),
|
||||
.read(tx_read),
|
||||
.rdata(tx_rdata),
|
||||
|
||||
.full(fifo_bus.tx_full),
|
||||
.almost_full(fifo_bus.tx_almost_full),
|
||||
.write(fifo_bus.tx_write),
|
||||
.wdata(fifo_bus.tx_wdata),
|
||||
|
||||
.count(sd_scb.tx_count)
|
||||
);
|
||||
|
||||
|
||||
// DAT state
|
||||
|
||||
typedef enum bit [1:0] {
|
||||
STATE_IDLE,
|
||||
STATE_RX_WAIT,
|
||||
STATE_RX
|
||||
} e_state;
|
||||
|
||||
e_state state;
|
||||
e_state next_state;
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset || sd_scb.dat_stop) begin
|
||||
state <= STATE_IDLE;
|
||||
end else begin
|
||||
state <= next_state;
|
||||
end
|
||||
end
|
||||
|
||||
assign sd_scb.dat_busy = (state != STATE_IDLE);
|
||||
|
||||
logic [10:0] counter;
|
||||
logic [7:0] blocks_remaining;
|
||||
|
||||
always_comb begin
|
||||
next_state = state;
|
||||
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
if (sd_scb.dat_start_read) begin
|
||||
next_state = STATE_RX_WAIT;
|
||||
end
|
||||
if (sd_scb.dat_start_write) begin
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX_WAIT: begin
|
||||
if (sd_clk_rising) begin
|
||||
if (!sd_dat_in[0]) begin
|
||||
next_state = STATE_RX;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX: begin
|
||||
if (sd_clk_rising) begin
|
||||
if (counter == 11'd1041) begin
|
||||
if (blocks_remaining == 8'd0) begin
|
||||
next_state = STATE_IDLE;
|
||||
end else begin
|
||||
next_state = STATE_RX_WAIT;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
|
||||
|
||||
// CRC16 units
|
||||
|
||||
logic crc_reset;
|
||||
logic crc_enable;
|
||||
logic crc_shift;
|
||||
logic [3:0] crc_data;
|
||||
logic [15:0] crc_result [0:3];
|
||||
|
||||
sd_crc_16 sd_crc_16_inst_0 (
|
||||
.clk(clk),
|
||||
.reset(crc_reset),
|
||||
.enable(crc_enable),
|
||||
.shift(crc_shift),
|
||||
.data(crc_data[0]),
|
||||
.result(crc_result[0])
|
||||
);
|
||||
|
||||
sd_crc_16 sd_crc_16_inst_1 (
|
||||
.clk(clk),
|
||||
.reset(crc_reset),
|
||||
.enable(crc_enable),
|
||||
.shift(crc_shift),
|
||||
.data(crc_data[1]),
|
||||
.result(crc_result[1])
|
||||
);
|
||||
|
||||
sd_crc_16 sd_crc_16_inst_2 (
|
||||
.clk(clk),
|
||||
.reset(crc_reset),
|
||||
.enable(crc_enable),
|
||||
.shift(crc_shift),
|
||||
.data(crc_data[2]),
|
||||
.result(crc_result[2])
|
||||
);
|
||||
|
||||
sd_crc_16 sd_crc_16_inst_3 (
|
||||
.clk(clk),
|
||||
.reset(crc_reset),
|
||||
.enable(crc_enable),
|
||||
.shift(crc_shift),
|
||||
.data(crc_data[3]),
|
||||
.result(crc_result[3])
|
||||
);
|
||||
|
||||
|
||||
// Data shifting
|
||||
|
||||
assign crc_data = rx_wdata[3:0];
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
rx_write <= 1'b0;
|
||||
crc_reset <= 1'b0;
|
||||
crc_enable <= 1'b0;
|
||||
crc_shift <= 1'b0;
|
||||
|
||||
if (reset || sd_scb.dat_stop) begin
|
||||
sd_dat_oe_data <= 1'b0;
|
||||
sd_dat_data <= 4'hF;
|
||||
end else begin
|
||||
case (state)
|
||||
STATE_IDLE: begin
|
||||
if (sd_scb.dat_start_read || sd_scb.dat_start_write) begin
|
||||
sd_scb.dat_error <= 1'b0;
|
||||
blocks_remaining <= sd_scb.dat_blocks;
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX_WAIT: begin
|
||||
if (sd_clk_rising) begin
|
||||
if (!sd_dat_in[0]) begin
|
||||
counter <= 8'd1;
|
||||
crc_reset <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
STATE_RX: begin
|
||||
if (sd_clk_rising) begin
|
||||
counter <= counter + 1'd1;
|
||||
rx_wdata <= {rx_wdata[3:0], sd_dat_in};
|
||||
if (counter <= 11'd1024) begin
|
||||
crc_enable <= 1'b1;
|
||||
if (!counter[0]) begin
|
||||
if (rx_full) begin
|
||||
sd_scb.dat_error <= 1'b1;
|
||||
end else begin
|
||||
rx_write <= 1'b1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
crc_shift <= 1'b1;
|
||||
if ({crc_result[3][15], crc_result[2][15], crc_result[1][15], crc_result[0][15]} != sd_dat_in) begin
|
||||
sd_scb.dat_error <= 1'b1;
|
||||
end
|
||||
end
|
||||
if (counter == 11'd1041) begin
|
||||
blocks_remaining <= blocks_remaining - 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
@ -2,12 +2,56 @@ interface sd_scb ();
|
||||
|
||||
logic [1:0] clock_mode;
|
||||
|
||||
logic [5:0] index;
|
||||
logic card_busy;
|
||||
|
||||
logic [10:0] rx_count;
|
||||
logic [10:0] tx_count;
|
||||
|
||||
logic [5:0] cmd_index;
|
||||
logic [31:0] cmd_arg;
|
||||
logic [127:0] cmd_rsp;
|
||||
logic cmd_start;
|
||||
logic cmd_skip_response;
|
||||
logic cmd_reserved_response;
|
||||
logic cmd_long_response;
|
||||
logic cmd_ignore_crc;
|
||||
logic cmd_busy;
|
||||
logic cmd_error;
|
||||
|
||||
logic dat_fifo_flush;
|
||||
logic dat_start_write;
|
||||
logic dat_start_read;
|
||||
logic dat_stop;
|
||||
logic [7:0] dat_blocks;
|
||||
logic dat_busy;
|
||||
logic dat_error;
|
||||
|
||||
modport controller (
|
||||
output clock_mode,
|
||||
|
||||
output index
|
||||
input card_busy,
|
||||
|
||||
input rx_count,
|
||||
input tx_count,
|
||||
|
||||
output cmd_index,
|
||||
output cmd_arg,
|
||||
input cmd_rsp,
|
||||
output cmd_start,
|
||||
output cmd_skip_response,
|
||||
output cmd_reserved_response,
|
||||
output cmd_long_response,
|
||||
output cmd_ignore_crc,
|
||||
input cmd_busy,
|
||||
input cmd_error,
|
||||
|
||||
output dat_fifo_flush,
|
||||
output dat_start_write,
|
||||
output dat_start_read,
|
||||
output dat_stop,
|
||||
output dat_blocks,
|
||||
input dat_busy,
|
||||
input dat_error
|
||||
);
|
||||
|
||||
modport clk (
|
||||
@ -15,7 +59,31 @@ interface sd_scb ();
|
||||
);
|
||||
|
||||
modport cmd (
|
||||
input index
|
||||
input cmd_index,
|
||||
input cmd_arg,
|
||||
output cmd_rsp,
|
||||
input cmd_start,
|
||||
input cmd_skip_response,
|
||||
input cmd_reserved_response,
|
||||
input cmd_long_response,
|
||||
input cmd_ignore_crc,
|
||||
output cmd_busy,
|
||||
output cmd_error
|
||||
);
|
||||
|
||||
modport dat (
|
||||
output card_busy,
|
||||
|
||||
output rx_count,
|
||||
output tx_count,
|
||||
|
||||
input dat_fifo_flush,
|
||||
input dat_start_write,
|
||||
input dat_start_read,
|
||||
input dat_stop,
|
||||
input dat_blocks,
|
||||
output dat_busy,
|
||||
output dat_error
|
||||
);
|
||||
|
||||
endinterface
|
||||
|
@ -11,8 +11,6 @@ module sd_top (
|
||||
inout [3:0] sd_dat
|
||||
);
|
||||
|
||||
assign sd_dat = 4'hZ;
|
||||
|
||||
logic sd_clk_rising;
|
||||
logic sd_clk_falling;
|
||||
|
||||
@ -40,4 +38,18 @@ module sd_top (
|
||||
.sd_cmd(sd_cmd)
|
||||
);
|
||||
|
||||
sd_dat sd_dat_inst (
|
||||
.clk(clk),
|
||||
.reset(reset),
|
||||
|
||||
.sd_scb(sd_scb),
|
||||
|
||||
.fifo_bus(fifo_bus),
|
||||
|
||||
.sd_clk_rising(sd_clk_rising),
|
||||
.sd_clk_falling(sd_clk_falling),
|
||||
|
||||
.sd_dat(sd_dat)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
@ -4,19 +4,25 @@ interface usb_scb ();
|
||||
logic reset_pending;
|
||||
logic reset_ack;
|
||||
logic write_buffer_flush;
|
||||
logic [10:0] rx_count;
|
||||
logic [10:0] tx_count;
|
||||
|
||||
modport controller (
|
||||
output fifo_flush,
|
||||
input reset_pending,
|
||||
output reset_ack,
|
||||
output write_buffer_flush
|
||||
output write_buffer_flush,
|
||||
input rx_count,
|
||||
input tx_count
|
||||
);
|
||||
|
||||
modport usb (
|
||||
input fifo_flush,
|
||||
output reset_pending,
|
||||
input reset_ack,
|
||||
input write_buffer_flush
|
||||
input write_buffer_flush,
|
||||
output rx_count,
|
||||
output tx_count
|
||||
);
|
||||
|
||||
endinterface
|
||||
@ -59,7 +65,9 @@ module usb_ft1248 (
|
||||
.full(rx_full),
|
||||
.almost_full(rx_almost_full),
|
||||
.write(rx_write),
|
||||
.wdata(rx_wdata)
|
||||
.wdata(rx_wdata),
|
||||
|
||||
.count(usb_scb.rx_count)
|
||||
);
|
||||
|
||||
fifo_8kb fifo_8kb_tx_inst (
|
||||
@ -74,7 +82,9 @@ module usb_ft1248 (
|
||||
.full(fifo_bus.tx_full),
|
||||
.almost_full(fifo_bus.tx_almost_full),
|
||||
.write(fifo_bus.tx_write),
|
||||
.wdata(fifo_bus.tx_wdata)
|
||||
.wdata(fifo_bus.tx_wdata),
|
||||
|
||||
.count(usb_scb.tx_count)
|
||||
);
|
||||
|
||||
logic [1:0] usb_pwrsav_ff;
|
||||
|
18
fw/rtl/vendor/lcmxo2/fifo_8kb.sv
vendored
18
fw/rtl/vendor/lcmxo2/fifo_8kb.sv
vendored
@ -10,7 +10,9 @@ module fifo_8kb (
|
||||
output full,
|
||||
output almost_full,
|
||||
input write,
|
||||
input [7:0] wdata
|
||||
input [7:0] wdata,
|
||||
|
||||
output logic [10:0] count
|
||||
);
|
||||
|
||||
fifo_8kb_lattice_generated fifo_8kb_lattice_generated_inst (
|
||||
@ -28,4 +30,18 @@ module fifo_8kb (
|
||||
.AlmostFull(almost_full)
|
||||
);
|
||||
|
||||
always_ff @(posedge clk) begin
|
||||
if (reset) begin
|
||||
count <= 11'd0;
|
||||
end else begin
|
||||
if (write && read) begin
|
||||
count <= count;
|
||||
end else if (write) begin
|
||||
count <= count + 1'd1;
|
||||
end else if (read) begin
|
||||
count <= count - 1'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
@ -1,36 +1,60 @@
|
||||
#include "ff.h"
|
||||
#include "diskio.h"
|
||||
#include "../io.h"
|
||||
#include "../sc64.h"
|
||||
#include "../error.h"
|
||||
|
||||
|
||||
// DSTATUS status[__DRIVE_COUNT] = { STA_NOINIT, STA_NOINIT };
|
||||
DSTATUS status = STA_NOINIT;
|
||||
|
||||
|
||||
DSTATUS disk_status (BYTE pdrv) {
|
||||
// if (pdrv >= __DRIVE_COUNT) {
|
||||
if (pdrv > 0) {
|
||||
return STA_NODISK;
|
||||
// }
|
||||
// return status[pdrv];
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
DSTATUS disk_initialize (BYTE pdrv) {
|
||||
// if (pdrv >= __DRIVE_COUNT) {
|
||||
if (pdrv > 0) {
|
||||
return STA_NODISK;
|
||||
// }
|
||||
// if (!sc64_storage_init((drive_id_t) (pdrv))) {
|
||||
// status[pdrv] &= ~(STA_NOINIT);
|
||||
// }
|
||||
// return status[pdrv];
|
||||
}
|
||||
if (!sc64_sd_card_initialize()) {
|
||||
status &= ~(STA_NOINIT);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
DRESULT disk_read (BYTE pdrv, BYTE *buff, LBA_t sector, UINT count) {
|
||||
// if (pdrv >= __DRIVE_COUNT) {
|
||||
// return RES_PARERR;
|
||||
// }
|
||||
// if (sc64_storage_read((drive_id_t) (pdrv), buff, sector, count)) {
|
||||
return RES_ERROR;
|
||||
// }
|
||||
// return RES_OK;
|
||||
if (pdrv > 0) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
uint32_t physical_address = ((uint32_t) (buff)) & 0x1FFFFFFF;
|
||||
uint32_t block = 0;
|
||||
while (count > 0) {
|
||||
if (physical_address < (8 * 1024 * 1024)) {
|
||||
block = ((count > 16) ? 16 : count);
|
||||
if (sc64_sd_read_sectors(sector, 0x1FFE0000UL, block * 512)) {
|
||||
return RES_ERROR;
|
||||
}
|
||||
for (uint32_t i = 0; i < (block * 512); i += 4) {
|
||||
uint32_t data = pi_io_read((uint32_t *) (0x1FFE0000UL + i));
|
||||
uint8_t *ptr = (uint8_t *) (&data);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
*buff++ = *ptr++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
block = ((count > 256) ? 256 : count);
|
||||
if (sc64_sd_read_sectors(sector, physical_address, block * 512)) {
|
||||
error_display("Kurwa 0x%08X, 0x%08X\n", physical_address, block);
|
||||
return RES_ERROR;
|
||||
}
|
||||
physical_address += (block * 512);
|
||||
}
|
||||
count -= block;
|
||||
sector += block;
|
||||
}
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
#if !FF_FS_READONLY
|
||||
|
@ -246,6 +246,7 @@ typedef struct {
|
||||
#define SC64_REGS_BASE (0x1FFF0000UL)
|
||||
#define SC64_REGS ((sc64_regs_t *) SC64_REGS_BASE)
|
||||
|
||||
#define SC64_SR_IRQ_PENDING (1 << 29)
|
||||
#define SC64_SR_CMD_ERROR (1 << 30)
|
||||
#define SC64_SR_CPU_BUSY (1 << 31)
|
||||
|
||||
|
@ -15,6 +15,10 @@ typedef enum {
|
||||
SC64_CMD_USB_WRITE = 'M',
|
||||
SC64_CMD_USB_READ_STATUS = 'u',
|
||||
SC64_CMD_USB_READ = 'm',
|
||||
SC64_CMD_SD_CARD_INITIALIZE = 'i',
|
||||
SC64_CMD_SD_SECTOR_SET = 'I',
|
||||
SC64_CMD_SD_READ = 's',
|
||||
SC64_CMD_SD_WRITE = 'S',
|
||||
} cmd_id_t;
|
||||
|
||||
|
||||
@ -136,3 +140,19 @@ bool sc64_usb_read (uint32_t *address, uint32_t length) {
|
||||
} while(result[0] & (1 << 24));
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sc64_sd_card_initialize (void) {
|
||||
if (sc64_execute_cmd(SC64_CMD_SD_CARD_INITIALIZE, NULL, NULL)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sc64_sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length) {
|
||||
uint32_t sector_set_args[2] = { starting_sector, 0 };
|
||||
uint32_t read_args[2] = { address, length };
|
||||
if (sc64_execute_cmd(SC64_CMD_SD_SECTOR_SET, sector_set_args, NULL)) {
|
||||
return true;
|
||||
}
|
||||
return sc64_execute_cmd(SC64_CMD_SD_READ, read_args, NULL);
|
||||
}
|
||||
|
@ -104,6 +104,8 @@ bool sc64_usb_write_ready (void);
|
||||
bool sc64_usb_write (uint32_t *address, uint32_t length);
|
||||
bool sc64_usb_read_ready (uint8_t *type, uint32_t *length);
|
||||
bool sc64_usb_read (uint32_t *address, uint32_t length);
|
||||
bool sc64_sd_card_initialize (void);
|
||||
bool sc64_sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -61,6 +61,8 @@ void storage_run_menu (storage_backend_t storage_backend) {
|
||||
FF_CHECK(f_mount(&fs, path, 1), "Couldn't mount drive");
|
||||
FF_CHECK(f_chdrive(path), "Couldn't chdrive");
|
||||
FF_CHECK(f_open(&fil, "sc64menu.n64", FA_READ), "Couldn't open menu file");
|
||||
FF_CHECK(f_lseek(&fil, 0), "debug 1");
|
||||
FF_CHECK(f_read(&fil, (void *) (0x10000000UL), f_size(&fil), &br), "debug 2");
|
||||
FF_CHECK(f_lseek(&fil, ROM_ENTRY_OFFSET), "Couldn't seek to entry point offset");
|
||||
FF_CHECK(f_read(&fil, &menu, sizeof(menu), &br), "Couldn't read entry point");
|
||||
FF_CHECK(f_lseek(&fil, ROM_CODE_OFFSET), "Couldn't seek to code start offset");
|
||||
|
@ -17,6 +17,7 @@ SRC_FILES = \
|
||||
isv.c \
|
||||
lcmxo2.c \
|
||||
rtc.c \
|
||||
sd.c \
|
||||
task.c \
|
||||
update.c \
|
||||
usb.c
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#define CIC_STACK_SIZE (256)
|
||||
#define RTC_STACK_SIZE (256)
|
||||
#define GVR_STACK_SIZE (1536)
|
||||
#define GVR_STACK_SIZE (2048)
|
||||
|
||||
|
||||
uint8_t cic_stack[CIC_STACK_SIZE] __attribute__((aligned(8)));
|
||||
|
@ -39,9 +39,9 @@ void button_init (void) {
|
||||
|
||||
void button_process (void) {
|
||||
usb_tx_info_t packet_info;
|
||||
uint32_t status = fpga_reg_get(REG_STATUS);
|
||||
uint32_t status = fpga_reg_get(REG_CFG_SCR);
|
||||
p.shift <<= 1;
|
||||
if (status & STATUS_BUTTON) {
|
||||
if (status & CFG_SCR_BUTTON_STATE) {
|
||||
p.shift |= (1 << 0);
|
||||
}
|
||||
if (!p.state && p.shift == 0xFFFFFFFFUL) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "fpga.h"
|
||||
#include "isv.h"
|
||||
#include "rtc.h"
|
||||
#include "sd.h"
|
||||
#include "usb.h"
|
||||
|
||||
|
||||
@ -66,6 +67,7 @@ typedef enum {
|
||||
CFG_ERROR_BAD_ADDRESS = 1,
|
||||
CFG_ERROR_BAD_CONFIG_ID = 2,
|
||||
CFG_ERROR_TIMEOUT = 3,
|
||||
CFG_ERROR_SD = 4,
|
||||
CFG_ERROR_UNKNOWN_CMD = -1,
|
||||
} cfg_error_t;
|
||||
|
||||
@ -76,6 +78,7 @@ struct process {
|
||||
cic_seed_t cic_seed;
|
||||
tv_type_t tv_type;
|
||||
bool usb_output_ready;
|
||||
uint32_t sd_card_sector;
|
||||
};
|
||||
|
||||
|
||||
@ -317,13 +320,16 @@ void cfg_init (void) {
|
||||
}
|
||||
|
||||
void cfg_process (void) {
|
||||
uint32_t reg;
|
||||
uint32_t args[2];
|
||||
usb_tx_info_t packet_info;
|
||||
|
||||
if (fpga_reg_get(REG_STATUS) & STATUS_CFG_PENDING) {
|
||||
reg = fpga_reg_get(REG_CFG_CMD);
|
||||
|
||||
if (reg & CFG_CMD_PENDING) {
|
||||
args[0] = fpga_reg_get(REG_CFG_DATA_0);
|
||||
args[1] = fpga_reg_get(REG_CFG_DATA_1);
|
||||
char cmd = (char) fpga_reg_get(REG_CFG_CMD);
|
||||
char cmd = (char) ((reg & CFG_CMD_MASK) >> CFG_CMD_BIT);
|
||||
|
||||
switch (cmd) {
|
||||
case 'v':
|
||||
@ -386,6 +392,26 @@ void cfg_process (void) {
|
||||
args[0] = p.usb_output_ready ? 1 : 0;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
if (sd_card_initialize()) {
|
||||
cfg_set_error(CFG_ERROR_SD);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
p.sd_card_sector = args[0];
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (cfg_translate_address(args)) {
|
||||
cfg_set_error(CFG_ERROR_BAD_ADDRESS);
|
||||
return;
|
||||
}
|
||||
if (sd_read_sectors(p.sd_card_sector, args[0], args[1])) {
|
||||
cfg_set_error(CFG_ERROR_SD);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cfg_set_error(CFG_ERROR_UNKNOWN_CMD);
|
||||
return;
|
||||
|
@ -18,7 +18,6 @@ typedef enum {
|
||||
} fpga_cmd_t;
|
||||
|
||||
typedef enum {
|
||||
REG_STATUS,
|
||||
REG_MEM_ADDRESS,
|
||||
REG_MEM_SCR,
|
||||
REG_USB_SCR,
|
||||
@ -69,16 +68,16 @@ typedef enum {
|
||||
#define MEM_SCR_BUSY (1 << 3)
|
||||
#define MEM_SCR_LENGTH_BIT (4)
|
||||
|
||||
#define STATUS_BUTTON (1 << 0)
|
||||
#define STATUS_SD_INSERTED (1 << 1)
|
||||
#define STATUS_CFG_PENDING (1 << 2)
|
||||
|
||||
#define USB_SCR_FIFO_FLUSH (1 << 0)
|
||||
#define USB_SCR_RXNE (1 << 1)
|
||||
#define USB_SCR_TXE (1 << 2)
|
||||
#define USB_SCR_RESET_PENDING (1 << 3)
|
||||
#define USB_SCR_RESET_ACK (1 << 4)
|
||||
#define USB_SCR_WRITE_FLUSH (1 << 5)
|
||||
#define USB_SCR_RX_COUNT_BIT (6)
|
||||
#define USB_SCR_RX_COUNT_MASK (0x7FF << USB_SCR_RX_COUNT_BIT)
|
||||
#define USB_SCR_TX_COUNT_BIT (17)
|
||||
#define USB_SCR_TX_COUNT_MASK (0x7FF << USB_SCR_TX_COUNT_BIT)
|
||||
|
||||
#define DMA_SCR_START (1 << 0)
|
||||
#define DMA_SCR_STOP (1 << 1)
|
||||
@ -97,10 +96,14 @@ typedef enum {
|
||||
#define CFG_SCR_EEPROM_ENABLED (1 << 9)
|
||||
#define CFG_SCR_EEPROM_16K (1 << 10)
|
||||
#define CFG_SCR_ROM_EXTENDED_ENABLED (1 << 11)
|
||||
#define CFG_SCR_BUTTON_STATE (1 << 31)
|
||||
|
||||
#define CFG_CMD_DONE (1 << 0)
|
||||
#define CFG_CMD_ERROR (1 << 1)
|
||||
#define CFG_CMD_IRQ (1 << 2)
|
||||
#define CFG_CMD_BIT (0)
|
||||
#define CFG_CMD_MASK (0xFF << CFG_CMD_BIT)
|
||||
#define CFG_CMD_PENDING (1 << 8)
|
||||
#define CFG_CMD_DONE (1 << 9)
|
||||
#define CFG_CMD_ERROR (1 << 10)
|
||||
#define CFG_CMD_IRQ (1 << 11)
|
||||
|
||||
#define FLASHRAM_SCR_DONE (1 << 0)
|
||||
#define FLASHRAM_SCR_PENDING (1 << 1)
|
||||
@ -120,6 +123,30 @@ typedef enum {
|
||||
#define SD_SCR_CLOCK_MODE_400KHZ (1 << 0)
|
||||
#define SD_SCR_CLOCK_MODE_25MHZ (2 << 0)
|
||||
#define SD_SCR_CLOCK_MODE_50MHZ (3 << 0)
|
||||
#define SD_SCR_CMD_BUSY (1 << 2)
|
||||
#define SD_SCR_CMD_ERROR (1 << 3)
|
||||
#define SD_SCR_CARD_BUSY (1 << 4)
|
||||
#define SD_SCR_CARD_INSERTED (1 << 5)
|
||||
#define SD_SCR_RX_COUNT_BIT (6)
|
||||
#define SD_SCR_RX_COUNT_MASK (0x7FF << SD_SCR_RX_COUNT_BIT)
|
||||
#define SD_SCR_TX_COUNT_BIT (17)
|
||||
#define SD_SCR_TX_COUNT_MASK (0x7FF << SD_SCR_TX_COUNT_BIT)
|
||||
|
||||
#define SD_CMD_INDEX_BIT (0)
|
||||
#define SD_CMD_INDEX_MASK (0x3F)
|
||||
#define SD_CMD_SKIP_RESPONSE (1 << 6)
|
||||
#define SD_CMD_RESERVED_RESPONSE (1 << 7)
|
||||
#define SD_CMD_LONG_RESPONSE (1 << 8)
|
||||
#define SD_CMD_IGNORE_CRC (1 << 9)
|
||||
|
||||
#define SD_DAT_FIFO_FLUSH (1 << 0)
|
||||
#define SD_DAT_START_WRITE (1 << 1)
|
||||
#define SD_DAT_START_READ (1 << 2)
|
||||
#define SD_DAT_STOP (1 << 3)
|
||||
#define SD_DAT_BLOCKS_BIT (4)
|
||||
#define SD_DAT_BLOCKS_MASK (0xFF << SD_DAT_BLOCKS_BIT)
|
||||
#define SD_DAT_BUSY (1 << 12)
|
||||
#define SD_DAT_ERROR (1 << 13)
|
||||
|
||||
#define DD_SCR_HARD_RESET (1 << 0)
|
||||
#define DD_SCR_HARD_RESET_CLEAR (1 << 1)
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "fpga.h"
|
||||
#include "isv.h"
|
||||
#include "rtc.h"
|
||||
#include "sd.h"
|
||||
#include "usb.h"
|
||||
|
||||
|
||||
@ -16,6 +17,7 @@ void gvr_task (void) {
|
||||
dd_init();
|
||||
flashram_init();
|
||||
isv_init();
|
||||
sd_init();
|
||||
usb_init();
|
||||
|
||||
while (1) {
|
||||
@ -25,6 +27,7 @@ void gvr_task (void) {
|
||||
flashram_process();
|
||||
isv_process();
|
||||
rtc_process();
|
||||
sd_process();
|
||||
usb_process();
|
||||
}
|
||||
}
|
||||
|
285
sw/controller/src/sd.c
Normal file
285
sw/controller/src/sd.c
Normal file
@ -0,0 +1,285 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "sd.h"
|
||||
#include "fpga.h"
|
||||
#include "debug.h"
|
||||
#include "hw.h"
|
||||
|
||||
|
||||
#define CMD8_ARG_SUPPLY_VOLTAGE_27_36_V (1 << 8)
|
||||
#define CMD8_ARG_CHECK_PATTERN (0xAA << 0)
|
||||
|
||||
#define ACMD41_ARG_HCS (1 << 30)
|
||||
|
||||
#define R3_CCS (1 << 30)
|
||||
#define R3_BUSY (1 << 31)
|
||||
|
||||
#define R7_SUPPLY_VOLTAGE_27_36_V (1 << 8)
|
||||
#define R7_CHECK_PATTERN (0xAA << 0)
|
||||
|
||||
|
||||
typedef enum {
|
||||
CLOCK_STOP,
|
||||
CLOCK_400KHZ,
|
||||
CLOCK_25MHZ,
|
||||
CLOCK_50MHZ,
|
||||
} sd_clock_t;
|
||||
|
||||
typedef enum {
|
||||
RSP_NONE,
|
||||
RSP_R1,
|
||||
RSP_R1b,
|
||||
RSP_R2,
|
||||
RSP_R3,
|
||||
RSP_R6,
|
||||
RSP_R7,
|
||||
} rsp_type_t;
|
||||
|
||||
|
||||
static bool sd_card_initialized;
|
||||
static bool sd_card_type_block;
|
||||
static uint32_t sd_rca = 0;
|
||||
static volatile bool timeout = false;
|
||||
|
||||
|
||||
static void sd_trigger_timeout (void) {
|
||||
timeout = true;
|
||||
}
|
||||
|
||||
static void sd_set_clock (sd_clock_t mode) {
|
||||
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_OFF);
|
||||
|
||||
switch (mode) {
|
||||
case CLOCK_400KHZ:
|
||||
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_400KHZ);
|
||||
break;
|
||||
case CLOCK_25MHZ:
|
||||
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_25MHZ);
|
||||
break;
|
||||
case CLOCK_50MHZ:
|
||||
fpga_reg_set(REG_SD_SCR, SD_SCR_CLOCK_MODE_50MHZ);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool sd_cmd (uint8_t cmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
|
||||
uint32_t scr;
|
||||
uint32_t cmd_data;
|
||||
|
||||
cmd_data = ((cmd << SD_CMD_INDEX_BIT) & SD_CMD_INDEX_MASK);
|
||||
switch (rsp_type) {
|
||||
case RSP_NONE:
|
||||
cmd_data |= SD_CMD_SKIP_RESPONSE;
|
||||
break;
|
||||
case RSP_R2:
|
||||
cmd_data |= (SD_CMD_LONG_RESPONSE | SD_CMD_RESERVED_RESPONSE);
|
||||
break;
|
||||
case RSP_R3:
|
||||
cmd_data |= (SD_CMD_IGNORE_CRC | SD_CMD_RESERVED_RESPONSE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
fpga_reg_set(REG_SD_ARG, arg);
|
||||
fpga_reg_set(REG_SD_CMD, cmd_data);
|
||||
|
||||
do {
|
||||
scr = fpga_reg_get(REG_SD_SCR);
|
||||
} while (scr & SD_SCR_CMD_BUSY);
|
||||
|
||||
if (rsp != NULL) {
|
||||
fpga_reg_t rsp_regs[4] = {
|
||||
REG_SD_RSP_3,
|
||||
REG_SD_RSP_2,
|
||||
REG_SD_RSP_1,
|
||||
REG_SD_RSP_0
|
||||
};
|
||||
bool rsp_long = rsp_type & SD_CMD_LONG_RESPONSE;
|
||||
fpga_reg_t rsp_reg = (rsp_long ? 0 : (sizeof(rsp_regs) - 1));
|
||||
uint8_t *rsp_8 = (uint8_t *) (rsp);
|
||||
while (rsp_reg < sizeof(rsp_regs)) {
|
||||
uint32_t rsp_data = fpga_reg_get(rsp_regs[rsp_reg++]);
|
||||
uint8_t *rsp_data_8 = (uint8_t *) (&rsp_data);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
*rsp_8++ = *rsp_data_8++;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (rsp_type == RSP_R1b) {
|
||||
do {
|
||||
scr = fpga_reg_get(REG_SD_SCR);
|
||||
} while (scr & SD_SCR_CARD_BUSY);
|
||||
}
|
||||
|
||||
return (scr & SD_SCR_CMD_ERROR);
|
||||
}
|
||||
|
||||
static bool sd_acmd (uint8_t acmd, uint32_t arg, rsp_type_t rsp_type, void *rsp) {
|
||||
if (sd_cmd(55, sd_rca, RSP_R1, NULL)) {
|
||||
return true;
|
||||
}
|
||||
if (sd_cmd(acmd, arg, rsp_type, rsp)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length) {
|
||||
if (!sd_card_initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((length == 0) || (length % 512 != 0) || (length > (256 * 512))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
do {
|
||||
uint32_t blocks = (length / 512);
|
||||
|
||||
timeout = false;
|
||||
hw_tim_setup(TIM_ID_GVR, 5000, sd_trigger_timeout);
|
||||
|
||||
if (!sd_card_type_block) {
|
||||
starting_sector *= 512;
|
||||
}
|
||||
|
||||
// fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP);
|
||||
// fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
|
||||
|
||||
fpga_reg_set(REG_SD_DMA_ADDRESS, address);
|
||||
fpga_reg_set(REG_SD_DMA_LENGTH, length);
|
||||
fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_DIRECTION | DMA_SCR_START);
|
||||
|
||||
fpga_reg_set(REG_SD_DAT, (((blocks - 1) << SD_DAT_BLOCKS_BIT) | SD_DAT_START_READ | SD_DAT_FIFO_FLUSH));
|
||||
|
||||
if (sd_cmd(23, blocks, RSP_R1, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sd_cmd(18, starting_sector, RSP_R1, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
|
||||
while (!timeout) {
|
||||
uint32_t sd_scr = fpga_reg_get(REG_SD_SCR);
|
||||
if (!(sd_scr & SD_SCR_CARD_INSERTED)) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
uint32_t sd_dat = fpga_reg_get(REG_SD_DAT);
|
||||
uint32_t sd_dma_scr = fpga_reg_get(REG_SD_DMA_SCR);
|
||||
if (sd_dat & SD_DAT_ERROR) {
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
if ((!(sd_dma_scr & DMA_SCR_BUSY)) && (!(sd_dat & SD_DAT_BUSY))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
break;
|
||||
}
|
||||
|
||||
hw_tim_stop(TIM_ID_GVR);
|
||||
|
||||
if (error) {
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
} while (0);
|
||||
|
||||
fpga_reg_set(REG_SD_DMA_SCR, DMA_SCR_STOP);
|
||||
fpga_reg_set(REG_SD_DAT, SD_DAT_STOP | SD_DAT_FIFO_FLUSH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sd_card_initialize (void) {
|
||||
bool error;
|
||||
uint32_t arg;
|
||||
uint32_t rsp;
|
||||
bool version_2_or_later = false;
|
||||
|
||||
if (sd_card_initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
sd_set_clock(CLOCK_400KHZ);
|
||||
|
||||
do {
|
||||
sd_cmd(0, 0, RSP_NONE, NULL);
|
||||
|
||||
arg = (CMD8_ARG_SUPPLY_VOLTAGE_27_36_V | CMD8_ARG_CHECK_PATTERN);
|
||||
if (!sd_cmd(8, arg, RSP_R7, &rsp)) {
|
||||
version_2_or_later = true;
|
||||
if (rsp != (R7_SUPPLY_VOLTAGE_27_36_V | R7_CHECK_PATTERN)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
arg = ((version_2_or_later ? ACMD41_ARG_HCS : 0) | 0x00FF8000);
|
||||
for (int i = 0; i < 4000; i++) {
|
||||
error = sd_acmd(41, arg, RSP_R3, &rsp);
|
||||
if (error || (rsp & R3_BUSY)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (error || ((rsp & 0x00FF8000) == 0)) {
|
||||
break;
|
||||
}
|
||||
sd_card_type_block = (rsp & R3_CCS);
|
||||
|
||||
if (sd_cmd(2, 0, RSP_R2, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sd_cmd(3, 0, RSP_R6, &rsp)) {
|
||||
break;
|
||||
}
|
||||
sd_rca = rsp & 0xFFFF0000;
|
||||
|
||||
if (sd_cmd(7, sd_rca, RSP_R1b, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (sd_acmd(6, 2, RSP_R1, NULL)) {
|
||||
break;
|
||||
}
|
||||
|
||||
sd_set_clock(CLOCK_50MHZ);
|
||||
|
||||
sd_card_initialized = true;
|
||||
|
||||
return false;
|
||||
} while (0);
|
||||
|
||||
sd_rca = 0;
|
||||
sd_cmd(0, 0, RSP_NONE, NULL);
|
||||
sd_set_clock(CLOCK_STOP);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sd_init (void) {
|
||||
sd_card_initialized = false;
|
||||
sd_set_clock(CLOCK_STOP);
|
||||
}
|
||||
|
||||
void sd_process (void) {
|
||||
if (!(fpga_reg_get(REG_SD_SCR) & SD_SCR_CARD_INSERTED)) {
|
||||
if (sd_card_initialized) {
|
||||
sd_card_initialized = false;
|
||||
sd_rca = 0;
|
||||
sd_set_clock(CLOCK_STOP);
|
||||
}
|
||||
}
|
||||
}
|
14
sw/controller/src/sd.h
Normal file
14
sw/controller/src/sd.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef SD_H__
|
||||
#define SD_H__
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
bool sd_read_sectors (uint32_t starting_sector, uint32_t address, uint32_t length);
|
||||
bool sd_card_initialize (void);
|
||||
void sd_init (void);
|
||||
void sd_process (void);
|
||||
|
||||
|
||||
#endif
|
11
sw/pc/.gitignore
vendored
11
sw/pc/.gitignore
vendored
@ -1,18 +1,9 @@
|
||||
**/__pycache__
|
||||
/backup
|
||||
/roms
|
||||
/saves
|
||||
*.a
|
||||
*.bak
|
||||
*.bin
|
||||
*.dat
|
||||
*.data
|
||||
*.dll
|
||||
*.dylib
|
||||
*.eep
|
||||
*.fla
|
||||
*.img
|
||||
*.n64
|
||||
*.srm
|
||||
*.upd
|
||||
*.v64
|
||||
*.z64
|
||||
|
@ -433,6 +433,11 @@ class SC64:
|
||||
address = self.__Address.EEPROM
|
||||
return self.__read_memory(address, length)
|
||||
|
||||
def upload_bootloader(self, data: bytes) -> None:
|
||||
if (len(data) > self.__Length.BOOTLOADER):
|
||||
raise ValueError('Bootloader size too big')
|
||||
self.__program_flash(self.__Address.BOOTLOADER, data)
|
||||
|
||||
def set_rtc(self, t: datetime) -> None:
|
||||
to_bcd = lambda v: ((int((v / 10) % 10) << 4) | int(int(v) % 10))
|
||||
data = bytes([
|
||||
@ -645,6 +650,7 @@ if __name__ == '__main__':
|
||||
parser.add_argument('--isv', action='store_true', help='enable IS-Viewer64 support')
|
||||
parser.add_argument('--debug', action='store_true', help='run debug loop (required for 64DD and IS-Viewer64)')
|
||||
parser.add_argument('--download-memory', help='download whole memory space and write it to specified file')
|
||||
parser.add_argument('--bootloader', help='bootloader')
|
||||
|
||||
if (len(sys.argv) <= 1):
|
||||
parser.print_help()
|
||||
@ -667,6 +673,12 @@ if __name__ == '__main__':
|
||||
status_callback = lambda status: print(f'{status} ', end='', flush=True)
|
||||
sc64.update_firmware(f.read(), status_callback)
|
||||
print('done')
|
||||
|
||||
if (args.bootloader):
|
||||
with open(args.bootloader, 'rb+') as f:
|
||||
print('Uploading Bootloader... ', end='', flush=True)
|
||||
sc64.upload_bootloader(f.read())
|
||||
print('done')
|
||||
|
||||
if (args.reset_state):
|
||||
sc64.reset_state()
|
||||
|
Loading…
Reference in New Issue
Block a user