Added Ulx4m support

This commit is contained in:
lawrie 2022-04-17 13:55:19 +01:00
parent a7c01443ae
commit a20b44bfc7
11 changed files with 1362 additions and 0 deletions

21
boards/ulx4m/README.md Normal file
View File

@ -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 built-in HDMI connector
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
```
## Use
To load BASIC type "E000R" (with CAPS LOCK on if you are using the UART rather than the PS/2 keyboard).

View File

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

Binary file not shown.

30
boards/ulx4m/yosys/slow.py Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env python3
import time
import os
import sys
if len(sys.argv) != 2:
print("Usage: " + sys.argv[0] + " <filename>")
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()

View File

@ -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;

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <hamster@snap.net.nz>
//
// 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 <hamster@snap.net.nz>
//
// 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

262
rtl/boards/ulx4m/vga2dvid.v Normal file
View File

@ -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 <hamster@snap.net.nz>
// 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 <hamster@snap.net.nz>
//
// 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