/* a spi master module. byte wide interface. start/end transactions. read/write bytes. also, contingous bitwise read. ____ ____ cs \_______________/ _____ _ _ _ _______ sck \_/ \_/ \_/ \_/ pdatain->sreg ^ sreg->pdataout ^ shift(in) left ^ ^ ^ ^ shift out ^ ^ ^ ^ */ module spim( input wire clk, input wire rst, output reg cs, output reg sck, output reg so, input wire si, input wire [7:0]data_in, output wire [7:0]data_out, input wire [2:0]cmd, input wire req, output reg busy, input wire rd_en, output reg bs_out ); `define CMD_STA 3'b001 `define CMD_END 3'b011 `define CMD_RW 3'b010 `define CMD_RDC 3'b110 `define CMD_NONE 3'b000 `define S_IDLE 1'b0 `define S_OP 1'b1 `include "gray.inc" //interface states reg s1; //current command reg reg [2:0]curr; reg shifting; reg loading; reg done; reg w1,w2; reg [7:0]sreg; wire s8b=(bin2gray(3'b111)==bitctr); wire firstbit=(bin2gray(3'b000)==bitctr); wire [2:0]bitctr; always @(posedge clk or posedge rst) if(rst) begin s1<=`S_IDLE; curr<=`CMD_NONE; end else case(s1) `S_IDLE: if(done && req) begin s1<=`S_OP; curr<=cmd; end `S_OP: if(done && !req) begin s1<=`S_IDLE; curr<=`CMD_NONE; end default: begin s1<=`S_IDLE; curr<=`CMD_NONE; end endcase //handshake always @* case(s1) `S_IDLE: busy=0; `S_OP: busy=1; default: busy=0; endcase //chip select always @(posedge clk or posedge rst) if(rst) cs<=1; else if(s1==`S_OP) case(curr) `CMD_STA: cs<=0; `CMD_END: cs<=1; default: cs<=cs; endcase else cs<=cs; //shifting always @* if(s1==`S_OP) case(curr) `CMD_RW: begin if(bitctr==0) begin loading=1; end else begin loading=0; end shifting=1; done=w2; bs_out=1; end `CMD_RDC: begin shifting=0; loading=0; done=!req&&!rd_en&&sck; bs_out=si || !rd_en; end default: begin shifting=0; loading=0; done=1; bs_out=1; end endcase else begin shifting=0; loading=0; done=1; bs_out=1; end gctr #(.WID(3))gbitctr( .clk(sck), .rst(rst), .ctr(bitctr), .init(3'b0), .down(1'b0), .ld(1'b0), .en(shifting) ); always @(posedge sck or posedge rst) if(rst) sreg<=0; else case ({shifting,loading}) 2'b00: sreg<=sreg; 2'b01: sreg<=data_in; 2'b10: sreg<={sreg[6:0],si}; 2'b11: sreg<={data_in[6:0],si}; endcase always @(posedge clk or posedge rst) if(rst) begin sck<=1; w1<=0; w2<=0; end else if(s1==`S_OP) case(curr) `CMD_RW: begin if(!w2 || !sck) sck<=~sck; w1<=s8b; w2<=w1; end `CMD_RDC: begin if(rd_en||(!sck)) begin sck<=~sck; w1<=0; w2<=0; end else begin sck<=sck; w1<=0; w2<=0; end end default: begin sck<=1; w1<=0; w2<=0; end endcase else begin sck<=1; w1<=0; w2<=0; end always @(negedge sck or posedge rst) if(rst) so<=1; else if(firstbit) so<=data_in[7]; else so<=sreg[7]; assign data_out=sreg; endmodule