diff --git a/boards/blackicemx/README.md b/boards/blackicemx/README.md new file mode 100644 index 0000000..4decf86 --- /dev/null +++ b/boards/blackicemx/README.md @@ -0,0 +1,21 @@ +# Blackice Mx with Digilent Pmods support + +This adds support for building the apple one design for [mystorm Blackice Mx](https://github.com/folknology/IceCore) with attached Digilent Pmods for vga and ps2 + +## Peripheral support + +VGA port is working through a Digilent VGA Pmod on the middle Mixmod + +PS/2 keyboard uses a Digilent PS/2 on bottom row of the Pmod next to the USB connector + +## Building +Install a recent IceStorm toolchain, and: + +``` +$ cd yosys +$ make +``` + +## Use + +To load BASIC type "E000R" with CAPS LOCK on. diff --git a/boards/blackicemx/yosys/Makefile b/boards/blackicemx/yosys/Makefile new file mode 100644 index 0000000..54b80b4 --- /dev/null +++ b/boards/blackicemx/yosys/Makefile @@ -0,0 +1,72 @@ +DEVICE = hx8k +PIN_DEF=blackicemx.pcf + +SOURCEDIR = ../../../rtl +BUILDDIR = build + +all: apple1 prog + +info: + @echo " To build: make apple1" + @echo " To program: make prog" + @echo "To build report: make report" + @echo " To clean up: make clean" + +dir: + mkdir -p $(BUILDDIR) + +# ------ TEMPLATES ------ +$(BUILDDIR)/%.json: $(SOURCEDIR)/%.v + yosys -q -p "chparam -list; hierarchy -top apple1_top; synth_ice40 -json $@" $^ + +$(BUILDDIR)/%.asc: $(PIN_DEF) $(BUILDDIR)/%.json + nextpnr-ice40 --${DEVICE} --package tq144:4k --freq 25 --asc $@ --json $(filter-out $<,$^) --pcf $< --placer heap + +$(BUILDDIR)/%.bin: $(BUILDDIR)/%.asc + icepack $^ $@ + +%.rpt: $(BUILDDIR)/%.asc + icetime -d $(DEVICE) -P $(PACKAGE) -c $(FREQ_PLL) -mtr $@ $< + +%_tb.vvp: %_tb.v %.v + iverilog -o $@ $^ + +%_tb.vcd: %_tb.vvp + vvp -N $< +vcd=$@ + +# ------ APPLE 1 ------ +apple1: dir $(BUILDDIR)/apple1.bin +report: dir apple1.rpt + +$(BUILDDIR)/apple1.bin: $(BUILDDIR)/apple1.asc +$(BUILDDIR)/apple1.asc: $(BUILDDIR)/apple1.json +$(BUILDDIR)/apple1.json: $(SOURCEDIR)/apple1.v \ + $(SOURCEDIR)/clock.v \ + $(SOURCEDIR)/pwr_reset.v \ + $(SOURCEDIR)/ram.v \ + $(SOURCEDIR)/rom_wozmon.v \ + $(SOURCEDIR)/rom_basic.v \ + $(SOURCEDIR)/cpu/arlet_6502.v \ + $(SOURCEDIR)/cpu/arlet/ALU.v \ + $(SOURCEDIR)/cpu/arlet/cpu.v \ + $(SOURCEDIR)/uart/uart.v \ + $(SOURCEDIR)/uart/async_tx_rx.v \ + $(SOURCEDIR)/vga/vga.v \ + $(SOURCEDIR)/vga/vram.v \ + $(SOURCEDIR)/vga/font_rom.v \ + $(SOURCEDIR)/ps2keyboard/debounce.v \ + $(SOURCEDIR)/ps2keyboard/ps2keyboard.v \ + $(SOURCEDIR)/boards/blackicemx/apple1_hx8k.v + +apple1.rpt: $(BUILDDIR)/apple1.asc + +prog: dir $(BUILDDIR)/apple1.bin + stty -F /dev/ttyACM0 raw + cat $(filter-out $<,$^) >/dev/ttyACM0 + +# ------ HELPERS ------ +clean: + rm -rf build apple1.rpt + +.SECONDARY: +.PHONY: all info clean prog iceprog diff --git a/boards/blackicemx/yosys/blackicemx.pcf b/boards/blackicemx/yosys/blackicemx.pcf new file mode 100644 index 0000000..be256ec --- /dev/null +++ b/boards/blackicemx/yosys/blackicemx.pcf @@ -0,0 +1,38 @@ +# For the Blackice Mx board + +### UART +set_io uart_rx 61 +set_io uart_tx 62 +set_io uart_cts 29 + +### LEDs +set_io led[0] 55 +set_io led[1] 56 +set_io led[2] 34 +set_io led[3] 33 + +### VGA Display +set_io vga_h_sync 1 +set_io vga_v_sync 2 +set_io vga_r[3] 139 +set_io vga_r[2] 138 +set_io vga_r[1] 142 +set_io vga_r[0] 141 +set_io vga_g[3] 4 +set_io vga_g[2] 3 +set_io vga_g[1] 144 +set_io vga_g[0] 143 +set_io vga_b[3] 135 +set_io vga_b[2] 134 +set_io vga_b[1] 137 +set_io vga_b[0] 136 + +set_io clk25 60 + +set_io ps2_din 19 +set_io ps2_clk 23 + +### Buttons +set_io -pullup yes button[0] 49 +set_io -pullup yes button[1] 52 + diff --git a/boards/ulx3s/README.md b/boards/ulx3s/README.md new file mode 100644 index 0000000..2e487be --- /dev/null +++ b/boards/ulx3s/README.md @@ -0,0 +1,22 @@ +# Ulx3s with HDMI + +This adds support for building the Apple One design for [Ulx3s](https://radiona.org/ulx3s/) with HDMI output and a PS/2 keyboard connected to the us2 USB connector. + +## Peripheral support + +HDMI output on the built-in HDMI connector + +PS/2 keyboard is connected to the us2 USB connector. +Note that some USB keyboards drup down to PS/2 mode and will work. + +## Building +Install a recent ECP5 open source toolchain, and do: + +``` +$ cd yosys +$ make +``` + +## Use + +To load BASIC type "E000R" (with CAPS LOCK on if you are using the UART rather than the PS/2 keyboard). diff --git a/boards/ulx3s/yosys/Makefile b/boards/ulx3s/yosys/Makefile new file mode 100644 index 0000000..a8ac6d9 --- /dev/null +++ b/boards/ulx3s/yosys/Makefile @@ -0,0 +1,69 @@ +DEVICE = 25k +PIN_DEF=ulx3s_v20.lpf +IDCODE ?= 0x21111043 # 12f + +SOURCEDIR = ../../../rtl +BUILDDIR = build + +all: apple1 prog + +info: + @echo " To build: make apple1" + @echo " To program: make prog" + @echo "To build report: make report" + @echo " To clean up: make clean" + +dir: + mkdir -p $(BUILDDIR) + +# ------ TEMPLATES ------ +$(BUILDDIR)/%.json: $(SOURCEDIR)/%.v + yosys -q -p "chparam -list; hierarchy -top apple1_top; synth_ecp5 -json $@" $^ + +$(BUILDDIR)/%.config: $(PIN_DEF) $(BUILDDIR)/%.json + nextpnr-ecp5 --${DEVICE} --package CABGA381 --freq 25 --textcfg $@ --json $(filter-out $<,$^) --lpf $< + +$(BUILDDIR)/%.bit: $(BUILDDIR)/%.config + ecppack --compress --idcode ${IDCODE} $^ $@ + +%_tb.vvp: %_tb.v %.v + iverilog -o $@ $^ + +%_tb.vcd: %_tb.vvp + vvp -N $< +vcd=$@ + +# ------ APPLE 1 ------ +apple1: dir $(BUILDDIR)/apple1.bit + +$(BUILDDIR)/apple1.bin: $(BUILDDIR)/apple1.asc +$(BUILDDIR)/apple1.asc: $(BUILDDIR)/apple1.json +$(BUILDDIR)/apple1.json: $(SOURCEDIR)/apple1.v \ + $(SOURCEDIR)/clock.v \ + $(SOURCEDIR)/pwr_reset.v \ + $(SOURCEDIR)/ram.v \ + $(SOURCEDIR)/rom_wozmon.v \ + $(SOURCEDIR)/rom_basic.v \ + $(SOURCEDIR)/cpu/arlet_6502.v \ + $(SOURCEDIR)/cpu/arlet/ALU.v \ + $(SOURCEDIR)/cpu/arlet/cpu.v \ + $(SOURCEDIR)/uart/uart.v \ + $(SOURCEDIR)/uart/async_tx_rx.v \ + $(SOURCEDIR)/vga/vga.v \ + $(SOURCEDIR)/vga/vram.v \ + $(SOURCEDIR)/vga/font_rom.v \ + $(SOURCEDIR)/ps2keyboard/debounce.v \ + $(SOURCEDIR)/ps2keyboard/ps2keyboard.v \ + $(SOURCEDIR)/boards/ulx3s/apple1_dvi.v \ + $(SOURCEDIR)/boards/ulx3s/vga2dvid.v \ + $(SOURCEDIR)/boards/ulx3s/clk_25_250_125_25.v \ + $(SOURCEDIR)/boards/ulx3s/tmds_encoder.v \ + $(SOURCEDIR)/boards/ulx3s/fake_differential.v + +prog: dir $(BUILDDIR)/apple1.bit + ujprog $(filter-out $<,$^) +# ------ HELPERS ------ +clean: + rm -rf build + +.SECONDARY: +.PHONY: all info clean prog diff --git a/boards/ulx3s/yosys/apple1.bit b/boards/ulx3s/yosys/apple1.bit new file mode 100644 index 0000000..e4a9a1e Binary files /dev/null and b/boards/ulx3s/yosys/apple1.bit differ diff --git a/boards/ulx3s/yosys/slow.py b/boards/ulx3s/yosys/slow.py new file mode 100755 index 0000000..6442796 --- /dev/null +++ b/boards/ulx3s/yosys/slow.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import time +import os +import sys + +if len(sys.argv) != 2: + print("Usage: " + sys.argv[0] + " ") + sys.exit(1) + +os.system('stty -F /dev/ttyUSB0 raw -echo 115200') +fin = open(sys.argv[1], "r") +fout = open("/dev/ttyUSB0", "w") + +for line in fin: + for ch in line.strip('\n'): + fout.write(ch) + fout.flush() + time.sleep(.1) + fout.write('\r') + fout.flush() + time.sleep(.5) +fin.close() +fout.close() + + + + + + diff --git a/boards/ulx3s/yosys/ulx3s_v20.lpf b/boards/ulx3s/yosys/ulx3s_v20.lpf new file mode 100644 index 0000000..bec4564 --- /dev/null +++ b/boards/ulx3s/yosys/ulx3s_v20.lpf @@ -0,0 +1,457 @@ +BLOCK RESETPATHS; +BLOCK ASYNCPATHS; +## ULX3S v2.x.x and v3.0.x + +# The clock "usb" and "gpdi" sheet +LOCATE COMP "clk_25mhz" SITE "G2"; +IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33; +FREQUENCY PORT "clk_25mhz" 25 MHZ; + +# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash +# write to FLASH possible any time from JTAG: +#SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=ENABLE SLAVE_PARALLEL_PORT=DISABLE; +# write to FLASH possible from user bitstream: +# SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; + +## USBSERIAL FTDI-FPGA serial port "usb" sheet +LOCATE COMP "uart_tx" SITE "L4"; # FPGA transmits to ftdi +LOCATE COMP "uart_rx" SITE "M1"; # FPGA receives from ftdi +LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives +LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives +LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives +IOBUF PORT "uart_tx" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "uart_rx" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33; +IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33; + +## LED indicators "blinkey" and "gpio" sheet +LOCATE COMP "led[7]" SITE "H3"; +LOCATE COMP "led[6]" SITE "E1"; +LOCATE COMP "led[5]" SITE "E2"; +LOCATE COMP "led[4]" SITE "D1"; +LOCATE COMP "led[3]" SITE "D2"; +LOCATE COMP "led[2]" SITE "C1"; +LOCATE COMP "led[1]" SITE "C2"; +LOCATE COMP "led[0]" SITE "B2"; +IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet +LOCATE COMP "button[0]" SITE "D6"; # BTN_PWRn (inverted logic) +LOCATE COMP "button[1]" SITE "R1"; # FIRE1 +LOCATE COMP "btn[2]" SITE "T1"; # FIRE2 +LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18 +LOCATE COMP "btn[4]" SITE "V1"; # DOWN +LOCATE COMP "btn[5]" SITE "U1"; # LEFT +LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16 +IOBUF PORT "button[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "button[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## DIP switch "blinkey", "gpio" sheet +LOCATE COMP "sw[0]" SITE "E8"; # SW1 +LOCATE COMP "sw[1]" SITE "D8"; # SW2 +LOCATE COMP "sw[2]" SITE "D7"; # SW3 +LOCATE COMP "sw[3]" SITE "E7"; # SW4 +IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet +LOCATE COMP "oled_clk" SITE "P4"; +LOCATE COMP "oled_mosi" SITE "P3"; +LOCATE COMP "oled_dc" SITE "P1"; +LOCATE COMP "oled_resn" SITE "P2"; +LOCATE COMP "oled_csn" SITE "N2"; +IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI Flash chip "flash" sheet +LOCATE COMP "flash_csn" SITE "R2"; +LOCATE COMP "flash_clk" SITE "U3"; +LOCATE COMP "flash_mosi" SITE "W2"; +LOCATE COMP "flash_miso" SITE "V2"; +LOCATE COMP "flash_holdn" SITE "W1"; +LOCATE COMP "flash_wpn" SITE "Y2"; +#LOCATE COMP "flash_csspin" SITE "AJ3"; +#LOCATE COMP "flash_initn" SITE "AG4"; +#LOCATE COMP "flash_done" SITE "AJ4"; +#LOCATE COMP "flash_programn" SITE "AH4"; +#LOCATE COMP "flash_cfg_select[0]" SITE "AM4"; +#LOCATE COMP "flash_cfg_select[1]" SITE "AL4"; +#LOCATE COMP "flash_cfg_select[2]" SITE "AK4"; +IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SD card "sdcard", "usb" sheet +LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14 +LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15 +LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2 +LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi GPIO4 +LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12 +LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13 +LOCATE COMP "sd_wp" SITE "P5"; # not connected +LOCATE COMP "sd_cdn" SITE "N5"; # not connected +IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement +IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## ADC SPI (MAX11123) "analog", "ram" sheet +LOCATE COMP "adc_csn" SITE "R17"; +LOCATE COMP "adc_mosi" SITE "R16"; +LOCATE COMP "adc_miso" SITE "U16"; +LOCATE COMP "adc_sclk" SITE "P17"; +IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## Audio 4-bit DAC "analog", "gpio" sheet +# 4-bit mode can drive down to 75 ohm load impedance. +# Lower impedance leads to IO overload, +# FPGA will stop working and need reboot. +# For standard 17 ohm earphones on PCB v1.7: +# use bits 2,3 as input (High-Z) and drive only bits 0,1. +# PCB v2.1.2 can use full 4 bits and 16mA drive for 17 ohm earphones. +LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio) +LOCATE COMP "audio_l[2]" SITE "C3"; +LOCATE COMP "audio_l[1]" SITE "D3"; +LOCATE COMP "audio_l[0]" SITE "E4"; +LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio) +LOCATE COMP "audio_r[2]" SITE "D5"; +LOCATE COMP "audio_r[1]" SITE "B5"; +LOCATE COMP "audio_r[0]" SITE "A3"; +LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio) +LOCATE COMP "audio_v[2]" SITE "F5"; +LOCATE COMP "audio_v[1]" SITE "F2"; +LOCATE COMP "audio_v[0]" SITE "H5"; +IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## WiFi ESP-32 "wifi", "usb", "flash" sheet +# other pins are shared with GP/GN, SD card and JTAG +LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi +LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi +LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi +LOCATE COMP "wifi_gpio0" SITE "L2"; +LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED +LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX +LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX +# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active +IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio5" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## PCB antenna 433 MHz (may be also used for FM) "usb" sheet +LOCATE COMP "ant_433mhz" SITE "G1"; +IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Second USB port "US2" going directly into FPGA "usb", "ram" sheet +LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only +LOCATE COMP "usb_fpga_dn" SITE "F16"; +IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +LOCATE COMP "ps2_clk" SITE "D15"; # single-ended bidirectional +LOCATE COMP "ps2_din" SITE "E15"; +IOBUF PORT "ps2_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "ps2_din" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control +LOCATE COMP "usb_fpga_pu_dn" SITE "C12"; +IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; + +## JTAG ESP-32 "usb" sheet +# connected to FT231X and ESP-32 +# commented out because those are dedicated pins, not directly useable as GPIO +# but could be used by some vendor-specific JTAG bridging (boundary scan) module +#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives +#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits +#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives +#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives +#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SDRAM "ram" sheet +LOCATE COMP "sdram_clk" SITE "F19"; +LOCATE COMP "sdram_cke" SITE "F20"; +LOCATE COMP "sdram_csn" SITE "P20"; +LOCATE COMP "sdram_wen" SITE "T20"; +LOCATE COMP "sdram_rasn" SITE "R20"; +LOCATE COMP "sdram_casn" SITE "T19"; +LOCATE COMP "sdram_a[0]" SITE "M20"; +LOCATE COMP "sdram_a[1]" SITE "M19"; +LOCATE COMP "sdram_a[2]" SITE "L20"; +LOCATE COMP "sdram_a[3]" SITE "L19"; +LOCATE COMP "sdram_a[4]" SITE "K20"; +LOCATE COMP "sdram_a[5]" SITE "K19"; +LOCATE COMP "sdram_a[6]" SITE "K18"; +LOCATE COMP "sdram_a[7]" SITE "J20"; +LOCATE COMP "sdram_a[8]" SITE "J19"; +LOCATE COMP "sdram_a[9]" SITE "H20"; +LOCATE COMP "sdram_a[10]" SITE "N19"; +LOCATE COMP "sdram_a[11]" SITE "G20"; +LOCATE COMP "sdram_a[12]" SITE "G19"; +LOCATE COMP "sdram_ba[0]" SITE "P19"; +LOCATE COMP "sdram_ba[1]" SITE "N20"; +LOCATE COMP "sdram_dqm[0]" SITE "U19"; +LOCATE COMP "sdram_dqm[1]" SITE "E20"; +LOCATE COMP "sdram_d[0]" SITE "J16"; +LOCATE COMP "sdram_d[1]" SITE "L18"; +LOCATE COMP "sdram_d[2]" SITE "M18"; +LOCATE COMP "sdram_d[3]" SITE "N18"; +LOCATE COMP "sdram_d[4]" SITE "P18"; +LOCATE COMP "sdram_d[5]" SITE "T18"; +LOCATE COMP "sdram_d[6]" SITE "T17"; +LOCATE COMP "sdram_d[7]" SITE "U20"; +LOCATE COMP "sdram_d[8]" SITE "E19"; +LOCATE COMP "sdram_d[9]" SITE "D20"; +LOCATE COMP "sdram_d[10]" SITE "D19"; +LOCATE COMP "sdram_d[11]" SITE "C20"; +LOCATE COMP "sdram_d[12]" SITE "E18"; +LOCATE COMP "sdram_d[13]" SITE "F18"; +LOCATE COMP "sdram_d[14]" SITE "J18"; +LOCATE COMP "sdram_d[15]" SITE "J17"; +IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +# GPDI differential interface (Video) "gpdi" sheet +LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue + +LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue - +LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green + +LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green - +LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red + +LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red - +LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock + +LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock - +LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet + +LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet - +LOCATE COMP "gpdi_cec" SITE "A18"; +LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC +LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12 +IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet +# Pins enumerated gp[0-27], gn[0-27]. +# With differential mode enabled on Lattice, +# gp[] (+) are used, gn[] (-) are ignored from design +# as they handle inverted signal by default. +# To enable differential, rename LVCMOS33->LVCMOS33D +LOCATE COMP "gp[0]" SITE "B11"; # J1_5+ GP0 +LOCATE COMP "gn[0]" SITE "C11"; # J1_5- GN0 +LOCATE COMP "gp[1]" SITE "A10"; # J1_7+ GP1 +LOCATE COMP "gn[1]" SITE "A11"; # J1_7- GN1 +LOCATE COMP "gp[2]" SITE "A9"; # J1_9+ GP2 +LOCATE COMP "gn[2]" SITE "B10"; # J1_9- GN2 +LOCATE COMP "gp[3]" SITE "B9"; # J1_11+ GP3 +LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3 +LOCATE COMP "gp[4]" SITE "A7"; # J1_13+ GP4 +LOCATE COMP "gn[4]" SITE "A8"; # J1_13- GN4 +LOCATE COMP "gp[5]" SITE "C8"; # J1_15+ GP5 +LOCATE COMP "gn[5]" SITE "B8"; # J1_15- GN5 +LOCATE COMP "gp[6]" SITE "C6"; # J1_17+ GP6 +LOCATE COMP "gn[6]" SITE "C7"; # J1_17- GN6 +IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[7]" SITE "A6"; # J1_23+ GP7 +LOCATE COMP "gn[7]" SITE "B6"; # J1_23- GN7 +LOCATE COMP "gp[8]" SITE "A4"; # J1_25+ GP8 +LOCATE COMP "gn[8]" SITE "A5"; # J1_25- GN8 +LOCATE COMP "gp[9]" SITE "A2"; # J1_27+ GP9 +LOCATE COMP "gn[9]" SITE "B1"; # J1_27- GN9 +LOCATE COMP "gp[10]" SITE "C4"; # J1_29+ GP10 WIFI_GPIO27 +LOCATE COMP "gn[10]" SITE "B4"; # J1_29- GN10 +LOCATE COMP "gp[11]" SITE "F4"; # J1_31+ GP11 WIFI_GPIO25 +LOCATE COMP "gn[11]" SITE "E3"; # J1_31- GN11 WIFI_GPIO26 +LOCATE COMP "gp[12]" SITE "G3"; # J1_33+ GP12 WIFI_GPIO32 +LOCATE COMP "gn[12]" SITE "F3"; # J1_33- GN12 WIFI_GPIO33 +LOCATE COMP "gp[13]" SITE "H4"; # J1_35+ GP13 WIFI_GPIO34 +LOCATE COMP "gn[13]" SITE "G5"; # J1_35- GN13 WIFI_GPIO35 +IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp[14]" SITE "U18"; # J2_5+ GP14 +LOCATE COMP "vga_g[3]" SITE "U17"; # J2_5- GN14 +LOCATE COMP "gp[15]" SITE "N17"; # J2_7+ GP15 +LOCATE COMP "vga_g[2]" SITE "P16"; # J2_7- GN15 +LOCATE COMP "vga_v_sync" SITE "N16"; # J2_9+ GP16 +LOCATE COMP "vga_g[1]" SITE "M17"; # J2_9- GN16 +LOCATE COMP "vga_h_sync" SITE "L16"; # J2_11+ GP17 +LOCATE COMP "vga_g[0]" SITE "L17"; # J2_11- GN17 +LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18 +LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18 +LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19 +LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19 +LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20 +LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20 +IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_g[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_g[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_v_sync" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_g[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_h_sync" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_g[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "vga_b[3]" SITE "C18"; # J2_23+ GP21 +LOCATE COMP "vga_r[3]" SITE "D17"; # J2_23- GN21 +LOCATE COMP "vga_b[2]" SITE "B15"; # J2_25+ GP22 D15->B15 +LOCATE COMP "vga_r[2]" SITE "C15"; # J2_25- GN22 E15->C15 +LOCATE COMP "vga_b[1]" SITE "B17"; # J2_27+ GP23 +LOCATE COMP "vga_r[1]" SITE "C17"; # J2_27- GN23 +LOCATE COMP "vga_b[0]" SITE "C16"; # J2_29+ GP24 +LOCATE COMP "vga_r[0]" SITE "D16"; # J2_29- GN24 +LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25 B15->D14 +LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25 C15->E14 +LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26 +LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26 +LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27 +LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27 +IOBUF PORT "vga_b[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_r[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_b[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_r[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_b[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_r[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_b[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "vga_r[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## PROGRAMN (reload bitstream from FLASH, exit from bootloader) +# PCB v2.0.5 and higher +LOCATE COMP "user_programn" SITE "M4"; +IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5) +# on PCB v1.7 shutdown is not connected to FPGA +LOCATE COMP "shutdown" SITE "G16"; # FPGA receives +IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; diff --git a/boards/ulx4m/README.md b/boards/ulx4m/README.md new file mode 100644 index 0000000..82b4aa0 --- /dev/null +++ b/boards/ulx4m/README.md @@ -0,0 +1,21 @@ +# Ulx4m with HDMI + +This adds support for building the Apple One design for [Ulx4m](https://intergalaktik.eu/projects/ulx4m/) with HDMI output and a PS/2 keyboard connected to a Digilent PS2 keyboard PMOD. + +## Peripheral support + +HDMI output on the first HDMI connector on a CM4 I/O board + +PS/2 keyboard via a Digilent PS2 keyboard PMOD on gpio[25] and gpio[26]. + +## Building +Install a recent ECP5 open source toolchain, and do: + +``` +$ cd yosys +$ make dfu +``` + +## Use + +To load BASIC type "E000R" (with CAPS LOCK on if you are using the UART rather than the PS/2 keyboard). diff --git a/boards/ulx4m/yosys/Makefile b/boards/ulx4m/yosys/Makefile new file mode 100644 index 0000000..a0b0abb --- /dev/null +++ b/boards/ulx4m/yosys/Makefile @@ -0,0 +1,73 @@ +DEVICE = um-45k +PIN_DEF=ulx4m_v002.lpf + +SOURCEDIR = ../../../rtl +BUILDDIR = build + +all: apple1 prog + +info: + @echo " To build: make apple1" + @echo " To program: make prog or make dfu" + @echo "To build report: make report" + @echo " To clean up: make clean" + +dir: + mkdir -p $(BUILDDIR) + +# ------ TEMPLATES ------ +$(BUILDDIR)/%.json: $(SOURCEDIR)/%.v + yosys -q -p "chparam -list; hierarchy -top apple1_top; synth_ecp5 -json $@" $^ + +$(BUILDDIR)/%.config: $(PIN_DEF) $(BUILDDIR)/%.json + nextpnr-ecp5 --${DEVICE} --package CABGA381 --freq 25 --textcfg $@ --json $(filter-out $<,$^) --lpf $< + +$(BUILDDIR)/%.bit: $(BUILDDIR)/%.config + ecppack --compress $^ $@ + +%_tb.vvp: %_tb.v %.v + iverilog -o $@ $^ + +%_tb.vcd: %_tb.vvp + vvp -N $< +vcd=$@ + +# ------ APPLE 1 ------ +apple1: dir $(BUILDDIR)/apple1.bit + +$(BUILDDIR)/apple1.bin: $(BUILDDIR)/apple1.asc +$(BUILDDIR)/apple1.asc: $(BUILDDIR)/apple1.json +$(BUILDDIR)/apple1.json: $(SOURCEDIR)/apple1.v \ + $(SOURCEDIR)/clock.v \ + $(SOURCEDIR)/pwr_reset.v \ + $(SOURCEDIR)/ram.v \ + $(SOURCEDIR)/rom_wozmon.v \ + $(SOURCEDIR)/rom_basic.v \ + $(SOURCEDIR)/cpu/arlet_6502.v \ + $(SOURCEDIR)/cpu/arlet/ALU.v \ + $(SOURCEDIR)/cpu/arlet/cpu.v \ + $(SOURCEDIR)/uart/uart.v \ + $(SOURCEDIR)/uart/async_tx_rx.v \ + $(SOURCEDIR)/vga/vga.v \ + $(SOURCEDIR)/vga/vram.v \ + $(SOURCEDIR)/vga/font_rom.v \ + $(SOURCEDIR)/ps2keyboard/debounce.v \ + $(SOURCEDIR)/ps2keyboard/ps2keyboard.v \ + $(SOURCEDIR)/boards/ulx4m/apple1_dvi.v \ + $(SOURCEDIR)/boards/ulx4m/vga2dvid.v \ + $(SOURCEDIR)/boards/ulx4m/clk_25_250_125_25.v \ + $(SOURCEDIR)/boards/ulx4m/tmds_encoder.v \ + $(SOURCEDIR)/boards/ulx4m/fake_differential.v + +prog: dir $(BUILDDIR)/apple1.bit + fujprog $(filter-out $<,$^) + +dfu: dir $(BUILDDIR)/apple1.bit + dfu-util -a 0 -D $(filter-out $<,$^) -R + + +# ------ HELPERS ------ +clean: + rm -rf build + +.SECONDARY: +.PHONY: all info clean prog diff --git a/boards/ulx4m/yosys/slow.py b/boards/ulx4m/yosys/slow.py new file mode 100755 index 0000000..6442796 --- /dev/null +++ b/boards/ulx4m/yosys/slow.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 + +import time +import os +import sys + +if len(sys.argv) != 2: + print("Usage: " + sys.argv[0] + " ") + sys.exit(1) + +os.system('stty -F /dev/ttyUSB0 raw -echo 115200') +fin = open(sys.argv[1], "r") +fout = open("/dev/ttyUSB0", "w") + +for line in fin: + for ch in line.strip('\n'): + fout.write(ch) + fout.flush() + time.sleep(.1) + fout.write('\r') + fout.flush() + time.sleep(.5) +fin.close() +fout.close() + + + + + + diff --git a/boards/ulx4m/yosys/ulx4m_v002.lpf b/boards/ulx4m/yosys/ulx4m_v002.lpf new file mode 100644 index 0000000..5aac3a0 --- /dev/null +++ b/boards/ulx4m/yosys/ulx4m_v002.lpf @@ -0,0 +1,397 @@ +BLOCK RESETPATHS; +BLOCK ASYNCPATHS; +## ULX4M-LS v0.0.2 + +# The clock "usb" and "gpdi" sheet +LOCATE COMP "clk_25mhz" SITE "G2"; +IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33; +FREQUENCY PORT "clk_25mhz" 25 MHZ; + +# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash +# write to FLASH possible any time from JTAG: +SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=ENABLE SLAVE_PARALLEL_PORT=DISABLE; +# write to FLASH possible from user bitstream: +# SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; + +## LED indicators "blinkey" and "gpio" sheet +LOCATE COMP "led[3]" SITE "C1"; +LOCATE COMP "led[2]" SITE "B3"; +LOCATE COMP "led[1]" SITE "B1"; +LOCATE COMP "led[0]" SITE "B2"; +IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Buttons "blinkey" and "gpio" sheet +LOCATE COMP "btn[1]" SITE "C3"; +LOCATE COMP "btn[2]" SITE "C2"; +IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SPI Flash chip "flash" sheet +LOCATE COMP "flash_csn" SITE "R2"; +LOCATE COMP "flash_clk" SITE "U3"; +LOCATE COMP "flash_mosi" SITE "W2"; +LOCATE COMP "flash_miso" SITE "V2"; +LOCATE COMP "flash_holdn" SITE "W1"; +LOCATE COMP "flash_wpn" SITE "Y2"; +#LOCATE COMP "flash_csspin" SITE "AJ3"; +#LOCATE COMP "flash_initn" SITE "AG4"; +#LOCATE COMP "flash_done" SITE "AJ4"; +#LOCATE COMP "flash_programn" SITE "AH4"; +#LOCATE COMP "flash_cfg_select[0]" SITE "AM4"; +#LOCATE COMP "flash_cfg_select[1]" SITE "AL4"; +#LOCATE COMP "flash_cfg_select[2]" SITE "AK4"; +IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## SD card "sdcard", "usb" sheet +LOCATE COMP "sd_clk" SITE "H2"; # sd_clk WiFi_GPIO14 CM4_GPIO12 +LOCATE COMP "sd_cmd" SITE "J1"; # sd_cmd_di (MOSI) WiFi_GPIO15 CM4_GPIO27 +LOCATE COMP "sd_d[0]" SITE "J3"; # sd_dat0_do (MISO) WiFi_GPIO2 CM4_GPIO4 +LOCATE COMP "sd_d[1]" SITE "H1"; # sd_dat1_irq WiFi_GPIO4 CM4_GPIO3 +LOCATE COMP "sd_d[2]" SITE "K1"; # sd_dat2 WiFi_GPIO12 CM4_GPIO2 +LOCATE COMP "sd_d[3]" SITE "K2"; # sd_dat3_csn WiFi_GPIO13 CM4_GPIO14 +LOCATE COMP "sd_wp" SITE "P5"; # not connected +LOCATE COMP "sd_cdn" SITE "N5"; # not connected +IOBUF PORT "sd_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cmd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # WiFi GPIO12 pulldown bootstrapping requirement +IOBUF PORT "sd_d[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_wp" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sd_cdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "sd_pwr_on" SITE "U17"; # J2_5- GN14 +IOBUF PORT "sd_pwr_on" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Second USB port "US2" going directly into FPGA "usb", "ram" sheet +LOCATE COMP "usb_fpga_dp" SITE "E16"; # same on ULX3S and ULX4M +LOCATE COMP "usb_fpga_dn" SITE "F16"; # same on ULX3S and ULX4M +IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16; +LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # single-ended bidirectional same on ULX3S and ULX4M +LOCATE COMP "usb_fpga_bd_dn" SITE "E15"; # single-ended bidirectional same on ULX3S and ULX4M +IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "usb_fpga_pu_dp" SITE "A2"; # pull up/down control +LOCATE COMP "usb_fpga_pu_dn" SITE "A3"; +IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16; +LOCATE COMP "usb_fpga_otg_id" SITE "A4"; +IOBUF PORT "usb_fpga_otg_id" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "n_extrst" SITE "U16"; +IOBUF PORT "n_extrst" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## JTAG ESP-32 "usb" sheet +# connected to FT231X and ESP-32 +# commented out because those are dedicated pins, not directly useable as GPIO +# but could be used by some vendor-specific JTAG bridging (boundary scan) module +#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI FPGA receives +#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS FPGA transmits +#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR FPGA receives +#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD FPGA receives +#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SDRAM "ram" sheet +LOCATE COMP "sdram_clk" SITE "G19"; +LOCATE COMP "sdram_cke" SITE "G20"; +LOCATE COMP "sdram_csn" SITE "P18"; +LOCATE COMP "sdram_wen" SITE "N20"; +LOCATE COMP "sdram_rasn" SITE "M18"; +LOCATE COMP "sdram_casn" SITE "N18"; +LOCATE COMP "sdram_a[0]" SITE "L19"; +LOCATE COMP "sdram_a[1]" SITE "L20"; +LOCATE COMP "sdram_a[2]" SITE "M19"; +LOCATE COMP "sdram_a[3]" SITE "H17"; +LOCATE COMP "sdram_a[4]" SITE "F20"; +LOCATE COMP "sdram_a[5]" SITE "F18"; +LOCATE COMP "sdram_a[6]" SITE "E19"; +LOCATE COMP "sdram_a[7]" SITE "F19"; +LOCATE COMP "sdram_a[8]" SITE "E20"; +LOCATE COMP "sdram_a[9]" SITE "C20"; +LOCATE COMP "sdram_a[10]" SITE "N19"; +LOCATE COMP "sdram_a[11]" SITE "D20"; +LOCATE COMP "sdram_a[12]" SITE "E18"; +LOCATE COMP "sdram_ba[0]" SITE "L18"; +LOCATE COMP "sdram_ba[1]" SITE "M20"; +LOCATE COMP "sdram_dqm[0]" SITE "P20"; +LOCATE COMP "sdram_dqm[1]" SITE "D19"; +LOCATE COMP "sdram_d[0]" SITE "U20"; +LOCATE COMP "sdram_d[1]" SITE "T20"; +LOCATE COMP "sdram_d[2]" SITE "U19"; +LOCATE COMP "sdram_d[3]" SITE "T19"; +LOCATE COMP "sdram_d[4]" SITE "T18"; +LOCATE COMP "sdram_d[5]" SITE "T17"; +LOCATE COMP "sdram_d[6]" SITE "R20"; +LOCATE COMP "sdram_d[7]" SITE "P19"; +LOCATE COMP "sdram_d[8]" SITE "H20"; +LOCATE COMP "sdram_d[9]" SITE "J19"; +LOCATE COMP "sdram_d[10]" SITE "K18"; +LOCATE COMP "sdram_d[11]" SITE "J18"; +LOCATE COMP "sdram_d[12]" SITE "H18"; +LOCATE COMP "sdram_d[13]" SITE "J16"; +LOCATE COMP "sdram_d[14]" SITE "K19"; +LOCATE COMP "sdram_d[15]" SITE "J17"; +IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +# GPDI differential interface (Video) "gpdi" sheet +LOCATE COMP "gpdi_dp[0]" SITE "F17"; # Blue + +LOCATE COMP "gpdi_dn[0]" SITE "G18"; # Blue - +LOCATE COMP "gpdi_dp[1]" SITE "D18"; # Green + +LOCATE COMP "gpdi_dn[1]" SITE "E17"; # Green - +LOCATE COMP "gpdi_dp[2]" SITE "C18"; # Red + +LOCATE COMP "gpdi_dn[2]" SITE "D17"; # Red - +LOCATE COMP "gpdi_dp[3]" SITE "J20"; # Clock + +LOCATE COMP "gpdi_dn[3]" SITE "K20"; # Clock - +#LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet + +#LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet - +LOCATE COMP "gpdi_cec" SITE "A18"; +#LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC +#LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12 +IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +#IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +LOCATE COMP "gpdi_dp[4]" SITE "B9"; # Blue + +#LOCATE COMP "gpdi_dn[4]" SITE "C10"; # Blue - +LOCATE COMP "gpdi_dp[5]" SITE "A7"; # Green + +#LOCATE COMP "gpdi_dn[5]" SITE "A8"; # Green - +LOCATE COMP "gpdi_dp[6]" SITE "C8"; # Red + +#LOCATE COMP "gpdi_dn[6]" SITE "B8"; # Red - +LOCATE COMP "gpdi_dp[7]" SITE "B11"; # Clock + +#LOCATE COMP "gpdi_dn[7]" SITE "C11"; # Clock - +IOBUF PORT "gpdi_dp[4]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[4]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[5]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[5]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[6]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[6]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[7]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[7]" IO_TYPE=LVCMOS33D DRIVE=4; + +# wifi - do not use together with CM4 GPIO +LOCATE COMP "wifi_gpio0" SITE "U1"; +LOCATE COMP "wifi_gpio2" SITE "K4"; # sd_d0_do (MISO) WiFi GPIO2 +LOCATE COMP "wifi_gpio4" SITE "J5"; # sd_d1_irq WiFi GPIO4 +LOCATE COMP "wifi_gpio5" SITE "U5"; # +LOCATE COMP "wifi_gpio12" SITE "K5"; # sd_d2 WiFi_GPIO12 +LOCATE COMP "wifi_gpio13" SITE "L4"; # sd_d3_csn WiFi_GPIO13 +LOCATE COMP "wifi_gpio14" SITE "L5"; # sd_clk WiFi_GPIO14 +LOCATE COMP "wifi_gpio15" SITE "N16"; # sd_cmd_di (MOSI) WiFi GPIO15 +LOCATE COMP "wifi_gpio19" SITE "P4"; +LOCATE COMP "wifi_gpio21" SITE "P17"; +LOCATE COMP "wifi_gpio22" SITE "P16"; +LOCATE COMP "wifi_gpio25" SITE "L16"; +LOCATE COMP "wifi_gpio26" SITE "N17"; +LOCATE COMP "wifi_gpio27" SITE "G16"; +LOCATE COMP "wifi_gpio33" SITE "H16"; +LOCATE COMP "wifi_gpio34" SITE "V4"; +LOCATE COMP "wifi_gpio35" SITE "N17"; + +IOBUF PORT "wifi_gpio0" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio2" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # pull down or drive 0 for esp32 programming +IOBUF PORT "wifi_gpio4" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio5" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio12" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio13" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; # pull down or drive 0 for esp32 programming +IOBUF PORT "wifi_gpio14" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio15" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio19" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio21" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio22" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio25" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio26" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio27" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio33" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio34" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_gpio35" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +LOCATE COMP "ftdi_txden" SITE "T1"; # FTDI_TXDEN +LOCATE COMP "LED1_HAT" SITE "N5"; # LED1 on HAT +LOCATE COMP "wifi_en" SITE "U18";# WIFI_EN +LOCATE COMP "ftdi_txd" SITE "N4"; # FTDI_TXD +LOCATE COMP "ftdi_rxd" SITE "N3"; # FTDI_RXD +LOCATE COMP "wifi_txd" SITE "P5"; # WIFI_TXD +LOCATE COMP "wifi_rxd" SITE "V1"; # WIFI_RXD + +IOBUF PORT "ftdi_txden" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "LED1_HAT" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "ftdi_txd" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "ftdi_rxd" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +LOCATE COMP "btn[3]" SITE "E3"; +LOCATE COMP "btn[4]" SITE "E4"; +LOCATE COMP "btn[5]" SITE "E5"; +LOCATE COMP "btn[6]" SITE "H5"; +LOCATE COMP "btn[0]" SITE "H4"; +LOCATE COMP "nc1" SITE "F2"; +LOCATE COMP "sw" SITE "G3"; +IOBUF PORT "btn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "btn[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "nc1" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "sw[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## CM4 GPIO +LOCATE COMP "gpio[0]" SITE "R16"; # SDA0 - WIFI_GPIO21 +LOCATE COMP "gpio[1]" SITE "R17"; # SCL0 - WIFI_GPIO22 +LOCATE COMP "gpio[2]" SITE "K5"; # SD_D2 - ESP32 SD share +LOCATE COMP "gpio[3]" SITE "J5"; # SD_D1 - ESP32 SD share +LOCATE COMP "gpio[4]" SITE "K4"; # SD_D0 - ESP32 SD share +LOCATE COMP "gpio[5]" SITE "H16"; # WIFI_GPIO33 +LOCATE COMP "gpio[6]" SITE "R1"; # BTN1 on HAT +LOCATE COMP "gpio[7]" SITE "P3"; # BTN2 on HAT +LOCATE COMP "gpio[8]" SITE "P4"; # WIFI_GPIO19 +LOCATE COMP "gpio[9]" SITE "G16"; # WIFI_GPIO27 +LOCATE COMP "gpio[10]" SITE "N17";# WIFI_GPIO26 +LOCATE COMP "gpio[11]" SITE "L16";# WIFI_GPIO25 +LOCATE COMP "gpio[12]" SITE "C4"; # FPGA TDI do not use - not connected! +LOCATE COMP "gpio[13]" SITE "T1"; # FTDI_TXDEN +LOCATE COMP "gpio[14]" SITE "L4"; # SD_D3 - ESP32 SD share +LOCATE COMP "gpio[15]" SITE "L5"; # SD_CLK - ESP32 SD share +LOCATE COMP "gpio[16]" SITE "B4"; # FPGA TDO do not use - not connected! +LOCATE COMP "gpio[17]" SITE "M17";# WIFI_GPIO35 +LOCATE COMP "gpio[18]" SITE "N5"; # LED1 on HAT +LOCATE COMP "gpio[19]" SITE "U1"; # WIFI_GPIO0 +LOCATE COMP "gpio[20]" SITE "E4"; # FPGA TCK do not use - not connected! +LOCATE COMP "gpio[21]" SITE "D5"; # FPGA TMS do not use - not connected! +LOCATE COMP "gpio[22]" SITE "U18";# WIFI_EN +LOCATE COMP "gpio[23]" SITE "N4"; # FTDI_TXD +LOCATE COMP "gpio[24]" SITE "N3"; # FTDI_RXD +LOCATE COMP "gpio[25]" SITE "P5"; # WIFI_TXD +LOCATE COMP "gpio[26]" SITE "V1"; # WIFI_RXD +LOCATE COMP "gpio[27]" SITE "N16";# SD_CMD - ESP32 SD share +IOBUF PORT "gpio[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[16]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[17]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[18]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[19]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[20]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[21]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[22]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[23]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[24]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[25]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[26]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpio[27]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## DSI +# +LOCATE COMP "dsiRX0_dp[0]" SITE "B12"; # Clk + +LOCATE COMP "dsiRX0_dn[0]" SITE "C12"; # Clk - +LOCATE COMP "dsiRX0_dp[1]" SITE "A12"; # DSI RX D0 + +LOCATE COMP "dsiRX0_dn[1]" SITE "A13"; # DSI RX D0 - +LOCATE COMP "dsiRX0_dp[2]" SITE "B13"; # DSI RX D1 + +LOCATE COMP "dsiRX0_dn[2]" SITE "C13"; # DSI RX D1 - +LOCATE COMP "dsiTX0_dp[0]" SITE "D12"; # Clk + +LOCATE COMP "dsiTX0_dn[0]" SITE "E12"; # Clk - +LOCATE COMP "dsiTX0_dp[1]" SITE "D13"; # DSI TX D0 + +LOCATE COMP "dsiTX0_dn[1]" SITE "E13"; # DSI TX D0 - +LOCATE COMP "dsiTX0_dp[2]" SITE "A14"; # DSI TX D1 + +LOCATE COMP "dsiTX0_dn[2]" SITE "C14"; # DSI TX D1 - +IOBUF PORT "dsiRX0_dp[0]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiRX0_dn[0]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiRX0_dp[1]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiRX0_dn[1]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiRX0_dp[2]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiRX0_dn[2]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiTX0_dp[0]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiTX0_dp[0]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiTX0_dp[1]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiTX0_dp[1]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiTX0_dp[2]" IO_TYPE=LVCMOS12 ; +IOBUF PORT "dsiTX0_dp[2]" IO_TYPE=LVCMOS12 ; + +## PROGRAMN (reload bitstream from FLASH, exit from bootloader) +# PCB v2.0.5 and higher +LOCATE COMP "user_programn" SITE "M4"; +IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; + +## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5) +# on PCB v1.7 shutdown is not connected to FPGA +LOCATE COMP "shutdown" SITE "G16"; # FPGA receives +IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; diff --git a/rtl/apple1.v b/rtl/apple1.v index 9800030..b33501d 100644 --- a/rtl/apple1.v +++ b/rtl/apple1.v @@ -49,6 +49,7 @@ module apple1 #( output vga_grn, // green VGA signal output vga_blu, // blue VGA signal input vga_cls, // clear screen button + output vga_blank, // set when vga not in active area // Debugging ports output [15:0] pc_monitor // spy for program counter / debugging @@ -102,7 +103,7 @@ module apple1 #( ////////////////////////////////////////////////////////////////////////// // Address Decoding - wire ram_cs = (ab[15:13] == 3'b000); // 0x0000 -> 0x1FFF + wire ram_cs = (ab[15] == 1'b0); // 0x0000 -> 0x7FFF // font mode, background and foreground colour wire vga_mode_cs = (ab[15:2] == 14'b11000000000000); // 0xC000 -> 0xC003 @@ -133,7 +134,7 @@ module apple1 #( .RAM_FILENAME (RAM_FILENAME) ) my_ram( .clk(clk25), - .address(ab[12:0]), + .address(ab[14:0]), .w_en(we & ram_cs), .din(dbo), .dout(ram_dout) @@ -223,6 +224,7 @@ module apple1 #( .mode(font_mode), .fg_colour(fg_colour), .bg_colour(bg_colour), + .vga_blank(vga_blank), .clr_screen(vga_cls) ); diff --git a/rtl/boards/blackicemx/apple1_hx8k.v b/rtl/boards/blackicemx/apple1_hx8k.v new file mode 100644 index 0000000..778f446 --- /dev/null +++ b/rtl/boards/blackicemx/apple1_hx8k.v @@ -0,0 +1,112 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// Description: Apple 1 implementation for the Blackeice II ICE40HX8K + +// +// Author.....: Lawrie Griffiths and Alan Garfield +// Date.......: 31-3-2018 +// + +module apple1_top #( + parameter BASIC_FILENAME = "../../../roms/basic.hex", + parameter FONT_ROM_FILENAME = "../../../roms/vga_font_bitreversed.hex", + parameter RAM_FILENAME = "../../../roms/ram.hex", + parameter VRAM_FILENAME = "../../../roms/vga_vram.bin", + parameter WOZMON_ROM_FILENAME = "../../../roms/wozmon.hex" +) ( + input clk25, // 25 MHz board clock + + // I/O interface to computer + input uart_rx, // asynchronous serial data input from computer + output uart_tx, // asynchronous serial data output to computer + output uart_cts, // clear to send flag to computer - not used + + // I/O interface to keyboard + input ps2_clk, // PS/2 keyboard serial clock input + input ps2_din, // PS/2 keyboard serial data input + + // Outputs to VGA display + output vga_h_sync, // hozizontal VGA sync pulse + output vga_v_sync, // vertical VGA sync pulse + + output [3:0] vga_r, // red VGA signal + output [3:0] vga_g, // green VGA signal + output [3:0] vga_b, // blue VGA signal + + // Debugging ports + output [3:0] led, + input [1:0] button // 2 buttons on board +); + + assign led[0] = 1; + assign led[1] = reset_n; + assign led[2] = clr_screen_n; + assign led[3] = 0; + + wire vga_bit; + + // set the monochrome base colour here.. + assign vga_r[3:0] = vga_bit ? 4'b1000 : 4'b0000; + assign vga_g[3:0] = vga_bit ? 4'b1111 : 4'b0000; + assign vga_b[3:0] = vga_bit ? 4'b1000 : 4'b0000; + + // debounce reset button + wire reset_n; + debounce reset_button ( + .clk25(clk25), + .rst(1'b0), + .sig_in(button[0]), + .sig_out(reset_n) + ); + + // debounce clear screen button + wire clr_screen_n; + debounce clr_button ( + .clk25(clk25), + .rst(~reset_n), + .sig_in(button[1]), + .sig_out(clr_screen_n) + ); + + // apple one main system + apple1 #( + .BASIC_FILENAME (BASIC_FILENAME), + .FONT_ROM_FILENAME (FONT_ROM_FILENAME), + .RAM_FILENAME (RAM_FILENAME), + .VRAM_FILENAME (VRAM_FILENAME), + .WOZMON_ROM_FILENAME (WOZMON_ROM_FILENAME) + ) my_apple1( + .clk25(clk25), + .rst_n(reset_n), + + .uart_rx(uart_rx), + .uart_tx(uart_tx), + .uart_cts(uart_cts), + + .ps2_clk(ps2_clk), + .ps2_din(ps2_din), + .ps2_select(1'b1), // PS/2 enabled, UART TX disabled + //.ps2_select(1'b0), // PS/2 disabled, UART TX enabled + + .vga_h_sync(vga_h_sync), + .vga_v_sync(vga_v_sync), + .vga_red(vga_bit), + //.vga_grn(vga_bit), + //.vga_blu(vga_bit), + .vga_cls(~clr_screen_n), + ); +endmodule diff --git a/rtl/boards/ulx3s/apple1_dvi.v b/rtl/boards/ulx3s/apple1_dvi.v new file mode 100644 index 0000000..3230de4 --- /dev/null +++ b/rtl/boards/ulx3s/apple1_dvi.v @@ -0,0 +1,183 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// Description: Apple 1 implementation for the Blackeice II ICE40HX8K + +// +// Author.....: Lawrie Griffiths and Alan Garfield +// Date.......: 31-3-2018 +// + +module apple1_top #( + parameter BASIC_FILENAME = "../../../roms/basic.hex", + parameter FONT_ROM_FILENAME = "../../../roms/vga_font_bitreversed.hex", + parameter RAM_FILENAME = "../../../roms/ram.hex", + parameter VRAM_FILENAME = "../../../roms/vga_vram.bin", + parameter WOZMON_ROM_FILENAME = "../../../roms/wozmon.hex" +) ( + input clk_25mhz, // 25 MHz board clock + + // I/O interface to computer + input uart_rx, // asynchronous serial data input from computer + output uart_tx, // asynchronous serial data output to computer + //output uart_cts, // clear to send flag to computer - not used + + // I/O interface to keyboard + input ps2_clk, // PS/2 keyboard serial clock input + input ps2_din, // PS/2 keyboard serial data input + + output usb_fpga_pu_dp, + output usb_fpga_pu_dn, + + output [3:0] gpdi_dp, gpdi_dn, + + // Debugging ports + output [3:0] led, + input [1:0] button, // 2 buttons on board + input [3:0] sw +); + wire uart_cts; + + parameter C_ddr = 1'b1; // 0:SDR 1:DDR + + // clock generator + wire clk_250MHz, clk_125MHz, clk_25MHz, clk_locked; + clk_25_250_125_25 + clock_instance + ( + .clki(clk_25mhz), + .clko(clk_250MHz), + .clks1(clk_125MHz), + .clks2(clk_25MHz), + .locked(clk_locked) + ); + + // shift clock choice SDR/DDR + wire clk_pixel, clk_shift; + assign clk_pixel = clk_25MHz; + generate + if(C_ddr == 1'b1) + assign clk_shift = clk_125MHz; + else + assign clk_shift = clk_250MHz; + endgenerate + + assign usb_fpga_pu_dp = 1; + assign usb_fpga_pu_dn = 1; + + assign led[0] = 1; + assign led[1] = reset_n; + assign led[2] = clr_screen_n; + assign led[3] = 0; + + wire vga_bit; + + // VGA signal generator + wire [7:0] vga_r, vga_g, vga_b; + wire vga_h_sync, vga_v_sync, vga_blank; + + // set the monochrome base colour here.. + assign vga_r = vga_bit ? 8'b10000000 : 8'b00000000; + assign vga_g = vga_bit ? 8'b11111111 : 8'b00000000; + assign vga_b = vga_bit ? 8'b10000000 : 8'b00000000; + + // debounce reset button + wire reset_n; + debounce reset_button ( + .clk25(clk_25mhz), + .rst(1'b0), + .sig_in(button[0]), + .sig_out(reset_n) + ); + + // debounce clear screen button + wire clr_screen_n; + debounce clr_button ( + .clk25(clk_25mhz), + .rst(~reset_n), + .sig_in(~button[1]), + .sig_out(clr_screen_n) + ); + + // apple one main system + apple1 #( + .BASIC_FILENAME (BASIC_FILENAME), + .FONT_ROM_FILENAME (FONT_ROM_FILENAME), + .RAM_FILENAME (RAM_FILENAME), + .VRAM_FILENAME (VRAM_FILENAME), + .WOZMON_ROM_FILENAME (WOZMON_ROM_FILENAME) + ) my_apple1( + .clk25(clk_25mhz), + .rst_n(reset_n), + + .uart_rx(uart_rx), + .uart_tx(uart_tx), + .uart_cts(uart_cts), + + .ps2_clk(ps2_clk), + .ps2_din(ps2_din), + .ps2_select(sw[0]), // PS/2 enabled, UART TX disabled + //.ps2_select(1'b0), // PS/2 disabled, UART TX enabled + + .vga_h_sync(vga_h_sync), + .vga_v_sync(vga_v_sync), + .vga_red(vga_bit), + //.vga_grn(vga_bit), + //.vga_blu(vga_bit), + .vga_blank(vga_blank), + .vga_cls(~clr_screen_n), + ); + + // VGA to digital video converter + wire [1:0] tmds[3:0]; + vga2dvid + #( + .C_ddr(C_ddr), + .C_shift_clock_synchronizer(1'b1) + ) + vga2dvid_instance + ( + .clk_pixel(clk_pixel), + .clk_shift(clk_shift), + .in_red(vga_r), + .in_green(vga_g), + .in_blue(vga_b), + .in_hsync(vga_h_sync), + .in_vsync(vga_v_sync), + .in_blank(vga_blank), + .out_clock(tmds[3]), + .out_red(tmds[2]), + .out_green(tmds[1]), + .out_blue(tmds[0]) + ); + + // output TMDS SDR/DDR data to fake differential lanes + fake_differential + #( + .C_ddr(C_ddr) + ) + fake_differential_instance + ( + .clk_shift(clk_shift), + .in_clock(tmds[3]), + .in_red(tmds[2]), + .in_green(tmds[1]), + .in_blue(tmds[0]), + .out_p(gpdi_dp), + .out_n(gpdi_dn) + ); + +endmodule diff --git a/rtl/boards/ulx3s/apple1_vga.v b/rtl/boards/ulx3s/apple1_vga.v new file mode 100644 index 0000000..b59d184 --- /dev/null +++ b/rtl/boards/ulx3s/apple1_vga.v @@ -0,0 +1,118 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// Description: Apple 1 implementation for the Blackeice II ICE40HX8K + +// +// Author.....: Lawrie Griffiths and Alan Garfield +// Date.......: 31-3-2018 +// + +module apple1_top #( + parameter BASIC_FILENAME = "../../../roms/basic.hex", + parameter FONT_ROM_FILENAME = "../../../roms/vga_font_bitreversed.hex", + parameter RAM_FILENAME = "../../../roms/ram.hex", + parameter VRAM_FILENAME = "../../../roms/vga_vram.bin", + parameter WOZMON_ROM_FILENAME = "../../../roms/wozmon.hex" +) ( + input clk_25mhz, // 25 MHz board clock + + // I/O interface to computer + input uart_rx, // asynchronous serial data input from computer + output uart_tx, // asynchronous serial data output to computer + output uart_cts, // clear to send flag to computer - not used + + // I/O interface to keyboard + input ps2_clk, // PS/2 keyboard serial clock input + input ps2_din, // PS/2 keyboard serial data input + + // Outputs to VGA display + output vga_h_sync, // hozizontal VGA sync pulse + output vga_v_sync, // vertical VGA sync pulse + + output [3:0] vga_r, // red VGA signal + output [3:0] vga_g, // green VGA signal + output [3:0] vga_b, // blue VGA signal + + output usb_fpga_pu_dp, + output usb_fpga_pu_dn, + + // Debugging ports + output [3:0] led, + input [1:0] button // 2 buttons on board +); + + assign usb_fpga_pu_dp = 1; + assign usb_fpga_pu_dn = 1; + + assign led[0] = 1; + assign led[1] = reset_n; + assign led[2] = clr_screen_n; + assign led[3] = 0; + + wire vga_bit; + + // set the monochrome base colour here.. + assign vga_r[3:0] = vga_bit ? 4'b1000 : 4'b0000; + assign vga_g[3:0] = vga_bit ? 4'b1111 : 4'b0000; + assign vga_b[3:0] = vga_bit ? 4'b1000 : 4'b0000; + + // debounce reset button + wire reset_n; + debounce reset_button ( + .clk25(clk_25mhz), + .rst(1'b0), + .sig_in(button[0]), + .sig_out(reset_n) + ); + + // debounce clear screen button + wire clr_screen_n; + debounce clr_button ( + .clk25(clk_25mhz), + .rst(~reset_n), + .sig_in(~button[1]), + .sig_out(clr_screen_n) + ); + + // apple one main system + apple1 #( + .BASIC_FILENAME (BASIC_FILENAME), + .FONT_ROM_FILENAME (FONT_ROM_FILENAME), + .RAM_FILENAME (RAM_FILENAME), + .VRAM_FILENAME (VRAM_FILENAME), + .WOZMON_ROM_FILENAME (WOZMON_ROM_FILENAME) + ) my_apple1( + .clk25(clk_25mhz), + .rst_n(reset_n), + + .uart_rx(uart_rx), + .uart_tx(uart_tx), + .uart_cts(uart_cts), + + .ps2_clk(ps2_clk), + .ps2_din(ps2_din), + .ps2_select(1'b1), // PS/2 enabled, UART TX disabled + //.ps2_select(1'b0), // PS/2 disabled, UART TX enabled + + .vga_h_sync(vga_h_sync), + .vga_v_sync(vga_v_sync), + .vga_red(vga_bit), + //.vga_grn(vga_bit), + //.vga_blu(vga_bit), + .vga_cls(~clr_screen_n), + ); +endmodule diff --git a/rtl/boards/ulx3s/clk_25_250_125_25.v b/rtl/boards/ulx3s/clk_25_250_125_25.v new file mode 100644 index 0000000..967e697 --- /dev/null +++ b/rtl/boards/ulx3s/clk_25_250_125_25.v @@ -0,0 +1,60 @@ +// diamond 3.7 accepts this PLL +// diamond 3.8-3.9 is untested +// diamond 3.10 or higher is likely to abort with error about unable to use feedback signal +// cause of this could be from wrong CPHASE/FPHASE parameters +module clk_25_250_125_25 +( + input clki, // 25 MHz, 0 deg + output clko, // 250 MHz, 0 deg + output clks1, // 125 MHz, 0 deg + output clks2, // 25 MHz, 0 deg + output locked +); +(* FREQUENCY_PIN_CLKI="25" *) +(* FREQUENCY_PIN_CLKOP="250" *) +(* FREQUENCY_PIN_CLKOS="125" *) +(* FREQUENCY_PIN_CLKOS2="25" *) +(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) +EHXPLLL #( + .PLLRST_ENA("DISABLED"), + .INTFB_WAKE("DISABLED"), + .STDBY_ENABLE("DISABLED"), + .DPHASE_SOURCE("DISABLED"), + .OUTDIVIDER_MUXA("DIVA"), + .OUTDIVIDER_MUXB("DIVB"), + .OUTDIVIDER_MUXC("DIVC"), + .OUTDIVIDER_MUXD("DIVD"), + .CLKI_DIV(1), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(2), + .CLKOP_CPHASE(0), + .CLKOP_FPHASE(0), + .CLKOS_ENABLE("ENABLED"), + .CLKOS_DIV(4), + .CLKOS_CPHASE(0), + .CLKOS_FPHASE(0), + .CLKOS2_ENABLE("ENABLED"), + .CLKOS2_DIV(20), + .CLKOS2_CPHASE(0), + .CLKOS2_FPHASE(0), + .FEEDBK_PATH("CLKOP"), + .CLKFB_DIV(10) + ) pll_i ( + .RST(1'b0), + .STDBY(1'b0), + .CLKI(clki), + .CLKOP(clko), + .CLKOS(clks1), + .CLKOS2(clks2), + .CLKFB(clko), + .CLKINTFB(), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b1), + .PHASESTEP(1'b1), + .PHASELOADREG(1'b1), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); +endmodule diff --git a/rtl/boards/ulx3s/fake_differential.v b/rtl/boards/ulx3s/fake_differential.v new file mode 100644 index 0000000..f690672 --- /dev/null +++ b/rtl/boards/ulx3s/fake_differential.v @@ -0,0 +1,63 @@ +// DDR mode uses Lattice ECP5 vendor-specific module ODDRX1F + +module fake_differential +( + input clk_shift, // used only in DDR mode + // [1:0]:DDR [0]:SDR TMDS + input [1:0] in_clock, in_red, in_green, in_blue, + // [3]:clock [2]:red [1]:green [0]:blue + output [3:0] out_p, out_n +); + parameter C_ddr = 1'b0; // 0:SDR 1:DDR + + wire [1:0] tmds[3:0]; + assign tmds[3] = in_clock; + assign tmds[2] = in_red; + assign tmds[1] = in_green; + assign tmds[0] = in_blue; + + // register stage to improve timing of the fake differential + reg [1:0] R_tmds_p[3:0], R_tmds_n[3:0]; + generate + genvar i; + for(i = 0; i < 4; i++) + begin : TMDS_pn_registers + always @(posedge clk_shift) R_tmds_p[i] <= tmds[i]; + always @(posedge clk_shift) R_tmds_n[i] <= ~tmds[i]; + end + endgenerate + + // output SDR/DDR to fake differential + generate + genvar i; + if(C_ddr == 1'b1) + for(i = 0; i < 4; i++) + begin : DDR_output_mode + ODDRX1F + ddr_p_instance + ( + .D0(R_tmds_p[i][0]), + .D1(R_tmds_p[i][1]), + .Q(out_p[i]), + .SCLK(clk_shift), + .RST(0) + ); + ODDRX1F + ddr_n_instance + ( + .D0(R_tmds_n[i][0]), + .D1(R_tmds_n[i][1]), + .Q(out_n[i]), + .SCLK(clk_shift), + .RST(0) + ); + end + else + for(i = 0; i < 4; i++) + begin : SDR_output_mode + assign out_p[i] = R_tmds_p[i][0]; + assign out_n[i] = R_tmds_n[i][0]; + end + endgenerate + +endmodule diff --git a/rtl/boards/ulx3s/tmds_encoder.v b/rtl/boards/ulx3s/tmds_encoder.v new file mode 100644 index 0000000..fbf4a27 --- /dev/null +++ b/rtl/boards/ulx3s/tmds_encoder.v @@ -0,0 +1,155 @@ +// File hdl/tmds_encoder.vhd translated with vhd2vl v3.0 VHDL to Verilog RTL translator +// vhd2vl settings: +// * Verilog Module Declaration Style: 2001 + +// vhd2vl is Free (libre) Software: +// Copyright (C) 2001 Vincenzo Liguori - Ocean Logic Pty Ltd +// http://www.ocean-logic.com +// Modifications Copyright (C) 2006 Mark Gonzales - PMC Sierra Inc +// Modifications (C) 2010 Shankar Giri +// Modifications Copyright (C) 2002-2017 Larry Doolittle +// http://doolittle.icarus.com/~larry/vhd2vl/ +// Modifications (C) 2017 Rodrigo A. Melo +// +// vhd2vl comes with ABSOLUTELY NO WARRANTY. Always check the resulting +// Verilog for correctness, ideally with a formal verification tool. +// +// You are welcome to redistribute vhd2vl under certain conditions. +// See the license (GPLv2) file included with the source for details. + +// The result of translation follows. Its copyright status should be +// considered unchanged from the original VHDL. + +//-------------------------------------------------------------------------------- +// Engineer: Mike Field +// +// Description: TMDS Encoder +// 8 bits colour, 2 control bits and one blanking bits in +// 10 bits of TMDS encoded data out +// Clocked at the pixel clock +// +//-------------------------------------------------------------------------------- +// See: http://hamsterworks.co.nz/mediawiki/index.php/Dvid_test +// http://hamsterworks.co.nz/mediawiki/index.php/FPGA_Projects +// +// Copyright (c) 2012 Mike Field +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// no timescale needed + +module tmds_encoder( +input wire clk, +input wire [7:0] data, +input wire [1:0] c, +input wire blank, +output reg [9:0] encoded +); + + + + +wire [8:0] xored; +wire [8:0] xnored; +wire [3:0] ones; +reg [8:0] data_word; +reg [8:0] data_word_inv; +wire [3:0] data_word_disparity; +reg [3:0] dc_bias = 1'b0; + + // Work our the two different encodings for the byte + assign xored[0] = data[0]; + assign xored[1] = data[1] ^ xored[0]; + assign xored[2] = data[2] ^ xored[1]; + assign xored[3] = data[3] ^ xored[2]; + assign xored[4] = data[4] ^ xored[3]; + assign xored[5] = data[5] ^ xored[4]; + assign xored[6] = data[6] ^ xored[5]; + assign xored[7] = data[7] ^ xored[6]; + assign xored[8] = 1'b1; + assign xnored[0] = data[0]; + assign xnored[1] = ~(data[1] ^ xnored[0]); + assign xnored[2] = ~(data[2] ^ xnored[1]); + assign xnored[3] = ~(data[3] ^ xnored[2]); + assign xnored[4] = ~(data[4] ^ xnored[3]); + assign xnored[5] = ~(data[5] ^ xnored[4]); + assign xnored[6] = ~(data[6] ^ xnored[5]); + assign xnored[7] = ~(data[7] ^ xnored[6]); + assign xnored[8] = 1'b0; + // Count how many ones are set in data + assign ones = 4'b0000 + data[0] + data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]; + // Decide which encoding to use + always @(ones, data[0], xnored, xored) begin + if(ones > 4 || (ones == 4 && data[0] == 1'b0)) begin + data_word <= xnored; + data_word_inv <= ~(xnored); + end + else begin + data_word <= xored; + data_word_inv <= ~(xored); + end + end + + // Work out the DC bias of the dataword; + assign data_word_disparity = 4'b1100 + data_word[0] + data_word[1] + data_word[2] + data_word[3] + data_word[4] + data_word[5] + data_word[6] + data_word[7]; + // Now work out what the output should be + always @(posedge clk) begin + if(blank == 1'b1) begin + // In the control periods, all values have and have balanced bit count + case(c) + 2'b00 : begin + encoded <= 10'b1101010100; + end + 2'b01 : begin + encoded <= 10'b0010101011; + end + 2'b10 : begin + encoded <= 10'b0101010100; + end + default : begin + encoded <= 10'b1010101011; + end + endcase + dc_bias <= {4{1'b0}}; + end + else begin + if(dc_bias == 5'b00000 || data_word_disparity == 0) begin + // dataword has no disparity + if(data_word[8] == 1'b1) begin + encoded <= {2'b01,data_word[7:0]}; + dc_bias <= dc_bias + data_word_disparity; + end + else begin + encoded <= {2'b10,data_word_inv[7:0]}; + dc_bias <= dc_bias - data_word_disparity; + end + end + else if((dc_bias[3] == 1'b0 && data_word_disparity[3] == 1'b0) || (dc_bias[3] == 1'b1 && data_word_disparity[3] == 1'b1)) begin + encoded <= {1'b1,data_word[8],data_word_inv[7:0]}; + dc_bias <= dc_bias + data_word[8] - data_word_disparity; + end + else begin + encoded <= {1'b0,data_word}; + dc_bias <= dc_bias - data_word_inv[8] + data_word_disparity; + end + end + end + + +endmodule diff --git a/rtl/boards/ulx3s/vga2dvid.v b/rtl/boards/ulx3s/vga2dvid.v new file mode 100644 index 0000000..916fb88 --- /dev/null +++ b/rtl/boards/ulx3s/vga2dvid.v @@ -0,0 +1,262 @@ +// File vga2dvid.vhd translated with vhd2vl v3.0 VHDL to Verilog RTL translator +// vhd2vl settings: +// * Verilog Module Declaration Style: 2001 + +// vhd2vl is Free (libre) Software: +// Copyright (C) 2001 Vincenzo Liguori - Ocean Logic Pty Ltd +// http://www.ocean-logic.com +// Modifications Copyright (C) 2006 Mark Gonzales - PMC Sierra Inc +// Modifications (C) 2010 Shankar Giri +// Modifications Copyright (C) 2002-2017 Larry Doolittle +// http://doolittle.icarus.com/~larry/vhd2vl/ +// Modifications (C) 2017 Rodrigo A. Melo +// +// vhd2vl comes with ABSOLUTELY NO WARRANTY. Always check the resulting +// Verilog for correctness, ideally with a formal verification tool. +// +// You are welcome to redistribute vhd2vl under certain conditions. +// See the license (GPLv2) file included with the source for details. + +// The result of translation follows. Its copyright status should be +// considered unchanged from the original VHDL. + +//------------------------------------------------------------------------------ +// Engineer: Mike Field +// Description: Converts VGA signals into DVID bitstreams. +// +// 'clk_shift' 10x clk_pixel for SDR +// 'clk_shift' 5x clk_pixel for DDR +// +// 'blank' should be asserted during the non-display +// portions of the frame +//------------------------------------------------------------------------------ +// See: http://hamsterworks.co.nz/mediawiki/index.php/Dvid_test +// http://hamsterworks.co.nz/mediawiki/index.php/FPGA_Projects +// +// Copyright (c) 2012 Mike Field +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// takes VGA input and prepares output +// for SDR buffer, which send 1 bit per 1 clock period output out_red(0), out_green(0), ... etc. +// for DDR buffers, which send 2 bits per 1 clock period output out_red(1 downto 0), ... +// EMARD unified SDR and DDR into one module +// no timescale needed + +module vga2dvid( +input wire clk_pixel, +input wire clk_shift, +input wire [C_depth - 1:0] in_red, +input wire [C_depth - 1:0] in_green, +input wire [C_depth - 1:0] in_blue, +input wire in_blank, +input wire in_hsync, +input wire in_vsync, +output wire [9:0] outp_red, +output wire [9:0] outp_green, +output wire [9:0] outp_blue, +output wire [1:0] out_red, +output wire [1:0] out_green, +output wire [1:0] out_blue, +output wire [1:0] out_clock +); + +parameter C_shift_clock_synchronizer=1'b1; +parameter C_parallel=1'b1; +parameter C_serial=1'b1; +parameter C_ddr=1'b0; +parameter [31:0] C_depth=8; +// VGA pixel clock, 25 MHz for 640x480 +// SDR: 10x clk_pixel, DDR: 5x clk_pixel, in phase with clk_pixel +// parallel outputs +// serial outputs + + + +wire [9:0] encoded_red; wire [9:0] encoded_green; wire [9:0] encoded_blue; +reg [9:0] latched_red = 1'b0; reg [9:0] latched_green = 1'b0; reg [9:0] latched_blue = 1'b0; +reg [9:0] shift_red = 1'b0; reg [9:0] shift_green = 1'b0; reg [9:0] shift_blue = 1'b0; +parameter C_shift_clock_initial = 10'b0000011111; +reg [9:0] shift_clock = C_shift_clock_initial; +reg R_shift_clock_off_sync = 1'b0; +reg [7:0] R_shift_clock_synchronizer = 1'b0; +reg [6:0] R_sync_fail; // counts sync fails, after too many, reinitialize shift_clock +parameter c_red = 1'b0; +parameter c_green = 1'b0; +wire [1:0] c_blue; +wire [7:0] red_d; +wire [7:0] green_d; +wire [7:0] blue_d; + + assign c_blue = {in_vsync,in_hsync}; + assign red_d[7:8 - C_depth] = in_red[C_depth - 1:0]; + assign green_d[7:8 - C_depth] = in_green[C_depth - 1:0]; + assign blue_d[7:8 - C_depth] = in_blue[C_depth - 1:0]; + // fill vacant low bits with value repeated (so min/max value is always 0 or 255) + generate if (C_depth < 8) begin: G_vacant_bits + genvar i; + generate for (i=0; i <= 8 - C_depth - 1; i = i + 1) begin: G_bits + assign red_d[i] = in_red[0]; + assign green_d[i] = in_green[0]; + assign blue_d[i] = in_blue[0]; + end + endgenerate + end + endgenerate + generate if (C_shift_clock_synchronizer == 1'b1) begin: G_shift_clock_synchronizer + // sampler verifies is shift_clock state synchronous with pixel_clock + always @(posedge clk_pixel) begin + // does 0 to 1 transition at bits 5 downto 4 happen at rising_edge of clk_pixel? + // if shift_clock = C_shift_clock_initial then + if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin + // same as above line but simplified + R_shift_clock_off_sync <= 1'b0; + end + else begin + R_shift_clock_off_sync <= 1'b1; + end + end + + // every N cycles of clk_shift: signal to skip 1 cycle in order to get in sync + always @(posedge clk_shift) begin + if(R_shift_clock_off_sync == 1'b1) begin + if(R_shift_clock_synchronizer[(7)] == 1'b1) begin + R_shift_clock_synchronizer <= {8{1'b0}}; + end + else begin + R_shift_clock_synchronizer <= R_shift_clock_synchronizer + 1; + end + end + else begin + R_shift_clock_synchronizer <= {8{1'b0}}; + end + end + + end + endgenerate + // shift_clock_synchronizer + tmds_encoder u21( + .clk(clk_pixel), + .data(red_d), + .c(c_red), + .blank(in_blank), + .encoded(encoded_red)); + + tmds_encoder u22( + .clk(clk_pixel), + .data(green_d), + .c(c_green), + .blank(in_blank), + .encoded(encoded_green)); + + tmds_encoder u23( + .clk(clk_pixel), + .data(blue_d), + .c(c_blue), + .blank(in_blank), + .encoded(encoded_blue)); + + always @(posedge clk_pixel) begin + latched_red <= encoded_red; + latched_green <= encoded_green; + latched_blue <= encoded_blue; + end + + generate if (C_parallel == 1'b1) begin: G_parallel + assign outp_red = latched_red; + assign outp_green = latched_green; + assign outp_blue = latched_blue; + end + endgenerate + generate if ((C_serial & ~C_ddr) == 1'b1) begin: G_SDR + always @(posedge clk_shift) begin + //if shift_clock = "0000011111" then + if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin + // same as above line but simplified + shift_red <= latched_red; + shift_green <= latched_green; + shift_blue <= latched_blue; + end + else begin + shift_red <= {1'b0,shift_red[9:1]}; + shift_green <= {1'b0,shift_green[9:1]}; + shift_blue <= {1'b0,shift_blue[9:1]}; + end + if(R_shift_clock_synchronizer[(7)] == 1'b0) begin + shift_clock <= {shift_clock[0],shift_clock[9:1]}; + end + else begin + // synchronization failed. + // after too many fails, reinitialize shift_clock + if(R_sync_fail[(6)] == 1'b1) begin + shift_clock <= C_shift_clock_initial; + R_sync_fail <= {7{1'b0}}; + end + else begin + R_sync_fail <= R_sync_fail + 1; + end + end + end + + end + endgenerate + generate if ((C_serial & C_ddr) == 1'b1) begin: G_DDR + always @(posedge clk_shift) begin + //if shift_clock = "0000011111" then + if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin + // same as above line but simplified + shift_red <= latched_red; + shift_green <= latched_green; + shift_blue <= latched_blue; + end + else begin + shift_red <= {2'b00,shift_red[9:2]}; + shift_green <= {2'b00,shift_green[9:2]}; + shift_blue <= {2'b00,shift_blue[9:2]}; + end + if(R_shift_clock_synchronizer[(7)] == 1'b0) begin + shift_clock <= {shift_clock[1:0],shift_clock[9:2]}; + end + else begin + // synchronization failed. + // after too many fails, reinitialize shift_clock + if(R_sync_fail[(6)] == 1'b1) begin + shift_clock <= C_shift_clock_initial; + R_sync_fail <= {7{1'b0}}; + end + else begin + R_sync_fail <= R_sync_fail + 1; + end + end + end + + end + endgenerate + // SDR: use only bit 0 from each out_* channel + // DDR: 2 bits per 1 clock period, + // (one bit output on rising edge, other on falling edge of clk_shift) + generate if (C_serial == 1'b1) begin: G_serial + assign out_red = shift_red[1:0]; + assign out_green = shift_green[1:0]; + assign out_blue = shift_blue[1:0]; + assign out_clock = shift_clock[1:0]; + end + endgenerate + +endmodule diff --git a/rtl/boards/ulx4m/apple1_dvi.v b/rtl/boards/ulx4m/apple1_dvi.v new file mode 100644 index 0000000..fe08a6b --- /dev/null +++ b/rtl/boards/ulx4m/apple1_dvi.v @@ -0,0 +1,183 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// Description: Apple 1 implementation for the Ulx4m +// +// Author.....: Lawrie Griffiths and Alan Garfield +// Date.......: 31-3-2018 +// + +module apple1_top #( + parameter BASIC_FILENAME = "../../../roms/basic.hex", + parameter FONT_ROM_FILENAME = "../../../roms/vga_font_bitreversed.hex", + parameter RAM_FILENAME = "../../../roms/ram.hex", + parameter VRAM_FILENAME = "../../../roms/vga_vram.bin", + parameter WOZMON_ROM_FILENAME = "../../../roms/wozmon.hex" +) ( + input clk_25mhz, // 25 MHz board clock + + // I/O interface to computer + input ftdi_txd, // asynchronous serial data input from computer + output ftdi_rxd, // asynchronous serial data output to computer + //output uart_cts, // clear to send flag to computer - not used + + // I/O interface to keyboard + //input ps2_clk, // PS/2 keyboard serial clock input + //input ps2_din, // PS/2 keyboard serial data input + + //output usb_fpga_pu_dp, + //output usb_fpga_pu_dn, + + input [26:25] gpio, + + output [3:0] gpdi_dp, gpdi_dn, + + // Debugging ports + output [3:0] led, + input [2:1] btn // 2 buttons on board +); + wire uart_cts; + + parameter C_ddr = 1'b1; // 0:SDR 1:DDR + + // clock generator + wire clk_250MHz, clk_125MHz, clk_25MHz, clk_locked; + clk_25_250_125_25 + clock_instance + ( + .clki(clk_25mhz), + .clko(clk_250MHz), + .clks1(clk_125MHz), + .clks2(clk_25MHz), + .locked(clk_locked) + ); + + // shift clock choice SDR/DDR + wire clk_pixel, clk_shift; + assign clk_pixel = clk_25MHz; + generate + if(C_ddr == 1'b1) + assign clk_shift = clk_125MHz; + else + assign clk_shift = clk_250MHz; + endgenerate + + //assign usb_fpga_pu_dp = 1; + //assign usb_fpga_pu_dn = 1; + + assign led[0] = 1; + assign led[1] = reset_n; + assign led[2] = clr_screen_n; + assign led[3] = 0; + + wire vga_bit; + + // VGA signal generator + wire [7:0] vga_r, vga_g, vga_b; + wire vga_h_sync, vga_v_sync, vga_blank; + + // set the monochrome base colour here.. + assign vga_r = vga_bit ? 8'b10000000 : 8'b00000000; + assign vga_g = vga_bit ? 8'b11111111 : 8'b00000000; + assign vga_b = vga_bit ? 8'b10000000 : 8'b00000000; + + // debounce reset button + wire reset_n; + debounce reset_button ( + .clk25(clk_25MHz), + .rst(1'b0), + .sig_in(~btn[1]), + .sig_out(reset_n) + ); + + // debounce clear screen button + wire clr_screen_n; + debounce clr_button ( + .clk25(clk_25MHz), + .rst(~reset_n), + .sig_in(~btn[2]), + .sig_out(clr_screen_n) + ); + + // apple one main system + apple1 #( + .BASIC_FILENAME (BASIC_FILENAME), + .FONT_ROM_FILENAME (FONT_ROM_FILENAME), + .RAM_FILENAME (RAM_FILENAME), + .VRAM_FILENAME (VRAM_FILENAME), + .WOZMON_ROM_FILENAME (WOZMON_ROM_FILENAME) + ) my_apple1( + .clk25(clk_25MHz), + .rst_n(reset_n), + + .uart_rx(ftdi_txd), + .uart_tx(ftdi_rxd), + .uart_cts(uart_cts), + + .ps2_clk(gpio[26]), + .ps2_din(gpio[25]), + .ps2_select(1'b1), // PS/2 enabled, UART TX disabled + + .vga_h_sync(vga_h_sync), + .vga_v_sync(vga_v_sync), + .vga_red(vga_bit), + //.vga_grn(vga_bit), + //.vga_blu(vga_bit), + .vga_blank(vga_blank), + .vga_cls(~clr_screen_n) + ); + + // VGA to digital video converter + wire [1:0] tmds[3:0]; + vga2dvid + #( + .C_ddr(C_ddr), + .C_shift_clock_synchronizer(1'b1) + ) + vga2dvid_instance + ( + .clk_pixel(clk_pixel), + .clk_shift(clk_shift), + .in_red(vga_r), + .in_green(vga_g), + .in_blue(vga_b), + .in_hsync(vga_h_sync), + .in_vsync(vga_v_sync), + .in_blank(vga_blank), + .out_clock(tmds[3]), + .out_red(tmds[2]), + .out_green(tmds[1]), + .out_blue(tmds[0]) + ); + + // output TMDS SDR/DDR data to fake differential lanes + fake_differential + #( + .C_ddr(C_ddr) + ) + fake_differential_instance + ( + .clk_shift(clk_shift), + .in_clock(tmds[3]), + .in_red(tmds[2]), + .in_green(tmds[1]), + .in_blue(tmds[0]), + .out_p(gpdi_dp), + .out_n(gpdi_dn) + ); + +endmodule diff --git a/rtl/boards/ulx4m/clk_25_250_125_25.v b/rtl/boards/ulx4m/clk_25_250_125_25.v new file mode 100644 index 0000000..967e697 --- /dev/null +++ b/rtl/boards/ulx4m/clk_25_250_125_25.v @@ -0,0 +1,60 @@ +// diamond 3.7 accepts this PLL +// diamond 3.8-3.9 is untested +// diamond 3.10 or higher is likely to abort with error about unable to use feedback signal +// cause of this could be from wrong CPHASE/FPHASE parameters +module clk_25_250_125_25 +( + input clki, // 25 MHz, 0 deg + output clko, // 250 MHz, 0 deg + output clks1, // 125 MHz, 0 deg + output clks2, // 25 MHz, 0 deg + output locked +); +(* FREQUENCY_PIN_CLKI="25" *) +(* FREQUENCY_PIN_CLKOP="250" *) +(* FREQUENCY_PIN_CLKOS="125" *) +(* FREQUENCY_PIN_CLKOS2="25" *) +(* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) +EHXPLLL #( + .PLLRST_ENA("DISABLED"), + .INTFB_WAKE("DISABLED"), + .STDBY_ENABLE("DISABLED"), + .DPHASE_SOURCE("DISABLED"), + .OUTDIVIDER_MUXA("DIVA"), + .OUTDIVIDER_MUXB("DIVB"), + .OUTDIVIDER_MUXC("DIVC"), + .OUTDIVIDER_MUXD("DIVD"), + .CLKI_DIV(1), + .CLKOP_ENABLE("ENABLED"), + .CLKOP_DIV(2), + .CLKOP_CPHASE(0), + .CLKOP_FPHASE(0), + .CLKOS_ENABLE("ENABLED"), + .CLKOS_DIV(4), + .CLKOS_CPHASE(0), + .CLKOS_FPHASE(0), + .CLKOS2_ENABLE("ENABLED"), + .CLKOS2_DIV(20), + .CLKOS2_CPHASE(0), + .CLKOS2_FPHASE(0), + .FEEDBK_PATH("CLKOP"), + .CLKFB_DIV(10) + ) pll_i ( + .RST(1'b0), + .STDBY(1'b0), + .CLKI(clki), + .CLKOP(clko), + .CLKOS(clks1), + .CLKOS2(clks2), + .CLKFB(clko), + .CLKINTFB(), + .PHASESEL0(1'b0), + .PHASESEL1(1'b0), + .PHASEDIR(1'b1), + .PHASESTEP(1'b1), + .PHASELOADREG(1'b1), + .PLLWAKESYNC(1'b0), + .ENCLKOP(1'b0), + .LOCK(locked) + ); +endmodule diff --git a/rtl/boards/ulx4m/fake_differential.v b/rtl/boards/ulx4m/fake_differential.v new file mode 100644 index 0000000..f690672 --- /dev/null +++ b/rtl/boards/ulx4m/fake_differential.v @@ -0,0 +1,63 @@ +// DDR mode uses Lattice ECP5 vendor-specific module ODDRX1F + +module fake_differential +( + input clk_shift, // used only in DDR mode + // [1:0]:DDR [0]:SDR TMDS + input [1:0] in_clock, in_red, in_green, in_blue, + // [3]:clock [2]:red [1]:green [0]:blue + output [3:0] out_p, out_n +); + parameter C_ddr = 1'b0; // 0:SDR 1:DDR + + wire [1:0] tmds[3:0]; + assign tmds[3] = in_clock; + assign tmds[2] = in_red; + assign tmds[1] = in_green; + assign tmds[0] = in_blue; + + // register stage to improve timing of the fake differential + reg [1:0] R_tmds_p[3:0], R_tmds_n[3:0]; + generate + genvar i; + for(i = 0; i < 4; i++) + begin : TMDS_pn_registers + always @(posedge clk_shift) R_tmds_p[i] <= tmds[i]; + always @(posedge clk_shift) R_tmds_n[i] <= ~tmds[i]; + end + endgenerate + + // output SDR/DDR to fake differential + generate + genvar i; + if(C_ddr == 1'b1) + for(i = 0; i < 4; i++) + begin : DDR_output_mode + ODDRX1F + ddr_p_instance + ( + .D0(R_tmds_p[i][0]), + .D1(R_tmds_p[i][1]), + .Q(out_p[i]), + .SCLK(clk_shift), + .RST(0) + ); + ODDRX1F + ddr_n_instance + ( + .D0(R_tmds_n[i][0]), + .D1(R_tmds_n[i][1]), + .Q(out_n[i]), + .SCLK(clk_shift), + .RST(0) + ); + end + else + for(i = 0; i < 4; i++) + begin : SDR_output_mode + assign out_p[i] = R_tmds_p[i][0]; + assign out_n[i] = R_tmds_n[i][0]; + end + endgenerate + +endmodule diff --git a/rtl/boards/ulx4m/tmds_encoder.v b/rtl/boards/ulx4m/tmds_encoder.v new file mode 100644 index 0000000..fbf4a27 --- /dev/null +++ b/rtl/boards/ulx4m/tmds_encoder.v @@ -0,0 +1,155 @@ +// File hdl/tmds_encoder.vhd translated with vhd2vl v3.0 VHDL to Verilog RTL translator +// vhd2vl settings: +// * Verilog Module Declaration Style: 2001 + +// vhd2vl is Free (libre) Software: +// Copyright (C) 2001 Vincenzo Liguori - Ocean Logic Pty Ltd +// http://www.ocean-logic.com +// Modifications Copyright (C) 2006 Mark Gonzales - PMC Sierra Inc +// Modifications (C) 2010 Shankar Giri +// Modifications Copyright (C) 2002-2017 Larry Doolittle +// http://doolittle.icarus.com/~larry/vhd2vl/ +// Modifications (C) 2017 Rodrigo A. Melo +// +// vhd2vl comes with ABSOLUTELY NO WARRANTY. Always check the resulting +// Verilog for correctness, ideally with a formal verification tool. +// +// You are welcome to redistribute vhd2vl under certain conditions. +// See the license (GPLv2) file included with the source for details. + +// The result of translation follows. Its copyright status should be +// considered unchanged from the original VHDL. + +//-------------------------------------------------------------------------------- +// Engineer: Mike Field +// +// Description: TMDS Encoder +// 8 bits colour, 2 control bits and one blanking bits in +// 10 bits of TMDS encoded data out +// Clocked at the pixel clock +// +//-------------------------------------------------------------------------------- +// See: http://hamsterworks.co.nz/mediawiki/index.php/Dvid_test +// http://hamsterworks.co.nz/mediawiki/index.php/FPGA_Projects +// +// Copyright (c) 2012 Mike Field +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// no timescale needed + +module tmds_encoder( +input wire clk, +input wire [7:0] data, +input wire [1:0] c, +input wire blank, +output reg [9:0] encoded +); + + + + +wire [8:0] xored; +wire [8:0] xnored; +wire [3:0] ones; +reg [8:0] data_word; +reg [8:0] data_word_inv; +wire [3:0] data_word_disparity; +reg [3:0] dc_bias = 1'b0; + + // Work our the two different encodings for the byte + assign xored[0] = data[0]; + assign xored[1] = data[1] ^ xored[0]; + assign xored[2] = data[2] ^ xored[1]; + assign xored[3] = data[3] ^ xored[2]; + assign xored[4] = data[4] ^ xored[3]; + assign xored[5] = data[5] ^ xored[4]; + assign xored[6] = data[6] ^ xored[5]; + assign xored[7] = data[7] ^ xored[6]; + assign xored[8] = 1'b1; + assign xnored[0] = data[0]; + assign xnored[1] = ~(data[1] ^ xnored[0]); + assign xnored[2] = ~(data[2] ^ xnored[1]); + assign xnored[3] = ~(data[3] ^ xnored[2]); + assign xnored[4] = ~(data[4] ^ xnored[3]); + assign xnored[5] = ~(data[5] ^ xnored[4]); + assign xnored[6] = ~(data[6] ^ xnored[5]); + assign xnored[7] = ~(data[7] ^ xnored[6]); + assign xnored[8] = 1'b0; + // Count how many ones are set in data + assign ones = 4'b0000 + data[0] + data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]; + // Decide which encoding to use + always @(ones, data[0], xnored, xored) begin + if(ones > 4 || (ones == 4 && data[0] == 1'b0)) begin + data_word <= xnored; + data_word_inv <= ~(xnored); + end + else begin + data_word <= xored; + data_word_inv <= ~(xored); + end + end + + // Work out the DC bias of the dataword; + assign data_word_disparity = 4'b1100 + data_word[0] + data_word[1] + data_word[2] + data_word[3] + data_word[4] + data_word[5] + data_word[6] + data_word[7]; + // Now work out what the output should be + always @(posedge clk) begin + if(blank == 1'b1) begin + // In the control periods, all values have and have balanced bit count + case(c) + 2'b00 : begin + encoded <= 10'b1101010100; + end + 2'b01 : begin + encoded <= 10'b0010101011; + end + 2'b10 : begin + encoded <= 10'b0101010100; + end + default : begin + encoded <= 10'b1010101011; + end + endcase + dc_bias <= {4{1'b0}}; + end + else begin + if(dc_bias == 5'b00000 || data_word_disparity == 0) begin + // dataword has no disparity + if(data_word[8] == 1'b1) begin + encoded <= {2'b01,data_word[7:0]}; + dc_bias <= dc_bias + data_word_disparity; + end + else begin + encoded <= {2'b10,data_word_inv[7:0]}; + dc_bias <= dc_bias - data_word_disparity; + end + end + else if((dc_bias[3] == 1'b0 && data_word_disparity[3] == 1'b0) || (dc_bias[3] == 1'b1 && data_word_disparity[3] == 1'b1)) begin + encoded <= {1'b1,data_word[8],data_word_inv[7:0]}; + dc_bias <= dc_bias + data_word[8] - data_word_disparity; + end + else begin + encoded <= {1'b0,data_word}; + dc_bias <= dc_bias - data_word_inv[8] + data_word_disparity; + end + end + end + + +endmodule diff --git a/rtl/boards/ulx4m/vga2dvid.v b/rtl/boards/ulx4m/vga2dvid.v new file mode 100644 index 0000000..916fb88 --- /dev/null +++ b/rtl/boards/ulx4m/vga2dvid.v @@ -0,0 +1,262 @@ +// File vga2dvid.vhd translated with vhd2vl v3.0 VHDL to Verilog RTL translator +// vhd2vl settings: +// * Verilog Module Declaration Style: 2001 + +// vhd2vl is Free (libre) Software: +// Copyright (C) 2001 Vincenzo Liguori - Ocean Logic Pty Ltd +// http://www.ocean-logic.com +// Modifications Copyright (C) 2006 Mark Gonzales - PMC Sierra Inc +// Modifications (C) 2010 Shankar Giri +// Modifications Copyright (C) 2002-2017 Larry Doolittle +// http://doolittle.icarus.com/~larry/vhd2vl/ +// Modifications (C) 2017 Rodrigo A. Melo +// +// vhd2vl comes with ABSOLUTELY NO WARRANTY. Always check the resulting +// Verilog for correctness, ideally with a formal verification tool. +// +// You are welcome to redistribute vhd2vl under certain conditions. +// See the license (GPLv2) file included with the source for details. + +// The result of translation follows. Its copyright status should be +// considered unchanged from the original VHDL. + +//------------------------------------------------------------------------------ +// Engineer: Mike Field +// Description: Converts VGA signals into DVID bitstreams. +// +// 'clk_shift' 10x clk_pixel for SDR +// 'clk_shift' 5x clk_pixel for DDR +// +// 'blank' should be asserted during the non-display +// portions of the frame +//------------------------------------------------------------------------------ +// See: http://hamsterworks.co.nz/mediawiki/index.php/Dvid_test +// http://hamsterworks.co.nz/mediawiki/index.php/FPGA_Projects +// +// Copyright (c) 2012 Mike Field +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// +// takes VGA input and prepares output +// for SDR buffer, which send 1 bit per 1 clock period output out_red(0), out_green(0), ... etc. +// for DDR buffers, which send 2 bits per 1 clock period output out_red(1 downto 0), ... +// EMARD unified SDR and DDR into one module +// no timescale needed + +module vga2dvid( +input wire clk_pixel, +input wire clk_shift, +input wire [C_depth - 1:0] in_red, +input wire [C_depth - 1:0] in_green, +input wire [C_depth - 1:0] in_blue, +input wire in_blank, +input wire in_hsync, +input wire in_vsync, +output wire [9:0] outp_red, +output wire [9:0] outp_green, +output wire [9:0] outp_blue, +output wire [1:0] out_red, +output wire [1:0] out_green, +output wire [1:0] out_blue, +output wire [1:0] out_clock +); + +parameter C_shift_clock_synchronizer=1'b1; +parameter C_parallel=1'b1; +parameter C_serial=1'b1; +parameter C_ddr=1'b0; +parameter [31:0] C_depth=8; +// VGA pixel clock, 25 MHz for 640x480 +// SDR: 10x clk_pixel, DDR: 5x clk_pixel, in phase with clk_pixel +// parallel outputs +// serial outputs + + + +wire [9:0] encoded_red; wire [9:0] encoded_green; wire [9:0] encoded_blue; +reg [9:0] latched_red = 1'b0; reg [9:0] latched_green = 1'b0; reg [9:0] latched_blue = 1'b0; +reg [9:0] shift_red = 1'b0; reg [9:0] shift_green = 1'b0; reg [9:0] shift_blue = 1'b0; +parameter C_shift_clock_initial = 10'b0000011111; +reg [9:0] shift_clock = C_shift_clock_initial; +reg R_shift_clock_off_sync = 1'b0; +reg [7:0] R_shift_clock_synchronizer = 1'b0; +reg [6:0] R_sync_fail; // counts sync fails, after too many, reinitialize shift_clock +parameter c_red = 1'b0; +parameter c_green = 1'b0; +wire [1:0] c_blue; +wire [7:0] red_d; +wire [7:0] green_d; +wire [7:0] blue_d; + + assign c_blue = {in_vsync,in_hsync}; + assign red_d[7:8 - C_depth] = in_red[C_depth - 1:0]; + assign green_d[7:8 - C_depth] = in_green[C_depth - 1:0]; + assign blue_d[7:8 - C_depth] = in_blue[C_depth - 1:0]; + // fill vacant low bits with value repeated (so min/max value is always 0 or 255) + generate if (C_depth < 8) begin: G_vacant_bits + genvar i; + generate for (i=0; i <= 8 - C_depth - 1; i = i + 1) begin: G_bits + assign red_d[i] = in_red[0]; + assign green_d[i] = in_green[0]; + assign blue_d[i] = in_blue[0]; + end + endgenerate + end + endgenerate + generate if (C_shift_clock_synchronizer == 1'b1) begin: G_shift_clock_synchronizer + // sampler verifies is shift_clock state synchronous with pixel_clock + always @(posedge clk_pixel) begin + // does 0 to 1 transition at bits 5 downto 4 happen at rising_edge of clk_pixel? + // if shift_clock = C_shift_clock_initial then + if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin + // same as above line but simplified + R_shift_clock_off_sync <= 1'b0; + end + else begin + R_shift_clock_off_sync <= 1'b1; + end + end + + // every N cycles of clk_shift: signal to skip 1 cycle in order to get in sync + always @(posedge clk_shift) begin + if(R_shift_clock_off_sync == 1'b1) begin + if(R_shift_clock_synchronizer[(7)] == 1'b1) begin + R_shift_clock_synchronizer <= {8{1'b0}}; + end + else begin + R_shift_clock_synchronizer <= R_shift_clock_synchronizer + 1; + end + end + else begin + R_shift_clock_synchronizer <= {8{1'b0}}; + end + end + + end + endgenerate + // shift_clock_synchronizer + tmds_encoder u21( + .clk(clk_pixel), + .data(red_d), + .c(c_red), + .blank(in_blank), + .encoded(encoded_red)); + + tmds_encoder u22( + .clk(clk_pixel), + .data(green_d), + .c(c_green), + .blank(in_blank), + .encoded(encoded_green)); + + tmds_encoder u23( + .clk(clk_pixel), + .data(blue_d), + .c(c_blue), + .blank(in_blank), + .encoded(encoded_blue)); + + always @(posedge clk_pixel) begin + latched_red <= encoded_red; + latched_green <= encoded_green; + latched_blue <= encoded_blue; + end + + generate if (C_parallel == 1'b1) begin: G_parallel + assign outp_red = latched_red; + assign outp_green = latched_green; + assign outp_blue = latched_blue; + end + endgenerate + generate if ((C_serial & ~C_ddr) == 1'b1) begin: G_SDR + always @(posedge clk_shift) begin + //if shift_clock = "0000011111" then + if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin + // same as above line but simplified + shift_red <= latched_red; + shift_green <= latched_green; + shift_blue <= latched_blue; + end + else begin + shift_red <= {1'b0,shift_red[9:1]}; + shift_green <= {1'b0,shift_green[9:1]}; + shift_blue <= {1'b0,shift_blue[9:1]}; + end + if(R_shift_clock_synchronizer[(7)] == 1'b0) begin + shift_clock <= {shift_clock[0],shift_clock[9:1]}; + end + else begin + // synchronization failed. + // after too many fails, reinitialize shift_clock + if(R_sync_fail[(6)] == 1'b1) begin + shift_clock <= C_shift_clock_initial; + R_sync_fail <= {7{1'b0}}; + end + else begin + R_sync_fail <= R_sync_fail + 1; + end + end + end + + end + endgenerate + generate if ((C_serial & C_ddr) == 1'b1) begin: G_DDR + always @(posedge clk_shift) begin + //if shift_clock = "0000011111" then + if(shift_clock[5:4] == C_shift_clock_initial[5:4]) begin + // same as above line but simplified + shift_red <= latched_red; + shift_green <= latched_green; + shift_blue <= latched_blue; + end + else begin + shift_red <= {2'b00,shift_red[9:2]}; + shift_green <= {2'b00,shift_green[9:2]}; + shift_blue <= {2'b00,shift_blue[9:2]}; + end + if(R_shift_clock_synchronizer[(7)] == 1'b0) begin + shift_clock <= {shift_clock[1:0],shift_clock[9:2]}; + end + else begin + // synchronization failed. + // after too many fails, reinitialize shift_clock + if(R_sync_fail[(6)] == 1'b1) begin + shift_clock <= C_shift_clock_initial; + R_sync_fail <= {7{1'b0}}; + end + else begin + R_sync_fail <= R_sync_fail + 1; + end + end + end + + end + endgenerate + // SDR: use only bit 0 from each out_* channel + // DDR: 2 bits per 1 clock period, + // (one bit output on rising edge, other on falling edge of clk_shift) + generate if (C_serial == 1'b1) begin: G_serial + assign out_red = shift_red[1:0]; + assign out_green = shift_green[1:0]; + assign out_blue = shift_blue[1:0]; + assign out_clock = shift_clock[1:0]; + end + endgenerate + +endmodule diff --git a/rtl/ram.v b/rtl/ram.v index cf891f1..003e348 100644 --- a/rtl/ram.v +++ b/rtl/ram.v @@ -26,16 +26,16 @@ module ram #( parameter RAM_FILENAME = "../../../roms/ram.hex" ) ( input clk, // clock signal - input [12:0] address, // address bus + input [14:0] address, // address bus input w_en, // active high write enable strobe input [7:0] din, // 8-bit data bus (input) output reg [7:0] dout // 8-bit data bus (output) ); - reg [7:0] ram_data[0:8191]; + reg [7:0] ram_data[0:32767]; - initial - $readmemh(RAM_FILENAME, ram_data, 0, 8191); + //initial + // $readmemh(RAM_FILENAME, ram_data, 0, 8191); always @(posedge clk) begin diff --git a/rtl/vga/vga.v b/rtl/vga/vga.v index 6b6aaab..d72aa90 100644 --- a/rtl/vga/vga.v +++ b/rtl/vga/vga.v @@ -38,6 +38,7 @@ module vga #( input [1:0] mode, // 2-bit mode setting for pixel doubling input [2:0] bg_colour, // 3 bit background colour input [2:0] fg_colour, // 3 bit foreground colour + output vga_blank, // set when out of active regions input clr_screen // clear screen button ); @@ -94,6 +95,8 @@ module vga #( assign h_active = (h_cnt >= hbp && h_cnt < hfp); assign v_active = (v_cnt >= vbp && v_cnt < vfp); + assign vga_blank = !(h_active && v_active); + ////////////////////////////////////////////////////////////////////////// // VGA Sync Generation //