├── .gitignore ├── LICENSE ├── README.md └── src ├── flash_a.v ├── flash_b.v └── test_tf.v /.gitignore: -------------------------------------------------------------------------------- 1 | work/ 2 | m25p64/ 3 | *swp 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Opal Kelly Incorporated 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # * Repository moved to design-resources * 2 | [SPIFlashController new location](https://github.com/opalkelly-opensource/design-resources/tree/main/HDLComponents/SPIFlashController) 3 | 4 | SPIFlashController Software Distribution 5 | ======================================== 6 | This is a SPI Flash Controller designed to brdige a basic FIFO interface 7 | and a SPI Flash device. The sources are relatively FPGA agnostic. 8 | 9 | This controller has been verified in FPGA hardware with multiple 10 | [Opal Kelly](https://www.opalkelly.com) devices. 11 | 12 | 13 | Simulation 14 | ---------- 15 | A test fixture is provided for the controller in the Simulation folder. 16 | This text fixture is designed to interact with a SPI flash simulation 17 | model (see below). This test is intended to demonstrate usage of the SPI 18 | flash controller only and is not indended to be used in verification. 19 | 20 | 21 | SPI Flash Device Simulation Models 22 | ---------------------------------- 23 | Simulation Models for Micron SPI Flash devices are used in the simulation 24 | of the controller. These models may be downloaded directly from Micron and 25 | are not included in this distribution. 26 | 27 | License 28 | ------- 29 | This project is released under the [MIT License](https://opensource.org/licenses/MIT). 30 | Please see the LICENSE file for more information. 31 | -------------------------------------------------------------------------------- /src/flash_a.v: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------ 2 | // flash_a.v 3 | // This is the flash "A" controller which handles the flash communication 4 | // at the bit level. Byte-wide requests are made to this controller 5 | // by the "B" controller which handles more elaborate commands. 6 | //------------------------------------------------------------------------ 7 | // Slices: 8 | // Slice FFs: 9 | // 4-LUTs: 10 | //------------------------------------------------------------------------ 11 | // Copyright (c) 2005-2017 Opal Kelly Incorporated 12 | // 13 | // Permission is hereby granted, free of charge, to any person obtaining a copy 14 | // of this software and associated documentation files (the "Software"), to deal 15 | // in the Software without restriction, including without limitation the rights 16 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | // copies of the Software, and to permit persons to whom the Software is 18 | // furnished to do so, subject to the following conditions: 19 | // 20 | // The above copyright notice and this permission notice shall be included in all 21 | // copies or substantial portions of the Software. 22 | // 23 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | // SOFTWARE. 30 | //------------------------------------------------------------------------ 31 | 32 | `default_nettype none 33 | `timescale 1ns / 1ps 34 | module flash_a( 35 | input wire clk, 36 | input wire reset, 37 | 38 | input wire write, 39 | input wire read, 40 | input wire deselect, 41 | input wire [7:0] din, 42 | output reg [7:0] dout, 43 | output reg done, 44 | 45 | // Flash interface 46 | input wire flash_q, 47 | output reg flash_c, 48 | output reg flash_s_n, 49 | output reg flash_d 50 | ); 51 | 52 | 53 | reg des; 54 | reg [7:0] shift; 55 | reg [3:0] count; 56 | reg [3:0] descount; 57 | 58 | parameter s_idle = 0, 59 | s_write1 = 1, 60 | s_write2 = 2, 61 | s_read1 = 3, 62 | s_read1a = 4, 63 | s_read2 = 5, 64 | s_deselect = 6; 65 | reg [31:0] state; 66 | always @(posedge clk) begin 67 | if (reset == 1'b1) begin 68 | state <= s_idle; 69 | done <= 1'b0; 70 | des <= 1'b0; 71 | shift <= 8'b0; 72 | flash_c <= 1'b0; 73 | flash_d <= 1'b0; 74 | flash_s_n <= 1'b1; 75 | end else begin 76 | done <= 1'b0; 77 | 78 | case (state) 79 | s_idle: begin 80 | flash_c <= 1'b0; 81 | shift <= din; 82 | count <= 7; 83 | descount <= 10; 84 | des <= deselect; 85 | if (deselect == 1'b1) begin 86 | descount <= 10; 87 | end else begin 88 | descount <= 0; 89 | end 90 | 91 | if (write == 1'b1) begin 92 | state <= s_write1; 93 | flash_s_n <= 1'b0; 94 | end else if (read == 1'b1) begin 95 | state <= s_read1; 96 | flash_s_n <= 1'b0; 97 | end 98 | end 99 | 100 | s_write1: begin 101 | state <= s_write2; 102 | flash_c <= 1'b0; 103 | flash_d <= shift[7]; 104 | shift <= {shift[6:0], 1'b0}; 105 | end 106 | 107 | s_write2: begin 108 | count <= count - 1; 109 | flash_c <= 1'b1; 110 | if (count == 0) begin 111 | state <= s_deselect; 112 | end else begin 113 | state <= s_write1; 114 | end 115 | end 116 | 117 | s_read1: begin 118 | state <= s_read1a; 119 | end 120 | 121 | s_read1a: begin 122 | state <= s_read2; 123 | flash_c <= 1'b1; 124 | shift <= {shift[6:0], flash_q}; 125 | end 126 | 127 | s_read2: begin 128 | flash_c <= 1'b0; 129 | count <= count - 1; 130 | if (count == 0) begin 131 | dout <= shift; 132 | state <= s_deselect; 133 | end else begin 134 | state <= s_read1; 135 | end 136 | end 137 | 138 | s_deselect: begin 139 | flash_c <= 1'b0; 140 | descount <= descount - 1; 141 | flash_s_n <= des; 142 | if (descount == 0) begin 143 | done <= 1'b1; 144 | state <= s_idle; 145 | end 146 | end 147 | 148 | endcase 149 | end 150 | 151 | end 152 | 153 | endmodule 154 | `default_nettype wire 155 | -------------------------------------------------------------------------------- /src/flash_b.v: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------ 2 | // flash_b.v 3 | // This is the flash "B" controller which handles the macro commands 4 | // to the flash device. This includes full commands such as 5 | // sector erase, page program, and so on. 6 | // 7 | // This controller uses the "A" controller for direct control of the 8 | // flash. 9 | // 10 | // Commands: 11 | // ERASE_SECTORS 12 | // + ADDR is the sector address to start erasing (0..127) 13 | // + LENGTH is the number of sectors to erase in sequence 14 | // WRITE 15 | // + ADDR is the page address to start writing (0..65535) 16 | // + LENGTH is the number of full (256-byte) pages to write. 17 | // READ 18 | // + ADDR is the page address to start reading (0..65535) 19 | // + LENGTH is the number of full (256-byte) pages to read. 20 | //------------------------------------------------------------------------ 21 | // Copyright (c) 2005-2017 Opal Kelly Incorporated 22 | // 23 | // Permission is hereby granted, free of charge, to any person obtaining a copy 24 | // of this software and associated documentation files (the "Software"), to deal 25 | // in the Software without restriction, including without limitation the rights 26 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 27 | // copies of the Software, and to permit persons to whom the Software is 28 | // furnished to do so, subject to the following conditions: 29 | // 30 | // The above copyright notice and this permission notice shall be included in all 31 | // copies or substantial portions of the Software. 32 | // 33 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 35 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 36 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 37 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 38 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 39 | // SOFTWARE. 40 | //------------------------------------------------------------------------ 41 | 42 | `default_nettype none 43 | `timescale 1ns / 1ps 44 | module flash_b( 45 | input wire clk, 46 | input wire reset, 47 | 48 | input wire cmd_erasesectors, 49 | input wire cmd_write, 50 | input wire cmd_read, 51 | input wire [15:0] addr, 52 | input wire [15:0] length, 53 | input wire [7:0] din, 54 | output reg [7:0] dout, 55 | output reg read, 56 | output reg write, 57 | output reg done, 58 | output wire [15:0] status, 59 | 60 | // Flash interface 61 | input wire flash_q, 62 | output wire flash_c, 63 | output wire flash_s_n, 64 | output wire flash_d 65 | ); 66 | 67 | reg a_write; 68 | reg a_read; 69 | reg a_deselect; 70 | wire a_done; 71 | wire [7:0] a_dout; 72 | reg [7:0] a_din; 73 | 74 | reg [15:0] count_a; 75 | reg [15:0] count_b; 76 | reg [23:0] count_c; 77 | 78 | assign status = count_b; 79 | 80 | flash_a f0( 81 | .clk(clk), 82 | .reset(reset), 83 | .write(a_write), 84 | .read(a_read), 85 | .deselect(a_deselect), 86 | .din(a_din), 87 | .dout(a_dout), 88 | .done(a_done), 89 | .flash_c(flash_c), 90 | .flash_s_n(flash_s_n), 91 | .flash_d(flash_d), 92 | .flash_q(flash_q)); 93 | 94 | parameter s_idle = 0, 95 | s_erase1 = 1, 96 | s_erase1w = 2, 97 | s_erase2 = 3, 98 | s_erase2w = 4, 99 | s_erase3 = 5, 100 | s_erase3w = 6, 101 | s_erase4 = 7, 102 | s_erase4w = 8, 103 | s_erase5 = 9, 104 | s_erase5w = 10, 105 | s_erase6 = 11, 106 | s_erase6w = 12, 107 | s_erase7 = 13, 108 | s_erase7w = 14, 109 | s_erase8 = 15, 110 | 111 | s_write1 = 20, 112 | s_write1w = 21, 113 | s_write2 = 22, 114 | s_write2w = 23, 115 | s_write3 = 24, 116 | s_write3w = 25, 117 | s_write4 = 26, 118 | s_write4w = 27, 119 | s_write5 = 28, 120 | s_write5w = 29, 121 | s_write6 = 30, 122 | s_write6w = 31, 123 | s_write7 = 32, 124 | s_write7w = 33, 125 | s_write8 = 34, 126 | s_write8w = 35, 127 | s_write9 = 36, 128 | 129 | s_read1 = 40, 130 | s_read1w = 41, 131 | s_read2 = 42, 132 | s_read2w = 43, 133 | s_read3 = 44, 134 | s_read3w = 45, 135 | s_read4 = 46, 136 | s_read4w = 47, 137 | s_read5 = 48, 138 | s_read5w = 49, 139 | s_read6 = 50, 140 | s_read6w = 51, 141 | s_read7 = 52; 142 | reg [31:0] state; 143 | always @(posedge clk) begin 144 | if (reset == 1'b1) begin 145 | state <= s_idle; 146 | done <= 1'b0; 147 | read <= 1'b0; 148 | write <= 1'b0; 149 | end else begin 150 | done <= 1'b0; 151 | read <= 1'b0; 152 | write <= 1'b0; 153 | a_write <= 1'b0; 154 | a_read <= 1'b0; 155 | a_deselect <= 1'b0; 156 | 157 | case (state) 158 | s_idle: begin 159 | if (cmd_erasesectors == 1'b1) begin 160 | state <= s_erase1; 161 | count_a <= addr; 162 | count_b <= length; 163 | end else if (cmd_write == 1'b1) begin 164 | state <= s_write1; 165 | count_a <= addr; 166 | count_b <= length; 167 | end else if (cmd_read == 1'b1) begin 168 | state <= s_read1; 169 | count_a <= addr; 170 | count_c <= {length, 8'hff}; 171 | end 172 | end 173 | 174 | //=============================================================== 175 | // ERASE SECTORS 176 | //=============================================================== 177 | // WREN 178 | s_erase1: begin 179 | a_write <= 1'b1; 180 | a_deselect <= 1'b1; 181 | a_din <= 8'h06; 182 | state <= s_erase1w; 183 | end 184 | s_erase1w: begin 185 | if (a_done == 1'b1) 186 | state <= s_erase2; 187 | end 188 | 189 | // SE 190 | s_erase2: begin 191 | a_write <= 1'b1; 192 | a_din <= 8'hd8; 193 | state <= s_erase2w; 194 | end 195 | s_erase2w: begin 196 | if (a_done == 1'b1) 197 | state <= s_erase3; 198 | end 199 | 200 | // ADDR[23:16] 201 | s_erase3: begin 202 | a_write <= 1'b1; 203 | a_din <= count_a[7:0]; 204 | state <= s_erase3w; 205 | end 206 | s_erase3w: begin 207 | if (a_done == 1'b1) 208 | state <= s_erase4; 209 | end 210 | 211 | // ADDR[15:8] 212 | s_erase4: begin 213 | a_write <= 1'b1; 214 | a_din <= 8'h00; 215 | state <= s_erase4w; 216 | end 217 | s_erase4w: begin 218 | if (a_done == 1'b1) 219 | state <= s_erase5; 220 | end 221 | 222 | // ADDR[7:0] 223 | s_erase5: begin 224 | a_write <= 1'b1; 225 | a_din <= 8'h00; 226 | a_deselect <= 1'b1; 227 | state <= s_erase5w; 228 | end 229 | s_erase5w: begin 230 | if (a_done == 1'b1) 231 | state <= s_erase6; 232 | end 233 | 234 | // RDSR 235 | s_erase6: begin 236 | a_write <= 1'b1; 237 | a_din <= 8'h05; 238 | state <= s_erase6w; 239 | end 240 | s_erase6w: begin 241 | if (a_done == 1'b1) 242 | state <= s_erase7; 243 | end 244 | 245 | s_erase7: begin 246 | a_read <= 1'b1; 247 | a_deselect <= 1'b1; 248 | state <= s_erase7w; 249 | end 250 | s_erase7w: begin 251 | if (a_done == 1'b1) begin 252 | if (a_dout[0] == 1'b1) 253 | state <= s_erase6; 254 | else 255 | state <= s_erase8; 256 | end 257 | end 258 | 259 | // Loop until all requested sectors are erased. 260 | s_erase8: begin 261 | count_b <= count_b - 1; 262 | count_a <= count_a + 1; 263 | if (count_b == 0) begin 264 | state <= s_idle; 265 | done <= 1'b1; 266 | end else begin 267 | state <= s_erase1; 268 | end 269 | end 270 | 271 | 272 | //=============================================================== 273 | // WRITE DATA 274 | //=============================================================== 275 | // WREN 276 | s_write1: begin 277 | a_write <= 1'b1; 278 | a_deselect <= 1'b1; 279 | a_din <= 8'h06; 280 | state <= s_write1w; 281 | end 282 | s_write1w: begin 283 | if (a_done == 1'b1) 284 | state <= s_write2; 285 | end 286 | 287 | // PP 288 | s_write2: begin 289 | a_write <= 1'b1; 290 | a_din <= 8'h02; 291 | state <= s_write2w; 292 | end 293 | s_write2w: begin 294 | if (a_done == 1'b1) 295 | state <= s_write3; 296 | end 297 | 298 | // ADDR[23:16] 299 | s_write3: begin 300 | a_write <= 1'b1; 301 | a_din <= count_a[15:8]; 302 | state <= s_write3w; 303 | end 304 | s_write3w: begin 305 | if (a_done == 1'b1) 306 | state <= s_write4; 307 | end 308 | 309 | // ADDR[15:8] 310 | s_write4: begin 311 | a_write <= 1'b1; 312 | a_din <= count_a[7:0]; 313 | state <= s_write4w; 314 | end 315 | s_write4w: begin 316 | if (a_done == 1'b1) 317 | state <= s_write5; 318 | end 319 | 320 | // ADDR[7:0] 321 | s_write5: begin 322 | a_write <= 1'b1; 323 | a_din <= 8'h00; 324 | read <= 1'b1; // Gets the first data word ready. 325 | state <= s_write5w; 326 | end 327 | s_write5w: begin 328 | if (a_done == 1'b1) begin 329 | state <= s_write6; 330 | count_c <= 8'd255; 331 | end 332 | end 333 | 334 | // DATA[0..255] 335 | s_write6: begin 336 | state <= s_write6w; 337 | a_write <= 1'b1; 338 | a_din <= din; 339 | if (count_c == 0) begin 340 | a_deselect <= 1'b1; 341 | end else begin 342 | read <= 1'b1; // Gets next word from memory. 343 | end 344 | end 345 | s_write6w: begin 346 | if (a_done == 1'b1) begin 347 | count_c <= count_c - 1; 348 | if (count_c == 0) begin 349 | state <= s_write7; 350 | end else begin 351 | state <= s_write6; 352 | end 353 | end 354 | end 355 | 356 | // RDSR 357 | s_write7: begin 358 | a_write <= 1'b1; 359 | a_din <= 8'h05; 360 | state <= s_write7w; 361 | end 362 | s_write7w: begin 363 | if (a_done == 1'b1) 364 | state <= s_write8; 365 | end 366 | 367 | s_write8: begin 368 | a_read <= 1'b1; 369 | a_deselect <= 1'b1; 370 | state <= s_write8w; 371 | end 372 | s_write8w: begin 373 | if (a_done == 1'b1) begin 374 | if (a_dout[0] == 1'b1) 375 | state <= s_write7; 376 | else 377 | state <= s_write9; 378 | end 379 | end 380 | 381 | // Loop until all pages have been written 382 | s_write9: begin 383 | count_a <= count_a + 1; 384 | count_b <= count_b - 1; 385 | if (count_b == 0) begin 386 | done <= 1'b1; 387 | state <= s_idle; 388 | end else begin 389 | state <= s_write1; 390 | end 391 | end 392 | 393 | 394 | //=============================================================== 395 | // READ DATA 396 | //=============================================================== 397 | // FAST_READ 398 | s_read1: begin 399 | a_write <= 1'b1; 400 | a_din <= 8'h0b; 401 | state <= s_read1w; 402 | end 403 | s_read1w: begin 404 | if (a_done == 1'b1) 405 | state <= s_read2; 406 | end 407 | 408 | // ADDR[23:16] 409 | s_read2: begin 410 | a_write <= 1'b1; 411 | a_din <= count_a[15:8]; 412 | state <= s_read2w; 413 | end 414 | s_read2w: begin 415 | if (a_done == 1'b1) 416 | state <= s_read3; 417 | end 418 | 419 | // ADDR[15:8] 420 | s_read3: begin 421 | a_write <= 1'b1; 422 | a_din <= count_a[7:0]; 423 | state <= s_read3w; 424 | end 425 | s_read3w: begin 426 | if (a_done == 1'b1) 427 | state <= s_read4; 428 | end 429 | 430 | // ADDR[7:0] 431 | s_read4: begin 432 | a_write <= 1'b1; 433 | a_din <= 8'h00; 434 | state <= s_read4w; 435 | end 436 | s_read4w: begin 437 | if (a_done == 1'b1) begin 438 | state <= s_read5; 439 | end 440 | end 441 | 442 | // DUMMY 443 | s_read5: begin 444 | a_read <= 1'b1; 445 | state <= s_read5w; 446 | end 447 | s_read5w: begin 448 | if (a_done == 1'b1) begin 449 | state <= s_read6; 450 | end 451 | end 452 | 453 | // DATA[n] 454 | s_read6: begin 455 | a_read <= 1'b1; 456 | state <= s_read6w; 457 | if (count_c == 0) begin 458 | a_deselect <= 1'b1; 459 | end 460 | end 461 | s_read6w: begin 462 | if (a_done == 1'b1) begin 463 | write <= 1'b1; 464 | dout <= a_dout; 465 | state <= s_read7; 466 | end 467 | end 468 | 469 | s_read7: begin 470 | count_c <= count_c - 1; 471 | if (count_c == 0) begin 472 | state <= s_idle; 473 | done <= 1'b1; 474 | end else begin 475 | state <= s_read6; 476 | end 477 | end 478 | 479 | endcase 480 | end 481 | 482 | end 483 | 484 | endmodule 485 | `default_nettype wire 486 | -------------------------------------------------------------------------------- /src/test_tf.v: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------ 2 | // test_tf.v 3 | // 4 | // This is a simple test fixture designed to demonstrate usage of the 5 | // flash controller. This is not intended to be an exhaustive test for 6 | // verification purposes. 7 | //------------------------------------------------------------------------ 8 | // Copyright (c) 2017 Opal Kelly Incorporated 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | //------------------------------------------------------------------------ 29 | 30 | `default_nettype none 31 | `timescale 1ns / 1ps 32 | 33 | module tf; 34 | reg clk; 35 | reg rst; 36 | reg cmd_erase; 37 | reg cmd_read; 38 | reg cmd_write; 39 | reg [15:0] cmd_addr; 40 | reg [15:0] cmd_length; 41 | 42 | reg [7:0] fifo_din; 43 | wire [7:0] fifo_dout; 44 | wire fifo_read; 45 | wire fifo_write; 46 | wire done; 47 | wire [15:0] status; 48 | 49 | wire flash_q, flash_c, flash_s_n, flash_d; 50 | 51 | 52 | //------------------------------------------------------------------------ 53 | // DUT 54 | //------------------------------------------------------------------------ 55 | flash_b dut ( 56 | .clk (clk), 57 | .reset (rst), 58 | 59 | .cmd_erasesectors (cmd_erase), 60 | .cmd_write (cmd_write), 61 | .cmd_read (cmd_read), 62 | .addr (cmd_addr), 63 | .length (cmd_length), 64 | 65 | // For this test/demonstration the din input is fixed to a single 66 | // value. It is relatively simple to generate a FIFO for a given 67 | // FPGA architecture and connect it to the signals below. 68 | .din (fifo_din), 69 | .dout (fifo_dout), 70 | .read (fifo_read), 71 | .write (fifo_write), 72 | 73 | .done (done), 74 | .status (status), 75 | 76 | .flash_q (flash_q), 77 | .flash_c (flash_c), 78 | .flash_s_n (flash_s_n), 79 | .flash_d (flash_d) 80 | ); 81 | 82 | M25P64 flash0 ( 83 | .c (flash_c), 84 | .data_in (flash_d), 85 | .data_out (flash_q), 86 | .s (flash_s_n), 87 | .w (1'b1), 88 | .hold (1'b1) 89 | ); 90 | 91 | 92 | // Clock Generation 93 | parameter tCLK = 10; 94 | initial clk = 0; 95 | always #(tCLK/2.0) clk = ~clk; 96 | 97 | initial cmd_erase = 1'b0; 98 | initial cmd_read = 1'b0; 99 | initial cmd_write = 1'b0; 100 | initial cmd_addr = 16'h00; 101 | initial cmd_length = 16'h00; 102 | 103 | 104 | initial begin 105 | //$dumpfile("dump.vcd"); $dumpvars; 106 | rst = 1'b1; 107 | #100; 108 | rst = 1'b0; 109 | #100; 110 | 111 | // Erase 8 sectors starting at sector 0 (each sector is 256 KiB) 112 | @(posedge clk); 113 | cmd_erase = 1'b1; 114 | cmd_addr = 16'h00; 115 | cmd_length = 16'h8; 116 | 117 | @(posedge clk); 118 | cmd_erase = 1'b0; 119 | 120 | // Wait done 121 | while(done == 1'b0) begin 122 | #tCLK; 123 | end 124 | 125 | // Write 0xBE to page 0x10 126 | @(posedge clk); 127 | cmd_write = 1'b1; 128 | cmd_addr = 16'h10; 129 | cmd_length = 1; 130 | fifo_din = 8'hBE; // This can be replaced with a FIFO for data transfer 131 | 132 | @(posedge clk); 133 | cmd_write = 1'b0; 134 | 135 | // Wait done 136 | while(done == 1'b0) begin 137 | #tCLK; 138 | end 139 | 140 | // Read 0x0F-0x11 141 | @(posedge clk); 142 | cmd_read = 1'b1; 143 | cmd_addr = 16'h0F; 144 | cmd_length = 8'h03; 145 | 146 | @(posedge clk); 147 | cmd_read = 1'b0; 148 | 149 | // Wait done 150 | while(done == 1'b0) begin 151 | #tCLK; 152 | end 153 | 154 | $finish; 155 | end 156 | 157 | 158 | endmodule 159 | --------------------------------------------------------------------------------