dineshannayya | 52e8a34 | 2022-02-15 14:19:56 +0530 | [diff] [blame] | 1 | `default_nettype none |
| 2 | /* |
| 3 | * SPDX-FileCopyrightText: 2022 <Dinesh Annayya> |
| 4 | * |
| 5 | * Riscdunio |
| 6 | * |
| 7 | * Copyright (C) 2022 Dinesh Annayya <dinesha.opencore.org> |
| 8 | * |
| 9 | * Permission to use, copy, modify, and/or distribute this software for any |
| 10 | * purpose with or without fee is hereby granted, provided that the above |
| 11 | * copyright notice and this permission notice appear in all copies. |
| 12 | * |
| 13 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 19 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| 20 | * |
| 21 | * SPDX-License-Identifier: ISC |
| 22 | */ |
| 23 | |
| 24 | `timescale 1 ns / 1 ps |
| 25 | |
| 26 | // |
| 27 | // Simple SPI Ram simulation model for 128Kx8 LOW VOLTAGE, FAST SERIAL SRAM |
| 28 | // (IS62/65WVS1288GALL) |
| 29 | // |
| 30 | // This model samples io input signals 1ns before the SPI clock edge and |
| 31 | // updates output signals 1ns after the SPI clock edge. |
| 32 | // |
| 33 | // Supported commands: |
| 34 | // 0x03, 0x02, 0x3B , 0x38, 0xFF, 0x05 , 0x01 |
| 35 | // Instruction Hex Description |
| 36 | // READ 0x03 Read data from memory array beginning at selected address |
| 37 | // WRITE 0x02 Write data to memory array beginning at selected address |
| 38 | // ESDI 0x3B Enter SDI mode |
| 39 | // ESQI 0x38 Enter SQI mode |
| 40 | // RSTDQI 0xFF Reset SDI/SQI mode |
| 41 | // RDMR 0x05 Read Mode Register |
| 42 | // WRMR 0x01 Write Mode Register |
| 43 | // |
| 44 | |
| 45 | module spiram #( |
| 46 | parameter mem_file_name = "firmware.hex" |
| 47 | )( |
| 48 | input csb, |
| 49 | input clk, |
| 50 | inout io0, // MOSI |
| 51 | inout io1, // MISO |
| 52 | inout io2, |
| 53 | inout io3 |
| 54 | ); |
| 55 | localparam verbose = 0; |
| 56 | localparam integer latency = 8; |
| 57 | |
| 58 | reg [7:0] buffer; |
| 59 | reg [3:0] reset_count = 0; |
| 60 | reg [3:0] reset_monitor = 0; |
| 61 | integer bitcount = 0; |
| 62 | integer bytecount = 0; |
| 63 | integer dummycount = 0; |
| 64 | |
| 65 | reg [7:0] spi_cmd; |
| 66 | reg [23:0] spi_addr; |
| 67 | |
| 68 | reg [7:0] spi_in; |
| 69 | reg [7:0] spi_out; |
| 70 | reg spi_io_vld; |
| 71 | |
| 72 | |
| 73 | localparam [1:0] sspi = 1; |
| 74 | localparam [1:0] dspi = 2; |
| 75 | localparam [1:0] qspi = 3; |
| 76 | |
| 77 | localparam [3:0] mode_sspi_rd = 1; |
| 78 | localparam [3:0] mode_sspi_wr = 2; |
| 79 | localparam [3:0] mode_dspi_rd = 3; |
| 80 | localparam [3:0] mode_dspi_wr = 4; |
| 81 | localparam [3:0] mode_qspi_rd = 5; |
| 82 | localparam [3:0] mode_qspi_wr = 6; |
| 83 | |
| 84 | reg [3:0] spi_phase = mode_sspi_rd; |
| 85 | reg [3:0] spi_data_phase = 0; |
| 86 | reg [3:0] spi_mode = sspi; |
| 87 | |
| 88 | reg io0_oe = 0; |
| 89 | reg io1_oe = 0; |
| 90 | reg io2_oe = 0; |
| 91 | reg io3_oe = 0; |
| 92 | |
| 93 | reg io0_dout = 0; |
| 94 | reg io1_dout = 0; |
| 95 | reg io2_dout = 0; |
| 96 | reg io3_dout = 0; |
| 97 | |
| 98 | assign #1 io0 = io0_oe ? io0_dout : 1'bz; |
| 99 | assign #1 io1 = io1_oe ? io1_dout : 1'bz; |
| 100 | assign #1 io2 = io2_oe ? io2_dout : 1'bz; |
| 101 | assign #1 io3 = io3_oe ? io3_dout : 1'bz; |
| 102 | |
| 103 | wire io0_delayed; |
| 104 | wire io1_delayed; |
| 105 | wire io2_delayed; |
| 106 | wire io3_delayed; |
| 107 | |
| 108 | assign #1 io0_delayed = io0; |
| 109 | assign #1 io1_delayed = io1; |
| 110 | assign #1 io2_delayed = io2; |
| 111 | assign #1 io3_delayed = io3; |
| 112 | |
| 113 | // 128KB RAM |
| 114 | reg [7:0] memory [0:128*1024-1]; |
| 115 | |
| 116 | initial begin |
| 117 | if (!(mem_file_name == "none")) |
| 118 | $readmemh(mem_file_name,memory); |
| 119 | end |
| 120 | |
| 121 | task spi_action; |
| 122 | begin |
| 123 | spi_in = buffer; |
| 124 | |
| 125 | if (bytecount == 1) begin |
| 126 | spi_cmd = buffer; |
| 127 | |
| 128 | if (spi_cmd == 8'h 3b) begin |
| 129 | spi_mode = dspi; |
| 130 | end |
| 131 | |
| 132 | if (spi_cmd == 8'h 38) begin |
| 133 | spi_mode = qspi; |
| 134 | end |
| 135 | |
| 136 | if (spi_cmd == 8'h ff) begin |
| 137 | spi_mode = sspi; |
| 138 | end |
| 139 | |
| 140 | // spi read |
| 141 | if (spi_cmd == 8'h 03 && spi_mode == sspi) |
| 142 | spi_phase = mode_sspi_rd; |
| 143 | |
| 144 | // spi write |
| 145 | if (spi_cmd == 8'h 02 && spi_mode == sspi) |
| 146 | spi_phase = mode_sspi_wr; |
| 147 | |
| 148 | // dual spi read |
| 149 | if (spi_cmd == 8'h 03 && spi_mode == dspi) |
| 150 | spi_phase = mode_dspi_rd; |
| 151 | |
| 152 | // dual spi write |
| 153 | if (spi_cmd == 8'h 02 && spi_mode == dspi) |
| 154 | spi_phase = mode_dspi_wr; |
| 155 | |
| 156 | // quad spi read |
| 157 | if (spi_cmd == 8'h 03 && spi_mode == qspi) |
| 158 | spi_phase = mode_qspi_rd; |
| 159 | |
| 160 | // quad spi write |
| 161 | if (spi_cmd == 8'h 02 && spi_mode == qspi) |
| 162 | spi_phase = mode_qspi_wr; |
| 163 | end |
| 164 | |
| 165 | if (spi_cmd == 'h 03 || (spi_cmd == 'h 02)) begin |
| 166 | if (bytecount == 2) |
| 167 | spi_addr[23:16] = buffer; |
| 168 | |
| 169 | if (bytecount == 3) |
| 170 | spi_addr[15:8] = buffer; |
| 171 | |
| 172 | if (bytecount == 4) begin |
| 173 | spi_addr[7:0] = buffer; |
| 174 | spi_data_phase = spi_phase; |
| 175 | end |
| 176 | |
| 177 | // Dummy by selection at end of address phase for read |
| 178 | // mode only |
| 179 | if (bytecount == 4 && spi_mode == sspi && spi_cmd ==8'h03 ) |
| 180 | dummycount = 8; |
| 181 | if (bytecount == 4 && spi_mode == dspi && spi_cmd ==8'h03) |
| 182 | dummycount = 4; |
| 183 | if (bytecount == 4 && spi_mode == qspi && spi_cmd ==8'h03) |
| 184 | dummycount = 2; |
| 185 | |
| 186 | if (bytecount >= 4 && spi_cmd ==8'h03) begin // Data Read Phase |
| 187 | buffer = memory[spi_addr]; |
| 188 | //$display("%m: Read Memory Address: %x Data: %x",spi_addr,buffer); |
| 189 | spi_addr = spi_addr + 1; |
| 190 | end |
| 191 | if (bytecount > 4 && spi_cmd ==8'h02) begin // Data Write Phase |
| 192 | memory[spi_addr] = buffer; |
| 193 | //$display("%m: Write Memory Address: %x Data: %x",spi_addr,buffer); |
| 194 | spi_addr = spi_addr + 1; |
| 195 | end |
| 196 | end |
| 197 | |
| 198 | spi_out = buffer; |
| 199 | spi_io_vld = 1; |
| 200 | |
| 201 | if (verbose) begin |
| 202 | if (bytecount == 1) |
| 203 | $write("<SPI-START>"); |
| 204 | $write("<SPI:%02x:%02x>", spi_in, spi_out); |
| 205 | end |
| 206 | |
| 207 | end |
| 208 | endtask |
| 209 | |
| 210 | |
| 211 | always @(csb) begin |
| 212 | if (csb) begin |
| 213 | if (verbose) begin |
| 214 | $display(""); |
| 215 | $fflush; |
| 216 | end |
| 217 | buffer = 0; |
| 218 | bitcount = 0; |
| 219 | bytecount = 0; |
| 220 | io0_oe = 0; |
| 221 | io1_oe = 0; |
| 222 | io2_oe = 0; |
| 223 | io3_oe = 0; |
| 224 | spi_data_phase = 0; |
| 225 | |
| 226 | end |
| 227 | end |
| 228 | |
| 229 | |
| 230 | always @(csb, clk) begin |
| 231 | spi_io_vld = 0; |
| 232 | if (!csb && !clk) begin |
| 233 | if (dummycount > 0) begin |
| 234 | io0_oe = 0; |
| 235 | io1_oe = 0; |
| 236 | io2_oe = 0; |
| 237 | io3_oe = 0; |
| 238 | end else |
| 239 | case (spi_data_phase) |
| 240 | mode_sspi_rd: begin |
| 241 | io0_oe = 0; |
| 242 | io1_oe = 1; |
| 243 | io2_oe = 0; |
| 244 | io3_oe = 0; |
| 245 | io1_dout = buffer[7]; |
| 246 | end |
| 247 | mode_sspi_wr: begin |
| 248 | io0_oe = 0; |
| 249 | io1_oe = 0; |
| 250 | io2_oe = 0; |
| 251 | io3_oe = 0; |
| 252 | end |
| 253 | mode_dspi_wr: begin |
| 254 | io0_oe = 0; |
| 255 | io1_oe = 0; |
| 256 | io2_oe = 0; |
| 257 | io3_oe = 0; |
| 258 | end |
| 259 | mode_dspi_rd: begin |
| 260 | io0_oe = 1; |
| 261 | io1_oe = 1; |
| 262 | io2_oe = 0; |
| 263 | io3_oe = 0; |
| 264 | io0_dout = buffer[6]; |
| 265 | io1_dout = buffer[7]; |
| 266 | end |
| 267 | mode_qspi_wr: begin |
| 268 | io0_oe = 0; |
| 269 | io1_oe = 0; |
| 270 | io2_oe = 0; |
| 271 | io3_oe = 0; |
| 272 | end |
| 273 | mode_qspi_rd: begin |
| 274 | io0_oe = 1; |
| 275 | io1_oe = 1; |
| 276 | io2_oe = 1; |
| 277 | io3_oe = 1; |
| 278 | io0_dout = buffer[4]; |
| 279 | io1_dout = buffer[5]; |
| 280 | io2_dout = buffer[6]; |
| 281 | io3_dout = buffer[7]; |
| 282 | end |
| 283 | default: begin |
| 284 | io0_oe = 0; |
| 285 | io1_oe = 0; |
| 286 | io2_oe = 0; |
| 287 | io3_oe = 0; |
| 288 | end |
| 289 | endcase |
| 290 | end |
| 291 | end |
| 292 | |
| 293 | always @(posedge clk) begin |
| 294 | if (!csb) begin |
| 295 | if (dummycount > 0) begin |
| 296 | dummycount = dummycount - 1; |
| 297 | end else |
| 298 | case (spi_mode) |
| 299 | sspi: begin |
| 300 | buffer = {buffer, io0}; |
| 301 | bitcount = bitcount + 1; |
| 302 | if (bitcount == 8) begin |
| 303 | bitcount = 0; |
| 304 | bytecount = bytecount + 1; |
| 305 | spi_action; |
| 306 | end |
| 307 | end |
| 308 | dspi: begin |
| 309 | buffer = {buffer, io1, io0}; |
| 310 | bitcount = bitcount + 2; |
| 311 | if (bitcount == 8) begin |
| 312 | bitcount = 0; |
| 313 | bytecount = bytecount + 1; |
| 314 | spi_action; |
| 315 | end |
| 316 | end |
| 317 | qspi: begin |
| 318 | buffer = {buffer, io3, io2, io1, io0}; |
| 319 | bitcount = bitcount + 4; |
| 320 | if (bitcount == 8) begin |
| 321 | bitcount = 0; |
| 322 | bytecount = bytecount + 1; |
| 323 | spi_action; |
| 324 | end |
| 325 | end |
| 326 | endcase |
| 327 | end |
| 328 | end |
| 329 | endmodule |