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.
236 lines
5.3 KiB
Systemverilog
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
|