Files
super6502/hw/fpga/sd_controller.sv
Byron Lathi ee95a592cd Reset bit count upon entering RXDATA
The but count should be set to 7 when entering RXDATA. previously it was
not reset or left at 0, which caused the first byte to only have the lsb
set and all other bits to be read incorrectly.
2022-04-14 11:20:48 -05:00

236 lines
5.3 KiB
Systemverilog

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