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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View File

@@ -0,0 +1,72 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Thu Dec 29 16:29:18 2022
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/00_HACK/HACK_tb.vcd"
[dumpfile_mtime] "Thu Dec 29 16:28:24 2022"
[dumpfile_size] 83632917
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/00_HACK/HACK_tb.gtkw"
[timestart] 281880000
[size] 1920 963
[pos] -1 -1
*-24.000000 40600000 -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
[treeopen] HACK_tb.
[sst_width] 281
[signals_width] 180
[sst_expanded] 1
[sst_vpaned_height] 259
@200
-GPIO
@28
HACK_tb.BUT[1:0]
HACK_tb.LED[1:0]
@200
-UART
@28
HACK_tb.UART_TX
HACK_tb.UART_RX
@200
-SPI
@28
HACK_tb.SPI_CSX
HACK_tb.SPI_SDI
HACK_tb.SPI_SDO
HACK_tb.SPI_SCK
@200
-SRAM
@22
HACK_tb.SRAM_ADDR[17:0]
@28
HACK_tb.SRAM_CSX
HACK_tb.SRAM_OEX
HACK_tb.SRAM_WEX
@22
HACK_tb.SRAM_DATA[15:0]
@200
-GO
@28
HACK_tb.HACK.loadGO
@200
-DEBUG
@28
HACK_tb.HACK.loadDEBUG0
@820
HACK_tb.HACK.outDEBUG0[15:0]
@28
HACK_tb.HACK.loadDEBUG1
@24
HACK_tb.HACK.outDEBUG1[15:0]
@28
HACK_tb.HACK.loadDEBUG2
@24
HACK_tb.HACK.outDEBUG2[15:0]
@28
HACK_tb.HACK.loadDEBUG3
@24
HACK_tb.HACK.outDEBUG3[15:0]
@28
HACK_tb.HACK.loadDEBUG4
@24
HACK_tb.HACK.outDEBUG4[15:0]
[pattern_trace] 1
[pattern_trace] 0

View File

@@ -0,0 +1,121 @@
`timescale 10ns/1ns
`default_nettype none
module HACK_tb();
// IN,OUT
reg CLK = 1;
reg [1:0] BUT = 3;
wire [1:0] LED;
wire UART_TX;
wire UART_RX;
wire SPI_SDO;
wire SPI_SDI;
wire SPI_SCK;
wire SPI_CSX;
wire [17:0] SRAM_ADDR;
wire [15:0] SRAM_DATA;
wire SRAM_WEX;
wire SRAM_OEX;
wire SRAM_CSX;
wire LCD_DCX;
wire LCD_SDO;
wire LCD_SCK;
wire LCD_CSX;
reg RTP_SDI;
wire RTP_SDO;
wire RTP_SCK;
// Part
HACK HACK(
.CLK(CLK), // external clock 100 MHz
.BUT(BUT), // user button ("pushed down" == 0) ("up" == 1)
.LED(LED), // leds (0 off, 1 on)
.UART_RX(UART_RX), // UART receive
.UART_TX(UART_TX), // UART transmit
.SPI_SDO(SPI_SDO), // SPI serial data out
.SPI_SDI(SPI_SDI), // SPI serial data in
.SPI_SCK(SPI_SCK), // SPI serial clock
.SPI_CSX(SPI_CSX), // SPI chip select not
.SRAM_ADDR(SRAM_ADDR), // SRAM address 18 Bit = 256K
.SRAM_DATA(SRAM_DATA), // SRAM data 16 Bit
.SRAM_WEX(SRAM_WEX), // SRAM write_enable_not
.SRAM_OEX(SRAM_OEX), // SRAM output_enable_not
.SRAM_CSX(SRAM_CSX), // SRAM chip_select_not
.LCD_DCX(LCD_DCX), // LCD data/command not
.LCD_SDO(LCD_SDO), // LCD serial data out
.LCD_SCK(LCD_SCK), // LCD serial clock
.LCD_CSX(LCD_CSX), // LCD chip select not
.RTP_SDI(RTP_SDI), // RTP serial data in
.RTP_SDO(RTP_SDO), // RTP serial data out in
.RTP_SCK(RTP_SCK) // RTP serial clock
);
// Simulate
always #0.5 CLK = ~CLK;
integer n=0;
always @(posedge CLK) n=n+1;
// Compare
reg [9:0] uart=10'b1111111111;
reg [15:0] baudrate = 0;
always @(posedge CLK)
baudrate <= ((baudrate==866)?0:baudrate+1);
always @(posedge CLK) begin
uart <= (n==5000)?((82<<2)+1):(n==15000)?((88<<2)+1):((baudrate==866)?{1'b1,uart[9:1]}:uart);
end
wire shift = (baudrate==866);
assign UART_RX = uart[0];
//Simulate SPI
reg spi_sleep=1;
reg [31:0] spi_cmd=0;
reg [95:0] spi=0;
assign SPI_SDI = (SPI_CSX | spi_sleep) ? 1'bz:spi[95];
always @(posedge (SPI_SCK))
spi <= {spi[95:0],1'b0};
always @(posedge (SPI_SCK))
spi_cmd <= {spi_cmd[30:0],SPI_SDO};
always @(negedge (SPI_CSX))
spi_cmd <= 0;
always @(spi_cmd) begin
if (spi_cmd==32'h000000AB) spi_sleep <= 0;
if (spi_cmd==32'h000000B9) spi_sleep <= 1;
if (spi_cmd==32'h03040000) spi <= "SPI! 123";
if (spi_cmd==32'h03010000) spi <= 96'h1001_FC10_1000_E308_0000_EA87;
end
//Simulate SRAM
reg [16:0] sram[0:7];
always @(posedge CLK)
if (~SRAM_WEX&&SRAM_OEX&&~SRAM_CSX) sram[SRAM_ADDR] <= SRAM_DATA;
assign SRAM_DATA = (~SRAM_CSX&&~SRAM_OEX)?sram[SRAM_ADDR]:16'bzzzzzzzzzzzzzzzz;
//Simulate LCD
reg [7:0] lcd_c;
reg [15:0] lcd_d;
always @(posedge LCD_SCK) begin
lcd_c <= (~LCD_DCX)?{lcd_c[6:0],LCD_SDO}:lcd_c;
lcd_d <= (LCD_DCX)?{lcd_d[6:0],LCD_SDO}:lcd_d;
end
always @(negedge LCD_CSX) begin
lcd_c <= 0;
lcd_d <= 0;
end
//simulate BUT
always @(posedge CLK) begin
if (n==10000) BUT<=0;
if (n==20000) BUT<=1;
if (n==30000) BUT<=2;
end
initial begin
$dumpfile("HACK_tb.vcd");
$dumpvars(0, HACK_tb);
$display("------------------------");
$display("Testbench: Hack");
#40000
$finish;
end
endmodule

View File

@@ -0,0 +1,49 @@
`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/RAM256.v"
`include "../../03_Sequential_Logic/RAM512.v"
`include "../../03_Sequential_Logic/RAM3840.v"
`include "../../03_Sequential_Logic/BitShift9R.v"
`include "../../03_Sequential_Logic/BitShift8L.v"
`include "../../05_Computer_Architecture/CPU.v"
`include "../../05_Computer_Architecture/Memory.v"
`include "../../05_Computer_Architecture/ROM.v"
`include "../../05_Computer_Architecture/Clock25_Reset20.v"
`include "../../06_IO_Devices/HACK.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,3 @@
[env]
board = iCE40-HX1K-EVB

View File

@@ -0,0 +1,68 @@
# physical constrain file
# assign io-pins to pin numbering of iCE40-HX1K on olimex board iCE40HX1K-EVB
# compare to the schematic of the board and the datasheet of fpga
set_io CLK 15 # SYSCLOCK 100 MHz
set_io BUT[0] 41 # BUT1
set_io BUT[1] 42 # BUT2
set_io LED[0] 40 # LED1
set_io LED[1] 51 # LED2
set_io UART_RX 36 # PIO2_8/RxD connected to pin 3 of UEXT (PGM)
set_io UART_TX 37 # PIO2_9/TxD connected to pin 4 of UEXT (PGM)
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
set_io SRAM_ADDR[0] 79 # SA0
set_io SRAM_ADDR[1] 80 # SA1
set_io SRAM_ADDR[2] 81 # SA2
set_io SRAM_ADDR[3] 82 # SA3
set_io SRAM_ADDR[4] 83 # SA4
set_io SRAM_ADDR[5] 85 # SA5
set_io SRAM_ADDR[6] 86 # SA6
set_io SRAM_ADDR[7] 87 # SA7
set_io SRAM_ADDR[8] 89 # SA8
set_io SRAM_ADDR[9] 90 # SA9
set_io SRAM_ADDR[10] 91 # SA10
set_io SRAM_ADDR[11] 93 # SA11
set_io SRAM_ADDR[12] 94 # SA12
set_io SRAM_ADDR[13] 95 # SA13
set_io SRAM_ADDR[14] 96 # SA14
set_io SRAM_ADDR[15] 97 # SA15
set_io SRAM_ADDR[16] 99 # SA16
set_io SRAM_ADDR[17] 100 # SA17
set_io SRAM_CSX 78 # SRAM_#CS
set_io SRAM_OEX 74 # SRAM_#OE
set_io SRAM_WEX 73 # SRAM_#WE
set_io SRAM_DATA[0] 62 # SD0
set_io SRAM_DATA[1] 63 # SD1
set_io SRAM_DATA[2] 64 # SD2
set_io SRAM_DATA[3] 65 # SD3
set_io SRAM_DATA[4] 66 # SD4
set_io SRAM_DATA[5] 68 # SD5
set_io SRAM_DATA[6] 69 # SD6
set_io SRAM_DATA[7] 71 # SD7
set_io SRAM_DATA[8] 72 # SD8
set_io SRAM_DATA[9] 60 # SD9
set_io SRAM_DATA[10] 59 # SD10
set_io SRAM_DATA[11] 57 # SD11
set_io SRAM_DATA[12] 56 # SD12
set_io SRAM_DATA[13] 54 # SD13
set_io SRAM_DATA[14] 53 # SD14
set_io SRAM_DATA[15] 52 # SD15
set_io LCD_DCX 1 # PIO3_1A connected to pin 5 of GPIO1
set_io LCD_SDO 2 # PIO3_1B connected to pin 7 of GPIO1
set_io LCD_SCK 3 # PIO3_2A connected to pin 9 of GPIO1
set_io LCD_CSX 4 # PIO3_2B connected to pin 11 of GPIO1
set_io RTP_SDI 7 # PIO3_3A connected to pin 13 of GPIO1
set_io RTP_SDO 8 # PIO3_3B connected to pin 15 of GPIO1
set_io RTP_SCK 9 # PIO3_5A connected to pin 17 of GPIO1

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

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 = hello
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,111 @@
## 01 UartTX
The special function register `UartTX` mapped to memory address 4098 enables HACK to send chars to the outer world over UART with 115200 baud 8N1. The timing diagramm for the TX wire should look like:
![](timing.jpg)
During idle TX line is high (logic 1). Transmission of a byte (8 bits) is initiated by the so called start bit, which always is low (logic 0), followed by the 8 data bits, starting with the least significant bit. The transmission is finished by sending the stop bit, which always is high (logic 1).
This protocoll is refered as 8N1 meaning (8 data bits, no parity bit, 1 stop bit). We use a transmission speed of 115200 baud (bits per second), meaning that each bit takes 1s/115200 = 8.68us or 217 cycles of the internal 25MHz clock clk.
### Chip specification
| IN/OUT | wire | function |
| ------ | ------- | --------------------------------------------------- |
| IN | in[7:0] | byte to be sent. |
| IN | load | =1 initiates the transmission |
| OUT | out[15] | =1 chip is busy, =0 chip is ready to send next byte |
| OUT | TX | transmission wire |
When load = 1 the chip starts serial transmission of the byte in[7:0] to the TX line according to the protocoll 8N1 with 115200 baud. During transmission out[15] is set to high (busy). The transmission is finished after 2170 clock cycles (10 byte a 217 cycle each). When transmission completes out[15] goes low again (ready).
### Proposed Implementation
Use a `Bit` to store the state (0 = ready, 1 = busy). Use a counter `PC` to count from 0 to 216. When clocked at 25MHz, this counter will produce the baudrate of 115200 bits per second. A second counter `PC` counts from 0 to 9 (the 10 bits to send). Finally we need a `BitShift9R`. This will be loaded with the bit pattern to be send (startbit, 8 data bits).
![](UartTX.png)
### memory map
The special function register `UartTX` is mapped to memory map of HACK according to:
| address | I/O device | R/W | function |
| ------- | ---------- | --- | ------------------------------------- |
| 4098 | UART_TX | R | out[15]=1 if busy, out[15]=0 if ready |
| 4098 | UART_TX | W | send char in[7:0] to TX |
### hello.asm
To test HACK with `UartTX` we need a little machine language programm `hello.asm`, which sends the String "Hi" to UART.
**Attention:** Use a loop to wait until UartTX is ready to send the next byte.
### UartTX in real hardware
The programmer Olimexino 32u4 can also be used as bridge to connect the PC to iCE40HX1K-EVB over UART. This can be done with the 10 wire UEXT cable which goes into the PGM1 connector of iCE40HX1K-EVB.
![](ICE40PGM.jpg)
**Note:** To connect RX and TX lines of UEXT-connector with iCE40-chip on iCE40-HX1K-EVB find the solder-jumper-pads RxD_E1 and TxD_E1 near the UEXT connector (refer to [datasheets/iCE40HX1K-EVB](../datasheets/iCE40HX1K-EVB_Rev_B.pdf)) and solder them together as in the foto below.
![](UARTJumper.jpg)
The programmer olimexino 32u4 works in two different mode:
- Mode 1 (yellow led on): programmer of iCE40-board. Used with iceprogduino.
- Mode 2 (green led on): UART Bridge to iCE40 chip. Use with terminal programm (e.g. tio or screen on linux).
To switch between the modes press the hardware button on olimexino 32u4 (HWB).
Now iCE40HX1K is connected to RX,TX of olimexino 32u4 according to `iCE40HX1K-EVB.pcf`. (Check by comparing the schematic of iCE40HX1K-EVB).
```
set_io UART_RX 36 # PIO2_8/RxD connected to pin 3 of UEXT (PGM)
set_io UART_TX 37 # PIO2_9/TxD connected to pin 4 of UEXT (PGM)
```
***
### Project
* Implement `UartTX` and simulate with testbench.
```
$ cd 01_UartTX
$ apio clean
$ apio sim
```
* Compare with CMP:
![](UartTX_tb.png)
* Edit `HACK` and add the special function register `UartTX` to the memory address 4098.
* Implement `hello.asm` and run in simulation:
```
$ cd 01_UartTX
$ make
$ cd ../00_HACK
$ apio clean
$ apio sim
```
* Check the TX wire of the simulation and look for the transmission of "Hi".
![](hi.png)
* build and upload HACK with `hello.asm` in ROM.BIN to iCE40HX1K-EVB.
* switch olimexino 32u4 to UART-Bridge
* open Terminal on your computer
* press reset button on iCE40HX1K-EVB and see if wou can recieve "Hi" on your Computer.
```
$ cd 00_HACK
$ apio clean
$ apio upload
$ tio /dev/ttyACM0
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 908 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,43 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Fri Dec 23 15:04:28 2022
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris/06_IO_Devices/01_UartTX/UartTX_tb.vcd"
[dumpfile_mtime] "Fri Dec 23 15:03:47 2022"
[dumpfile_size] 3855989
[savefile] "/home/micha/gitlab/nand2tetris/06_IO_Devices/01_UartTX/UartTX_tb.gtkw"
[timestart] 0
[size] 1659 507
[pos] 165 50
*-26.000000 0 -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
[treeopen] UartTX_tb.
[sst_width] 281
[signals_width] 170
[sst_expanded] 1
[sst_vpaned_height] 108
@28
UartTX_tb.clk
@200
-IN
@28
UartTX_tb.load
@22
UartTX_tb.in[15:0]
@200
-OUT
@22
UartTX_tb.out[15:0]
@28
UartTX_tb.TX
@200
-CMP
@23
UartTX_tb.out_cmp[15:0]
@28
UartTX_tb.TX_cmp
@200
-Test
@28
UartTX_tb.fail
[pattern_trace] 1
[pattern_trace] 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -0,0 +1,74 @@
`timescale 10ns/1ns
`default_nettype none
module UartTX_tb();
// IN,OUT
reg clk = 0;
reg load = 0;
reg [15:0] in = 0;
wire TX;
wire [15:0] out;
// Part
UartTX UartTX(
.clk(clk),
.load(load),
.in(in),
.TX(TX),
.out(out)
);
// Simulate
always #2 clk=~clk;
wire trigger;
assign trigger = (n==1000) || (n==5000) || (n==9000);
always @(posedge clk) begin
in <= trigger?$random:in;
load <= trigger;
end
// Compare
reg [9:0] uart=10'b1111111111;
reg [15:0] baudrate = 0;
reg [15:0] bits = 0;
wire is216=(baudrate==216);
reg [15:0] out_cmp=0;
always @(posedge clk)
out_cmp <=load?16'h8000:(bits==9)&is216?16'd0:out_cmp;
always @(posedge clk)
bits <= (load)?0:is216?bits+1:bits;
always @(posedge clk)
baudrate <= (is216?0:out_cmp?baudrate+1:baudrate);
always @(posedge clk)
uart <= (load)?((in<<2)|1):(is216?{1'b1,uart[9:1]}:uart);
wire TX_cmp;
assign TX_cmp = uart[1];
reg fail = 0;
reg [31:0] n = 0;
task check;
#4
if ((TX != TX_cmp) ||(out != out_cmp))
begin
$display("FAIL: clk=%1b, load=%1b, in=%16b, out=%16b, TX=%1b",clk,load,in,out,TX);
fail=1;
end
endtask
initial begin
$dumpfile("UartTX_tb.vcd");
$dumpvars(0, UartTX_tb);
$display("------------------------");
$display("Testbench: UartTX");
for (n=0; n<13000;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,4 @@
// hello.asm
// this little assembler programm outputs "Hi" on UART_TX
//
// Put your code here:

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

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 = echo
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,85 @@
## 02 UartRX
The special functino register `UartRX` receives bytes over UART with 8N1 at 115200 baud. When RX line goes low, the sampling process is initiated. Sampling of the individual bits is done in the middle of each bit.
![](timing.jpg)
### Chip specification
| IN/OUT | wire | function |
| ------ | -------- | ----------------------------------------------------------------------- |
| IN | clear | =1 clears the data register, chip is now ready to receive the next byte |
| IN | RX | receive wire |
| OUT | out[15] | =1 waiting for next byte, =0 byte completed |
| OUT | out[7:0] | last received byte (when out[15]=0) |
When clear = 1 the chip clears the data register and is ready to receive next byte. out[15] is set to 1 to show, that chip is ready to receive next byte. When RX goes low the chip starts sampling the RX line. After reading of byte completes, chip ouputs the received byte to out[7:0] with out[15]=0. The sampling of a complete byte takes 2170 clock cycles. Sampling is done in the middle of each bit at clock count number108.
### Proposed Implementation
Use a `Bit` to store run state. run goes high, when rx=0 and run=0. run stops, when last bit is received. When run=1 a Counter increments every clock cycle. After 217 clock cycles the Counter resets. A second counter increments every 217 cycles to count the bits. At count number 108 the rx is shifted into a `BitShift9R`. When transmission of the byte completes (10-bit sampled), the content of the shiftregister is loaded into the data register with out[15] set to 0 (valid byte). The data register can be cleared by software (clear) at any time by setting the highest bit of data register to 1 (byte not ready yet).
**Attention:** RX must pass a `DFF` to be registered in the clock domain of clk.
![](UartRX.png)
### Memory map
The special function register `UartRX` is mapped to memory map of HACK according to:
| address | I/O device | R/W | function |
| ------- | ---------- | --- | ----------------------------------------------------------------------------------------------- |
| 4099 | UART_RX | R | when out[15]=1 data register is not valid, when out[15]=0 out[7:0] holds the last received byte |
| 4099 | UART_RX | W | clear data register |
### echo.asm
To test HACK with `UartRX` we need a little machine language programm `echo.asm`, which reads bytes from UartRX and sends them to UART_TX.
**Attention:** Use a loop to wait until UartRX is ready before reading the next byte. Clear data register of UartRX after reading a byte.
***
### Project
* Implement `UartRX.v` and simulate with test bench:
```
$ cd 02_UartRX
$ apio clean
$ apio sim
```
* Compare with CMP:
![](UartRX_tb.png)
* Edit `HACK.v` and add special function register `UartRX` to memory address 4099.
- Implement `echo.asm` and run in simulation:
```
$ cd 02_UartRX
$ make
$ cd ../00_HACK
$ apio clean
$ apio sim
```
- Check the TX wire of the simulation and compare with the received bytes at RX.
![](echo.png)
- build and upload HACK with `echo.asm` preloaded into ROM to iCE40HX1K-EVB.
- switch olimexino 32u4 to UART-Bridge (yellow led)
- open terminal on your computer
- type chars in the terminal and see if they are echoed by HACK.
```
$ cd 00_HACK
$ apio clean
$ apio upload
$ tio /dev/ttyACM0
```

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,34 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Fri Dec 30 13:36:50 2022
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/02_UartRX/UartRX_tb.vcd"
[dumpfile_mtime] "Fri Dec 30 13:36:33 2022"
[dumpfile_size] 3203743
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/02_UartRX/UartRX_tb.gtkw"
[timestart] 0
[size] 1920 963
[pos] -1 -1
*-26.000000 162700000 -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
[treeopen] UartRX_tb.
[sst_width] 281
[signals_width] 160
[sst_expanded] 1
[sst_vpaned_height] 259
@28
UartRX_tb.clk
@200
-IN
@28
UartRX_tb.clear
UartRX_tb.rx
@200
-OUT
@22
UartRX_tb.out[15:0]
@200
-CMP
@22
UartRX_tb.out_cmp[15:0]
[pattern_trace] 1
[pattern_trace] 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,76 @@
`timescale 10ns/1ns
`default_nettype none
module UartRX_tb();
// IN,OUT
reg clk = 0;
reg clear = 0;
wire RX;
wire [15:0] out;
// Part
UartRX UARTRX(
.clk(clk),
.clear(clear),
.RX(RX),
.out(out)
);
// Simulate
always #2 clk=~clk;
wire trigger;
reg load=0;
assign trigger = (n==1000) || (n==5000) || (n==9000);
reg [15:0] in=0;
always @(posedge clk) begin
in <= trigger?$random:in;
load <= trigger;
clear <= (n==200);
end
// Compare
reg [9:0] uart=10'b1111111111;
reg [15:0] baudrate = 0;
reg [15:0] bits = 0;
always @(posedge clk)
bits <= (load&~out_tx)?0:((baudrate==216)?bits+1:bits);
always @(posedge clk)
baudrate <= (load&~out_tx)?0:((baudrate==216)?0:(out_tx)?baudrate+1:baudrate);
always @(posedge clk)
uart <= (load&~out_tx)?((in<<2)|1):((baudrate==216)?{1'b1,uart[9:1]}:uart);
reg out_tx = 0;
always @(posedge clk)
out_tx <= load?1:((bits==10)?0:out_tx);
assign RX = uart[1];
reg [15:0] out_cmp =0;
always @(posedge clk)
out_cmp <= clear?16'b1000000000000000:((baudrate==216)&(bits==9)?in& 16'h00ff:out_cmp);
reg fail = 0;
reg [31:0] n = 0;
task check;
#4
if (out_cmp != out)
begin
$display("FAIL: clk=%1b, out=%16b",clk,out);
fail=1;
end
endtask
initial begin
$dumpfile("UartRX_tb.vcd");
$dumpvars(0, UartRX_tb);
$display("------------------------");
$display("Testbench: UartRX");
for (n=0; n<10000;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 @@
// echo.asm
//
// receive byte over UART_RX and transmit the received byte to UART_TX
// repeat in an endless loop
//
// Put your code here:

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

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

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 = buffer
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,168 @@
## 04 SRAM
The evaluation board iCE40HX1K-EVB includes an 512kbyte static ram chip K6R4016V1D. The SRAM chip connects to iCE40HX1K with 37 wires;
- SRAM_ADDR 18 bit
- SRAM_DATA 16 bit (bidiretional inout)
- SRAM_CSX (chip select not)
- SRAM_OEX (output enable not)
- SRAM_WEX (write enable not)
To read and write to the SRAM chip we will add two special function register to HACK:
1. SRAM_A is a 16 bit register mapped at memory location 4104. SRAM_ADDR controls the 16 lower bits of the 18 bit address bus. The two most significant bits are allways 0, so we can only access 64k x 16 bit words of SRAM chip.
2. SRAM_D is a special function register mapped at memory location 4105. SRAM_D controls the bidirectional data bus and the control wires CSX, OEX and WEX.
**Note:** the 16 bit data bus is bidirectional and has therefore to be connected over a tristate buffer. This is done with `InOut.v` which is considered primitive and must not be implemented.
### Chip specification SRAM_A
SRAM_A is a simple `Register` that stores the lower 16 bit of the 18 bit address of the SRAM chip.
### Chip specification SRAM_D
| IN/OUT | wire | function |
| ------ | --------------- | -------------------------- |
| IN | clk | system clock (25MHz) |
| IN | load | initiate a write operation |
| IN | in[15:0] | data to write to SRAM |
| OUT | out[15:0] | data read from SRAM |
| INOUT | SRAM_DATA[15:0] | bidirectional data bus |
| OUT | SRAM_CSX | chip select not |
| OUT | SRAM_OEX | output enable not |
| OUT | SRAM_WEX | write enable not |
When load[t]=1 transmission of word in[15:0] is initiated. The word is send to SRAM over the bidirectional wires SRAM_DATA (direction out) and a write pulse will be triggered for one cycle at t+1:
* SRAM_OEX=1
* SRAM_WEX=0
When load=0 SRAM_DATA will be used as input and the data of the SRAM chip will be presented at out[15:0]
- SRAM_OEX=0
- SRAM_WEX=1
SRAM_CSX can be set to low all the time.
### Proposed Implementation ADDR_A
Use a `Register` to store the lower 16 bit of SRAM_ADDR (The two most significant bits are hardwired to 0).
### Proposed Implementation ADDR_D
Use a `DFF` to delay the load signal. Use a `Register` to store the data in[15:0] to be stored. Use a tristate buffer `InOut.v` to control the direction of the bidirectional SRAM_DATA data bus.
### Memory map
The special function register `SRAM_A` and `SRAM_D` are mapped to memory map of HACK according to:
| address | I/O device | R/W | function |
| ------- | ---------- | --- | ------------------------------ |
| 4101 | SRAM_A | R | address of SRAM |
| 4102 | SRAM_D | R | read data from SRAM |
| 4102 | SRAM_D | W | initiate a write cylce to SRAM |
### buffer.asm
To test HACK with SRAM we need a little machine language programm `buffer.asm`, which reads the first four bytes of an ASCII file previosuly stored to the SPI flash memory chip W25Q16BV of iCE40HX1K-EVB, starting at address 0x040000 (256k) and stores the four bytes to SRAM. Finally we read the four bytes from SRAM and write them to UART.
### SRAM in real hardware
The board iCE40HX1K-EVB comes with a static ram chip K6R4016V1D. The chip is already connected to iCE40HX1K according `iCE40HX1K-EVB.pcf` (Compare with schematic [iCE40HX1K_EVB](../../doc/iCE40HX1K-EVB_Rev_B.pdf).
```
set_io SRAM_ADDR[0] 79 # SA0
set_io SRAM_ADDR[1] 80 # SA1
set_io SRAM_ADDR[2] 81 # SA2
set_io SRAM_ADDR[3] 82 # SA3
set_io SRAM_ADDR[4] 83 # SA4
set_io SRAM_ADDR[5] 85 # SA5
set_io SRAM_ADDR[6] 86 # SA6
set_io SRAM_ADDR[7] 87 # SA7
set_io SRAM_ADDR[8] 89 # SA8
set_io SRAM_ADDR[9] 90 # SA9
set_io SRAM_ADDR[10] 91 # SA10
set_io SRAM_ADDR[11] 93 # SA11
set_io SRAM_ADDR[12] 94 # SA12
set_io SRAM_ADDR[13] 95 # SA13
set_io SRAM_ADDR[14] 96 # SA14
set_io SRAM_ADDR[15] 97 # SA15
set_io SRAM_ADDR[16] 99 # SA16
set_io SRAM_ADDR[17] 100 # SA17
set_io SRAM_CSX 78 # SRAM_#CS
set_io SRAM_OEX 74 # SRAM_#OE
set_io SRAM_WEX 73 # SRAM_#WE
set_io SRAM_DATA[0] 62 # SD0
set_io SRAM_DATA[1] 63 # SD1
set_io SRAM_DATA[2] 64 # SD2
set_io SRAM_DATA[3] 65 # SD3
set_io SRAM_DATA[4] 66 # SD4
set_io SRAM_DATA[5] 68 # SD5
set_io SRAM_DATA[6] 69 # SD6
set_io SRAM_DATA[7] 71 # SD7
set_io SRAM_DATA[8] 72 # SD8
set_io SRAM_DATA[9] 60 # SD9
set_io SRAM_DATA[10] 59 # SD10
set_io SRAM_DATA[11] 57 # SD11
set_io SRAM_DATA[12] 56 # SD12
set_io SRAM_DATA[13] 54 # SD13
set_io SRAM_DATA[14] 53 # SD14
set_io SRAM_DATA[15] 52 # SD15
```
***
### Project
* Implement `SRAM_D.v` and simulate with testbench:
```
$ cd 04_SRAM_D
$ apio clean
$ apio sim
```
* Compare output of your chip `OUT` with `CMP`.
![](sram_tb.png)
* Edit `HACK.v` and add a `Register` for SRAM_A memory mapped to 4101.
* Edit `HACK.v` and add a special function register `SRAM_D` to memory address 4102.
* Implement `buffer.asm` and test with the testbench:
```
$ cd 04_SRAM_D
$ make
$ cd ../00_HACK
$ apio clean
$ apio sim
```
* Check the SRAM wires of the simulation and look for the storing of "SPI!" (which was preloaded in SPI chip at memory address 0x040000 of the testbench).
![](buffer1.png)
* Check the output at UART_TX in the long run. You should see the string "SPI!" output to UART_TX:
![](buffer.png)
* preload the SPI memory chip with some text file at address 0x040000.
* build and upload HACK with `buffer.asm` in ROM.BIN to iCE40HX1K-EVB.
- press reset button on iCE40HX1K-EVB and see if wou can receive the preloaded text file on your Computer.
```
$ echo SPI! > spi.txt
$ iceprogduino -o 256k -w spi.txt
$ cd 04_SRAM_D
$ make
$ cd ../00_HACK
$ apio clean
$ apio upload
$ tio /dev/ttyACM0
```

View File

@@ -0,0 +1,44 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Wed Dec 28 09:52:04 2022
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/04_SRAM/SRAM_D_tb.vcd"
[dumpfile_mtime] "Wed Dec 28 09:50:13 2022"
[dumpfile_size] 42940
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/04_SRAM/SRAM_D_tb.gtkw"
[timestart] 0
[size] 1920 963
[pos] -51 -51
*-18.000000 -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 -1
[sst_width] 281
[signals_width] 160
[sst_expanded] 1
[sst_vpaned_height] 259
@200
-IN
@28
SRAM_D_tb.load
@22
SRAM_D_tb.in[15:0]
@200
-OUT
@28
SRAM_D_tb.CSX
SRAM_D_tb.OEX
SRAM_D_tb.WEX
@22
SRAM_D_tb.out[15:0]
@200
-CMP
@28
SRAM_D_tb.CSX_cmp
SRAM_D_tb.OEX_cmp
SRAM_D_tb.WEX_cmp
@22
SRAM_D_tb.out_cmp[15:0]
@200
-Test
@29
SRAM_D_tb.fail
[pattern_trace] 1
[pattern_trace] 0

View File

@@ -0,0 +1,72 @@
`timescale 10ns/1ns
`default_nettype none
module SRAM_D_tb();
// IN,OUT
reg clk = 0;
reg load = 0;
reg [15:0] in=0;
wire [15:0] out;
wire CSX;
wire OEX;
wire WEX;
wire [15:0] DATA;
// Part
SRAM_D SRAM_D(
.clk(clk),
.load(load),
.in(in),
.out(out),
.CSX(CSX),
.OEX(OEX),
.WEX(WEX),
.DATA(DATA)
);
// Simulate
always #2 clk=~clk;
wire trigger;
reg write;
assign trigger = (n==4) || (n==8) || (n==12) || (n==16) || (n==20);
always @(posedge clk) begin
in <= $random;
load <= trigger;
write <= load;
end
reg [15:0] data;
always @(posedge clk)
if (load) data <= in;
// Compare
wire CSX_cmp = 0;
wire OEX_cmp = write;
wire WEX_cmp = ~write;
wire [15:0] out_cmp = (~CSX_cmp&~OEX_cmp)?16'bzzzzzzzzzzzzzzzz:data;
reg fail = 0;
reg [31:0] n = 0;
task check;
#4
if ((out!=out_cmp)||(CSX!=CSX_cmp)||(OEX!=OEX_cmp)||(WEX!=WEX_cmp))
begin
$display("FAIL: clk=%1b, load=%1b, in=%16b, out=%16b, CSX=%1b, OEX=%1b, SEX=%1b, DATA=%16b",clk,load,in,out,CSX,OEX,WEX,DATA);
fail=1;
end
endtask
initial begin
$dumpfile("SRAM_D_tb.vcd");
$dumpvars(0, SRAM_D_tb);
$display("------------------------");
$display("Testbench: SRAM_D");
for (n=0; n<24;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,7 @@
// buffer.asm
//
// read 4 bytes of textfile from SPI starting at address 0x040000 and write
// the string to SRAM. Finally read the string from SRAM and send
// the string to UART_TX
//
// Put your code here:

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

View File

@@ -0,0 +1,42 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Thu Dec 29 18:09:36 2022
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/05_GO/GO_tb.vcd"
[dumpfile_mtime] "Thu Dec 29 18:09:26 2022"
[dumpfile_size] 80439
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/05_GO/GO_tb.gtkw"
[timestart] 0
[size] 1440 713
[pos] 34 87
*-17.000000 -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 -1
[sst_width] 281
[signals_width] 240
[sst_expanded] 1
[sst_vpaned_height] 172
@200
-IN
@28
GO_tb.clk
GO_tb.load
@22
GO_tb.pc[15:0]
GO_tb.sram_addr[15:0]
GO_tb.ROM_data[15:0]
GO_tb.sram_data[15:0]
@200
-OUT
@22
GO_tb.SRAM_ADDR[15:0]
GO_tb.instruction[15:0]
@200
-CMP
@22
GO_tb.SRAM_ADDR_cmp[15:0]
GO_tb.instruction_cmp[15:0]
@200
-Test
@28
GO_tb.fail
[pattern_trace] 1
[pattern_trace] 0

View File

@@ -0,0 +1,73 @@
`timescale 10ns/1ns
`default_nettype none
module GO_tb();
// IN,OUT
reg clk = 0;
reg load = 0;
reg [15:0] sram_addr=0;
reg [15:0] pc=0;
wire [15:0] SRAM_ADDR;
reg [15:0] ROM_data=0;
reg [15:0] sram_data=0;
wire [15:0] instruction;
// Part
GO GO(
.clk(clk),
.load(load),
.sram_addr(sram_addr),
.pc(pc),
.SRAM_ADDR(SRAM_ADDR),
.ROM_data(ROM_data),
.sram_data(sram_data),
.instruction(instruction)
);
// Simulate
always #2 clk=~clk;
wire trigger;
reg write;
assign trigger = (n==10);
always @(posedge clk) begin
sram_addr <= $random;
pc <= $random;
ROM_data <= $random;
sram_data <= $random;
load <= trigger;
end
// Compare
reg fail = 0;
reg [31:0] n = 0;
reg run=0;
always @(posedge clk)
if (load) run <=1;
wire [15:0] SRAM_ADDR_cmp=run?pc:sram_addr;
wire [15:0] instruction_cmp=run?sram_data:ROM_data;
task check;
#4
if ((SRAM_ADDR!=SRAM_ADDR_cmp) || (instruction!=instruction_cmp))
begin
$display("FAIL: clk=%1b, load=%1b",clk,load);
fail=1;
end
endtask
initial begin
$dumpfile("GO_tb.vcd");
$dumpvars(0, GO_tb);
$display("------------------------");
$display("Testbench: GO");
for (n=0; n<20;n=n+1)
check();
if (fail==0) $display("passed");
$display("------------------------");
$finish;
end
endmodule

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 = boot
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,82 @@
## 05 GO
The instrucition memory ROM of HACK is limited to 256 words. In order to run bigger programs written in JACK (e.g. tetris) we will store the program to SRAM and use the SRAM memory chip as instruction memory. For this we need:
1. A bootloader program written in assembler (which is stored in the 256 words of ROM), that reads a (bigger) hack binary program previously stored on SPI memory chip starting at address 0x010000 and stores it to SRAM.
2. A multiplexer, that switches instruction memory from ROM to SRAM.
### Chip specification
When load=1 `GO` switches HACK operation from boot mode to run mode. In boot mode instruction=ROM_data and SRAM_ADDR=sram_a. In run mode instruction=sram_data and SRAM_ADDR=pc.
### Memory map
The special function register `GO` is memory mapped to address 4103
| addr | R/W | function |
| ---- | --- | ----------------------------------------------------------------------------------------------------------- |
| 4103 | W | a write resets the HACK CPU and switches instrucion memory from ROM (bootloader) to SRAM (JACK application) |
### boot.asm
bootloader that reads 64k words from SPI flash memory starting from address 0x010000 and writes them to SRAM. FInally it resets the CPU and starts program execution from SRAM.
To run the testbench it's sufficient to read only the first 6 words. The SPI in the testbench is preloaded with the following 6 assembler instructions of the program `leds.asm` translated into HACK machine language:
```
@BUT
D=M
@LED
M=D
@0
0;JMP
```
***
### Project
* Implement `boot.asm` (read only the first 6 words) and run the testbench:
```
$ cd 05_GO
$ make
$ cd ../00_HACK
$ apio
$ apio sim
```
![](go.png)
* Check, if HACK reads 6 instrucions from SPI and writes them to SRAM.
* Check, if HACK can switch from instruction memory ROM (bootloader= to instruction memory SRAM (application) when loadGO=1.
* Check, if HACK runs `leds.asm` after switching from boot to run.
### Run in real hardware
* preload SPI flash rom with the hack programm `leds.asm.`
```
$ cd ../../04_Machine_Language
$ make leds
$ make upload
```
* upload HACK with bootloader to iCE40HX1K-EVB
```
$ cd 05_GO
$ make
$ cd ../00HACK
$ apio clean
$ apio upload
```
* Check if iCE40HX1K-EVB runs the bootloader, which loads `leds.asm` from SPI and starts execution of leds.asm.
If `leds.asm` is working, you are ready to start implementing the operating system JACK-OS. Proceed to project `07_Operating_System` and come back later to implement the last to IO-Devices `LCD` and `RTP` to connect the screen with resitive touch panel MOD-LCD2.8RTP.

View File

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

View File

@@ -0,0 +1,5 @@
//*****************************************************************************
// Boot loader. Load HACK code from SPI address 0x010000 (64k) into SRAM and GO
//*****************************************************************************
//
// Put your code here:

BIN
06_IO_Devices/05_GO/go.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

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"

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -0,0 +1,50 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Fri Dec 30 13:59:38 2022
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/06_LCD/LCD_tb.vcd"
[dumpfile_mtime] "Fri Dec 30 13:59:22 2022"
[dumpfile_size] 258098
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/06_LCD/LCD_tb.gtkw"
[timestart] 0
[size] 1634 636
[pos] -1 -1
*-19.886099 213000 -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
[treeopen] LCD_tb.
[sst_width] 281
[signals_width] 160
[sst_expanded] 1
[sst_vpaned_height] 137
@28
LCD_tb.clk
@200
-INPUT
@28
LCD_tb.load
LCD_tb.load16
@22
LCD_tb.in[15:0]
@200
-OUTPUT
@28
LCD_tb.CSX
LCD_tb.DCX
LCD_tb.SDO
LCD_tb.SCK
(0)LCD_tb.out[15:0]
@200
-CMP
@28
LCD_tb.CSX_cmp
LCD_tb.DCX_cmp
LCD_tb.SDO_cmp
@29
LCD_tb.SCK_cmp
@28
LCD_tb.out_cmp
@200
-Test
@28
LCD_tb.fail
[pattern_trace] 1
[pattern_trace] 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@@ -0,0 +1,89 @@
`timescale 10ns/1ns
`default_nettype none
module LCD_tb();
// IN,OUT
reg clk = 0;
reg load = 0;
reg load16 = 0;
reg [15:0] in = 0;
wire [15:0] out;
wire DCX;
wire CSX;
wire SDO;
wire SCK;
// Part
LCD LCD(
.clk(clk),
.load(load),
.load16(load16),
.in(in),
.out(out),
.DCX(DCX), //SPI-line data/command not
.CSX(CSX), //SPI-line chip enabled not
.SDO(SDO), //SPI-Line master out slave in
.SCK(SCK) //SPI-clock
);
// Simulate
always #2 clk=~clk;
wire trigger;
assign trigger = (n==20) || (n==40) || (n==60) || (n==80) || (n==100);
reg [1:0] xx=0;
always @(posedge clk) begin
in <= trigger?$random&16'h02ff:in;
if (trigger) xx<=xx+1;
load <= trigger&&(~xx[1]);
load16 <= trigger&&(xx==2);
end
// Compare
reg[5:0] bits=0;
reg d16=0;
always @(posedge clk)
d16 <= load16?1:(load)?0:d16;
always @(posedge clk)
bits <= (load&~in[8]|load16)?1:(((bits[4]&~d16)|bits[5])?0:(busy?bits+1:0));
wire busy=|bits;
wire out_cmp = busy;
reg [15:0] shift=0;
always @(posedge clk)
shift <= (load|load16)?in:(~SCK_cmp?shift:{shift[14:0],1'b0});
wire SCK_cmp=busy&~bits[0];
reg ce_cmp=0;
always @(posedge clk)
ce_cmp<=(load|load16)?(load16|load&~in[8]):ce_cmp;
wire CSX_cmp=~ce_cmp;
reg DCX_cmp=0;
always @(posedge clk)
DCX_cmp<=load?in[9]:(load16)?1:DCX_cmp;
wire SDO_cmp=(d16&shift[15])|(~d16&shift[7]);
reg fail = 0;
reg [31:0] n = 0;
task check;
#4
if ((out[15]!=out_cmp)||(SDO!=SDO_cmp)||(CSX!=CSX_cmp)||(SCK!=SCK_cmp)||(DCX!=DCX_cmp))
begin
$display("FAIL: clk=%1b, load=%1b, in=%16b, out=%16b, DCX=%1b, CSX=%1b, SDO=%1b, SCK=%1b",clk,load,in,out,DCX,CSX,SDO,SCK);
fail=1;
end
endtask
initial begin
$dumpfile("LCD_tb.vcd");
$dumpvars(0, LCD_tb);
$display("------------------------");
$display("Testbench: LCD");
for (n=0; n<400;n=n+1)
check();
if (fail==0) $display("passed");
$display("------------------------");
$finish;
end
endmodule

View File

@@ -0,0 +1,91 @@
## 06 LCD
The special function register `LCD` memory mapped to addresses 4104 and 4105 enables HACK to write bytes to the LCD controller chip ILI9341V situated on MOD-LCD2.8RTP. The communication protocol is SPI with one additional wire DCX. The protocol defines transmission of 8 bit commands with DCX = 0 followed data with DCX=1. Data packets can have any length depending on the launched command.
### Chip specification
| IN/OUT | wire | function |
| ------ | ------- | -------------------------------------------------- |
| IN | in[7:0] | byte to be sent. |
| IN | in[8] | =0 send byte and set CSX low |
| IN | in[8] | =1 pull CSX high without sending byte |
| IN | in[9] | value of DCX when transmitting a byte. |
| IN | load | initiates the transmission of a byte, when in[8]=0 |
| IN | load16 | initiates the transmission of 16 bit in[15:0] |
| OUT | out[15] | =0 chip is busy, =0 ready |
| OUT | DCX | =0 command, =1 data |
| OUT | SDO | serial data out |
| OUT | SCK | serial clock |
| OUT | CSX | chip select not |
The special function register `LCD` communicates with ILI9341V LCD controller over 4 wire SPI.
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). DCX is set to in[9]. The byte in[7:0] is send to SDO bitwise together with 8 clock signals on SCK. During transmission out[15] is 1. After 16 clock cycles transmission is completed and out[15] is set to 0.
When load=1 and in[8]=1 CSX goes high and DCX=in[9] without transmission of any bit.
When load16=1 transmission of word in[15:0] is initiated. CSX is goes low (and stays low even when transmission is completed). DCX is set to 1 (data). After 32 clock cycles transmission is completed and out[15] is set to 0.
### Proposed Implementation
Use a `Bit` to store the state (0 = ready, 1 = busy) which is output to out[15]. Another two `Bit` store the state of DCX and CSX. Use a counter `PC` to count from 0 to 15 or 31 according to load/load16. Finally we need two connected `BitShift8L`. They will be loaded with the byte in[7:0] or the word in[15:0] to be send. After 8/16 bits are transmitted the module cleares out[15].
![](LCD.png)
### Memory map
The special function register `LCD` is mapped to memory map of HACK according to:
| address | I/O device | R/W | function |
| --------- | ---------- | --- | ----------------------------------- |
| 4104 | LCD | W | start transmittion of byte in[7:0] |
| 4105 | LCD | W | start transmittion of word in[15:0] |
| 4104/4105 | LCD | R | out[15]=1 busy, out[15]=0 idle |
### LCD in real hardware
The board MO-LCD2.8RTP comes with a 2.8 inch LCD screen controlled by a controller chip ILI8341V. MOD-LCD2.8RTP must be connected to iCE40HX1K-EVB with 6 jumper wire cables: +3.3V, GND plus 4 data wires according to `iCE40HX1K-EVB.pcf` (Compare with schematic [iCE40HX1K_EVB](../../doc/iCE40HX1K-EVB_Rev_B.pdf) and [MOD-LCD2.8RTP_RevB.pdf](../../doc/MOD-LCD2.8RTP_RevB.pdf).
```
set_io LCD_DCX 1 # PIO3_1A connected to pin 5 of GPIO1
set_io LCD_SDO 2 # PIO3_1B connected to pin 7 of GPIO1
set_io LCD_SCK 3 # PIO3_2A connected to pin 9 of GPIO1
set_io LCD_CSX 4 # PIO3_2B connected to pin 11 of GPIO1
```
| wire | iCE40HX1K-EVB (GPIO1) | MOD-LCD2.8RTP (UEXT) |
| ------- | --------------------- | -------------------- |
| +3.3V | 3 | 1 +3.3V |
| GND | 4 | 2 GND |
| LCD_DCX | 5 | 7 D/C |
| LCD_SDO | 7 | 8 MOSI |
| LCD_SCK | 9 | 9 SCK |
| LCD_CSX | 11 | 11 CS |
***
### Project
* Implement `LCD.v` and test with testbench:
```
$ cd 06_LCD
$ apio clean
$ apio sim
```
* Compare output `OUT` of special chip`LCD` with `CMP`.
![](LCD_tb.png)
* Add special function register`LCD` to `HACK` at memory addresses 4104/4105 and upload to iCE40HX1K-EVB with the bootloader boot.asm preloaded into ROM
```
$ cd ../05_GO
$ make
$ cd ../00_HACK
$ apio clean
$ apio upload
```
* Proceed to `07_Operating_System` and implement the driver class `Screen.jack` that sends command over `LCD` the controller chip ILI9341V on MOD-LCD2.8RTP

View File

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

View File

@@ -0,0 +1,49 @@
[*]
[*] GTKWave Analyzer v3.3.98 (w)1999-2019 BSI
[*] Wed Jun 17 13:06:36 2020
[*]
[dumpfile] "/home/micha/git/gitlab/nand2tetris/12_hack-12-nand/lcd/lcd_tb.vcd"
[dumpfile_mtime] "Wed Jun 17 13:05:40 2020"
[dumpfile_size] 150367
[savefile] "/home/micha/git/gitlab/nand2tetris/12_hack-12-nand/lcd/lcd_tb.gtkw"
[timestart] 0
[size] 1280 703
[pos] -1 -1
*-6.000000 230 -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
[treeopen] lcd_tb.
[treeopen] lcd_tb.LCD.
[treeopen] lcd_tb.LCD.ISC.
[sst_width] 238
[signals_width] 134
[sst_expanded] 1
[sst_vpaned_height] 174
@28
lcd_tb.startD8
lcd_tb.LCD.startD16
@29
lcd_tb.LCD.startC
@22
lcd_tb.in[15:0]
lcd_tb.in[15:0]
@28
lcd_tb.clk
@22
lcd_tb.LCD.bitc[4:0]
@28
lcd_tb.LCD.spi_mosi
lcd_tb.LCD.mosi
lcd_tb.LCD.spi_sck
lcd_tb.LCD.sck
lcd_tb.LCD.spi_cen
lcd_tb.LCD.idle
lcd_tb.LCD.spi_cdn
lcd_tb.LCD.dcn
lcd_tb.LCD.clk_baud
@22
lcd_tb.LCD.data_r[17:0]
@28
lcd_tb.LCD.load
lcd_tb.LCD.BAUDRATE.reset
lcd_tb.LCD.SWITCH_CLOCK.out
[pattern_trace] 1
[pattern_trace] 0

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"

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,48 @@
[*]
[*] GTKWave Analyzer v3.3.104 (w)1999-2020 BSI
[*] Mon Jan 2 15:25:24 2023
[*]
[dumpfile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/07_RTP/RTP_tb.vcd"
[dumpfile_mtime] "Mon Jan 2 15:24:52 2023"
[dumpfile_size] 898324
[savefile] "/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/07_RTP/RTP_tb.gtkw"
[timestart] 0
[size] 1920 963
[pos] -1 -1
*-22.000000 2190000 -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
[treeopen] RTP_tb.
[sst_width] 281
[signals_width] 160
[sst_expanded] 1
[sst_vpaned_height] 259
@28
RTP_tb.clk
@200
-IN
@28
RTP_tb.load
@22
RTP_tb.in[15:0]
@28
RTP_tb.RTP.SDI
@200
-OUT
@28
RTP_tb.RTP.SDO
RTP_tb.RTP.SCK
@22
RTP_tb.out[15:0]
@200
-CMP
@29
RTP_tb.SDO_cmp
@28
RTP_tb.SCK_cmp
@22
RTP_tb.out_cmp[15:0]
@200
-Test
@28
RTP_tb.fail
[pattern_trace] 1
[pattern_trace] 0

View File

@@ -0,0 +1,81 @@
`timescale 10ns/1ns
`default_nettype none
module RTP_tb();
// IN,OUT
reg clk = 0;
reg load = 0;
reg [15:0] in = 0;
wire [15:0] out;
wire SDO;
reg SDI=0;
wire SCK;
// Part
RTP RTP(
.clk(clk),
.load(load),
.in(in),
.out(out),
.SDO(SDO),
.SDI(SDI),
.SCK(SCK)
);
// Simulate
always #2 clk=~clk;
wire trigger;
assign trigger = (n==20) || (n==420) || (n==820) || (n==1220) || (n==1620);
always @(posedge clk) begin
in <= trigger?$random&16'h03ff:in;
load <= trigger;
end
always @(posedge SCK_cmp)
SDI <= $random;
// Compare
reg[8:0] bits=0;
always @(posedge clk)
bits <= load?1:((bits==256)?0:(busy?bits+1:0));
wire busy=|bits[8:0];
wire [15:0] out_cmp = {busy,7'd0,shift};
reg [7:0] shift=0;
wire tr=~|bits[3:0]&busy;
reg lsb=0;
always @(posedge clk)
lsb<=(tr&SCK_cmp)?SDI:lsb;
always @(posedge clk)
shift <= load?in[7:0]:((tr&~SCK_cmp)?{shift[6:0],lsb}:shift);
reg SCK_cmp=0;
always @(posedge clk)
SCK_cmp <= load?1:(tr&busy&~bits[8])?~SCK_cmp:SCK_cmp;
wire SDO_cmp;
assign 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))
begin
$display("FAIL: clk=%1b, load=%1b, in=%16b, out=%16b, SDO=%1b, SDI=%1b, SCK=%1b",clk,load,in,out,SDO,SDI,SCK);
fail=1;
end
endtask
initial begin
$dumpfile("RTP_tb.vcd");
$dumpvars(0, RTP_tb);
$display("------------------------");
$display("Testbench: RTP");
for (n=0; n<2000;n=n+1)
check();
if (fail==0) $display("passed");
$display("------------------------");
$finish;
end
endmodule

View File

@@ -0,0 +1,96 @@
## 07 RTP
The special function register `RTP` memory mapped to addresses 4106 enables HACK to read bytes from the resistive touch panel controller chip AR1021 situated on MOD-LCD2.8RTP. The communication is protocol is SPI.
**Attention:** The specification of AR1200 requires, that SCK is inverted (compare `03_SPI/Readme.md` with CPOL=1) and a slower transfer rate of max. 900kHz
### Chip specification
| IN/OUT | wire | function |
| ------ | -------- | ----------------------------- |
| IN | in[7:0] | byte to be sent. |
| IN | load | =1 initiates the transmission |
| OUT | out[15] | =0 chip is busy, =0 ready |
| OUT | out[7:0] | received byte |
| IN | SDI | serial data in |
| OUT | SDO | serial data out |
| OUT | SCK | serial clock |
When load=1 transmission of byte in[7:0] is initiated. The byte is send to SDO bitwise together with 8 clock signals on SCK. At the same time `RTP` receives a byte at SDI. During transmission out[15] is 1. The transmission of a byte takes 256 clock cycles (32 cycles for each bit to achieve a slower transfer rate). Every 32 clock cycles one bit is shifted out. In the middle of each bit at counter number 31 the bit SDI is sampled. When transmission is completed out[15]=0 and `RTP` outputs the received byte to out[7:0].
### Proposed Implementation
Use a `Bit` to store the state (0 = ready, 1 = busy) which is output to out[15]. Use a counter `PC` that counts from 0 to 511. Finally we need a `BitShift8L`. It will be loaded with the byte in[7:0] to be send. Use a `Bit` to sample the SDI line. After 8 bits are transmitted/received `RTP` cleares out[15] and outputs the received byte to in[7:0].
**Attention:** sample on rising edge of SCK and shift on falling edge of SCK.
![](RTP.png)
### Memory map
The special function register `RTP` is mapped to memory map of HACK according to:
| address | I/O device | R/W | function |
| ------- | ---------- | --- | ----------------------------------------------------------- |
| 4106 | LCD | W | start transmittion of byte in[7:0] |
| 4106 | LCD | R | out[15]=1 busy, out[15]=0 idle, out[7:0] last received byte |
### RTP in real hardware
The board MOD-LCD2.8RTP comes with a resistive touch panel controlled by a controller chip AR1021. MOD-LCD2.8RTP must be connected to iCE40HX1K-EVB with 3 more jumper wire cables according to `iCE40HX1K-EVB.pcf` (Compare with schematic [iCE40HX1K_EVB](../../doc/iCE40HX1K-EVB_Rev_B.pdf) and [MOD-LCD2.8RTP_RevB.pdf](../../doc/MOD-LCD2.8RTP_RevB.pdf).
```
set_io RTP_SDI 7 # PIO3_3A connected to pin 13 of GPIO1
set_io RTP_SDO 8 # PIO3_3B connected to pin 15 of GPIO1
set_io RTP_SCK 9 # PIO3_5A connected to pin 17 of GPIO1
```
| wire | iCE40HX1K-EVB (GPIO1) | MOD-LCD2.8RTP (UEXT) |
| ------- | --------------------- | ---------------------------------- |
| +3.3V | 3 | +3.3V |
| GND | 4 | 2 GND |
| LCD_DCX | 5 | 7 D/C |
| LCD_SDO | 7 | 8 MOSI |
| LCD_SCK | 9 | 9 SCK |
| LCD_CSX | 11 | 10 CS |
| RTP_SDI | 13 | 4 IRQ/SDO (with solder jumper SJ3) |
| RTP_SDO | 15 | 6 SDA |
| RTP_SCK | 17 | 5 SCL |
**Attention:** To enable SPI communication on the RTP controller chip AR1021 we must modify two solder jumpers. (Compare with schematic of MOD-LCD2.8RTP together with Datasheet of AR1021).
1. Cut connection SJ1-GND with a sharp cutter knife. (green)
2. Connect SJ1 to +3.3V to activate SPI mode of AR1021 (yellow)
3. Connect SJ3 (UEXT pin4 with SDO) (yellow)
![](jumper_rtp.jpg)
***
### Project
* Implement special function register `RTP` and test with testbench:
```
$ cd 07_RTP
$ apio clean
$ apio sim
```
* Compare output `OUT` of special chip`RTP` with `CMP`.
![](rtp_tb.png)
* Add special function register`RTP` to `HACK` at memory addresses 4106 and upload to iCE40HX1K-EVB with bootloader boot.asm preloaded into ROM.
```
$ cd ../05_GO
$ make
$ cd ../00_HACK
$ apio clean
$ apio upload
```
* Proceed to `07_Operating_System` and implement the driver class `Touch.jack` that sends command over `RTP` the controller chip AR1021 on MOD-LCD2.8RTP

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

18
06_IO_Devices/GO.v Normal file
View File

@@ -0,0 +1,18 @@
/**
* GO switches from boot to run mode.
*/
`default_nettype none
module GO(
input clk,
input load,
input [15:0] pc,
input [15:0] sram_addr,
output [15:0] SRAM_ADDR,
input [15:0] sram_data,
input [15:0] ROM_data,
output [15:0] instruction
);
// Put your code here:
endmodule

39
06_IO_Devices/HACK.v Normal file
View File

@@ -0,0 +1,39 @@
/**
* The HACK computer, including CPU, ROM and RAM.
* When RST is 1, the program stored in the computer's ROM executes.
* When RST is 0, the execution of the program restarts.
* Thus, to start a program's execution, reset must be pushed "down" (0)
* and "up" (1). From this point onward the user is at the mercy of
* the software. In particular, depending on the program's code, the
* LED may show some output and the user may be able to interact
* with the computer via the BUT.
*/
`default_nettype none
module HACK(
input CLK, // external clock 100 MHz
input [1:0] BUT, // user button ("pushed down" == 0) ("up" == 1)
output [1:0] LED, // leds (0 off, 1 on)
input UART_RX, // UART recieve
output UART_TX, // UART transmit
output SPI_SDO, // SPI data out
input SPI_SDI, // SPI data in
output SPI_SCK, // SPI serial clock
output SPI_CSX, // SPI chip select not
output [17:0] SRAM_ADDR,// SRAM address 18 Bit = 256K
inout [15:0] SRAM_DATA, // SRAM data 16 Bit
output SRAM_WEX, // SRAM write_enable_not
output SRAM_OEX, // SRAM output_enable_not
output SRAM_CSX, // SRAM chip_select_not
output LCD_DCX, // LCD data/command not
output LCD_SDO, // LCD data out
output LCD_SCK, // LCD serial clock
output LCD_CSX, // LCD chip select not
input RTP_SDI, // RTP data in s
output RTP_SDO, // RTP data out
output RTP_SCK // RTP serial clock
);
// Put your code here:
endmodule

20
06_IO_Devices/InOut.v Normal file
View File

@@ -0,0 +1,20 @@
/**
* Tristate Buffer (16 bit)
*
* if (dir == 0) IN: PIN are set to High-Z, dataR = external PIN
* if (dir == 1) OUTPUT: dataW is output to external PIN, dataR = dataW
*/
`default_nettype none
module InOut(
inout [15:0] PIN,
input [15:0] dataW,
output [15:0] dataR,
input dir
);
// No need to implement this chip.
// This chip is implemented using tristate value z
assign PIN = dir? dataW: 16'bzzzzzzzzzzzzzzzz;
assign dataR = PIN;
endmodule

32
06_IO_Devices/LCD.v Normal file
View File

@@ -0,0 +1,32 @@
/*
* LCD communicates with ILI9341V LCD controller over 4 wire SPI.
*
* 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).
* DCX is set to in[9]. The byte in[7:0] is send to SDO bitwise together
* with 8 clock signals on SCK. During transmission out[15] is 1.
* After 16 clock cycles transmission is completed and out[15] is set to 0.
*
* When load=1 and in[8]=1 CSX goes high and DCX=in[9] without transmission
* of any bit.
*
* When load16=1 transmission of word in[15:0] is initiated. CSX is goes low
* (and stays low even when transmission is completed). DCX is set to 1 (data).
* After 32 clock cycles transmission is completed and out[15] is set to 0.
*/
`default_nettype none
module LCD(
input clk, //clock 25 MHz
input load, //start send command/byte over SPI
input load16, //start send data (16 bits)
input [15:0] in, //data to be send
output [15:0] out, //data to be send
output DCX, //SPI data/command not
output CSX, //SPI chip select not
output SDO, //SPI serial data out
output SCK //SPI serial clock
);
// Put your code here:
endmodule

27
06_IO_Devices/RTP.v Normal file
View File

@@ -0,0 +1,27 @@
/**
* The special function register RTP receives bytes from the touch panel
* controller AR1021.
*
* When load=1 transmission of byte in[7:0] is initiated. The byte is send to
* SDO bitwise together with 8 clock signals on SCK. At the same time RTP
* receives a byte at SDI. During transmission out[15] is 1. The transmission
* of a byte takes 256 clock cycles (32 cycles for each bit to achieve a slower
* transfer rate). Every 32 clock cycles one bit is shifted out. In the middle
* of each bit at counter number 31 the bit SDI is sampled. When transmission
* is completed out[15]=0 and RTP outputs the received byte to out[7:0].
*/
`default_nettype none
module RTP(
input clk,
input load,
input [15:0] in,
output [15:0] out,
output SDO,
input SDI,
output SCK
);
// Put your code here:
endmodule

59
06_IO_Devices/Readme.md Normal file
View File

@@ -0,0 +1,59 @@
# 06 IO Devices
Build the following special function register to connect HACK to I/O-devices: `UART_TX`, `UART_RX`, `SPI`, `SRAM`, `GO`, `LCD` and `RTP`. For every special function register we provide a folder with implementation details and a testbench. The special function register must be memory mapped, so HACK can read/write data from/to the IO-device.
| address | I/O dev | function |
| ------- | --------- | -------------------------------------------------- |
| 4096 | LED | 0 = led off, 1 = led on |
| 4097 | BUT | 0 = button pressed "down", 1 = button released |
| 4098 | UART_TX | transmit byte to UART with 115200 baud 8N1 |
| 4099 | UART_RX | receive byte from UART with 115200 baud 8N1 |
| 4100 | SPI | read/write spi flash memory chip |
| 4101 | SRAM_ADDR | address of external SRAM chip |
| 4102 | SRAM_DATA | read/write data from/to external SRAM chip |
| 4103 | GO | Start execution of instructions from external SRAM |
| 4104 | LCD8 | write 8bit command/data to LCD screen |
| 4105 | LCD16 | write 16bit data to LCD screen |
| 4106 | RTP | read/write byte from/to resistive touch panel |
| 4107 | DEBUG0 | used for debugging |
| 4108 | DEBUG1 | used for debugging |
| 4109 | DEBUG2 | used for debugging |
| 4110 | DEBUG3 | used for debugging |
| 4111 | DEBUG4 | used for debugging |
For every special function register we will need the appropriate software to talk to the device. The simpler device drivers (UART, SPI, SRAM and GO) can be implemented in assembler. After completing the devices UART, SPI, SRAM and GO we will be able to fill the SRAM chip with up to 64K words (16bit) of HACK code. This will enable us to run JACK-OS and applications on HACK. The more sofisticated device drivers for LCD and RTP will be implemented in JACK language.
### Proposed implementation
![](/home/micha/gitlab/nand2tetris-fpga/06_IO_Devices/00_HACK/HACK.png)
***
### Project
+ Copy `HACK.v` from `05_Computer_Architecture` into `06_IO_Devices` and add one IO-Device at time at the designated memory mapped address. Implement the corresponding special function register and run the test bench.
```shell
$ cd 0X_device
$ apio clean
$ apio sim
```
+ Implement the designated assembler program, install the binary into `00_HACK` and run the testbench:
```shell
$ cd 0X_device
$ make
$ cd ../00_HACK
$ apio clean
$ apio sim
```
* Run `HACK` in real hardware on iCE40HX1K-EVB with the device attached as real device.
```shell
$ cd 00_HACK
$ apio clean
$ apio upload
```
* Check if attached IO-Device is working accorging to the uploaded software.

24
06_IO_Devices/SPI.v Normal file
View File

@@ -0,0 +1,24 @@
/**
* SPI controller for W25Q16BV
*
* When load=1 transmission of byte in[7:0] is initiated. The byte is send to
* MOSI (master out slave in) bitwise together with 8 clock signals on SCK.
* At the same time the SPI recieves a byte at MISO (master in slave out).
* Sampling of MISO is done at rising edge of SCK and shiftingis done at
*/
`default_nettype none
module SPI(
input clk,
input load,
input [15:0] in,
output [15:0] out,
output CSX,
output SDO,
input SDI,
output SCK
);
// Put your code here:
endmodule

25
06_IO_Devices/SRAM_D.v Normal file
View File

@@ -0,0 +1,25 @@
/**
* SRAM controller:
* If load[t] == 1 then out[t+1] = in[t]
* OEX[t+1] = 1
* WEX[t+1] = 0
* DATA[t+1] = in[t] (DATA is configured as output)
* At any other time:
* out = DATA (DATA is configured as input)
* CSX =0;
*/
`default_nettype none
module SRAM_D(
input clk,
input load,
input [15:0] in,
output [15:0] out,
inout [15:0] DATA, // SRAM data 16 Bit
output CSX, // SRAM chip_enable_not
output OEX, // SRAM output_enable_not
output WEX // SRAM write_enable_not
);
// Put your code here:
endmodule

20
06_IO_Devices/UartRX.v Normal file
View File

@@ -0,0 +1,20 @@
/**
* UartRX receives bytes over UART
*
* When clear = 1 the chip clears the receive buffer and is ready to receive
* next byte. out[15] is set to 1 to show, that chip is ready to receive next
* byte. When RX goes low the chip starts sampling the RX line. After reading
* of byte completes, chip ouputs the received byte to out[7:0]] with out[15]=0.
*/
`default_nettype none
module UartRX(
input clk,
input clear,
input RX,
output [15:0] out
);
// Put your code here:
endmodule

21
06_IO_Devices/UartTX.v Normal file
View File

@@ -0,0 +1,21 @@
/**
* UartTX controls transmission of bytes over UART.
*
* When load = 1 the chip starts serial transmission of the byte in[7:0] to the
* TX line according to the protocoll 8N1 with 115200 baud. During transmission
* out[15] is set to high (busy). The transmission is finished after 2170 clock
* cycles (10 byte a 217 cycle each). When transmission completes out[15] goes
* low again (ready).
*/
`default_nettype none
module UartTX(
input clk,
input load,
input [15:0] in,
output TX,
output [15:0] out
);
// Put your code here:
endmodule