Merge branch 'sdcard' into 'master'

Add SD Card Controller

See merge request bslathi19/super6502!11
This commit is contained in:
Byron Lathi
2022-04-11 22:38:48 +00:00
16 changed files with 843 additions and 78 deletions

View File

@@ -45,3 +45,17 @@ test_mm:
script:
- cd hw/fpga/simulation/modelsim/
- vsim -do "do mm_testbench.do"
test_crc7:
stage: test
image: bslathi19/modelsim_18.1:lite
script:
- cd hw/fpga/simulation/modelsim/
- vsim -do "do crc7_testbench.do"
test_sd_cmd:
stage: test
image: bslathi19/modelsim_18.1:lite
script:
- cd hw/fpga/simulation/modelsim/
- vsim -do "sd_cmd_testbench.do"

View File

@@ -6,8 +6,9 @@ module addr_decode(
output logic uart_cs,
output logic irq_cs,
output logic board_io_cs,
output logic mm_cs1,
output logic mm_cs2
output logic mm_cs1,
output logic mm_cs2,
output logic sd_cs
);
assign rom_cs = addr >= 24'h008000 && addr < 24'h010000;
@@ -17,6 +18,7 @@ assign hex_cs = addr >= 24'h007ff0 && addr < 24'h007ff4;
assign uart_cs = addr >= 24'h007ff4 && addr < 24'h007ff6;
assign board_io_cs = addr == 24'h007ff6;
assign mm_cs2 = addr == 24'h007ff7;
assign sd_cs = addr >= 24'h007ff8 && addr < 24'h007ffe;
assign irq_cs = addr == 24'h007fff;
endmodule

106
hw/fpga/crc7.sv Normal file
View File

@@ -0,0 +1,106 @@
module crc7 #(parameter POLYNOMIAL = 8'h89)
(
input clk,
input rst,
input load,
input [39:0] data_in,
output logic [6:0] crc_out,
output logic valid
);
logic [46:0] data;
logic [46:0] next_data;
logic [46:0] polyshift;
typedef enum bit [1:0] {IDLE, WORKING, VALID} macro_t;
struct packed {
macro_t macro;
logic [5:0] count;
} state, next_state;
always_ff @(posedge clk) begin
if (rst) begin
polyshift <= {POLYNOMIAL, 39'b0}; //start all the way at the left
data <= '0;
state.macro <= IDLE;
state.count <= '0;
end else begin
if (load) begin
data <= {data_in, 7'b0};
end else begin
data <= next_data;
end
state <= next_state;
if (state.macro == WORKING) begin
polyshift <= polyshift >> 1;
end
if (state.macro == VALID) begin
polyshift <= {POLYNOMIAL, 39'b0};
end
end
end
always_comb begin
next_state = state;
case (state.macro)
IDLE: begin
if (load) begin
next_state.macro = WORKING;
next_state.count = '0;
end
end
WORKING: begin
if (state.count < 39) begin
next_state.count = state.count + 6'b1;
end else begin
next_state.macro = VALID;
next_state.count = '0;
end
end
VALID: begin // Same as IDLE, but IDLE is just for reset.
if (load) begin
next_state.macro = WORKING;
next_state.count = '0;
end
end
default:;
endcase
end
always_comb begin
valid = 0;
next_data = '0;
crc_out = '0;
case (state.macro)
IDLE: begin
valid = 0;
end
WORKING: begin
if (data[6'd46 - state.count]) begin
next_data = data ^ polyshift;
end else begin
next_data = data;
end
end
VALID: begin
valid = ~load;
next_data = data;
crc_out = data[6:0];
end
default:;
endcase
end
endmodule

View File

@@ -0,0 +1,65 @@
module testbench();
timeunit 10ns;
timeprecision 1ns;
logic clk;
logic rst;
logic load;
logic [39:0] data_in;
logic [6:0] crc_out;
logic valid;
crc7 dut(.*);
always #1 clk = clk === 1'b0;
task create_sd_packet(logic [5:0] cmd, logic [31:0] data, output logic [47:0] _packet);
@(posedge clk);
data_in <= {1'b0, 1'b1, cmd, data};
load <= '1;
@(posedge clk);
load <= '0;
while (~valid) begin
//$display("Working %b", dut.data);
@(posedge clk);
end
_packet = {1'b0, 1'b1, cmd, data, crc_out, 1'b1};
endtask
logic [47:0] packet;
initial begin
rst <= '1;
repeat(5) @(posedge clk);
rst <= '0;
create_sd_packet(6'h0, 32'h0, packet);
$display("Result: %x", packet);
assert(packet == 48'h400000000095) else
$error("Bad crc7. Got %x expected %x", packet, 48'h400000000095);
create_sd_packet(6'd8, 32'h1aa, packet);
$display("Result: %x", packet);
assert(packet == 48'h48000001aa87) else
$error("Bad crc7. Got %x expected %x", packet, 48'h48000001aa87);
create_sd_packet(6'd55, 32'h0, packet);
$display("Result: %x", packet);
assert(packet == 48'h770000000065) else
$error("Bad crc7. Got %x expected %x", packet, 48'h770000000065);
create_sd_packet(6'd41, 32'h40180000, packet);
$display("Result: %x", packet);
assert(packet == 48'h694018000019) else
$error("Bad crc7. Got %x expected %x", packet, 48'h694018000019);
$finish();
end
endmodule

View File

@@ -13,8 +13,9 @@ logic uart_cs;
logic irq_cs;
logic mm_cs2;
logic mm_cs1;
logic sd_cs;
int cs_count = sdram_cs + rom_cs + hex_cs + uart_cs + board_io_cs + mm_cs2 + mm_cs1;
int cs_count = sdram_cs + rom_cs + hex_cs + uart_cs + board_io_cs + mm_cs2 + mm_cs1 + sd_cs;
addr_decode dut(.*);
@@ -56,6 +57,11 @@ initial begin : TEST_VECTORS
else
$error("Bad CS! addr=%4x should have mm_cs1!", addr);
end
if (i >= 24'h007ff8 && i < 24'h007ffe) begin
assert(sd_cs == '1)
else
$error("Bad CS! addr=%4x should have sd_cs!", addr);
end
if (i == 16'h7fff) begin
assert(irq_cs == '1)
else

View File

@@ -25,61 +25,61 @@ assign MA = cpu_addr[15:12];
assign mm_address = {MO, cpu_addr[11:0]};
memory_mapper dut(
.data_in(_data_in),
.data_out(_data_out),
.*
.data_in(_data_in),
.data_out(_data_out),
.*
);
always #1 clk_50 = clk_50 === 1'b0;
always #100 clk = clk === 1'b0;
task write_reg(logic [3:0] addr, logic [7:0] data);
@(negedge clk);
cs <= '1;
RS <= addr;
data_in <= data;
rw <= '0;
@(posedge clk);
cs <= '0;
rw <= '1;
@(negedge clk);
@(negedge clk);
cs <= '1;
RS <= addr;
data_in <= data;
rw <= '0;
@(posedge clk);
cs <= '0;
rw <= '1;
@(negedge clk);
endtask
task enable(logic [7:0] data);
@(negedge clk);
MM_cs <= '1;
rw <= '0;
data_in <= data;
@(posedge clk);
rw <= '1;
MM_cs <= '0;
@(negedge clk);
@(negedge clk);
MM_cs <= '1;
rw <= '0;
data_in <= data;
@(posedge clk);
rw <= '1;
MM_cs <= '0;
@(negedge clk);
endtask
initial begin
rst <= '1;
repeat(5) @(posedge clk);
rst <= '0;
rst <= '1;
repeat(5) @(posedge clk);
rst <= '0;
cpu_addr <= 16'h0abc;
write_reg(4'h0, 8'hcc);
$display("Address: %x", mm_address);
assert(mm_address == 24'h000abc) else begin
$error("Bad address before enable!");
end
cpu_addr <= 16'h0abc;
write_reg(4'h0, 8'hcc);
$display("Address: %x", mm_address);
assert(mm_address == 24'h000abc) else begin
$error("Bad address before enable!");
end
enable(1);
$display("Address: %x", mm_address);
assert(mm_address == 24'h0ccabc) else begin
$error("Bad address after enable!");
end
enable(1);
$display("Address: %x", mm_address);
assert(mm_address == 24'h0ccabc) else begin
$error("Bad address after enable!");
end
enable(0);
$display("Address: %x", mm_address);
assert(mm_address == 24'h000abc) else begin
$error("Bad address after enable!");
end
$finish();
enable(0);
$display("Address: %x", mm_address);
assert(mm_address == 24'h000abc) else begin
$error("Bad address after enable!");
end
$finish();
end
endmodule

View File

@@ -0,0 +1,89 @@
module testbench();
timeunit 10ns;
timeprecision 1ns;
logic clk;
logic rw;
logic clk_50;
logic rst;
logic [2:0] addr;
logic [7:0] data;
logic cs;
logic i_sd_cmd;
logic o_sd_cmd;
logic i_sd_data;
logic o_sd_data;
logic cpu_phi2;
always @(posedge clk) begin
cpu_phi2 <= cpu_phi2 === '0;
end
sd_controller dut(
.sd_clk(cpu_phi2),
.*);
always #1 clk_50 = clk_50 === 1'b0;
always #100 clk = clk === 1'b0;
task write_reg(logic [3:0] _addr, logic [7:0] _data);
@(posedge clk);
cs = '1;
addr = _addr;
rw = '0;
data = '1;
@(posedge clk);
data = _data;
@(posedge clk);
cs = '0;
rw = '1;
endtask
task verify_cmd(logic [5:0] cmd, logic [31:0] arg, logic [47:0] verify);
write_reg(0, arg[7:0]);
write_reg(1, arg[15:8]);
write_reg(2, arg[23:16]);
write_reg(3, arg[31:24]);
write_reg(4, cmd);
$display("arg: %x", dut.arg);
$display("dut.cmd: %x", dut.cmd);
@(posedge clk);
@(posedge clk);
while (dut.state.macro == dut.TXCMD) begin
assert(o_sd_cmd == verify[47-dut.state.count]) else begin
$error("cmd output error: Expected %h:%b, got %h:%b",
47-dut.state.count, verify[47-dut.state.count],
47-dut.state.count, o_sd_cmd);
end
@(negedge clk);
end
endtask
localparam cmd0 = 48'h400000000095;
localparam cmd8 = 48'h48000001aa87;
localparam cmd55 = 48'h770000000065;
localparam cmd41 = 48'h694018000019;
initial begin
rst <= '1;
repeat(5) @(posedge clk);
rst <= '0;
verify_cmd(0, 0, cmd0);
verify_cmd(8, 'h1aa, cmd8);
verify_cmd('d55, 0, cmd55);
verify_cmd('d41, 'h40180000, cmd41);
$finish();
end
endmodule

233
hw/fpga/sd_controller.sv Normal file
View File

@@ -0,0 +1,233 @@
module sd_controller(
input clk,
input sd_clk,
input rst,
input [2:0] addr,
input [7:0] data,
input cs,
input rw,
input i_sd_cmd,
output logic o_sd_cmd,
input i_sd_data,
output logic o_sd_data,
output logic [7:0] data_out
);
logic [31:0] arg;
logic [5:0] cmd;
logic [47:0] rxcmd_buf;
logic [31:0] rx_val;
logic [7:0] rxdata_buf [512];
logic [9:0] data_count;
logic [15:0] data_crc;
assign rx_val = rxcmd_buf[39:8];
always_comb begin
data_out = 'x;
if (addr < 4'h4) begin
data_out = rx_val[8 * addr +: 8];
end else if (addr == 4'h4) begin
data_out = {data_flag, read_flag};
end else if (addr == 4'h5) begin
data_out = rxdata_buf[data_count];
end
end
logic read_flag, next_read_flag;
logic data_flag, next_data_flag;
typedef enum bit [2:0] {IDLE, LOAD, CRC, TXCMD, RXCMD, TXDATA, RXDATA, RXDCRC} macro_t;
struct packed {
macro_t macro;
logic [8:0] count;
logic [2:0] d_bit_count;
} state, next_state;
always_ff @(posedge clk) begin
if (rst) begin
state.macro <= IDLE;
state.count <= '0;
state.d_bit_count <= '1;
read_flag <= '0;
data_flag <= '0;
data_count <= '0;
end else begin
if (state.macro == TXCMD || state.macro == CRC) begin
if (sd_clk) begin
state <= next_state;
end
end else if (state.macro == RXCMD || state.macro == RXDATA || state.macro == RXDCRC) begin
if (~sd_clk) begin
state <= next_state;
end
end else begin
state <= next_state;
end
end
if (sd_clk) begin
read_flag <= next_read_flag;
data_flag <= next_data_flag;
end
if (cs & ~rw) begin
if (addr < 4'h4) begin
arg[8 * addr +: 8] <= data;
end else if (addr == 4'h4) begin
cmd <= data[6:0];
end
end
if (cs & addr == 4'h5 && sd_clk) begin
data_count <= data_count + 9'b1;
end
if (state.macro == RXCMD) begin
rxcmd_buf[6'd46-state.count] <= i_sd_cmd; //we probabily missed bit 47
end
if (state.macro == RXDATA && ~sd_clk) begin
rxdata_buf[state.count][state.d_bit_count] <= i_sd_data;
end
if (state.macro == RXDCRC && ~sd_clk) begin
data_crc[4'd15-state.count] <= i_sd_data;
end
end
logic [6:0] crc;
logic load_crc;
logic crc_valid;
logic [39:0] _packet;
assign _packet = {1'b0, 1'b1, cmd, arg};
logic [47:0] packet_crc;
assign packet_crc = {_packet, crc, 1'b1};
crc7 u_crc7(
.clk(clk),
.rst(rst),
.load(load_crc),
.data_in(_packet),
.crc_out(crc),
.valid(crc_valid)
);
always_comb begin
next_state = state;
next_read_flag = read_flag;
next_data_flag = data_flag;
case (state.macro)
IDLE: begin
if (~i_sd_cmd) begin // receive data if sd pulls cmd low
next_state.macro = RXCMD;
end
if (~i_sd_data) begin
next_state.macro = RXDATA;
end
if (addr == 4'h4 & cs & ~rw) begin // transmit if cpu writes to cmd
next_state.macro = LOAD;
end
if (addr == 4'h4 & cs & rw) begin
next_read_flag = '0;
end
if (addr == 4'h5 & cs) begin
next_data_flag = '0;
end
end
LOAD: begin
next_state.macro = CRC;
end
CRC: begin
next_state.macro = TXCMD;
end
TXCMD: begin
if (state.count < 47) begin
next_state.count = state.count + 6'b1;
end else begin
next_state.macro = IDLE;
next_state.count = '0;
end
end
RXCMD: begin
if (state.count < 47) begin
next_state.count = state.count + 6'b1;
end else begin
next_read_flag = '1;
next_state.macro = IDLE;
next_state.count = '0;
end
end
RXDATA: begin
if (state.count < 511 || (state.count == 511 && state.d_bit_count > 0)) begin
if (state.d_bit_count == 8'h0) begin
next_state.count = state.count + 9'b1;
end
next_state.d_bit_count = state.d_bit_count - 3'h1;
end else begin
next_data_flag = '1;
next_state.macro = RXDCRC;
next_state.count = '0;
end
end
RXDCRC: begin
if (state.count < 16) begin
next_state.count = state.count + 9'b1;
end else begin
next_state.macro = IDLE;
next_state.count = '0;
end
end
default: begin
next_state.macro = IDLE;
next_state.count = '0;
end
endcase
end
always_comb begin
o_sd_cmd = '1; //default to 1
o_sd_data = '1;
load_crc = '0;
case (state.macro)
IDLE:;
CRC: begin
load_crc = '1;
end
TXCMD: begin
o_sd_cmd = packet_crc[6'd47 - state.count];
end
RXCMD:;
default:;
endcase
end
endmodule

View File

@@ -0,0 +1,23 @@
transcript on
if {[file exists rtl_work]} {
vdel -lib rtl_work -all
}
vlib rtl_work
vmap work rtl_work
vlog -sv -work work {../../crc7.sv}
vlog -sv -work work {../../hvl/crc7_testbench.sv}
vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L stratixv_ver -L stratixv_hssi_ver -L stratixv_pcie_hip_ver -L rtl_work -L work -voptargs="+acc" testbench
add wave -group {dut} -radix hexadecimal sim:/testbench/dut/*
onfinish stop
run -all
if { [coverage attribute -name TESTSTATUS -concise] == "1"} {
echo Warning
quit -f -code 0
}
quit -code [coverage attribute -name TESTSTATUS -concise]

View File

@@ -0,0 +1,24 @@
transcript on
if {[file exists rtl_work]} {
vdel -lib rtl_work -all
}
vlib rtl_work
vmap work rtl_work
vlog -sv -work work {../../sd_controller.sv}
vlog -sv -work work {../../crc7.sv}
vlog -sv -work work {../../hvl/sd_cmd_testbench.sv}
vsim -t 1ps -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L altera_lnsim_ver -L stratixv_ver -L stratixv_hssi_ver -L stratixv_pcie_hip_ver -L rtl_work -L work -voptargs="+acc" testbench
add wave -group {dut} -radix hexadecimal sim:/testbench/dut/*
onfinish stop
run -all
if { [coverage attribute -name TESTSTATUS -concise] == "1"} {
echo Warning
quit -f -code 0
}
quit -code [coverage attribute -name TESTSTATUS -concise]

View File

@@ -188,7 +188,7 @@ set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_sob
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to cpu_sync
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to clk_50
set_global_assignment -name ENABLE_SIGNALTAP OFF
set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp2.stp
set_global_assignment -name USE_SIGNALTAP_FILE output_files/sd.stp
set_location_assignment PIN_F20 -to HEX4[6]
set_location_assignment PIN_F19 -to HEX4[5]
set_location_assignment PIN_H19 -to HEX4[4]
@@ -205,6 +205,20 @@ set_location_assignment PIN_F18 -to HEX4[0]
set_location_assignment PIN_E20 -to HEX4[1]
set_location_assignment PIN_AB5 -to UART_RXD
set_location_assignment PIN_AB6 -to UART_TXD
set_location_assignment PIN_AB7 -to ARDUINO_IO[2]
set_location_assignment PIN_AB8 -to ARDUINO_IO[3]
set_location_assignment PIN_AB9 -to ARDUINO_IO[4]
set_location_assignment PIN_Y10 -to ARDUINO_IO[5]
set_location_assignment PIN_AA11 -to ARDUINO_IO[6]
set_location_assignment PIN_AA12 -to ARDUINO_IO[7]
set_location_assignment PIN_AB17 -to ARDUINO_IO[8]
set_location_assignment PIN_AA17 -to ARDUINO_IO[9]
set_location_assignment PIN_AB19 -to ARDUINO_IO[10]
set_location_assignment PIN_AA19 -to ARDUINO_IO[11]
set_location_assignment PIN_Y19 -to ARDUINO_IO[12]
set_location_assignment PIN_AB20 -to ARDUINO_IO[13]
set_location_assignment PIN_AB21 -to ARDUINO_IO[14]
set_location_assignment PIN_AA20 -to ARDUINO_IO[15]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_RXD
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to UART_TXD
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to HEX0[6]
@@ -350,6 +364,8 @@ set_location_assignment PIN_V22 -to DRAM_LDQM
set_location_assignment PIN_U22 -to DRAM_RAS_N
set_location_assignment PIN_J21 -to DRAM_UDQM
set_location_assignment PIN_V20 -to DRAM_WE_N
set_global_assignment -name SYSTEMVERILOG_FILE sd_controller.sv
set_global_assignment -name SYSTEMVERILOG_FILE crc7.sv
set_global_assignment -name SYSTEMVERILOG_FILE memory_mapper.sv
set_global_assignment -name SYSTEMVERILOG_FILE board_io.sv
set_global_assignment -name SYSTEMVERILOG_FILE sdram.sv
@@ -365,4 +381,23 @@ set_global_assignment -name SYSTEMVERILOG_FILE SevenSeg.sv
set_global_assignment -name QIP_FILE cpu_clk.qip
set_global_assignment -name SIGNALTAP_FILE output_files/stp1.stp
set_global_assignment -name SIGNALTAP_FILE output_files/stp2.stp
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[15]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[14]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[13]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[12]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[11]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[10]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[9]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[8]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[7]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[6]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[5]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[4]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[3]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[2]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[1]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to ARDUINO_IO[0]
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to ARDUINO_IO[11]
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to ARDUINO_IO[12]
set_global_assignment -name SIGNALTAP_FILE output_files/sd.stp
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@@ -26,8 +26,10 @@ module super6502(
input logic UART_RXD,
output logic UART_TXD,
input [7:0] SW,
output [7:0] LED,
input [7:0] SW,
output logic [7:0] LED,
inout logic [15: 2] ARDUINO_IO,
///////// SDRAM /////////
output DRAM_CLK,
@@ -54,6 +56,16 @@ assign cpu_data_in = cpu_data;
logic [7:0] cpu_data_out;
assign cpu_data = cpu_rwb ? cpu_data_out : 'z;
logic o_sd_cmd, i_sd_cmd;
logic o_sd_data, i_sd_data;
assign ARDUINO_IO[11] = o_sd_cmd ? 1'bz : 1'b0;
assign ARDUINO_IO[12] = o_sd_data ? 1'bz : 1'b0;
assign ARDUINO_IO[13] = cpu_phi2;
assign ARDUINO_IO[6] = 1'b1;
assign i_sd_cmd = ARDUINO_IO[11];
assign i_sd_data = ARDUINO_IO[12];
logic [7:0] rom_data_out;
logic [7:0] sdram_data_out;
@@ -61,6 +73,7 @@ logic [7:0] uart_data_out;
logic [7:0] irq_data_out;
logic [7:0] board_io_data_out;
logic [7:0] mm_data_out;
logic [7:0] sd_data_out;
logic sdram_cs;
logic rom_cs;
@@ -70,10 +83,11 @@ logic irq_cs;
logic board_io_cs;
logic mm_cs1;
logic mm_cs2;
logic sd_cs;
cpu_clk cpu_clk(
.inclk0(clk_50),
.c0(clk)
.inclk0(clk_50),
.c0(clk)
);
always @(posedge clk) begin
@@ -93,16 +107,16 @@ logic [23:0] mm_addr;
assign mm_addr = {mm_MO, cpu_addr[11:0]};
memory_mapper memory_mapper(
.clk(clk),
.clk(clk),
.rst(rst),
.rw(cpu_rwb),
.cs(mm_cs1),
.MM_cs(mm_cs2),
.RS(cpu_addr[3:0]),
.MA(cpu_addr[15:12]),
.data_in(cpu_data_in),
.data_out(mm_data_out),
.MO(mm_MO)
.rw(cpu_rwb),
.cs(mm_cs1),
.MM_cs(mm_cs2),
.RS(cpu_addr[3:0]),
.MA(cpu_addr[15:12]),
.data_in(cpu_data_in),
.data_out(mm_data_out),
.MO(mm_MO)
);
addr_decode decode(
@@ -113,8 +127,9 @@ addr_decode decode(
.uart_cs(uart_cs),
.irq_cs(irq_cs),
.board_io_cs(board_io_cs),
.mm_cs1(mm_cs1),
.mm_cs2(mm_cs2)
.mm_cs1(mm_cs1),
.mm_cs2(mm_cs2),
.sd_cs(sd_cs)
);
@@ -129,8 +144,10 @@ always_comb begin
cpu_data_out = irq_data_out;
else if (board_io_cs)
cpu_data_out = board_io_data_out;
else if (mm_cs1)
cpu_data_out = mm_data_out;
else if (mm_cs1)
cpu_data_out = mm_data_out;
else if (sd_cs)
cpu_data_out = sd_data_out;
else
cpu_data_out = 'x;
end
@@ -204,6 +221,24 @@ uart uart(
.data_out(uart_data_out)
);
sd_controller sd_controller(
.clk(clk),
.sd_clk(cpu_phi2),
.rst(rst),
.addr(cpu_addr[2:0]),
.data(cpu_data_in),
.cs(sd_cs),
.rw(cpu_rwb),
.i_sd_cmd(i_sd_cmd),
.o_sd_cmd(o_sd_cmd),
.i_sd_data(i_sd_data),
.o_sd_data(o_sd_data),
.data_out(sd_data_out)
);
always_ff @(posedge clk_50) begin
if (rst)
irq_data_out <= '0;

View File

@@ -11,4 +11,8 @@ SW = LED
MM_CTRL = $7ff7
MM_DATA = $7fe0
SD_ARG = $7ff8
SD_CMD = $7ffc
SD_DATA = $7ffd
IRQ_STATUS = $7fff

View File

@@ -4,15 +4,17 @@
#include "board_io.h"
#include "uart.h"
#include "mapper.h"
#include "sd_card.h"
int main() {
int i;
uint8_t sw;
char s[16];
s[15] = 0;
int i;
uint8_t sw;
uint32_t resp;
char s[16];
s[15] = 0;
clrscr();
cprintf("Hello, world!\n");
clrscr();
cprintf("Hello, world!\n");
for (i = 0; i < 16; i++){
cprintf("Mapping %1xxxx to %2xxxx\n", i, i);
@@ -46,18 +48,67 @@ int main() {
cprintf("Reading from 0x4000: %x\n", *(unsigned int*)(0x4000));
cprintf("Reading from 0x5000: %x\n", *(unsigned int*)(0x5000));
while (1) {
// This will read a 512 block from the sd card.
// The RCA is hard coded for the one that I have on hand as responses
// are not implemented yet.
sd_card_command(0, 0);
sw = sw_read();
led_set(sw);
sd_card_command(0x000001aa, 8);
sd_card_resp(&resp);
cprintf("CMD8: %lx\n", resp);
cscanf("%15s", s);
cprintf("\n");
for (i = 0; i < 16; i++)
cprintf("s[%d]=%c ", i, s[i]);
cprintf("\n");
cprintf("Read string: %s\n", s);
}
sd_card_command(0, 55);
sd_card_command(0x40180000, 41);
sd_card_resp(&resp);
cprintf("CMD41: %lx\n", resp);
return 0;
sd_card_command(0, 55);
sd_card_command(0x40180000, 41);
sd_card_resp(&resp);
cprintf("CMD41: %lx\n", resp);
sd_card_command(0, 2);
sd_card_resp(&resp);
cprintf("CMD2: %lx\n", resp);
sd_card_command(0, 3);
sd_card_resp(&resp);
cprintf("CMD3: %lx\n", resp);
sd_card_command(0x59b40000, 7);
sd_card_resp(&resp);
cprintf("CMD7: %lx\n", resp);
sd_card_command(0x59b41000, 13);
sd_card_resp(&resp);
cprintf("CMD13: %lx\n", resp);
sd_card_command(0, 17);
sd_card_resp(&resp);
cprintf("CMD17: %lx\n", resp);
while(sw_read());
sd_card_wait_for_data();
cprintf("Read data: \n");
for (i = 0; i < 512; i++){
cprintf("%c", sd_card_read_byte());
}
while (1) {
sw = sw_read();
led_set(sw);
cscanf("%15s", s);
cprintf("\n");
for (i = 0; i < 16; i++)
cprintf("s[%d]=%c ", i, s[i]);
cprintf("\n");
cprintf("Read string: %s\n", s);
}
return 0;
}

12
sw/sd_card.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef _SD_CARD_H
#define _SD_CARD_H
#include <stdint.h>
void sd_card_command(uint32_t arg, uint8_t cmd);
void sd_card_resp(uint32_t* resp);
uint8_t sd_card_read_byte();
void sd_card_wait_for_data();
#endif

66
sw/sd_card.s Normal file
View File

@@ -0,0 +1,66 @@
.include "io.inc65"
.importzp sp, sreg, ptr1
.export _sd_card_command
.export _sd_card_resp
.export _sd_card_read_byte
.export _sd_card_wait_for_data
.autoimport on
.code
; Send sd card command.
; command is in A register, the args are on the stack
; I think the order is high byte first?
_sd_card_command:
pha
jsr popeax
sta SD_ARG
stx SD_ARG+1
lda sreg
sta SD_ARG+2
lda sreg+1
sta SD_ARG+3
pla
sta SD_CMD
rts
; void sd_card_resp(uint32_t* resp);
_sd_card_resp:
phy
sta ptr1 ; store pointer
stx ptr1+1
@1: lda SD_CMD ; wait for status flag
and #$01
beq @1
lda SD_ARG
ldy #$0
sta (ptr1),y
lda SD_ARG+1
iny
sta (ptr1),y
lda SD_ARG+2
iny
sta (ptr1),y
lda SD_ARG+3
iny
sta (ptr1),y
ply
rts
_sd_card_read_byte:
lda SD_DATA
ldx #$00
rts
_sd_card_wait_for_data:
pha
@1: lda SD_CMD ; wait for status flag
and #$02
beq @1
pla
rts