1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-04-29 13:33:00 +00:00
Files
mist-devel.mist-board/cores/mist/data_io.v
2014-01-28 19:58:48 +00:00

197 lines
4.4 KiB
Verilog

// SPI data client (rom, floppy, harddisk io)
module data_io (
// clocks
input clk_8,
input reset,
input [1:0] bus_cycle,
output reg [31:0] ctrl_out,
// spi interface
input sdi,
input sck,
input ss,
output sdo,
// dma status interface
output [4:0] dma_idx,
input [7:0] dma_data,
output reg dma_ack,
output reg br,
// horizontal and vertical screen adjustments
output reg [15:0] video_adj,
// ram interface
output reg read,
output reg write,
output [22:0] addr,
output reg [15:0] data_out, // write data register
input [15:0] data_in
);
assign dma_idx = bcnt;
reg [4:0] cnt; // bit counter (counting spi bits, rolling from 23 to 8)
reg [4:0] bcnt; // payload byte counter
reg [14:0] sbuf; // receive buffer (buffer used to assemble spi bytes/words)
reg [7:0] cmd; // command byte (first byte of spi transmission)
reg [30:0] addrR;// address register (word address for memory transfers)
reg writeCmd; // write request received via SPI
reg writeD; // write synchonized to 8Mhz clock
reg writeD2; // synchronized write delayed by one 8Mhz clock
reg readCmd; // read request received via SPI
reg readD; // read synchonized to 8Mhz clock
reg readD2; // synchronized read delayed by one 8Mhz clock
reg [15:0] ram_data; // latch for incoming ram data
reg brI; // signals to bring br into local clock domain
// during write the address needs to be decremented by one as the
// address auto increment takes place at the beginning of each transfer
assign addr = (cmd==2)?(addrR[22:0]-23'd1):addrR[22:0];
// latch bus cycle to have it stable at the end of the cycle (rising edge of clk8)
reg [1:0] bus_cycle_L;
always @(negedge clk_8)
bus_cycle_L <= bus_cycle;
// generate state signals required to control the sdram host interface
always @(posedge clk_8) begin
// start io transfers clock cycles after bus_cycle 0
// (after the cpu cycle)
writeD <= writeCmd && ((bus_cycle_L == 3) || writeD);
writeD2 <= writeD;
readD <= readCmd && ((bus_cycle_L == 3) || readD);
readD2 <= readD;
br <= brI;
// at the end of a read cycle latch the incoming ram data for later spi transmission
if(read) ram_data <= data_in;
if(reset) begin
read <= 1'b0;
write <= 1'b0;
end else begin
if(writeD && ~writeD2) begin
write <= 1'b1;
read <= 1'b0;
end else if(readD && ~readD2) begin
write <= 1'b0;
read <= 1'b1;
end else begin
write <= 1'b0;
read <= 1'b0;
end
end
end
reg [15:0] txData;
assign sdo = txData[15];
always@(negedge sck) begin
// memory read
if(cmd == 3) begin
if(cnt == 8)
txData <= ram_data;
else
txData[15:1] <= txData[14:0];
end
// dma status read
if(cmd == 5) begin
if((cnt == 8) || (cnt == 16))
txData[15:8] <= dma_data;
else
txData[15:1] <= txData[14:0];
end
end
always@(posedge sck, posedge ss) begin
if(ss == 1'b1) begin
cnt <= 5'd0;
bcnt <= 4'd0;
writeCmd <= 1'b0;
readCmd <= 1'b0;
dma_ack <= 1'b0;
end else begin
dma_ack <= 1'b0;
sbuf <= { sbuf[13:0], sdi};
// 0:7 is command, 8:15 and 16:23 is payload bytes
if(cnt < 5'd23)
cnt <= cnt + 5'd1;
else
cnt <= 5'd8;
// count payload bytes
if((cnt == 15) || (cnt == 23))
bcnt <= bcnt + 4'd1;
if(cnt == 5'd7) begin
cmd <= {sbuf[6:0], sdi};
// send ack
if({sbuf[6:0], sdi } == 8'd6)
dma_ack <= 1'b1;
// request bus
if({sbuf[6:0], sdi } == 8'd7)
brI <= 1'b1;
// release bus
if({sbuf[6:0], sdi } == 8'd8)
brI <= 1'b0;
// if we can see a read coming initiate sdram read transfer asap
if({sbuf[6:0], sdi } == 8'd3)
readCmd <= 1;
end
// handle "payload"
if(cnt >= 8) begin
// set address
if(cmd == 1)
addrR <= { addrR[29:0], sdi};
// write ram
if(cmd == 2) begin
if(cnt == 5'd16)
writeCmd <= 1'b0;
if(cnt == 5'd23) begin
data_out <= { sbuf, sdi };
addrR <= addrR + 31'b1;
writeCmd <= 1'b1;
end
end
// read ram
if(cmd == 3) begin
if(cnt == 16)
readCmd <= 0;
if(cnt == 23) begin
addrR <= addrR + 31'b1;
readCmd <= 1;
end
end
// set control register (32 bits written in 2 * 16 bits)
if((cmd == 4) && (cnt == 5'd23)) begin
if(bcnt < 2)
ctrl_out[31:16] <= { sbuf, sdi };
else
ctrl_out[15:0] <= { sbuf, sdi };
end
// set video offsets
if((cmd == 9) && (cnt == 5'd23))
video_adj <= { sbuf, sdi };
end
end
end
endmodule