preliminary sd card support

This commit is contained in:
Polprzewodnikowy 2022-09-08 23:36:46 +02:00
parent 2cc618b268
commit 321f3d37aa
28 changed files with 1161 additions and 72 deletions

View File

@ -1,6 +1,7 @@
.recovery
*.dir/
*.ccl
*.dmp
*.html
*.ini
*.rva

View File

@ -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">

View File

@ -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

View File

@ -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 &&

View File

@ -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];

View File

@ -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 ();

View File

@ -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
View 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
View 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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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

View File

@ -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");

View File

@ -17,6 +17,7 @@ SRC_FILES = \
isv.c \
lcmxo2.c \
rtc.c \
sd.c \
task.c \
update.c \
usb.c

View File

@ -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)));

View File

@ -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) {

View File

@ -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;

View File

@ -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)

View File

@ -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
View 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
View 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
View File

@ -1,18 +1,9 @@
**/__pycache__
/backup
/roms
/saves
*.a
*.bak
*.bin
*.dat
*.data
*.dll
*.dylib
*.eep
*.fla
*.img
*.n64
*.srm
*.upd
*.v64
*.z64

View File

@ -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()
@ -668,6 +674,12 @@ if __name__ == '__main__':
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()
print('SC64 internal state reset')