added v2.0

This commit is contained in:
Michael Schröder
2023-01-11 11:13:09 +01:00
parent 2a5a64ca91
commit 971b323822
584 changed files with 159319 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
`include "../../01_Boolean_Logic/Nand.v"
`include "../../01_Boolean_Logic/Not.v"
`include "../../01_Boolean_Logic/Buffer.v"
`include "../../01_Boolean_Logic/And.v"
`include "../../01_Boolean_Logic/Or.v"
`include "../../01_Boolean_Logic/Xor.v"
`include "../../01_Boolean_Logic/Mux.v"
`include "../../01_Boolean_Logic/DMux.v"
`include "../../01_Boolean_Logic/Not16.v"
`include "../../01_Boolean_Logic/Buffer16.v"
`include "../../01_Boolean_Logic/And16.v"
`include "../../01_Boolean_Logic/Or16.v"
`include "../../01_Boolean_Logic/Mux16.v"
`include "../../01_Boolean_Logic/Or8Way.v"
`include "../../01_Boolean_Logic/Mux4Way16.v"
`include "../../01_Boolean_Logic/Mux8Way16.v"
`include "../../01_Boolean_Logic/DMux4Way.v"
`include "../../01_Boolean_Logic/DMux8Way.v"
`include "../../02_Boolean_Arithmetic/HalfAdder.v"
`include "../../02_Boolean_Arithmetic/FullAdder.v"
`include "../../02_Boolean_Arithmetic/Add16.v"
`include "../../02_Boolean_Arithmetic/Inc16.v"
`include "../../02_Boolean_Arithmetic/ALU.v"
`include "../../03_Sequential_Logic/DFF.v"
`include "../../03_Sequential_Logic/Bit.v"
`include "../../03_Sequential_Logic/Register.v"
`include "../../03_Sequential_Logic/PC.v"
`include "../../03_Sequential_Logic/BitShift9R.v"
`include "../../03_Sequential_Logic/BitShift8L.v"
`include "../../06_IO_Devices/UartTX.v"
`include "../../06_IO_Devices/UartRX.v"
`include "../../06_IO_Devices/SPI.v"
`include "../../06_IO_Devices/InOut.v"
`include "../../06_IO_Devices/SRAM_D.v"
`include "../../06_IO_Devices/GO.v"
`include "../../06_IO_Devices/LCD.v"
`include "../../06_IO_Devices/RTP.v"

View File

@@ -0,0 +1,12 @@
NAME = cat
all: asm install
asm:
../../tools/Assembler/assembler.pyc $(NAME).asm
install:
cp $(NAME).hack ../00_HACK/ROM.hack
clean:
rm -f *.hack *~
.PHONY: all clean

View File

@@ -0,0 +1,119 @@
## 03 SPI
The special function register `SPI` memory mapped to address 4100 enables HACK to read/write bytes from the spi flash memory chip W25Q16BV situated on iCE40HX1K-EVB. The timing diagramm for SPI communication looks like the following diagram (we use CPOL=0 and CPHA=0).
![](spi-timing.png)
### Chip specification
| IN/OUT | wire | function |
| ------ | -------- | ------------------------------------------- |
| IN | in[7:0] | byte to be sent. |
| IN | in[8] | =1 send byte and set CSX low |
| IN | in[8] | =0 pull CSX high without sending byte |
| IN | load | =1 initiates the transmission, when in[8]=1 |
| OUT | out[15] | =0 chip is busy, =0 chip is ready |
| OUT | out[7:0] | received byte (when out[15]=0) |
| OUT | CSX | chip select not |
| OUT | SDO | serial data out |
| OUT | SCK | serial clock |
| IN | SDI | serial data in |
When load=1 and in[8]=0 transmission of byte in[7:0] is initiated. CSX is goes low (and stays low even when transmission is completed). The byte is send to SDO bitwise together with 8 clock signals on SCK. At the same time the SPI receives a byte at SDI. During transmission out[15] is 1. After 16 clock cycles the transmission of one byte is completed. out[15] goes low and SPI outputs the received byte to out[7:0].
When load=1 and in[8]=1 CSX goes high without transmission of any bit.
**Attention:** Sampling of SDO is done at rising edge of SCK and shifting is done at falling edge of SCK.
### Proposed Implementation
Use a `Bit` to store the state (0 = ready, 1 = busy) which is output to out[15]. Use a counter `PC` to count from 0 to 15. Finally we need a `BitShift8L`. This will be loaded with the byte in[7:0] to be send. Another `Bit` will sample the SDI wire when SCK=0 and shift the stored bit into the `BitShift8L` when SCK=1. After 8 bits are transmitted the module cleares out[15] and outputs the received byte to out[7:0].
![](SPI.png)
### Memory map
The special function register `SPI` is mapped to memory map of HACK according to:
| address | I/O device | R/W | function |
| ------- | ---------- | --- | ----------------------------------------- |
| 4100 | SPI | R | out[15]=1 if busy, out[7:0] received byte |
| 4100 | SPI | W | start transmittion of byte in[7:0] |
### cat.asm
To test HACK with SPI we need a little machine language programm `cat.asm`, which reads 4 consecutive bytes of SPI flash memory chip W25Q16BV of iCE40HX1K-EVB, starting at address 0x040000 (256k) and sends them to UART_TX.
According to the datasheet of spi flash rom chip W25Q16BV the commands needed to read the flash rom chip are:
| command | function |
| ------------------- | ---------------------------------------------------------------------- |
| 0xAB | wake up from deep power down (wait 3us) before launching next command. |
| 0x03 0x04 0x00 0x00 | read data (command 0x03) starting at address 0x040000 (256k) |
| 0xB9 | go in power down |
### SPI in real hardware
The board iCE40HX1K-EVB comes with a SPI flash rom chip W25Q16BV. The chip is already connected to iCE40HX1K according `iCE40HX1K-EVB.pcf` (Compare with schematic [iCE40HX1K_EVB](../../doc/iCE40HX1K-EVB_Rev_B.pdf).
```
set_io SPI_SDO 45 # iCE40-SDO
set_io SPI_SDI 46 # iCE40-SDI
set_io SPI_SCK 48 # iCE40-SCK
set_io SPI_CSX 49 # iCE40-SS_B
```
***
### Project
* Implement `SPI.v` and test with testbench:
```
$ cd 03_SPI
$ apio clean
$ apio sim
```
* Compare output `OUT` of special function tregister `SPI` with `CMP`.
![](spi_tb.png)
* Add special function register`SPI` to `HACK.v` at memory address 4100.
* Implement `cat.asm` and test in simulation:
```
$ cd 03_SPI
$ make
$ cd ../00_HACK
$ apio clean
$ apio sim
```
* Check the wake up command 0xAB:
![](spi_wakeup.png)
* Check command 0x03040000 (read from address 0x040000)
![](spi_read040000.png)
* Check reading of string "SPI!" output to UartTX.
![](echo.png)
* preload the SPI memory chip with some text file at address 0x040000.
* build and upload HACK with `cat.asm` in ROM.BIN to iCE40HX1K-EVB.
```
$ echo SPI! > spi.txt
$ iceprogduino -o 256k -w spi.txt
$ cd 00_HACK
$ apio clean
$ apio upload
$ tio /dev/ttyACM0
```
* Check if you see "SPI!" in your terminal.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,48 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Fri Dec 30 13:39:55 2022
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/03_SPI/SPI_tb.vcd"
[dumpfile_mtime] "Fri Dec 30 13:39:20 2022"
[dumpfile_size] 238580
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/03_SPI/SPI_tb.gtkw"
[timestart] 0
[size] 1606 597
[pos] 88 59
*-19.000000 107000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[sst_width] 281
[signals_width] 160
[sst_expanded] 1
[sst_vpaned_height] 132
@28
SPI_tb.clk
@200
-IN
@28
SPI_tb.load
@22
SPI_tb.in[15:0]
@28
SPI_tb.SDI
@200
-OUT
@28
SPI_tb.CSX
SPI_tb.SDO
SPI_tb.SCK
@22
SPI_tb.out[15:0]
@200
-CMP
@28
SPI_tb.CSX_cmp
SPI_tb.SDO_cmp
SPI_tb.SCK_cmp
@22
SPI_tb.out_cmp[15:0]
@200
-Test
@29
SPI_tb.fail
[pattern_trace] 1
[pattern_trace] 0

View File

@@ -0,0 +1,81 @@
`timescale 10ns/1ns
`default_nettype none
module SPI_tb();
// IN,OUT
reg clk = 0;
reg load = 0;
reg [15:0] in = 0;
wire [15:0] out;
wire CSX;
wire SDO;
reg SDI=0;
wire SCK;
// Part
SPI SPI(
.clk(clk),
.load(load),
.in(in),
.out(out),
.CSX(CSX),
.SDO(SDO),
.SDI(SDI),
.SCK(SCK)
);
// Simulate
always #2 clk=~clk;
wire trigger;
assign trigger = (n==20) || (n==40) || (n==60) || (n==80) || (n==100);
always @(posedge clk) begin
in <= $random;
load <= trigger;
SDI <= $random;
end
// Compare
reg[4:0] bits=0;
always @(posedge clk)
bits <= (load&~in[8])?1:((bits==16)?0:(busy?bits+1:0));
wire busy=|bits;
wire [15:0] out_cmp = {busy,7'd0,shift};
reg [7:0] shift=0;
reg miso_s;
always @(posedge clk)
miso_s <= SDI;
always @(posedge clk)
shift <= load?in[7:0]:(~SCK_cmp?shift:{shift[6:0],miso_s});
wire SCK_cmp=busy&~bits[0];
reg CSX_cmp=1;
always @(posedge clk)
CSX_cmp<=load?in[8]:CSX_cmp;
wire SDO_cmp=shift[7];
reg fail = 0;
reg [31:0] n = 0;
task check;
#4
if ((out!=out_cmp)||(SCK!=SCK_cmp)||(SDO!=SDO_cmp)||(CSX!=CSX_cmp))
begin
$display("FAIL: clk=%1b, load=%1b, in=%16b, out=%16b, CSX=%1b, SDO=%1b, SDI=%1b, SCK=%1b",clk,load,in,out,CSX,SDO,SDI,SCK);
fail=1;
end
endtask
initial begin
$dumpfile("SPI_tb.vcd");
$dumpvars(0, SPI_tb);
$display("------------------------");
$display("Testbench: SPI");
for (n=0; n<400;n=n+1)
check();
if (fail==0) $display("passed");
$display("------------------------");
$finish;
end
endmodule

View File

@@ -0,0 +1,3 @@
[env]
board = iCE40-HX1K-EVB

View File

@@ -0,0 +1,6 @@
// cat.asm
//
// load spi flash rom starting at address 0x040000 and write the
// data to UART_TX
//
// Put your code here:

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB