diff --git a/experiments/arbiter/Top.bsv b/experiments/arbiter/Top.bsv new file mode 100644 index 0000000..9db54f2 --- /dev/null +++ b/experiments/arbiter/Top.bsv @@ -0,0 +1,101 @@ +package Top; + +import MemoryArbiter::*; +import Vector::*; +import DReg::*; +import DelayLine::*; + +typedef UInt#(2) Addr; + +(* always_ready *) +interface Top; + method Action cpu(Bool write, Addr addr); + method Action debugger(Bool write, Addr addr); + method Action palette(Addr addr); + + method Action tile1(Addr addr); + method Action tile2(Addr addr); + method Action sprite(Addr addr); + + method Bit#(6) grants(); +endinterface + +typedef struct { + Bool write; + Addr address; +} WriteReq deriving (Bits, Eq); + +(* synthesize, clock_prefix="clk_25mhz", reset_prefix="rst_btn" *) +module mkTop(Top); + Vector#(2, Reg#(Maybe#(WriteReq))) wrin <- replicateM(mkDReg(tagged Invalid)); + Vector#(4, Reg#(Maybe#(Addr))) rdin <- replicateM(mkDReg(tagged Invalid)); + + MemoryArbiter#(Addr) ret <- mkMemoryArbiter(); + + Reg#(Vector#(6, Bool)) ok <- mkReg(replicate(False)); + + rule req_cpu (wrin[0] matches tagged Valid .req &&& req matches WriteReq{write: .write, address: .addr}); + ret.cpu.request(write, addr); + endrule + + rule req_debugger (wrin[1] matches tagged Valid .req &&& req matches WriteReq{write: .write, address: .addr}); + ret.debugger.request(write, addr); + endrule + + rule req_palette (rdin[0] matches tagged Valid .addr); + ret.palette.request(addr); + endrule + + rule req_tile1 (rdin[1] matches tagged Valid .addr); + ret.tile1.request(addr); + endrule + + rule req_tile2 (rdin[2] matches tagged Valid .addr); + ret.tile2.request(addr); + endrule + + rule req_sprite (rdin[3] matches tagged Valid .addr); + ret.sprite.request(addr); + endrule + + rule resp; + Vector#(6, Bool) r = newVector; + r[0] = ret.cpu.grant(); + r[1] = ret.debugger.grant(); + r[2] = ret.palette.grant(); + r[3] = ret.tile1.grant(); + r[4] = ret.tile2.grant(); + r[5] = ret.sprite.grant(); + ok <= r; + endrule + + method Action cpu(Bool write, Addr addr); + wrin[0] <= tagged Valid WriteReq{write: write, address: addr}; + endmethod + + method Action debugger(Bool write, Addr addr); + wrin[1] <= tagged Valid WriteReq{write: write, address: addr}; + endmethod + + method Action palette(Addr addr); + rdin[0] <= tagged Valid addr; + endmethod + + method Action tile1(Addr addr); + rdin[1] <= tagged Valid addr; + endmethod + + method Action tile2(Addr addr); + rdin[2] <= tagged Valid addr; + endmethod + + method Action sprite(Addr addr); + rdin[3] <= tagged Valid addr; + endmethod + + method Bit#(6) grants(); + return pack(ok); + endmethod +endmodule + +endpackage diff --git a/experiments/arbiter/pin_map.lpf b/experiments/arbiter/pin_map.lpf new file mode 100644 index 0000000..5f2bec9 --- /dev/null +++ b/experiments/arbiter/pin_map.lpf @@ -0,0 +1,598 @@ +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" 150 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 "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi +LOCATE COMP "ftdi_txd" 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 "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "ftdi_txd" 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 "cpu_write" SITE "H3"; +LOCATE COMP "cpu_addr[0]" SITE "E1"; +LOCATE COMP "cpu_addr[1]" SITE "E2"; +LOCATE COMP "EN_cpu" SITE "D1"; +LOCATE COMP "debugger_write" SITE "D2"; +LOCATE COMP "debugger_addr[0]" SITE "C1"; +LOCATE COMP "debugger_addr[1]" SITE "C2"; +LOCATE COMP "EN_debugger" SITE "B2"; +IOBUF PORT "EN_cpu" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "cpu_write" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "cpu_addr[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "cpu_addr[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "EN_debugger" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "debugger_write" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "debugger_addr[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "debugger_addr[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4; + +## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet +LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic) +LOCATE COMP "palette_addr[0]" SITE "R1"; # FIRE1 +LOCATE COMP "palette_addr[1]" SITE "T1"; # FIRE2 +LOCATE COMP "EN_palette" SITE "R18"; # UP W1->R18 +LOCATE COMP "tile1_addr[0]" SITE "V1"; # DOWN +LOCATE COMP "tile1_addr[1]" SITE "U1"; # LEFT +LOCATE COMP "EN_tile1" SITE "H16"; # RIGHT Y2->H16 +IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "palette_addr[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "palette_addr[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "EN_palette" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "tile1_addr[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "tile1_addr[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "EN_tile1" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4; + +## DIP switch "blinkey", "gpio" sheet +LOCATE COMP "tile2_addr[0]" SITE "E8"; # SW1 +LOCATE COMP "tile2_addr[1]" SITE "D8"; # SW2 +LOCATE COMP "EN_tile2" SITE "D7"; # SW3 +LOCATE COMP "reqs[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 +# wifi_gpio2,4,12,13,14,15 are shared with SD card. +# If any of wifi_gpio2,4,12,13 is used in toplevel, don't use sd_d[]. +# If SD is used in 1-bit SPI mode, wifi_gpio4,12 = sd_d[1,2] are free, +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_d0_do (MISO) WiFi GPIO2 +LOCATE COMP "sd_d[1]" SITE "H1"; # sd_d1_irq WiFi GPIO4 +LOCATE COMP "sd_d[2]" SITE "K1"; # sd_d2 WiFi_GPIO12 +LOCATE COMP "sd_d[3]" SITE "K2"; # sd_d3_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 without 3.3V efuse +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 +# input lines shared with GP,GN14-17 +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 +# output impedance: 75 ohm +# Stereo 16 ohm earphones, analog audio, +# SPDIF digital audio and composite video. +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 +# wifi_gpio2,4,12,13,14,15 are shared with SD card. +# If any of wifi_gpio2,4,12,13 is used in toplevel, don't use sd_d[]. +# If SD is used in 1-bit SPI mode, wifi_gpio4,12 = sd_d[1,2] are free, +# other pins are shared with GP/GN, 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 +# wifi lines shared with SD card +LOCATE COMP "wifi_gpio2" SITE "J3"; # sd_d0_do (MISO) WiFi GPIO2 +LOCATE COMP "wifi_gpio4" SITE "H1"; # sd_d1_irq WiFi GPIO4 +LOCATE COMP "wifi_gpio12" SITE "K1"; # sd_d2 WiFi_GPIO12 +LOCATE COMP "wifi_gpio13" SITE "K2"; # sd_d3_csn WiFi_GPIO13 +LOCATE COMP "wifi_gpio14" SITE "H2"; # sd_clk WiFi_GPIO14 +LOCATE COMP "wifi_gpio15" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15 +# wifi lines shared with JTAG +# LOCATE COMP "wifi_gpio21" SITE "U5"; # JTAG TMS +# LOCATE COMP "wifi_gpio18" SITE "T5"; # JTAG TCK +# LOCATE COMP "wifi_gpio23" SITE "R5"; # JTAG TDI +# LOCATE COMP "wifi_gpio19" SITE "V4"; # JTAG TDO +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=DOWN IO_TYPE=LVCMOS33 DRIVE=4; # pull down or drive 0 for esp32 programming +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 "usb_fpga_bd_dp" SITE "D15"; # single-ended bidirectional +LOCATE COMP "usb_fpga_bd_dn" SITE "E15"; +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 "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_util" SITE "A19"; # add 10k parallel to C +LOCATE COMP "gpdi_hpd" SITE "B20"; # add 549ohm parallel to C +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=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33D DRIVE=4; +IOBUF PORT "gpdi_util" IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gpdi_hpd" 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 +# FEMALE ANGLED (90 deg PMOD) on TOP or +# MALE VERTICAL ( 0 deg pins) on BOTTOM and flat cable +LOCATE COMP "gp[0]" SITE "B11"; # PCLK +LOCATE COMP "gn[0]" SITE "C11"; # PCLK +LOCATE COMP "gp[1]" SITE "A10"; # PCLK +LOCATE COMP "gn[1]" SITE "A11"; # PCLK +LOCATE COMP "gp[2]" SITE "A9"; # GR_PCLK +LOCATE COMP "gn[2]" SITE "B10"; # GR_PCLK +LOCATE COMP "gp[3]" SITE "B9"; +LOCATE COMP "gn[3]" SITE "C10"; +LOCATE COMP "gp[4]" SITE "A7"; +LOCATE COMP "gn[4]" SITE "A8"; +LOCATE COMP "gp[5]" SITE "C8"; +LOCATE COMP "gn[5]" SITE "B8"; +LOCATE COMP "gp[6]" SITE "C6"; +LOCATE COMP "gn[6]" SITE "C7"; +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"; +LOCATE COMP "gn[7]" SITE "B6"; +LOCATE COMP "gp[8]" SITE "A4"; # DIFF +LOCATE COMP "gn[8]" SITE "A5"; # DIFF +LOCATE COMP "gp[9]" SITE "A2"; # DIFF +LOCATE COMP "gn[9]" SITE "B1"; # DIFF +LOCATE COMP "gp[10]" SITE "C4"; # DIFF +LOCATE COMP "gn[10]" SITE "B4"; # DIFF +LOCATE COMP "gp[11]" SITE "F4"; # DIFF wifi_gpio26 +LOCATE COMP "gn[11]" SITE "E3"; # DIFF wifi_gpio25 +LOCATE COMP "gp[12]" SITE "G3"; # DIFF wifi_gpio33 PCLK +LOCATE COMP "gn[12]" SITE "F3"; # DIFF wifi_gpio32 PCLK +LOCATE COMP "gp[13]" SITE "H4"; # DIFF wifi_gpio35 +LOCATE COMP "gn[13]" SITE "G5"; # DIFF wifi_gpio34 +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=NONE IO_TYPE=LVCMOS33; +FREQUENCY PORT "gn[12]" 50 MHZ; +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"; # DIFF ADC AIN1 +LOCATE COMP "gn[14]" SITE "U17"; # DIFF ADC AIN0 +LOCATE COMP "gp[15]" SITE "N17"; # DIFF ADC AIN3 +LOCATE COMP "gn[15]" SITE "P16"; # DIFF ADC AIN2 +LOCATE COMP "gp[16]" SITE "N16"; # DIFF ADC AIN5 +LOCATE COMP "gn[16]" SITE "M17"; # DIFF ADC AIN4 +LOCATE COMP "gp[17]" SITE "L16"; # DIFF ADC AIN7 GR_PCLK +LOCATE COMP "gn[17]" SITE "L17"; # DIFF ADC AIN6 +LOCATE COMP "gp[18]" SITE "H18"; # DIFF +LOCATE COMP "gn[18]" SITE "H17"; # DIFF +LOCATE COMP "gp[19]" SITE "F17"; # DIFF +LOCATE COMP "gn[19]" SITE "G18"; # DIFF +LOCATE COMP "gp[20]" SITE "D18"; # DIFF +LOCATE COMP "gn[20]" SITE "E17"; # DIFF +IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[17]" 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 "gp[21]" SITE "C18"; # DIFF +LOCATE COMP "gn[21]" SITE "D17"; # DIFF +LOCATE COMP "gp[22]" SITE "B15"; +LOCATE COMP "gn[22]" SITE "C15"; +LOCATE COMP "gp[23]" SITE "B17"; +LOCATE COMP "gn[23]" SITE "C17"; +LOCATE COMP "gp[24]" SITE "C16"; +LOCATE COMP "gn[24]" SITE "D16"; +LOCATE COMP "gp[25]" SITE "D14"; +LOCATE COMP "gn[25]" SITE "E14"; +LOCATE COMP "gp[26]" SITE "B13"; +LOCATE COMP "gn[26]" SITE "C13"; +LOCATE COMP "gp[27]" SITE "D13"; +LOCATE COMP "gn[27]" SITE "E13"; +IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn[24]" 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; + +## GPIO repeated as individual signals (non-vector) +# Allows mixed input, output, bidirectional, clock, differential +# If any of individual gp is used, then don't use gp[] vector. +# Same for gn and gn[]. +# FEMALE ANGLED (90 deg PMOD) on TOP or +# MALE VERTICAL ( 0 deg pins) on BOTTOM and flat cable +LOCATE COMP "sprite_addr[0]" SITE "B11"; # PCLK +LOCATE COMP "sprite_addr[1]" SITE "C11"; # PCLK +LOCATE COMP "EN_sprite" SITE "A10"; # PCLK +LOCATE COMP "grants[0]" SITE "A11"; # PCLK +LOCATE COMP "grants[1]" SITE "A9"; # GR_PCLK +LOCATE COMP "grants[2]" SITE "B10"; # GR_PCLK +LOCATE COMP "grants[3]" SITE "B9"; +LOCATE COMP "grants[4]" SITE "C10"; +LOCATE COMP "grants[5]" SITE "A7"; +LOCATE COMP "rst_btn" SITE "A8"; +LOCATE COMP "gp5" SITE "C8"; +LOCATE COMP "gn5" SITE "B8"; +LOCATE COMP "gp6" SITE "C6"; +LOCATE COMP "gn6" SITE "C7"; +IOBUF PORT "gp0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp1" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn1" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp2" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn2" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp3" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn3" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp4" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn4" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp5" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn5" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp6" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn6" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp7" SITE "A6"; +LOCATE COMP "gn7" SITE "B6"; +LOCATE COMP "gp8" SITE "A4"; # DIFF +LOCATE COMP "gn8" SITE "A5"; # DIFF +LOCATE COMP "gp9" SITE "A2"; # DIFF +LOCATE COMP "gn9" SITE "B1"; # DIFF +LOCATE COMP "gp10" SITE "C4"; # DIFF +LOCATE COMP "gn10" SITE "B4"; # DIFF +LOCATE COMP "gp11" SITE "F4"; # DIFF wifi_gpio26 +LOCATE COMP "gn11" SITE "E3"; # DIFF wifi_gpio25 +LOCATE COMP "gp12" SITE "G3"; # DIFF wifi_gpio33 PCLK +LOCATE COMP "gn12" SITE "F3"; # DIFF wifi_gpio32 PCLK +LOCATE COMP "gp13" SITE "H4"; # DIFF wifi_gpio35 +LOCATE COMP "gn13" SITE "G5"; # DIFF wifi_gpio34 +# wifi sharing PCB v2.0.6-v3.0.8 +# prior to v2.0.6 see schematics +IOBUF PORT "gp7" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn7" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp8" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn8" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp9" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn9" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp10" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn10" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp11" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn11" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp12" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn12" PULLMODE=NONE IO_TYPE=LVCMOS33; +FREQUENCY PORT "gn12" 50 MHZ; +IOBUF PORT "gp13" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn13" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp14" SITE "U18"; # DIFF ADC AIN1 +LOCATE COMP "gn14" SITE "U17"; # DIFF ADC AIN0 +LOCATE COMP "gp15" SITE "N17"; # DIFF ADC AIN3 +LOCATE COMP "gn15" SITE "P16"; # DIFF ADC AIN2 +LOCATE COMP "gp16" SITE "N16"; # DIFF ADC AIN5 +LOCATE COMP "gn16" SITE "M17"; # DIFF ADC AIN4 +LOCATE COMP "gp17" SITE "L16"; # DIFF ADC AIN7 GR_PCLK +LOCATE COMP "gn17" SITE "L17"; # DIFF ADC AIN6 +LOCATE COMP "gp18" SITE "H18"; # DIFF +LOCATE COMP "gn18" SITE "H17"; # DIFF +LOCATE COMP "gp19" SITE "F17"; # DIFF +LOCATE COMP "gn19" SITE "G18"; # DIFF +LOCATE COMP "gp20" SITE "D18"; # DIFF +LOCATE COMP "gn20" SITE "E17"; # DIFF +IOBUF PORT "gp14" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn14" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp15" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn15" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp18" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn18" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp19" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn19" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp20" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn20" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +LOCATE COMP "gp21" SITE "C18"; # DIFF +LOCATE COMP "gn21" SITE "D17"; # DIFF +LOCATE COMP "gp22" SITE "B15"; +LOCATE COMP "gn22" SITE "C15"; +LOCATE COMP "gp23" SITE "B17"; +LOCATE COMP "gn23" SITE "C17"; +LOCATE COMP "gp24" SITE "C16"; +LOCATE COMP "gn24" SITE "D16"; +LOCATE COMP "gp25" SITE "D14"; +LOCATE COMP "gn25" SITE "E14"; +LOCATE COMP "gp26" SITE "B13"; +LOCATE COMP "gn26" SITE "C13"; +LOCATE COMP "gp27" SITE "D13"; +LOCATE COMP "gn27" SITE "E13"; +IOBUF PORT "gp21" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn21" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp22" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn22" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp23" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn23" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp24" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn24" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp25" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn25" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp26" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn26" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gp27" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4; +IOBUF PORT "gn27" 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/tasks.py b/tasks.py index 3e7837f..1d75d79 100644 --- a/tasks.py +++ b/tasks.py @@ -89,7 +89,7 @@ def build(c, target="."): for target in expand_build_target(target): out_info, out_verilog, out_bsc = ensure_build_dirs(target, "info", "verilog", "bsc") print(f"Building {target}") - c.run(f"bsc -aggressive-conditions -check-assert -remove-dollar -remove-empty-rules -remove-false-rules -remove-starved-rules -remove-unused-modules -show-method-conf -show-method-bvi -u -verilog -info-dir {out_info} -vdir {out_verilog} -bdir {out_bsc} -p {target.parent}:lib:%/Libraries -show-module-use -show-compiles {target}") + c.run(f"bsc -aggressive-conditions -check-assert -remove-dollar -remove-empty-rules -remove-false-rules -remove-starved-rules -remove-unused-modules -show-method-conf -show-method-bvi -u -verilog -info-dir {out_info} -vdir {out_verilog} -bdir {out_bsc} -p {target.parent}:vram:lib:%/Libraries -show-module-use -show-compiles {target}") module_name = Path(f"mk{target.stem}") verilog_main_file = out_verilog / module_name.with_suffix(".v") diff --git a/vram/MemoryArbiter.bsv b/vram/MemoryArbiter.bsv new file mode 100644 index 0000000..6f262b0 --- /dev/null +++ b/vram/MemoryArbiter.bsv @@ -0,0 +1,190 @@ +package MemoryArbiter; + +import Vector::*; + +export MemoryArbiterWriter(..); +export MemoryArbiterReader(..); +export MemoryArbiter(..); +export mkMemoryArbiter; + +// A MemoryArbiterWriter can request use of a memory port to write to +// an address. When a request is feasible, grant() returns True in the +// same cycle. +(* always_ready *) +interface MemoryArbiterWriter#(type addr); + method Action request(Bool write, addr address); + method Bool grant(); +endinterface + +// MemoryArbiterReader can request use of a memory port to read from +// an address. When a request is feasible, grant() returns True in the +// same cycle. +(* always_ready *) +interface MemoryArbiterReader#(type addr); + method Action request(addr address); + method Bool grant(); +endinterface + +// A MemoryArbiter manages concurrent access to memory ports. It +// mediates access between 2 writers and 4 readers, which are +// statically allocated to one of 2 internal memory ports. +interface MemoryArbiter#(type addr); + // Assigned to port A. + interface MemoryArbiterWriter#(addr) cpu; + interface MemoryArbiterWriter#(addr) debugger; + interface MemoryArbiterReader#(addr) palette; + + // Assigned to port B. + interface MemoryArbiterReader#(addr) tile1; + interface MemoryArbiterReader#(addr) tile2; + interface MemoryArbiterReader#(addr) sprite; +endinterface + +// mkMemoryArbiter builds a GARY memory arbiter. +// +// Port A arbitrates with strict priority: CPU requests always proceed +// first, followed by debugger requests, then the palette DAC. +// +// Port B does round-robin arbitration, giving each client a fair +// chance of having its requests processed. +module mkMemoryArbiter(MemoryArbiter#(addr) ifc) + provisos(Bits#(addr, _), + Eq#(addr), + Alias#(write_req, Tuple2#(Bool, addr))); + + ////// + // Port A users + + RWire#(write_req) cpu_req <- mkRWire(); + RWire#(write_req) debugger_req <- mkRWire(); + PulseWire palette_req <- mkPulseWire(); + + PulseWire cpu_ok <- mkPulseWire(); + PulseWire debugger_ok <- mkPulseWire(); + PulseWire palette_ok <- mkPulseWire(); + + // Address written to by port A, if any. Used to block port B + // clients that are trying to read the same address. + RWire#(addr) written_addr <- mkRWire(); + + // We could be fancy with rule conditions to express the priorities + // between clients, but Bluespec has the preempts annotation to + // express the ranking directly. + (* preempts = "grant_cpu, (grant_debugger, grant_palette)" *) + (* preempts = "grant_debugger, grant_palette" *) + + (* fire_when_enabled *) + rule grant_cpu (cpu_req.wget matches tagged Valid {.write, .addr}); + cpu_ok.send(); + if (write) + written_addr.wset(addr); + endrule + + rule grant_debugger (debugger_req.wget matches tagged Valid {.write, .addr}); + debugger_ok.send(); + if (write) + written_addr.wset(addr); + endrule + + rule grant_palette (palette_req); + palette_ok.send(); + endrule + + ////// + // Port B users + + Vector#(3, RWire#(addr)) portB_req <- replicateM(mkRWire); + Wire#(Vector#(3, Bool)) portB_grant <- mkBypassWire(); + + Vector#(3, Bool) init = replicate(False); init[0] = True; + Reg#(Vector#(3, Bool)) priority_vec <- mkReg(init); + + rule grant_portB; + Vector#(3, Bool) grants = replicate(False); + Bool port_available = False; + + // This algorithm is a little mystifying at first glance, but it + // works. priority_vec has one bool per client, only one of + // which is True. That True bit identifies the client with the + // highest priority on the next request. + // + // This loop goes through each client twice, using + // port_available to track whether a client can grab the port or + // not. When we start iterating, the port is marked unavailable + // until we reach the top priority client, at which point we + // mark the port available and keep scanning. That effectively + // makes the search for a requesting client start at the top + // priority one. + // + // As we loop back around a second time, the availability bool + // gets reset again, but if you take the example of the True bit + // being in the middle of the vector, and consider cases where + // the first requestor is before/after that starting point, + // you'll see that it all works out, and at the end of the loop + // we have a new bit vector where only one client is True - the + // one whose request is granted. + for (Integer i = 0; i < 6; i=i+1) begin + Integer idx = i % 3; + if (priority_vec[idx]) + port_available = True; + let req = portB_req[idx].wget(); + if (port_available && isValid(req) && req != written_addr.wget()) begin + port_available = False; + grants[idx] = True; + end + end + portB_grant <= grants; + // If we granted a request, the grantee becomes the lowest + // priority client for the next round of requests. If nobody + // requested anything, keep the same priority as before. + if (any(id, grants)) + priority_vec <= rotateR(grants); + endrule + + ////// + // External interface + + interface MemoryArbiterWriter cpu; + method Action request(write, addr); + cpu_req.wset(tuple2(write, addr)); + endmethod + method grant = cpu_ok; + endinterface + + interface MemoryArbiterWriter debugger; + method Action request(write, addr); + debugger_req.wset(tuple2(write, addr)); + endmethod + method grant = debugger_ok; + endinterface + + interface MemoryArbiterReader palette; + method Action request(addr); + palette_req.send(); + endmethod + method grant = palette_ok; + endinterface + + interface MemoryArbiterReader tile1; + method Action request(addr); + portB_req[0].wset(addr); + endmethod + method grant = portB_grant[0]; + endinterface + + interface MemoryArbiterReader tile2; + method Action request(addr); + portB_req[1].wset(addr); + endmethod + method grant = portB_grant[1]; + endinterface + + interface MemoryArbiterReader sprite; + method Action request(addr); + portB_req[2].wset(addr); + endmethod + method grant = portB_grant[2]; + endinterface +endmodule + +endpackage diff --git a/vram/MemoryArbiter_Test.bsv b/vram/MemoryArbiter_Test.bsv new file mode 100644 index 0000000..59971bf --- /dev/null +++ b/vram/MemoryArbiter_Test.bsv @@ -0,0 +1,310 @@ +package MemoryArbiter_Test; + +import Assert::*; +import StmtFSM::*; +import Testing::*; +import Printf::*; +import List::*; +import Vector::*; +import BuildVector::*; + +import MemoryArbiter::*; + +typedef UInt#(4) Addr; + +typedef struct { + Bool write; + Addr addr; +} WriteReq deriving (Bits, Eq); + +typedef struct { + String name; + Maybe#(WriteReq) cpu; + Maybe#(WriteReq) debugger; + Maybe#(Addr) palette; + Maybe#(Addr) tile1; + Maybe#(Addr) tile2; + Maybe#(Addr) sprite; + + Vector#(6, Bool) want; +} TestCase deriving (Bits, Eq); + +function Maybe#(WriteReq) rwRead(Addr addr); + return tagged Valid WriteReq{write: False, addr: addr}; +endfunction + +function Maybe#(WriteReq) rwWrite(Addr addr); + return tagged Valid WriteReq{write: True, addr: addr}; +endfunction + +function Maybe#(Addr) read(Addr addr); + return tagged Valid addr; +endfunction + +function Maybe#(t) idle(); + return tagged Invalid; +endfunction + +function Vector#(6, Bool) grant(Integer granted_a, Integer granted_b); + let ret = replicate(False); + if (granted_a >= 0) + ret[granted_a] = True; + if (granted_b >= 0) + ret[granted_b+3] = True; + return ret; +endfunction + +function TestCase testCase(String name, + Maybe#(WriteReq) cpu, + Maybe#(WriteReq) debugger, + Maybe#(Addr) palette, + Maybe#(Addr) tile1, + Maybe#(Addr) tile2, + Maybe#(Addr) sprite, + Integer portA, + Integer portB); + return TestCase{ + name: name, + cpu: cpu, + debugger: debugger, + palette: palette, + tile1: tile1, + tile2: tile2, + sprite: sprite, + want: grant(portA, portB) + }; +endfunction + +module mkTB(); + MemoryArbiter#(Addr) dut <- mkMemoryArbiter(); + + Vector#(26, TestCase) tests = vec( + testCase("All idle", + idle, idle, idle, + idle, idle, idle, + -1, -1), + + // Single client accesses at a time + testCase("CPU read", rwRead(1), idle, idle, + idle, idle, idle, + 0, -1), + testCase("CPU write", rwWrite(1), idle, idle, + idle, idle, idle, + 0, -1), + testCase("Debugger read", + idle, rwRead(1), idle, + idle, idle, idle, + 1, -1), + testCase("Debugger write", + idle, rwWrite(1), idle, + idle, idle, idle, + 1, -1), + testCase("Palette read", + idle, idle, read(1), + idle, idle, idle, + 2, -1), + testCase("Tile1 read", + idle, idle, idle, + read(1), idle, idle, + -1, 0), + testCase("Tile2 read", + idle, idle, idle, + idle, read(1), idle, + -1, 1), + testCase("Sprite read", + idle, idle, idle, + idle, idle, read(1), + -1, 2), + + // Strict priority on port A + testCase("CPU + Debugger + Palette", + rwRead(1), rwRead(2), read(3), + idle, idle, idle, + 0, -1), + testCase("CPU + Palette", + rwRead(1), idle, read(3), + idle, idle, idle, + 0, -1), + testCase("Debugger + Palette", + idle, rwRead(2), read(3), + idle, idle, idle, + 1, -1), + + // Round-robin on port B + testCase("Sprite read", // to reset round robin + idle, idle, idle, + idle, idle, read(1), + -1, 2), + testCase("Tile1 + Tile2 + Sprite", + idle, idle, idle, + read(1), read(2), read(3), + -1, 0), + testCase("Tile1 + Tile2 + Sprite", + idle, idle, idle, + read(1), read(2), read(3), + -1, 1), + testCase("Tile1 + Tile2 + Sprite", + idle, idle, idle, + read(1), read(2), read(3), + -1, 2), + testCase("Tile1 + Tile2 + Sprite", + idle, idle, idle, + read(1), read(2), read(3), + -1, 0), + testCase("Tile1 + Sprite", + idle, idle, idle, + read(1), idle, read(3), + -1, 2), + testCase("Tile2 + Sprite", + idle, idle, idle, + idle, read(2), read(3), + -1, 1), + testCase("Tile2 + Sprite", + idle, idle, idle, + idle, read(2), read(3), + -1, 2), + + testCase("Read/read, no conflict", + rwRead(0), idle, idle, + read(0), idle, idle, + 0, 0), + testCase("Write/read, no conflict", + rwWrite(1), idle, idle, + read(0), idle, idle, + 0, 0), + testCase("Tile1 write conflict", + rwWrite(0), idle, idle, + read(0), idle, idle, + 0, -1), + testCase("Tile2 write conflict", + rwWrite(0), idle, idle, + idle, read(0), idle, + 0, -1), + testCase("Sprite write conflict", + rwWrite(0), idle, idle, + idle, idle, read(0), + 0, -1), + testCase("Tile1 write conflict with debugger", + idle, rwWrite(0), idle, + read(0), idle, idle, + 1, -1) + +); + + Reg#(UInt#(32)) idx <- mkReg(0); + + rule display_test (idx == 0); + $display("RUN TestMemoryArbiter"); + endrule + + (* no_implicit_conditions, fire_when_enabled *) + rule input_cpu (tests[idx].cpu matches tagged Valid .req &&& req matches WriteReq {write: .write, addr: .addr}); + dut.cpu.request(write, addr); + endrule + + (* no_implicit_conditions, fire_when_enabled *) + rule input_debugger (tests[idx].debugger matches tagged Valid .req &&& req matches WriteReq {write: .write, addr: .addr}); + dut.debugger.request(write, addr); + endrule + + (* no_implicit_conditions, fire_when_enabled *) + rule input_palette (tests[idx].palette matches tagged Valid .addr); + dut.palette.request(addr); + endrule + + (* no_implicit_conditions, fire_when_enabled *) + rule input_tile1 (tests[idx].tile1 matches tagged Valid .addr); + dut.tile1.request(addr); + endrule + + (* no_implicit_conditions, fire_when_enabled *) + rule input_tile2 (tests[idx].tile2 matches tagged Valid .addr); + dut.tile2.request(addr); + endrule + + (* no_implicit_conditions, fire_when_enabled *) + rule input_sprite (tests[idx].sprite matches tagged Valid .addr); + dut.sprite.request(addr); + endrule + + function Fmt rw_str(Maybe#(WriteReq) v); + case (v) matches + tagged Valid .req: begin + if (req.write) + return $format("Write(%0d)", req.addr); + else + return $format("Read(%0d)", req.addr); + end + tagged Invalid: return $format("Idle"); + endcase + endfunction + + function Fmt ro_str(Maybe#(Addr) v); + case (v) matches + tagged Valid .addr: return $format("Read(%0d)", addr); + tagged Invalid: return $format("Idle"); + endcase + endfunction + + (* no_implicit_conditions, fire_when_enabled *) + rule check_grants; + Vector#(6, Bool) gotVec = newVector; + gotVec[0] = dut.cpu.grant(); + gotVec[1] = dut.debugger.grant(); + gotVec[2] = dut.palette.grant(); + gotVec[3] = dut.tile1.grant(); + gotVec[4] = dut.tile2.grant(); + gotVec[5] = dut.sprite.grant(); + + let test = tests[idx]; + let got = pack(reverse(gotVec)); + let want = pack(reverse(test.want)); + + $display("\n # %0d: %s", idx+1, tests[idx].name); + $display(" input:", + "\n 0:", rw_str(test.cpu), "\n 1:", rw_str(test.debugger), "\n 2:", ro_str(test.palette), + "\n 3:", ro_str(test.tile1), "\n 4:", ro_str(test.tile2), "\n 5:", ro_str(test.sprite)); + $display(" got : %03b %03b", got[5:3], got[2:0]); + $display(" want: %03b %03b", want[5:3], want[2:0]); + dynamicAssert(got == want, "wrong arbiter output"); + endrule + + (* no_implicit_conditions, fire_when_enabled *) + rule advance_test; + let next = idx+1; + let max = fromInteger(arrayLength(vectorToArray(tests))); + if (next == max) begin + $display("OK TestMemoryArbiter"); + $finish; + end + else + idx <= next; + endrule + + // function Stmt testMemoryArbiter(); + // return seq + // testCase(idle, idle, idle, idle, idle, idle, + // grant(-1, -1)); + // + // // Simple single-client accesses + // testCase(readA(1), idle, idle, idle, idle, idle, + // grant(0, -1)); + // testCase(writeA(1), idle, idle, idle, idle, idle, + // grant(0, -1)); + // testCase(idle, readA(1), idle, idle, idle, idle, + // grant(1, -1)); + // testCase(idle, writeA(1), idle, idle, idle, idle, + // grant(1, -1)); + // testCase(idle, idle, read(1), idle, idle, idle, + // grant(2, -1)); + // testCase(idle, idle, idle, read(1), idle, idle, + // grant(-1, 0)); + // testCase(idle, idle, idle, idle, read(1), idle, + // grant(-1, 1)); + // testCase(idle, idle, idle, idle, idle, read(1), + // grant(-1, 2)); + // endseq; + // endfunction +endmodule + +endpackage