1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-02-06 16:14:42 +00:00
Files
mist-devel.mist-board/tutorials/soc/lesson7c/block_io.v
2016-01-08 22:57:10 +01:00

129 lines
3.9 KiB
Verilog

//
// block_io.v
//
// This file implements a simple block interface to the SD card.
// It can be used instead of the sd_card.v whenever there's no need
// on core side for a full sd card interface. This is usually the
// case if the core is not ported from/to other boards.
//
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the Lesser GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
module block_io (
// link to user_io for io controller
output reg [31:0] io_lba,
output reg io_rd,
output io_wr,
input io_ack,
output io_conf,
output io_sdhc,
// data coming in from io controller
input [7:0] io_din,
input io_din_strobe,
// data going out to io controller
output [7:0] io_dout,
input io_dout_strobe,
// interface to the cpu
input reset,
input clk,
input rd,
input wr,
input [7:0] din,
input [2:0] addr,
output [7:0] dout
);
assign io_wr = 1'b0; // we never write ...
assign io_dout = 1'b0; // ... and thus never send data to the io controller
assign io_conf = 1'b0; // we need no configuration info from the SD card
// raise io_rd signal whenever SoC requests a sector and release it
// once IO controller acknowleges it
always @(posedge io_rd_req or posedge io_ack) begin
if(io_ack) io_rd <= 1'b0;
else io_rd <= 1'b1;
end
// ---------------------------------------------------------------
// --------------------- sector buffer ---------------------------
// ---------------------------------------------------------------
reg [7:0] buffer [511:0];
reg [8:0] buffer_wptr; // buffer write pointer
reg [8:0] buffer_rptr; // buffer read pointer
// IO controller writes to buffer
always @(posedge io_din_strobe)
buffer[buffer_wptr] <= io_din;
// buffer is not busy anymore if IO controller ack'd io_rd and has
// tranferred 512 bytes (counter wrapped to 0 again)
wire busy = io_rd || (buffer_wptr != 0);
// write pointer increases whenever io controller writes a byte. It's reset
// when the SoC requests a new sector.
always @(negedge io_din_strobe or posedge io_rd_req) begin
if(io_rd_req) buffer_wptr <= 9'd0;
else buffer_wptr <= buffer_wptr + 9'd1;
end
// clock data out of buffer to allow for embedded ram
reg [7:0] buffer_dout;
always @(posedge clk)
buffer_dout <= buffer[buffer_rptr];
// read pointer increases whenever cpu reads a byte from the buffer. It's
// reset when the SoC requests a new sector
always @(posedge cpu_byte_rd or posedge io_rd_req) begin
if(io_rd_req) buffer_rptr <= 9'd0;
else buffer_rptr <= buffer_rptr + 9'd1;
end
// ---------------------- CPU register read/write -----------------
reg io_rd_req; // cpu triggers a sector read
reg cpu_byte_rd; // cpu read a byte
// only addresses 4 and 5 can be read and return valid data
assign dout = (addr == 4)?{7'b0000000, busy }:
(addr == 5)?buffer_dout:
8'hff;
always @(negedge clk) begin
io_rd_req <= 1'b0;
cpu_byte_rd <= 1'b0;
// cpu reads from the data register
if(rd && addr == 5)
cpu_byte_rd <= 1'b1;
if(wr) begin
case(addr)
// cpu writes the four bytes of the sector address
0: io_lba[31:24] <= din;
1: io_lba[23:16] <= din;
2: io_lba[15: 8] <= din;
3: io_lba[ 7: 0] <= din;
// cpu writes 1 to bit 0 of the control register
4: io_rd_req <= din[0];
endcase
end
end
endmodule