Files
TSConf_MiST/rtl/spi.v
2020-05-11 23:17:53 +08:00

89 lines
2.8 KiB
Verilog

// part of NeoGS project (c) 2007-2008 NedoPC
//
// SPI mode 0 8-bit master module
//
// short diagram for speed=0 (Fclk/Fspi=2, no rdy shown)
//
// clk: ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ (positive edges)
// counter: 00|00|00|10|11|12|13|14|15|16|17|18|19|1A|1B|1C|1D|1E|1F|00|00|00 // internal!
// sck: ___________/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\_______
// sdo: --------< do7 | do6 | do5 | do4 | do3 | do2 | do1 | do0 >-------
// sdi: --------< di7 | di6 | di5 | di4 | di3 | di2 | di1 | di0 >-------
// bsync: ________/`````\_________________________________________________
// start: _____/``\_______________________________________________________
// din: -----<IN>-------------------------------------------------------
// dout: old old old old old old old old old old old old old | new new new
//
// data on sdo must be latched by slave on rising sck edge. data on sdo changes on falling edge of sck
//
// data from sdi is latched by master on positive edge of sck, while slave changes it on falling edge.
// WARNING: slave must emit valid di7 bit BEFORE first pulse on sck!
//
// start is synchronous pulse, which starts all transfer and also latches din data on the same clk edge
// as it is registered high. start can be given anytime (only when speed=0),
// so it is functioning then as synchronous reset. when speed!=0, there is global enable for majority of
// flipflops in the module, so start can't be accepted at any time
//
// dout updates with freshly received data at the clk edge in which sck goes high for the last time, thus
// latching last bit on sdi.
//
// sdo emits last bit shifted out after the transfer end
module spi
(
// SPI wires
input clk, // system clock
output sck, // SCK
output reg sdo, // MOSI
input sdi, // MISO
// DMA interface
input dma_req,
input [7:0] dma_din,
// Z80 interface
input cpu_req,
input [7:0] cpu_din,
// output
output start, // start strobe, 1 clock length
output reg [7:0] dout
);
assign sck = counter[0];
assign start = req && rdy;
wire [7:0] din = dma_req ? dma_din : cpu_din;
wire rdy = counter[4]; // 0 - transmission in progress
wire req = cpu_req || dma_req;
reg [4:0] counter;
always @(posedge clk) begin
reg [7:0] shift;
if (start) begin
counter <= 5'b0;
sdo <= din[7];
shift[7:1] <= din[6:0];
end
else if (!rdy) begin
counter <= counter + 5'd1;
// shift in (rising edge of SCK)
if (!sck) begin
shift[0] <= sdi;
if (&counter[3:1]) dout <= {shift[7:1], sdi};
end
// shift out (falling edge of sck)
if (sck) begin
sdo <= shift[7];
shift[7:1] <= shift[6:0]; // last bit remains after end of exchange
end
end
end
endmodule