mirror of https://github.com/lnis-uofu/SOFA.git
375 lines
14 KiB
Verilog
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
|
|
|
|
|
|
|
|
|
|
|