Tim Edwards | cd64af5 | 2020-08-07 11:11:58 -0400 | [diff] [blame^] | 1 | //------------------------------------------------ |
| 2 | // spi_slave.v |
| 3 | //------------------------------------------------ |
| 4 | // General purpose SPI slave module |
| 5 | //------------------------------------------------ |
| 6 | // Written by Tim Edwards |
| 7 | // efabless, inc., april 23, 2017 |
| 8 | //------------------------------------------------ |
| 9 | // This file is distributed free and open source |
| 10 | //------------------------------------------------ |
| 11 | |
| 12 | // SCK --- Clock input |
| 13 | // SDI --- Data input |
| 14 | // SDO --- Data output |
| 15 | // CSB --- Chip select (sense negative) |
| 16 | // idata --- Data from chip to transmit out, in 8 bits |
| 17 | // odata --- Input data to chip, in 8 bits |
| 18 | // addr --- Decoded address to upstream circuits |
| 19 | // rdstb --- Read strobe, tells upstream circuit to supply next byte to idata |
| 20 | // wrstb --- Write strobe, tells upstream circuit to latch odata. |
| 21 | |
| 22 | // Data format (general purpose): |
| 23 | // 8 bit format |
| 24 | // 1st byte: Command word (see below) |
| 25 | // 2nd byte: Address word (register 0 to 255) |
| 26 | // 3rd byte: Data word (value 0 to 255) |
| 27 | |
| 28 | // Command format: |
| 29 | // 00000000 No operation |
| 30 | // 10000000 Write until CSB raised |
| 31 | // 01000000 Read until CSB raised |
| 32 | // 11000000 Simultaneous read/write until CSB raised |
| 33 | // wrnnn000 Read/write as above, for nnn = 1 to 7 bytes, then terminate |
| 34 | |
| 35 | // Lower three bits are reserved for future use. |
| 36 | // All serial bytes are read and written msb first. |
| 37 | |
| 38 | // Fixed control and status registers |
| 39 | |
| 40 | // Address 0 is reserved and contains flags for SPI mode. This is |
| 41 | // currently undefined and is always value 0. |
| 42 | // Address 1 is reserved and contains manufacturer ID low 8 bits. |
| 43 | // Address 2 is reserved and contains manufacturer ID high 4 bits |
| 44 | // and mask revision number (4 bits). |
| 45 | // Address 3 is reserved and contains product ID (8 bits). |
| 46 | // Addresses 4 to 255 are available for general purpose use. |
| 47 | |
| 48 | `define COMMAND 2'b00 |
| 49 | `define ADDRESS 2'b01 |
| 50 | `define DATA 2'b10 |
| 51 | `define IDLE 2'b11 // Not used |
| 52 | |
| 53 | module spi_slave(SCK, SDI, CSB, SDO, sdoenb, idata, odata, oaddr, rdstb, wrstb); |
| 54 | input SCK; |
| 55 | input SDI; |
| 56 | input CSB; |
| 57 | output SDO; |
| 58 | output sdoenb; |
| 59 | input [7:0] idata; |
| 60 | output [7:0] odata; |
| 61 | output [7:0] oaddr; |
| 62 | output rdstb; |
| 63 | output wrstb; |
| 64 | |
| 65 | reg [7:0] addr; |
| 66 | reg wrstb; |
| 67 | reg rdstb; |
| 68 | reg sdoenb; |
| 69 | reg [1:0] state; |
| 70 | reg [2:0] count; |
| 71 | reg writemode; |
| 72 | reg readmode; |
| 73 | reg [2:0] fixed; |
| 74 | wire [7:0] odata; |
| 75 | reg [6:0] predata; |
| 76 | wire [7:0] oaddr; |
| 77 | reg [7:0] ldata; |
| 78 | |
| 79 | assign odata = {predata, SDI}; |
| 80 | assign oaddr = (state == `ADDRESS) ? {addr[6:0], SDI} : addr; |
| 81 | assign SDO = ldata[7]; |
| 82 | |
| 83 | // Readback data is captured on the falling edge of SCK so that |
| 84 | // it is guaranteed valid at the next rising edge. |
| 85 | always @(negedge SCK or posedge CSB) begin |
| 86 | if (CSB == 1'b1) begin |
| 87 | wrstb <= 1'b0; |
| 88 | ldata <= 8'b00000000; |
| 89 | sdoenb <= 1'b1; |
| 90 | end else begin |
| 91 | |
| 92 | // After CSB low, 1st SCK starts command |
| 93 | |
| 94 | if (state == `DATA) begin |
| 95 | if (readmode == 1'b1) begin |
| 96 | sdoenb <= 1'b0; |
| 97 | if (count == 3'b000) begin |
| 98 | ldata <= idata; |
| 99 | end else begin |
| 100 | ldata <= {ldata[6:0], 1'b0}; // Shift out |
| 101 | end |
| 102 | end else begin |
| 103 | sdoenb <= 1'b1; |
| 104 | end |
| 105 | |
| 106 | // Apply write strobe on SCK negative edge on the next-to-last |
| 107 | // data bit so that it updates data on the rising edge of SCK |
| 108 | // on the last data bit. |
| 109 | |
| 110 | if (count == 3'b111) begin |
| 111 | if (writemode == 1'b1) begin |
| 112 | wrstb <= 1'b1; |
| 113 | end |
| 114 | end else begin |
| 115 | wrstb <= 1'b0; |
| 116 | end |
| 117 | end else begin |
| 118 | wrstb <= 1'b0; |
| 119 | sdoenb <= 1'b1; |
| 120 | end // ! state `DATA |
| 121 | end // ! CSB |
| 122 | end // always @ ~SCK |
| 123 | |
| 124 | always @(posedge SCK or posedge CSB) begin |
| 125 | if (CSB == 1'b1) begin |
| 126 | // Default state on reset |
| 127 | addr <= 8'h00; |
| 128 | rdstb <= 1'b0; |
| 129 | predata <= 7'b0000000; |
| 130 | state <= `COMMAND; |
| 131 | count <= 3'b000; |
| 132 | readmode <= 1'b0; |
| 133 | writemode <= 1'b0; |
| 134 | fixed <= 3'b000; |
| 135 | end else begin |
| 136 | // After CSB low, 1st SCK starts command |
| 137 | if (state == `COMMAND) begin |
| 138 | rdstb <= 1'b0; |
| 139 | count <= count + 1; |
| 140 | if (count == 3'b000) begin |
| 141 | writemode <= SDI; |
| 142 | end else if (count == 3'b001) begin |
| 143 | readmode <= SDI; |
| 144 | end else if (count < 3'b101) begin |
| 145 | fixed <= {fixed[1:0], SDI}; |
| 146 | end else if (count == 3'b111) begin |
| 147 | state <= `ADDRESS; |
| 148 | end |
| 149 | end else if (state == `ADDRESS) begin |
| 150 | count <= count + 1; |
| 151 | addr <= {addr[6:0], SDI}; |
| 152 | if (count == 3'b111) begin |
| 153 | if (readmode == 1'b1) begin |
| 154 | rdstb <= 1'b1; |
| 155 | end |
| 156 | state <= `DATA; |
| 157 | end else begin |
| 158 | rdstb <= 1'b0; |
| 159 | end |
| 160 | end else if (state == `DATA) begin |
| 161 | predata <= {predata[6:0], SDI}; |
| 162 | count <= count + 1; |
| 163 | if (count == 3'b111) begin |
| 164 | if (fixed == 3'b001) begin |
| 165 | state <= `COMMAND; |
| 166 | end else if (fixed != 3'b000) begin |
| 167 | fixed <= fixed - 1; |
| 168 | addr <= addr + 1; // Auto increment address (fixed) |
| 169 | end else begin |
| 170 | addr <= addr + 1; // Auto increment address (streaming) |
| 171 | end |
| 172 | end else begin |
| 173 | rdstb <= 1'b0; |
| 174 | end |
| 175 | end // ! state `DATA |
| 176 | end // ! CSB |
| 177 | end // always @ SCK |
| 178 | |
| 179 | endmodule // spi_slave |