diff --git a/hw/efinix_fpga/addr_decode.sv b/hw/efinix_fpga/addr_decode.sv index ede04af..48320cd 100644 --- a/hw/efinix_fpga/addr_decode.sv +++ b/hw/efinix_fpga/addr_decode.sv @@ -8,6 +8,7 @@ module addr_decode output o_multiplier_cs, output o_divider_cs, output o_uart_cs, + output o_sdcard_cs, output o_sdram_cs ); @@ -16,6 +17,7 @@ assign o_timer_cs = i_addr >= 16'heff8 && i_addr <= 16'heffb; assign o_multiplier_cs = i_addr >= 16'heff0 && i_addr <= 16'heff7; assign o_divider_cs = i_addr >= 16'hefe8 && i_addr <= 16'hefef; assign o_uart_cs = i_addr >= 16'hefe6 && i_addr <= 16'hefe7; +assign o_sdcard_cs = i_addr >= 16'hefd8 && i_addr <= 16'hefdf; assign o_leds_cs = i_addr == 16'hefff; assign o_sdram_cs = i_addr < 16'h8000; diff --git a/hw/efinix_fpga/crc7.sv b/hw/efinix_fpga/crc7.sv new file mode 100644 index 0000000..e009826 --- /dev/null +++ b/hw/efinix_fpga/crc7.sv @@ -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 diff --git a/hw/efinix_fpga/debug_profile.wizard.json b/hw/efinix_fpga/debug_profile.wizard.json index 43dfd1f..5d55d9a 100644 --- a/hw/efinix_fpga/debug_profile.wizard.json +++ b/hw/efinix_fpga/debug_profile.wizard.json @@ -3,7 +3,7 @@ { "name": "la0", "type": "la", - "uuid": "44caec2ec3a74324b8ff7cb201ab080b", + "uuid": "cb44f83ddf674d66b2dd550675cad77d", "trigin_en": false, "trigout_en": false, "auto_inserted": true, @@ -12,127 +12,37 @@ "input_pipeline": 1, "probes": [ { - "name": "u_uart/addr", + "name": "sd_data_OUT", "width": 1, "probe_type": 1 }, { - "name": "u_uart/baud_rate", + "name": "sd_cmd_IN", "width": 1, "probe_type": 1 }, { - "name": "u_uart/baud_x16_ce", + "name": "sd_data_OE", "width": 1, "probe_type": 1 }, { - "name": "u_uart/clk", + "name": "sd_data_IN", "width": 1, "probe_type": 1 }, { - "name": "u_uart/clk_50", + "name": "sd_cmd_OE", "width": 1, "probe_type": 1 }, { - "name": "u_uart/control", - "width": 8, - "probe_type": 1 - }, - { - "name": "u_uart/cs", + "name": "sd_cmd_OUT", "width": 1, "probe_type": 1 }, { - "name": "u_uart/irqb", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/i_data", - "width": 8, - "probe_type": 1 - }, - { - "name": "u_uart/next_state", - "width": 2, - "probe_type": 1 - }, - { - "name": "u_uart/o_data", - "width": 8, - "probe_type": 1 - }, - { - "name": "u_uart/reset", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/rwb", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/rx_busy", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/rx_data", - "width": 8, - "probe_type": 1 - }, - { - "name": "u_uart/rx_data_valid", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/rx_error", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/rx_i", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/rx_parity_error", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/state", - "width": 2, - "probe_type": 1 - }, - { - "name": "u_uart/status", - "width": 8, - "probe_type": 1 - }, - { - "name": "u_uart/tx_busy", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/tx_data", - "width": 8, - "probe_type": 1 - }, - { - "name": "u_uart/tx_en", - "width": 1, - "probe_type": 1 - }, - { - "name": "u_uart/tx_o", + "name": "w_sdcard_cs", "width": 1, "probe_type": 1 } @@ -267,486 +177,38 @@ }, { "name": "la0_probe0", - "net": "addr", - "path": [ - "u_uart" - ] + "net": "sd_data_OUT", + "path": [] }, { "name": "la0_probe1", - "net": "baud_rate", - "path": [ - "u_uart" - ] + "net": "sd_cmd_IN", + "path": [] }, { "name": "la0_probe2", - "net": "baud_x16_ce", - "path": [ - "u_uart" - ] + "net": "sd_data_OE", + "path": [] }, { "name": "la0_probe3", - "net": "clk", - "path": [ - "u_uart" - ] + "net": "sd_data_IN", + "path": [] }, { "name": "la0_probe4", - "net": "clk_50", - "path": [ - "u_uart" - ] + "net": "sd_cmd_OE", + "path": [] }, { - "name": "la0_probe5[0]", - "net": "control[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe5[1]", - "net": "control[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe5[2]", - "net": "control[2]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe5[3]", - "net": "control[3]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe5[4]", - "net": "control[4]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe5[5]", - "net": "control[5]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe5[6]", - "net": "control[6]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe5[7]", - "net": "control[7]", - "path": [ - "u_uart" - ] + "name": "la0_probe5", + "net": "sd_cmd_OUT", + "path": [] }, { "name": "la0_probe6", - "net": "cs", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe7", - "net": "irqb", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[0]", - "net": "i_data[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[1]", - "net": "i_data[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[2]", - "net": "i_data[2]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[3]", - "net": "i_data[3]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[4]", - "net": "i_data[4]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[5]", - "net": "i_data[5]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[6]", - "net": "i_data[6]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe8[7]", - "net": "i_data[7]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe9[0]", - "net": "next_state[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe9[1]", - "net": "next_state[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[0]", - "net": "o_data[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[1]", - "net": "o_data[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[2]", - "net": "o_data[2]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[3]", - "net": "o_data[3]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[4]", - "net": "o_data[4]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[5]", - "net": "o_data[5]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[6]", - "net": "o_data[6]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe10[7]", - "net": "o_data[7]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe11", - "net": "reset", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe12", - "net": "rwb", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe13", - "net": "rx_busy", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[0]", - "net": "rx_data[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[1]", - "net": "rx_data[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[2]", - "net": "rx_data[2]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[3]", - "net": "rx_data[3]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[4]", - "net": "rx_data[4]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[5]", - "net": "rx_data[5]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[6]", - "net": "rx_data[6]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe14[7]", - "net": "rx_data[7]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe15", - "net": "rx_data_valid", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe16", - "net": "rx_error", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe17", - "net": "rx_i", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe18", - "net": "rx_parity_error", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe19[0]", - "net": "state[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe19[1]", - "net": "state[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[0]", - "net": "status[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[1]", - "net": "status[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[2]", - "net": "status[2]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[3]", - "net": "status[3]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[4]", - "net": "status[4]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[5]", - "net": "status[5]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[6]", - "net": "status[6]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe20[7]", - "net": "status[7]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe21", - "net": "tx_busy", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[0]", - "net": "tx_data[0]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[1]", - "net": "tx_data[1]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[2]", - "net": "tx_data[2]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[3]", - "net": "tx_data[3]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[4]", - "net": "tx_data[4]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[5]", - "net": "tx_data[5]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[6]", - "net": "tx_data[6]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe22[7]", - "net": "tx_data[7]", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe23", - "net": "tx_en", - "path": [ - "u_uart" - ] - }, - { - "name": "la0_probe24", - "net": "tx_o", - "path": [ - "u_uart" - ] + "net": "w_sdcard_cs", + "path": [] } ] } @@ -764,270 +226,60 @@ "capture_control": false, "selected_nets": [ { - "name": "addr", + "name": "sd_data_OUT", "width": 1, "clk_domain": "clk_2", "selected_probe_type": "DATA AND TRIGGER", "child": [], - "path": [ - "u_uart" - ] + "path": [] }, { - "name": "baud_rate", + "name": "sd_cmd_IN", "width": 1, "clk_domain": "clk_2", "selected_probe_type": "DATA AND TRIGGER", "child": [], - "path": [ - "u_uart" - ] + "path": [] }, { - "name": "baud_x16_ce", + "name": "sd_data_OE", "width": 1, "clk_domain": "clk_2", "selected_probe_type": "DATA AND TRIGGER", "child": [], - "path": [ - "u_uart" - ] + "path": [] }, { - "name": "clk", + "name": "sd_data_IN", "width": 1, "clk_domain": "clk_2", "selected_probe_type": "DATA AND TRIGGER", "child": [], - "path": [ - "u_uart" - ] + "path": [] }, { - "name": "clk_50", + "name": "sd_cmd_OE", "width": 1, "clk_domain": "clk_2", "selected_probe_type": "DATA AND TRIGGER", "child": [], - "path": [ - "u_uart" - ] + "path": [] }, { - "name": "control", - "width": 8, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 7, - "net_idx_right": 0 - }, - { - "name": "cs", + "name": "sd_cmd_OUT", "width": 1, "clk_domain": "clk_2", "selected_probe_type": "DATA AND TRIGGER", "child": [], - "path": [ - "u_uart" - ] + "path": [] }, { - "name": "irqb", + "name": "w_sdcard_cs", "width": 1, "clk_domain": "clk_2", "selected_probe_type": "DATA AND TRIGGER", "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "i_data", - "width": 8, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 7, - "net_idx_right": 0 - }, - { - "name": "next_state", - "width": 2, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 1, - "net_idx_right": 0 - }, - { - "name": "o_data", - "width": 8, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 7, - "net_idx_right": 0 - }, - { - "name": "reset", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "rwb", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "rx_busy", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "rx_data", - "width": 8, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 7, - "net_idx_right": 0 - }, - { - "name": "rx_data_valid", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "rx_error", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "rx_i", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "rx_parity_error", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "state", - "width": 2, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 1, - "net_idx_right": 0 - }, - { - "name": "status", - "width": 8, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 7, - "net_idx_right": 0 - }, - { - "name": "tx_busy", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "tx_data", - "width": 8, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ], - "net_idx_left": 7, - "net_idx_right": 0 - }, - { - "name": "tx_en", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] - }, - { - "name": "tx_o", - "width": 1, - "clk_domain": "clk_2", - "selected_probe_type": "DATA AND TRIGGER", - "child": [], - "path": [ - "u_uart" - ] + "path": [] } ], "top_module": "super6502", diff --git a/hw/efinix_fpga/ip/bram/bram_ini.vh b/hw/efinix_fpga/ip/bram/bram_ini.vh index 1d9741d..31553a5 100644 --- a/hw/efinix_fpga/ip/bram/bram_ini.vh +++ b/hw/efinix_fpga/ip/bram/bram_ini.vh @@ -4,25 +4,25 @@ input integer index;//Mode type input integer val_; //Port A index, Port B Index, Number of Items in Loop, Port A Start, Port B Start, reserved case (index) 0: bram_ini_table= -(val_== 0)?256'h008d000ef000e6000ad000f9000f00000100089000ef000e7000ad00000000a2: -(val_== 1)?256'h0000000000000000000000000000000000000000000000f100080000ef000e60: -(val_== 2)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_== 3)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_== 4)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_== 5)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_== 6)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_== 7)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_== 8)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_== 9)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==10)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==11)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==12)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==13)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==14)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==15)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==16)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==17)?256'h0000000000000000000000000000000000000000000000000000000000000000: -(val_==18)?256'h0000000000000000000000000000000000000000000000000000000000000000: +(val_== 0)?256'h001000085000aa000a9000ea000ff0002b0002000000000a9000ff0002200020: +(val_== 1)?256'h07b0002000000000a200010000a9000ff0002b0002000008000a900011000e60: +(val_== 2)?256'h6400011000640001000064000fd00080000cb000ea000f000010000a5000ff00: +(val_== 3)?256'h90008e000ef000d80008d000ff000d3000200004800060000130006400012000: +(val_== 4)?256'h00068000ef000db0008d00003000a5000ef000da0008d00002000a5000ef000d: +(val_== 5)?256'h0029000ef000dc000ad000090008600008000850005a00060000ef000dc0008d: +(val_== 6)?256'h0ef000d9000ad000080009100000000a0000ef000d8000ad000f9000f0000010: +(val_== 7)?256'hc8000ef000db000ad0000800091000c8000ef000da000ad0000800091000c800: +(val_== 8)?256'hc000ad000480006000000000a2000ef000dd000ad000600007a0000800091000: +(val_== 9)?256'h000090008600008000850005a0006000068000f9000f00000200029000ef000d: +(val_==10)?256'h00c80000800091000c80000800091000c8000080009100000000a000000000a9: +(val_==11)?256'h0f00000100029000ef000dc000ad00026000f00008800009000a000008000910: +(val_==12)?256'h91000c8000ef000d9000ad000080009100000000a0000ef000d8000ad000f600: +(val_==13)?256'h800091000c8000ef000db000ad0000800091000c8000ef000da000ad00008000: +(val_==14)?256'h00060000ff000a2000ff000a90007a0006000000000a200000000a90007a0000: +(val_==15)?256'h006800001000e6000020009000000000850000000065000980001800048000c8: +(val_==16)?256'h088000030008500000000b100003000a0000ff000c10004c00004000a0000600: +(val_==17)?256'hce0004c00000000b100088000aa00000000b100088000020008500000000b100: +(val_==18)?256'h00000000000000000000000000000000000000000000000000000000000ff000: (val_==19)?256'h000ff00000000ff00000000ff000000000000000000000000000000000000000: (val_==20)?256'h0000000000000000000000000000000000000000000000000000000000000000: (val_==21)?256'h0000000000000000000000000000000000000000000000000000000000000000: diff --git a/hw/efinix_fpga/ip/bram/init_hex.mem b/hw/efinix_fpga/ip/bram/init_hex.mem index c297903..5083c1e 100644 --- a/hw/efinix_fpga/ip/bram/init_hex.mem +++ b/hw/efinix_fpga/ip/bram/init_hex.mem @@ -1,235 +1,235 @@ +20 +22 +ff +a9 +00 +20 +2b +ff +ea +a9 +aa +85 +10 +e6 +11 +a9 +08 +20 +2b +ff +a9 +10 a2 00 -ad -e7 +20 +7b +ff +a5 +10 +f0 +ea +cb +80 +fd +64 +10 +64 +11 +64 +12 +64 +13 +60 +48 +20 +d3 +ff +8d +d8 ef -89 +8e +d9 +ef +a5 +02 +8d +da +ef +a5 +03 +8d +db +ef +68 +8d +dc +ef +60 +5a +85 +08 +86 +09 +ad +dc +ef +29 01 f0 f9 ad -e6 +d8 ef -8d -e6 +a0 +00 +91 +08 +ad +d9 ef -80 -f1 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 -00 +c8 +91 +08 +ad +da +ef +c8 +91 +08 +ad +db +ef +c8 +91 +08 +7a +60 +ad +dd +ef +a2 +00 +60 +48 +ad +dc +ef +29 +02 +f0 +f9 +68 +60 +5a +85 +08 +86 +09 +a9 +00 +a0 +00 +91 +08 +c8 +91 +08 +c8 +91 +08 +c8 +91 +08 +a0 +09 +88 +f0 +26 +ad +dc +ef +29 +01 +f0 +f6 +ad +d8 +ef +a0 +00 +91 +08 +ad +d9 +ef +c8 +91 +08 +ad +da +ef +c8 +91 +08 +ad +db +ef +c8 +91 +08 +7a +a9 +00 +a2 +00 +60 +7a +a9 +ff +a2 +ff +60 +c8 +48 +18 +98 +65 +00 +85 +00 +90 +02 +e6 +01 +68 +60 +a0 +04 +4c +c1 +ff +a0 +03 +b1 +00 +85 +03 +88 +b1 +00 +85 +02 +88 +b1 +00 +aa +88 +b1 +00 +4c +ce +ff 00 00 00 diff --git a/hw/efinix_fpga/sd_controller.sv b/hw/efinix_fpga/sd_controller.sv new file mode 100644 index 0000000..f1bc691 --- /dev/null +++ b/hw/efinix_fpga/sd_controller.sv @@ -0,0 +1,235 @@ +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 [8: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 @(negedge 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 + 8'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; + data_count <= '0; + 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.d_bit_count = '1; + 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 diff --git a/hw/efinix_fpga/super6502.sv b/hw/efinix_fpga/super6502.sv index 6609142..efc5eb5 100644 --- a/hw/efinix_fpga/super6502.sv +++ b/hw/efinix_fpga/super6502.sv @@ -38,10 +38,33 @@ module super6502 output logic [1:0] o_sdr_DQM, input uart_rx, - output uart_tx + output uart_tx, + output sd_cs, + output sd_clk, + + input sd_cmd_IN, + output sd_cmd_OUT, + output sd_cmd_OE, + + input sd_data_IN, + output sd_data_OUT, + output sd_data_OE ); +assign sd_cs = '1; + +logic o_sd_cmd, i_sd_cmd; +logic o_sd_data, i_sd_data; + +assign i_sd_cmd = sd_cmd_IN; +assign sd_cmd_OUT = '0; +assign sd_cmd_OE = ~o_sd_cmd; + +assign i_sd_data = sd_data_IN; +assign sd_data_OUT = '0; +assign sd_data_OE = ~o_sd_data; + assign pll_cpu_reset = '1; assign o_pll_reset = '1; @@ -72,6 +95,7 @@ logic w_timer_cs; logic w_multiplier_cs; logic w_divider_cs; logic w_uart_cs; +logic w_sdcard_cs; addr_decode u_addr_decode( .i_addr(cpu_addr), @@ -81,6 +105,7 @@ addr_decode u_addr_decode( .o_multiplier_cs(w_multiplier_cs), .o_divider_cs(w_divider_cs), .o_uart_cs(w_uart_cs), + .o_sdcard_cs(w_sdcard_cs), .o_sdram_cs(w_sdram_cs) ); @@ -90,6 +115,7 @@ logic [7:0] w_timer_data_out; logic [7:0] w_multiplier_data_out; logic [7:0] w_divider_data_out; logic [7:0] w_uart_data_out; +logic [7:0] w_sdcard_data_out; logic [7:0] w_sdram_data_out; always_comb begin @@ -105,6 +131,8 @@ always_comb begin cpu_data_out = w_divider_data_out; else if (w_uart_cs) cpu_data_out = w_uart_data_out; + else if (w_sdcard_cs) + cpu_data_out = w_sdcard_data_out; else if (w_sdram_cs) cpu_data_out = w_sdram_data_out; else @@ -182,6 +210,31 @@ uart_wrapper u_uart( .irqb(w_uart_irqb) ); +logic sd_clk; +always @(posedge clk_2) begin + sd_clk <= ~sd_clk; +end + + +sd_controller sd_controller( + .clk(clk_2), + .sd_clk(sd_clk), + .rst(rst), + .addr(cpu_addr[2:0]), + .data(cpu_data_in), + .cs(w_sdcard_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(w_sdcard_data_out) +); + + sdram_adapter u_sdram_adapter( .i_cpuclk(clk_2), .i_arst(~button_reset), diff --git a/hw/efinix_fpga/super6502.xml b/hw/efinix_fpga/super6502.xml index 65b88f1..4d38d40 100644 --- a/hw/efinix_fpga/super6502.xml +++ b/hw/efinix_fpga/super6502.xml @@ -1,5 +1,5 @@ - + @@ -21,6 +21,8 @@ + + diff --git a/hw/efinix_fpga/test_programs/Makefile b/hw/efinix_fpga/test_programs/Makefile index 89aa73f..9ec3830 100644 --- a/hw/efinix_fpga/test_programs/Makefile +++ b/hw/efinix_fpga/test_programs/Makefile @@ -1,4 +1,4 @@ -TARGETS=stacktest runram timer timer_irq multiplier divider uart uart2 +TARGETS=stacktest runram timer timer_irq multiplier divider uart uart2 sdcard SRC=$(wildcard *.s) DIR=../ip/bram diff --git a/hw/efinix_fpga/test_programs/sdcard.s b/hw/efinix_fpga/test_programs/sdcard.s new file mode 100644 index 0000000..97bd17e --- /dev/null +++ b/hw/efinix_fpga/test_programs/sdcard.s @@ -0,0 +1,153 @@ +.importzp sp, sreg, ptr1, tmp1, tmp2, tmp3, tmp4 + +.export _sd_card_command +.export _sd_card_resp +.export _sd_card_read_byte +.export _sd_card_wait_for_data + +.autoimport on + +.code + + +SD_ARG = $efd8 +SD_CMD = $efdc +SD_DATA = $efdd + +_resp = $10 + + +main: +@cmd0: + jsr stztmp ; arg = 0 + lda #$00 ; cmd = 0 + jsr _sd_card_command + + nop ; no resp, so need to wait for cmd to finish +@cmd8: + lda #$aa + sta tmp1 + inc tmp2 ; arg = 000001aa + lda #$08 ; cmd = 8 + jsr _sd_card_command + + lda #<_resp + ldx #>_resp + jsr _sd_card_resp_timeout + + lda _resp + beq @cmd8 + +end: + wai + bra end + +stztmp: + stz tmp1 + stz tmp2 + stz tmp3 + stz tmp4 + rts + +; 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 + + +; int sd_card_resp_timeout(uint32_t* resp); +_sd_card_resp_timeout: + phy + sta ptr1 ; store pointer + stx ptr1+1 + lda #$0 + ldy #$0 + sta (ptr1),y + iny + sta (ptr1),y + iny + sta (ptr1),y + iny + sta (ptr1),y + ldy #$9 +@1: dey + beq @timeout + 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 + lda #$00 + ldx #$00 + rts +@timeout: + ply + lda #$ff + ldx #$ff + rts + +.segment "VECTORS" + +.addr main +.addr main +.addr main \ No newline at end of file