added v2.0
BIN
06_IO_Devices/00_HACK/HACK.dia
Normal file
BIN
06_IO_Devices/00_HACK/HACK.png
Normal file
After Width: | Height: | Size: 100 KiB |
72
06_IO_Devices/00_HACK/HACK_tb.gtkw
Normal 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
|
121
06_IO_Devices/00_HACK/HACK_tb.v
Normal 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
|
49
06_IO_Devices/00_HACK/Include.v
Normal 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"
|
3
06_IO_Devices/00_HACK/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
68
06_IO_Devices/00_HACK/iCE40HX1K-EVB.pcf
Normal 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
|
BIN
06_IO_Devices/01_UartTX/ICE40PGM.jpg
Normal file
After Width: | Height: | Size: 77 KiB |
40
06_IO_Devices/01_UartTX/Include.v
Normal 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"
|
12
06_IO_Devices/01_UartTX/Makefile
Normal 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
|
111
06_IO_Devices/01_UartTX/Readme.md
Normal 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:
|
||||
|
||||

|
||||
|
||||
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).
|
||||
|
||||

|
||||
|
||||
### 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.
|
||||
|
||||

|
||||
|
||||
**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.
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||

|
||||
|
||||
* 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".
|
||||
|
||||

|
||||
|
||||
* 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
|
||||
```
|
BIN
06_IO_Devices/01_UartTX/UARTJumper.jpg
Normal file
After Width: | Height: | Size: 908 KiB |
BIN
06_IO_Devices/01_UartTX/UartTX.dia
Normal file
BIN
06_IO_Devices/01_UartTX/UartTX.png
Normal file
After Width: | Height: | Size: 21 KiB |
43
06_IO_Devices/01_UartTX/UartTX_tb.gtkw
Normal 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
|
BIN
06_IO_Devices/01_UartTX/UartTX_tb.png
Normal file
After Width: | Height: | Size: 56 KiB |
74
06_IO_Devices/01_UartTX/UartTX_tb.v
Normal 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
|
3
06_IO_Devices/01_UartTX/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
4
06_IO_Devices/01_UartTX/hello.asm
Normal file
@@ -0,0 +1,4 @@
|
||||
// hello.asm
|
||||
// this little assembler programm outputs "Hi" on UART_TX
|
||||
//
|
||||
// Put your code here:
|
BIN
06_IO_Devices/01_UartTX/hi.png
Normal file
After Width: | Height: | Size: 45 KiB |
BIN
06_IO_Devices/01_UartTX/timing.jpg
Normal file
After Width: | Height: | Size: 12 KiB |
40
06_IO_Devices/02_UartRX/Include.v
Normal 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"
|
12
06_IO_Devices/02_UartRX/Makefile
Normal 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
|
85
06_IO_Devices/02_UartRX/Readme.md
Normal 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.
|
||||
|
||||

|
||||
|
||||
### 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.
|
||||
|
||||

|
||||
|
||||
### 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:
|
||||
|
||||

|
||||
|
||||
* 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.
|
||||
|
||||

|
||||
|
||||
- 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
|
||||
```
|
BIN
06_IO_Devices/02_UartRX/UartRX.dia
Normal file
BIN
06_IO_Devices/02_UartRX/UartRX.png
Normal file
After Width: | Height: | Size: 26 KiB |
34
06_IO_Devices/02_UartRX/UartRX_tb.gtkw
Normal 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
|
BIN
06_IO_Devices/02_UartRX/UartRX_tb.png
Normal file
After Width: | Height: | Size: 48 KiB |
76
06_IO_Devices/02_UartRX/UartRX_tb.v
Normal 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
|
3
06_IO_Devices/02_UartRX/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
6
06_IO_Devices/02_UartRX/echo.asm
Normal 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:
|
BIN
06_IO_Devices/02_UartRX/echo.png
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
06_IO_Devices/02_UartRX/timing.jpg
Normal file
After Width: | Height: | Size: 47 KiB |
40
06_IO_Devices/03_SPI/Include.v
Normal 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"
|
12
06_IO_Devices/03_SPI/Makefile
Normal 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
|
119
06_IO_Devices/03_SPI/Readme.md
Normal 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).
|
||||
|
||||

|
||||
|
||||
### 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].
|
||||
|
||||

|
||||
|
||||
### 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`.
|
||||
|
||||

|
||||
|
||||
* 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:
|
||||
|
||||

|
||||
|
||||
* Check command 0x03040000 (read from address 0x040000)
|
||||
|
||||

|
||||
|
||||
* Check reading of string "SPI!" output to UartTX.
|
||||
|
||||

|
||||
|
||||
* 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.
|
BIN
06_IO_Devices/03_SPI/SPI.dia
Normal file
BIN
06_IO_Devices/03_SPI/SPI.png
Normal file
After Width: | Height: | Size: 21 KiB |
48
06_IO_Devices/03_SPI/SPI_tb.gtkw
Normal 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
|
81
06_IO_Devices/03_SPI/SPI_tb.v
Normal 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
|
3
06_IO_Devices/03_SPI/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
6
06_IO_Devices/03_SPI/cat.asm
Normal 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:
|
BIN
06_IO_Devices/03_SPI/echo.png
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
06_IO_Devices/03_SPI/spi-timing.png
Normal file
After Width: | Height: | Size: 206 KiB |
BIN
06_IO_Devices/03_SPI/spi_read040000.png
Normal file
After Width: | Height: | Size: 66 KiB |
BIN
06_IO_Devices/03_SPI/spi_tb.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
06_IO_Devices/03_SPI/spi_wakeup.png
Normal file
After Width: | Height: | Size: 65 KiB |
40
06_IO_Devices/04_SRAM/Include.v
Normal 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"
|
12
06_IO_Devices/04_SRAM/Makefile
Normal 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
|
168
06_IO_Devices/04_SRAM/Readme.md
Normal 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`.
|
||||
|
||||

|
||||
|
||||
* 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).
|
||||
|
||||

|
||||
|
||||
* Check the output at UART_TX in the long run. You should see the string "SPI!" output to UART_TX:
|
||||
|
||||

|
||||
|
||||
* 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
|
||||
```
|
44
06_IO_Devices/04_SRAM/SRAM_D_tb.gtkw
Normal 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
|
72
06_IO_Devices/04_SRAM/SRAM_D_tb.v
Normal 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
|
3
06_IO_Devices/04_SRAM/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
7
06_IO_Devices/04_SRAM/buffer.asm
Normal 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:
|
BIN
06_IO_Devices/04_SRAM/buffer.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
06_IO_Devices/04_SRAM/buffer1.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
06_IO_Devices/04_SRAM/sram_tb.png
Normal file
After Width: | Height: | Size: 74 KiB |
42
06_IO_Devices/05_GO/GO_tb.gtkw
Normal 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
|
73
06_IO_Devices/05_GO/GO_tb.v
Normal 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
|
40
06_IO_Devices/05_GO/Include.v
Normal 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"
|
12
06_IO_Devices/05_GO/Makefile
Normal 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
|
82
06_IO_Devices/05_GO/Readme.md
Normal 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
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
* 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.
|
3
06_IO_Devices/05_GO/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
5
06_IO_Devices/05_GO/boot.asm
Normal 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
After Width: | Height: | Size: 104 KiB |
40
06_IO_Devices/06_LCD/Include.v
Normal 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"
|
BIN
06_IO_Devices/06_LCD/LCD.dia
Normal file
BIN
06_IO_Devices/06_LCD/LCD.png
Normal file
After Width: | Height: | Size: 33 KiB |
50
06_IO_Devices/06_LCD/LCD_tb.gtkw
Normal 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
|
BIN
06_IO_Devices/06_LCD/LCD_tb.png
Normal file
After Width: | Height: | Size: 67 KiB |
89
06_IO_Devices/06_LCD/LCD_tb.v
Normal 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
|
91
06_IO_Devices/06_LCD/Readme.md
Normal 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].
|
||||
|
||||

|
||||
|
||||
### 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`.
|
||||
|
||||

|
||||
|
||||
* 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
|
3
06_IO_Devices/06_LCD/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
49
06_IO_Devices/06_LCD/lcd_tb.gtkw
Normal 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
|
40
06_IO_Devices/07_RTP/Include.v
Normal 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"
|
BIN
06_IO_Devices/07_RTP/RTP.dia
Normal file
BIN
06_IO_Devices/07_RTP/RTP.png
Normal file
After Width: | Height: | Size: 19 KiB |
48
06_IO_Devices/07_RTP/RTP_tb.gtkw
Normal 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
|
81
06_IO_Devices/07_RTP/RTP_tb.v
Normal 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
|
96
06_IO_Devices/07_RTP/Readme.md
Normal 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.
|
||||
|
||||

|
||||
|
||||
### 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)
|
||||
|
||||

|
||||
|
||||
***
|
||||
|
||||
### 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`.
|
||||
|
||||

|
||||
|
||||
* 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
|
3
06_IO_Devices/07_RTP/apio.ini
Normal file
@@ -0,0 +1,3 @@
|
||||
[env]
|
||||
board = iCE40-HX1K-EVB
|
||||
|
BIN
06_IO_Devices/07_RTP/jumper_rtp.jpg
Normal file
After Width: | Height: | Size: 217 KiB |
BIN
06_IO_Devices/07_RTP/rtp_tb.png
Normal file
After Width: | Height: | Size: 68 KiB |
18
06_IO_Devices/GO.v
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||

|
||||
|
||||
***
|
||||
|
||||
### 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
@@ -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
@@ -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
@@ -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
@@ -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
|