# SPI example for csrGen.pl script # %B is the block name %B spi_example # %C for clock %C spi_clk # %RST allows us to name the low true reset, default would be "initl" %RST reset_l # %WD is to specify the data bus that write data should be taken from %WD write_data # %RD similarly is a name for the read data bus - used in read case statement %RD rd_data_D %REV $Id: example_spi.csrs,v 1.2 2004/08/03 20:14:56 cbenz Exp cbenz $ # Now, aside from the register case statements which are done automatically, # this script has you prepare the surrounding logic yourself. So you specify # those IOs and flops. %I is input, %F is a flop, and %OF is a flopped output. %I spi_select %I mosi %O miso %A 0 7:0 control0 %A 1 7:0 status1 RO %F spi_selectQ 1 1 spi_select %F mosiQ 1 0 mosi %V parameter ADDR_WIDTH = 8, DATA_WIDTH = 8 ; reg [127:0] shift_in ; // over-sized, synth will trim. reg [7:0] command ; reg [ADDR_WIDTH-1:0] addr ; reg [ADDR_WIDTH-1:0] addr_D ; reg [DATA_WIDTH-1:0] wr_data ; reg [DATA_WIDTH-1:0] rd_data_D ; reg [7:0] spi_counter ; reg [7:0] shift_out ; reg [7:0] write_data ; reg miso ; always @ (negedge spi_clk or negedge reset_l) if (~reset_l) miso <= 0 ; else miso <= (command[0] == 0) && (spi_selectQ == 0) && // send msbit of rd data ((rd_data_D[DATA_WIDTH-1] && (spi_counter ==(7+ADDR_WIDTH))) || // and the rest of the rd data shift_out[DATA_WIDTH-2]) ; always @ (posedge spi_clk or negedge reset_l) if (~reset_l) begin /*AUTORESET*/ // Beginning of autoreset for uninitialized flops addr <= {(1+(ADDR_WIDTH-1)){1'b0}}; command <= 8'h0; shift_in <= 128'h0; shift_out <= 8'h0; spi_counter <= 8'h0; // End of automatics end else begin // ensure use of IOB flops on SS and MOSI shift_in <= {shift_in, mosiQ} ; addr <= addr_D ; if (spi_counter == 8) command <= shift_in[7:0] ; if (spi_selectQ) spi_counter <= 0 ; else if (~spi_selectQ && (spi_counter == 0)) begin spi_counter <= 1 ; end else begin // spi_selectQ is 0, spi_counter is already counting if (spi_counter == (7 + ADDR_WIDTH + DATA_WIDTH)) spi_counter <= 8 + ADDR_WIDTH ; else spi_counter <= spi_counter + 1 ; end if (spi_counter == (7 + ADDR_WIDTH)) shift_out <= rd_data_D ; else shift_out <= shift_out << 1 ; end %E // need to use v2k SENSTAR (aka always @*) because we have gone around // some of the declarations... %SENSTAR %VCL addr_D = addr ; if (spi_counter == (6 + ADDR_WIDTH)) addr_D[ADDR_WIDTH-1:1] = {shift_in[ADDR_WIDTH-3:0], mosiQ} ; if (spi_counter == (7 + ADDR_WIDTH)) addr_D[0] = mosiQ ; write_data = {shift_in, mosiQ} ; rd_data_D = 0 ; case ({addr[ADDR_WIDTH-1:1], addr_D[0]}) %READCASE endcase if (command[0] && (spi_selectQ == 0) && (spi_counter == (7 + ADDR_WIDTH + DATA_WIDTH))) case (addr) %WRITECASE endcase %E # and a final %E completes the file %E