SOFA/BENCHMARK/sdc_controller/rtl/sd_data_serial_host.v

375 lines
14 KiB
Verilog

//////////////////////////////////////////////////////////////////////
//// ////
//// WISHBONE SD Card Controller IP Core ////
//// ////
//// sd_data_serial_host.v ////
//// ////
//// This file is part of the WISHBONE SD Card ////
//// Controller IP Core project ////
//// http://opencores.org/project,sd_card_controller ////
//// ////
//// Description ////
//// Module resposible for sending and receiving data through ////
//// 4-bit sd card data interface ////
//// ////
//// Author(s): ////
//// - Marek Czerski, ma.czerski@gmail.com ////
//// ////
//////////////////////////////////////////////////////////////////////
//// ////
//// Copyright (C) 2013 Authors ////
//// ////
//// Based on original work by ////
//// Adam Edvardsson (adam.edvardsson@orsoc.se) ////
//// ////
//// Copyright (C) 2009 Authors ////
//// ////
//// This source file may be used and distributed without ////
//// restriction provided that this copyright statement is not ////
//// removed from the file and that any derivative work contains ////
//// the original copyright notice and the associated disclaimer. ////
//// ////
//// This source file is free software; you can redistribute it ////
//// and/or modify it under the terms of the GNU Lesser General ////
//// Public License as published by the Free Software Foundation; ////
//// either version 2.1 of the License, or (at your option) any ////
//// later version. ////
//// ////
//// This source is distributed in the hope that it will be ////
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
//// PURPOSE. See the GNU Lesser General Public License for more ////
//// details. ////
//// ////
//// You should have received a copy of the GNU Lesser General ////
//// Public License along with this source; if not, download it ////
//// from http://www.opencores.org/lgpl.shtml ////
//// ////
//////////////////////////////////////////////////////////////////////
`include "sd_defines.v"
module sd_data_serial_host(
input sd_clk,
input rst,
//Tx Fifo
input [31:0] data_in,
output reg rd,
//Rx Fifo
output reg [31:0] data_out,
output reg we,
//tristate data
output reg DAT_oe_o,
output reg[3:0] DAT_dat_o,
input [3:0] DAT_dat_i,
//Controll signals
input [`BLKSIZE_W-1:0] blksize,
input bus_4bit,
input [`BLKCNT_W-1:0] blkcnt,
input [1:0] start,
output sd_data_busy,
output busy,
output reg crc_ok
);
reg [3:0] DAT_dat_reg;
reg [`BLKSIZE_W-1+3:0] data_cycles;
reg bus_4bit_reg;
//CRC16
reg [3:0] crc_in;
reg crc_en;
reg crc_rst;
wire [15:0] crc_out [3:0];
reg [15:0] transf_cnt;
parameter SIZE = 6;
reg [SIZE-1:0] state;
reg [SIZE-1:0] next_state;
parameter IDLE = 6'b000001;
parameter WRITE_DAT = 6'b000010;
parameter WRITE_CRC = 6'b000100;
parameter WRITE_BUSY = 6'b001000;
parameter READ_WAIT = 6'b010000;
parameter READ_DAT = 6'b100000;
reg [2:0] crc_status;
reg busy_int;
reg [`BLKCNT_W-1:0] blkcnt_reg;
reg next_block;
wire start_bit;
reg [4:0] crc_c;
reg [3:0] last_din;
reg [2:0] crc_s ;
reg [4:0] data_send_index;
//sd data input pad register
always @(posedge sd_clk)
DAT_dat_reg <= DAT_dat_i;
genvar i;
generate
for(i=0; i<4; i=i+1) begin: CRC_16_gen
sd_crc_16 CRC_16_i (crc_in[i],crc_en, sd_clk, crc_rst, crc_out[i]);
end
endgenerate
assign busy = (state != IDLE);
assign start_bit = !DAT_dat_reg[0];
assign sd_data_busy = !DAT_dat_reg[0];
always @(state or start or start_bit or transf_cnt or data_cycles or crc_status or crc_ok or busy_int or next_block)
begin: FSM_COMBO
case(state)
IDLE: begin
if (start == 2'b01)
next_state <= WRITE_DAT;
else if (start == 2'b10)
next_state <= READ_WAIT;
else
next_state <= IDLE;
end
WRITE_DAT: begin
if (transf_cnt >= data_cycles+21 && start_bit)
next_state <= WRITE_CRC;
else if (start == 2'b11)
next_state <= IDLE;
else
next_state <= WRITE_DAT;
end
WRITE_CRC: begin
if (crc_status == 3)
next_state <= WRITE_BUSY;
else
next_state <= WRITE_CRC;
end
WRITE_BUSY: begin
if (!busy_int && next_block && crc_ok)
next_state <= WRITE_DAT;
else if (!busy_int)
next_state <= IDLE;
else
next_state <= WRITE_BUSY;
end
READ_WAIT: begin
if (start_bit)
next_state <= READ_DAT;
else
next_state <= READ_WAIT;
end
READ_DAT: begin
if (transf_cnt == data_cycles+17 && next_block && crc_ok)
next_state <= READ_WAIT;
else if (transf_cnt == data_cycles+17)
next_state <= IDLE;
else if (start == 2'b11)
next_state <= IDLE;
else
next_state <= READ_DAT;
end
default: next_state <= IDLE;
endcase
end
always @(posedge sd_clk or posedge rst)
begin: FSM_OUT
if (rst) begin
state <= IDLE;
DAT_oe_o <= 0;
crc_en <= 0;
crc_rst <= 1;
transf_cnt <= 0;
crc_c <= 15;
rd <= 0;
last_din <= 0;
crc_c <= 0;
crc_in <= 0;
DAT_dat_o <= 0;
crc_status <= 0;
crc_s <= 0;
we <= 0;
data_out <= 0;
crc_ok <= 0;
busy_int <= 0;
data_send_index <= 0;
next_block <= 0;
blkcnt_reg <= 0;
data_cycles <= 0;
bus_4bit_reg <= 0;
end
else begin
state <= next_state;
case(state)
IDLE: begin
DAT_oe_o <= 0;
DAT_dat_o <= 4'b1111;
crc_en <= 0;
crc_rst <= 1;
transf_cnt <= 0;
crc_c <= 16;
crc_status <= 0;
crc_s <= 0;
we <= 0;
rd <= 0;
data_send_index <= 0;
next_block <= 0;
blkcnt_reg <= blkcnt;
data_cycles <= (bus_4bit ? (blksize << 1) : (blksize << 3));
bus_4bit_reg <= bus_4bit;
end
WRITE_DAT: begin
crc_ok <= 0;
transf_cnt <= transf_cnt + 16'h1;
next_block <= 0;
rd <= 0;
if (transf_cnt == 1) begin
crc_rst <= 0;
crc_en <= 1;
if (bus_4bit_reg) begin
last_din <= data_in[31:28];
crc_in <= data_in[31:28];
end
else begin
last_din <= {3'h7, data_in[31]};
crc_in <= {3'h7, data_in[31]};
end
DAT_oe_o <= 1;
DAT_dat_o <= bus_4bit_reg ? 4'h0 : 4'he;
data_send_index <= 1;
end
else if ((transf_cnt >= 2) && (transf_cnt <= data_cycles+1)) begin
DAT_oe_o<=1;
if (bus_4bit_reg) begin
last_din <= {
data_in[31-(data_send_index[2:0]<<2)],
data_in[30-(data_send_index[2:0]<<2)],
data_in[29-(data_send_index[2:0]<<2)],
data_in[28-(data_send_index[2:0]<<2)]
};
crc_in <= {
data_in[31-(data_send_index[2:0]<<2)],
data_in[30-(data_send_index[2:0]<<2)],
data_in[29-(data_send_index[2:0]<<2)],
data_in[28-(data_send_index[2:0]<<2)]
};
if (data_send_index[2:0] == 3'h5/*not 7 - read delay !!!*/) begin
rd <= 1;
end
if (data_send_index[2:0] == 3'h7) begin
data_send_index <= 0;
end
else
data_send_index<=data_send_index + 5'h1;
end
else begin
last_din <= {3'h7, data_in[31-data_send_index]};
crc_in <= {3'h7, data_in[31-data_send_index]};
if (data_send_index == 29/*not 31 - read delay !!!*/) begin
rd <= 1;
end
if (data_send_index == 31) begin
data_send_index <= 0;
end
else
data_send_index<=data_send_index + 5'h1;
end
DAT_dat_o<= last_din;
if (transf_cnt == data_cycles+1)
crc_en<=0;
end
else if (transf_cnt > data_cycles+1 & crc_c!=0) begin
crc_en <= 0;
crc_c <= crc_c - 5'h1;
DAT_oe_o <= 1;
DAT_dat_o[0] <= crc_out[0][crc_c-1];
if (bus_4bit_reg)
DAT_dat_o[3:1] <= {crc_out[3][crc_c-1], crc_out[2][crc_c-1], crc_out[1][crc_c-1]};
else
DAT_dat_o[3:1] <= {3'h7};
end
else if (transf_cnt == data_cycles+18) begin
DAT_oe_o <= 1;
DAT_dat_o <= 4'hf;
end
else if (transf_cnt >= data_cycles+19) begin
DAT_oe_o <= 0;
end
end
WRITE_CRC: begin
DAT_oe_o <= 0;
if (crc_status < 3)
crc_s[crc_status] <= DAT_dat_reg[0];
crc_status <= crc_status + 3'h1;
busy_int <= 1;
end
WRITE_BUSY: begin
if (crc_s == 3'b010)
crc_ok <= 1;
else
crc_ok <= 0;
busy_int <= !DAT_dat_reg[0];
next_block <= (blkcnt_reg != 0);
if (next_state != WRITE_BUSY) begin
blkcnt_reg <= blkcnt_reg - `BLKCNT_W'h1;
crc_rst <= 1;
crc_c <= 16;
crc_status <= 0;
end
transf_cnt <= 0;
end
READ_WAIT: begin
DAT_oe_o <= 0;
crc_rst <= 0;
crc_en <= 1;
crc_in <= 0;
crc_c <= 15;// end
next_block <= 0;
transf_cnt <= 0;
end
READ_DAT: begin
if (transf_cnt < data_cycles) begin
if (bus_4bit_reg) begin
we <= (transf_cnt[2:0] == 7);
data_out[31-(transf_cnt[2:0]<<2)] <= DAT_dat_reg[3];
data_out[30-(transf_cnt[2:0]<<2)] <= DAT_dat_reg[2];
data_out[29-(transf_cnt[2:0]<<2)] <= DAT_dat_reg[1];
data_out[28-(transf_cnt[2:0]<<2)] <= DAT_dat_reg[0];
end
else begin
we <= (transf_cnt[4:0] == 31);
data_out[31-transf_cnt[4:0]] <= DAT_dat_reg[0];
end
crc_in <= DAT_dat_reg;
crc_ok <= 1;
transf_cnt <= transf_cnt + 16'h1;
end
else if (transf_cnt <= data_cycles+16) begin
transf_cnt <= transf_cnt + 16'h1;
crc_en <= 0;
last_din <= DAT_dat_reg;
we<=0;
if (transf_cnt > data_cycles) begin
crc_c <= crc_c - 5'h1;
if (crc_out[0][crc_c] != last_din[0])
crc_ok <= 0;
if (crc_out[1][crc_c] != last_din[1] && bus_4bit_reg)
crc_ok<=0;
if (crc_out[2][crc_c] != last_din[2] && bus_4bit_reg)
crc_ok <= 0;
if (crc_out[3][crc_c] != last_din[3] && bus_4bit_reg)
crc_ok <= 0;
if (crc_c == 0) begin
next_block <= (blkcnt_reg != 0);
blkcnt_reg <= blkcnt_reg - `BLKCNT_W'h1;
crc_rst <= 1;
end
end
end
end
endcase
end
end
endmodule