Compare commits

..

6 Commits

Author SHA1 Message Date
David Anderson f61328dac4 experiments/primitive_ram: clean up old testing code 2024-09-06 16:23:49 -07:00
David Anderson 930f9f7078 sentinel65x: start of Sentinel 65X top-level glue, with a PLL module
The PLL generates a 100MHz clock for GARY, 10MHz for the CPU and
system bus, and 25MHz for VGA out.
2024-09-06 16:21:25 -07:00
David Anderson f7cb4b6ba2 vram/VRAM: early VRAM implementation
Only checked up to mkByteRAMArray, main VRAM still WIP
2024-09-06 16:11:55 -07:00
David Anderson 7560199251 tasks: support running nextpnr with a generic ulx3s pin map
This is handy for quick experiments, rather than having to define a
bespoke pin map for each experiment.
2024-09-06 16:11:03 -07:00
David Anderson 2953106ec7 lib/ECP5_RAM: mark interfaces always_ready
Elides a couple of unnecessary signals from the design
2024-09-06 16:10:22 -07:00
David Anderson ab20db44f4 vram: rename MemoryArbiter to something shorter
As I implement the whole transaction-level modeling thing with
arbitration, the interface names are getting longer and longer.
2024-09-06 10:04:20 -07:00
11 changed files with 989 additions and 45 deletions

View File

@ -1,6 +1,6 @@
package Top; package Top;
import MemoryArbiter::*; import MemArbiter::*;
import Vector::*; import Vector::*;
import DReg::*; import DReg::*;
import DelayLine::*; import DelayLine::*;
@ -30,7 +30,7 @@ module mkTop(Top);
Vector#(2, Reg#(Maybe#(WriteReq))) wrin <- replicateM(mkDReg(tagged Invalid)); Vector#(2, Reg#(Maybe#(WriteReq))) wrin <- replicateM(mkDReg(tagged Invalid));
Vector#(4, Reg#(Maybe#(Addr))) rdin <- replicateM(mkDReg(tagged Invalid)); Vector#(4, Reg#(Maybe#(Addr))) rdin <- replicateM(mkDReg(tagged Invalid));
MemoryArbiter#(Addr) ret <- mkMemoryArbiter(); MemArbiter#(Addr) ret <- mkMemArbiter();
Reg#(Vector#(6, Bool)) ok <- mkReg(replicate(False)); Reg#(Vector#(6, Bool)) ok <- mkReg(replicate(False));

View File

@ -10,8 +10,6 @@ interface Top;
method Action putB((* port="flash_csn" *) Bool write, (* port="audio_l" *) Bit#(4) addr, (* port="audio_r" *) Bit#(4) data); method Action putB((* port="flash_csn" *) Bool write, (* port="audio_l" *) Bit#(4) addr, (* port="audio_r" *) Bit#(4) data);
(* result="led" *) (* result="led" *)
method Bit#(8) read(); method Bit#(8) read();
//interface EBRPort#(Bit#(12), Bit#(4)) ram1;
//interface EBRPort#(Bit#(12), Bit#(4)) ram2;
endinterface endinterface
(* synthesize,clock_prefix="clk_25mhz",reset_prefix="audio_v" *) (* synthesize,clock_prefix="clk_25mhz",reset_prefix="audio_v" *)
@ -20,8 +18,6 @@ module mkTop(Top ifc);
cfgA.write_mode = Normal; cfgA.write_mode = Normal;
cfgA.chip_select_addr = 5; cfgA.chip_select_addr = 5;
EBRPortConfig cfgB = defaultValue; EBRPortConfig cfgB = defaultValue;
// cfgB.clk = tagged Valid clk2;
// cfgB.rstN = tagged Valid rst2;
cfgB.register_output = True; cfgB.register_output = True;
let r <- mkEBR(cfgA, cfgB); let r <- mkEBR(cfgA, cfgB);
@ -40,8 +36,6 @@ module mkTop(Top ifc);
method Bit#(8) read(); method Bit#(8) read();
return out; return out;
endmethod endmethod
//interface EBRPort ram1 = r.portA;
//interface EBRPort ram2 = r.portB;
endmodule endmodule
endpackage endpackage

38
experiments/vram/Top.bsv Normal file
View File

@ -0,0 +1,38 @@
package Top;
import VRAM::*;
import ECP5_RAM::*;
import TriState::*;
(* always_enabled *)
interface Top;
method Action phi2(bit v);
method Action we(bit we);
method Action addr(UInt#(24) addr);
interface InOut#(Bit#(8)) data();
endinterface
(* synthesize *)
module mkTop(Top);
Reg#(PortReq) reqA <- mkRegU();
Reg#(VRAMData) respA <- mkRegU();
let _ret <- mkByteRAMArray(8);
rule putA;
_ret.portA.put(reqA.chip_select, reqA.write, reqA.addr, reqA.datain);
endrule
rule getA;
respA <= _ret.portA.read();
endrule
method portA_read = respA._read;
method Action portA_put(cs, w, a, d);
reqA <= PortReq{chip_select: cs, write: w, addr: a, datain: d};
endmethod
method portB_read = _ret.portB.read;
method portB_put = _ret.portB.put;
endmodule
endpackage

View File

@ -237,6 +237,7 @@ endfunction
// //
// EBRPort is a port of an EBR memory. // EBRPort is a port of an EBR memory.
(* always_ready *)
interface EBRPort#(type addr, type data); interface EBRPort#(type addr, type data);
method Action put(UInt#(3) chip_select, Bool write, addr address, data datain); method Action put(UInt#(3) chip_select, Bool write, addr address, data datain);
method data read(); method data read();

598
lib/ulx3s_v20.lpf Normal file
View File

@ -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" 25 MHZ;
# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
# write to FLASH possible any time from JTAG:
SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=ENABLE SLAVE_PARALLEL_PORT=DISABLE;
# write to FLASH possible from user bitstream:
# SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
## USBSERIAL FTDI-FPGA serial port "usb" sheet
LOCATE COMP "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 "led[7]" SITE "H3";
LOCATE COMP "led[6]" SITE "E1";
LOCATE COMP "led[5]" SITE "E2";
LOCATE COMP "led[4]" SITE "D1";
LOCATE COMP "led[3]" SITE "D2";
LOCATE COMP "led[2]" SITE "C1";
LOCATE COMP "led[1]" SITE "C2";
LOCATE COMP "led[0]" SITE "B2";
IOBUF PORT "led[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "led[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "led[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "led[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "led[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "led[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "led[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "led[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
LOCATE COMP "btn[0]" SITE "D6"; # BTN_PWRn (inverted logic)
LOCATE COMP "btn[1]" SITE "R1"; # FIRE1
LOCATE COMP "btn[2]" SITE "T1"; # FIRE2
LOCATE COMP "btn[3]" SITE "R18"; # UP W1->R18
LOCATE COMP "btn[4]" SITE "V1"; # DOWN
LOCATE COMP "btn[5]" SITE "U1"; # LEFT
LOCATE COMP "btn[6]" SITE "H16"; # RIGHT Y2->H16
IOBUF PORT "btn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "btn[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "btn[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "btn[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "btn[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "btn[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "btn[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
## DIP switch "blinkey", "gpio" sheet
LOCATE COMP "sw[0]" SITE "E8"; # SW1
LOCATE COMP "sw[1]" SITE "D8"; # SW2
LOCATE COMP "sw[2]" SITE "D7"; # SW3
LOCATE COMP "sw[3]" SITE "E7"; # SW4
IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
LOCATE COMP "oled_clk" SITE "P4";
LOCATE COMP "oled_mosi" SITE "P3";
LOCATE COMP "oled_dc" SITE "P1";
LOCATE COMP "oled_resn" SITE "P2";
LOCATE COMP "oled_csn" SITE "N2";
IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
## SPI Flash chip "flash" sheet
LOCATE COMP "flash_csn" SITE "R2";
LOCATE COMP "flash_clk" SITE "U3";
LOCATE COMP "flash_mosi" SITE "W2";
LOCATE COMP "flash_miso" SITE "V2";
LOCATE COMP "flash_holdn" SITE "W1";
LOCATE COMP "flash_wpn" SITE "Y2";
#LOCATE COMP "flash_csspin" SITE "AJ3";
#LOCATE COMP "flash_initn" SITE "AG4";
#LOCATE COMP "flash_done" SITE "AJ4";
#LOCATE COMP "flash_programn" SITE "AH4";
#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
IOBUF PORT "flash_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_clk" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_holdn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_wpn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
## SD card "sdcard", "usb" sheet
# 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 "gp0" SITE "B11"; # PCLK
LOCATE COMP "gn0" SITE "C11"; # PCLK
LOCATE COMP "gp1" SITE "A10"; # PCLK
LOCATE COMP "gn1" SITE "A11"; # PCLK
LOCATE COMP "gp2" SITE "A9"; # GR_PCLK
LOCATE COMP "gn2" SITE "B10"; # GR_PCLK
LOCATE COMP "gp3" SITE "B9";
LOCATE COMP "gn3" SITE "C10";
LOCATE COMP "gp4" SITE "A7";
LOCATE COMP "gn4" 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;

49
sentinel65x/PLL.bsv Normal file
View File

@ -0,0 +1,49 @@
package PLL;
// Frequencies: FPGA 100MHz, CPU 10MHz, VGA 25MHz
//
// To regenerate, see 'inv genclk -h'
// Clocks are the various clocks used in GARY.
interface Clocks;
// main_clk is the internal clock that most of the design runs at.
interface Clock main_clk;
// cpu_clk is the clock generated and output for use by the 65X
// CPU. The system bus interface is clocked by cpu_clk.
interface Clock cpu_clk;
// vga_clk is the pixel clock for the video output.
interface Clock vga_clk;
// locked is whether the PLL has locked and is producing stable
// clocks.
//
// TODO: hook this into clock gating or global reset, to hold the
// FPGA in a safe state while the PLL starts up and locks.
(* always_ready *)
method Bool locked();
endinterface
// mkPLL takes in a reference clock signal and generates GARY's
// clocks. All the output clocks are in phase with main_clk,
// i.e. every posedge of cpu_clk and vga_clk is also a posedge of
// main_clk.
import "BVI" PLL =
module mkPLL(Clock clk, Clocks ifc);
default_clock no_clock;
default_reset no_reset;
input_clock ref_clk(CLK_REF, (* unused *)CLK_REF_GATE) = clk;
output_clock main_clk(CLK_MAIN);
output_clock cpu_clk(CLK_CPU);
output_clock vga_clk(CLK_VGA);
ancestor(cpu_clk, main_clk);
ancestor(vga_clk, main_clk);
method locked locked();
schedule locked CF locked;
endmodule
endpackage

60
sentinel65x/PLL.v Normal file
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 PLL
(
input CLK_REF, // 25 MHz, 0 deg
output CLK_MAIN, // 100 MHz, 0 deg
output CLK_CPU, // 10 MHz, 0 deg
output CLK_VGA, // 25 MHz, 0 deg
output locked
);
(* FREQUENCY_PIN_CLKI="25" *)
(* FREQUENCY_PIN_CLKOP="100" *)
(* FREQUENCY_PIN_CLKOS="10" *)
(* 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(6),
.CLKOP_CPHASE(2),
.CLKOP_FPHASE(0),
.CLKOS_ENABLE("ENABLED"),
.CLKOS_DIV(60),
.CLKOS_CPHASE(2),
.CLKOS_FPHASE(0),
.CLKOS2_ENABLE("ENABLED"),
.CLKOS2_DIV(24),
.CLKOS2_CPHASE(2),
.CLKOS2_FPHASE(0),
.FEEDBK_PATH("CLKOP"),
.CLKFB_DIV(4)
) pll_i (
.RST(1'b0),
.STDBY(1'b0),
.CLKI(CLK_REF),
.CLKOP(CLK_MAIN),
.CLKOS(CLK_CPU),
.CLKOS2(CLK_VGA),
.CLKFB(CLK_MAIN),
.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

@ -157,22 +157,27 @@ def synth(c, target):
print(f"Compiled : {yosys_compiled}") print(f"Compiled : {yosys_compiled}")
print(f" Dot : {yosys_preprocessed_graph}.dot") print(f" Dot : {yosys_preprocessed_graph}.dot")
pin_map = target.parent / "pin_map.lpf"
if not pin_map.is_file():
print(f"WARNING: no pin map at {pin_map}, skipping place&route and bitstream generation")
return
phase("Place and route") phase("Place and route")
pin_map = target.parent / "pin_map.lpf"
if pin_map.is_file():
pin_map_arg = f"--lpf {pin_map}"
else:
print(f"WARNING: no pin map at {pin_map}, executing place&route with no constraints")
pin_map_arg = f"--lpf-allow-unconstrained --lpf=lib/ulx3s_v20.lpf"
nextpnr_out = out_nextpnr / module_name.with_suffix(".pnr") nextpnr_out = out_nextpnr / module_name.with_suffix(".pnr")
nextpnr_log = out_nextpnr / module_name.with_suffix(".log") nextpnr_log = out_nextpnr / module_name.with_suffix(".log")
nextpnr_timing = out_nextpnr / module_name.with_suffix(".log") nextpnr_timing = out_nextpnr / module_name.with_suffix(".timing.log")
out = c.run(f"nextpnr-ecp5 --85k --detailed-timing-report -l {nextpnr_log} --report {nextpnr_timing} --json {yosys_json} --lpf {pin_map} --package=CABGA381 --speed=6 --textcfg {nextpnr_out}", hide='stderr') out = c.run(f"nextpnr-ecp5 --85k --detailed-timing-report -l {nextpnr_log} --report {nextpnr_timing} --json {yosys_json} --package=CABGA381 {pin_map_arg} --speed=6 --textcfg {nextpnr_out}", hide='stderr')
print_filtered_paragraphs(out.stderr, "Device utilisation", "Critical path", "Max frequency", "Max delay", common_prefix="Info: ") print_filtered_paragraphs(out.stderr, "Device utilisation", "Critical path", "Max frequency", "Max delay", common_prefix="Info: ")
print(f" PNR : {nextpnr_out}") print(f" PNR : {nextpnr_out}")
print(f" Log : {nextpnr_log}") print(f" Log : {nextpnr_log}")
print(f"Timing : {nextpnr_timing}") print(f"Timing : {nextpnr_timing}")
if not pin_map.is_file():
print("WARNING: skipping bitstream generation, unconstrained p&r")
return
phase("Bitstream generation") phase("Bitstream generation")
bitstream = nextpnr_out.with_suffix(".bit") bitstream = nextpnr_out.with_suffix(".bit")
c.run(f"ecppack {nextpnr_out} {bitstream}") c.run(f"ecppack {nextpnr_out} {bitstream}")
@ -197,3 +202,21 @@ def test(c, target):
def clean(c): def clean(c):
if Path("out").is_dir(): if Path("out").is_dir():
shutil.rmtree("out") shutil.rmtree("out")
@task
def genclk(c, in_mhz=25, main_mhz=100, cpu_mhz=10, vga_mhz=25):
out = Path("gary/PLL.v")
c.run(f"ecppll -f {out} --module PLL --clkin_name CLK_REF --clkin {in_mhz} --clkout0_name CLK_MAIN --clkout0 {main_mhz} --clkout1_name CLK_CPU --clkout1 {cpu_mhz} --clkout2_name CLK_VGA --clkout2 {vga_mhz}")
bsv_out = out.with_suffix(".bsv")
with open(bsv_out) as f:
lines = f.readlines()
idx = None
for i, l in enumerate(lines):
if l.startswith("// Frequencies: "):
idx = i
break
if idx is None:
print(f"WARNING: couldn't find frequencies line in {bsv_out}, not updating")
lines[i] = f"// Frequencies: FPGA {main_mhz}MHz, CPU {cpu_mhz}MHz, VGA {vga_mhz}MHz\n"
with open(bsv_out, "w") as f:
f.write("".join(lines))

View File

@ -1,52 +1,52 @@
package MemoryArbiter; package MemArbiter;
import Vector::*; import Vector::*;
export MemoryArbiterWriter(..); export MemArbiterWriter(..);
export MemoryArbiterReader(..); export MemArbiterReader(..);
export MemoryArbiter(..); export MemArbiter(..);
export mkMemoryArbiter; export mkMemArbiter;
// A MemoryArbiterWriter can request use of a memory port to read or // A MemArbiterWriter can request use of a memory port to read or
// write to an address. When a request is feasible, grant() returns // write to an address. When a request is feasible, grant() returns
// True in the same cycle. // True in the same cycle.
(* always_ready *) (* always_ready *)
interface MemoryArbiterWriter#(type addr); interface MemArbiterWriter#(type addr);
method Action request(Bool write, addr address); method Action request(Bool write, addr address);
method Bool grant(); method Bool grant();
endinterface endinterface
// MemoryArbiterReader can request use of a memory port to read from // MemArbiterReader can request use of a memory port to read from
// an address. When a request is feasible, grant() returns True in the // an address. When a request is feasible, grant() returns True in the
// same cycle. // same cycle.
(* always_ready *) (* always_ready *)
interface MemoryArbiterReader#(type addr); interface MemArbiterReader#(type addr);
method Action request(addr address); method Action request(addr address);
method Bool grant(); method Bool grant();
endinterface endinterface
// A MemoryArbiter manages concurrent access to memory ports. It // A MemArbiter manages concurrent access to memory ports. It
// mediates access between 2 writers and 4 readers. // mediates access between 2 writers and 4 readers.
interface MemoryArbiter#(type addr); interface MemArbiter#(type addr);
// Assigned to port A. // Assigned to port A.
interface MemoryArbiterWriter#(addr) cpu; interface MemArbiterWriter#(addr) cpu;
interface MemoryArbiterWriter#(addr) debugger; interface MemArbiterWriter#(addr) debugger;
interface MemoryArbiterReader#(addr) palette; interface MemArbiterReader#(addr) palette;
// Assigned to port B. // Assigned to port B.
interface MemoryArbiterReader#(addr) tile1; interface MemArbiterReader#(addr) tile1;
interface MemoryArbiterReader#(addr) tile2; interface MemArbiterReader#(addr) tile2;
interface MemoryArbiterReader#(addr) sprite; interface MemArbiterReader#(addr) sprite;
endinterface endinterface
// mkMemoryArbiter builds a GARY memory arbiter. // mkMemArbiter builds a GARY memory arbiter.
// //
// Port A arbitrates with strict priority: CPU requests always proceed // Port A arbitrates with strict priority: CPU requests always proceed
// first, followed by debugger requests, then the palette DAC. // first, followed by debugger requests, then the palette DAC.
// //
// Port B does round-robin arbitration, giving each client a fair // Port B does round-robin arbitration, giving each client a fair
// chance of having its requests processed. // chance of having its requests processed.
module mkMemoryArbiter(MemoryArbiter#(addr) ifc) module mkMemArbiter(MemArbiter#(addr) ifc)
provisos(Bits#(addr, _), provisos(Bits#(addr, _),
Eq#(addr), Eq#(addr),
Alias#(write_req, Tuple2#(Bool, addr))); Alias#(write_req, Tuple2#(Bool, addr)));
@ -143,42 +143,42 @@ module mkMemoryArbiter(MemoryArbiter#(addr) ifc)
////// //////
// External interface // External interface
interface MemoryArbiterWriter cpu; interface MemArbiterWriter cpu;
method Action request(write, addr); method Action request(write, addr);
cpu_req.wset(tuple2(write, addr)); cpu_req.wset(tuple2(write, addr));
endmethod endmethod
method grant = cpu_ok; method grant = cpu_ok;
endinterface endinterface
interface MemoryArbiterWriter debugger; interface MemArbiterWriter debugger;
method Action request(write, addr); method Action request(write, addr);
debugger_req.wset(tuple2(write, addr)); debugger_req.wset(tuple2(write, addr));
endmethod endmethod
method grant = debugger_ok; method grant = debugger_ok;
endinterface endinterface
interface MemoryArbiterReader palette; interface MemArbiterReader palette;
method Action request(addr); method Action request(addr);
palette_req.send(); palette_req.send();
endmethod endmethod
method grant = palette_ok; method grant = palette_ok;
endinterface endinterface
interface MemoryArbiterReader tile1; interface MemArbiterReader tile1;
method Action request(addr); method Action request(addr);
portB_req[0].wset(addr); portB_req[0].wset(addr);
endmethod endmethod
method grant = portB_grant[0]; method grant = portB_grant[0];
endinterface endinterface
interface MemoryArbiterReader tile2; interface MemArbiterReader tile2;
method Action request(addr); method Action request(addr);
portB_req[1].wset(addr); portB_req[1].wset(addr);
endmethod endmethod
method grant = portB_grant[1]; method grant = portB_grant[1];
endinterface endinterface
interface MemoryArbiterReader sprite; interface MemArbiterReader sprite;
method Action request(addr); method Action request(addr);
portB_req[2].wset(addr); portB_req[2].wset(addr);
endmethod endmethod

View File

@ -1,4 +1,4 @@
package MemoryArbiter_Test; package MemArbiter_Test;
import Assert::*; import Assert::*;
import StmtFSM::*; import StmtFSM::*;
@ -8,7 +8,7 @@ import List::*;
import Vector::*; import Vector::*;
import BuildVector::*; import BuildVector::*;
import MemoryArbiter::*; import MemArbiter::*;
typedef UInt#(4) Addr; typedef UInt#(4) Addr;
@ -76,7 +76,7 @@ function TestCase testCase(String name,
endfunction endfunction
module mkTB(); module mkTB();
MemoryArbiter#(Addr) dut <- mkMemoryArbiter(); MemArbiter#(Addr) dut <- mkMemArbiter();
Vector#(29, TestCase) tests = vec( Vector#(29, TestCase) tests = vec(
testCase("All idle", testCase("All idle",
@ -205,7 +205,7 @@ module mkTB();
Reg#(UInt#(32)) idx <- mkReg(0); Reg#(UInt#(32)) idx <- mkReg(0);
rule display_test (idx == 0); rule display_test (idx == 0);
$display("RUN TestMemoryArbiter"); $display("RUN TestMemArbiter");
endrule endrule
(* no_implicit_conditions, fire_when_enabled *) (* no_implicit_conditions, fire_when_enabled *)
@ -289,7 +289,7 @@ module mkTB();
let next = idx+1; let next = idx+1;
let max = fromInteger(arrayLength(vectorToArray(tests))); let max = fromInteger(arrayLength(vectorToArray(tests)));
if (next == max) begin if (next == max) begin
$display("OK TestMemoryArbiter"); $display("OK TestMemArbiter");
$finish; $finish;
end end
else else

181
vram/VRAM.bsv Normal file
View File

@ -0,0 +1,181 @@
package VRAM;
import GetPut::*;
import ClientServer::*;
import DReg::*;
import BRAM::*;
import Vector::*;
import FIFOF::*;
import SpecialFIFOs::*;
import DelayLine::*;
import ECP5_RAM::*;
typedef UInt#(17) VRAMAddr;
typedef Bit#(8) VRAMData;
// Each byte RAM we build below can address 4096 bytes, which is 12
// address bits.
typedef UInt#(12) ByteAddr;
// The difference between ByteRAM_Addr and VRAMAddr is the chip
// select ID.
typedef UInt#(5) ChipAddr;
// ByteRAM is two EBRs glued together to make a whole-byte memory.
typedef EBR#(ByteAddr, VRAMData, ByteAddr, VRAMData) ByteRAM;
// mkByteRAM glues two ECP5 EBRs together to make a 4096x8b memory
// block. Like the underlying ECP5 EBRs, callers must bring their own
// flow control to read out responses one cycle after putting a read
// request.
module mkByteRAM(UInt#(3) chip_addr, ByteRAM ifc);
EBRPortConfig cfg = defaultValue;
cfg.chip_select_addr = chip_addr;
EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) upper <- mkEBRCore(cfg, cfg);
EBR#(ByteAddr, Bit#(4), ByteAddr, Bit#(4)) lower <- mkEBRCore(cfg, cfg);
interface EBRPort portA;
method Action put(UInt#(3) chip_select, Bool write, ByteAddr addr, VRAMData data_in);
upper.portA.put(chip_select, write, addr, truncate(data_in>>4));
lower.portA.put(chip_select, write, addr, truncate(data_in));
endmethod
method VRAMData read();
return (extend(upper.portA.read())<<4) | (extend(lower.portA.read()));
endmethod
endinterface
interface EBRPort portB;
method Action put(UInt#(3) chip_select, Bool write, ByteAddr addr, VRAMData data_in);
upper.portB.put(chip_select, write, addr, truncate(data_in>>4));
lower.portB.put(chip_select, write, addr, truncate(data_in));
endmethod
method VRAMData read();
return (extend(upper.portB.read())<<4) | (extend(lower.portB.read()));
endmethod
endinterface
endmodule : mkByteRAM
module mkByteRAMArray(Integer num_chips, ByteRAM ifc);
if (num_chips > 8)
error("mkByteRAMArray can only array 8 raw ByteRAMs");
ByteRAM blocks[num_chips];
for (Integer i=0; i<num_chips; i=i+1)
blocks[i] <- mkByteRAM(fromInteger(i));
DelayLine#(UInt#(3)) read_chip_A <- mkDelayLine(1);
DelayLine#(UInt#(3)) read_chip_B <- mkDelayLine(1);
interface EBRPort portA;
method Action put(UInt#(3) chip_select, Bool write, ByteAddr addr, VRAMData data_in);
for (Integer i=0; i<num_chips; i=i+1)
blocks[i].portA.put(chip_select, write, addr, data_in);
if (write)
read_chip_A <= chip_select;
endmethod
method VRAMData read();
if (read_chip_A.ready)
if (read_chip_A <= fromInteger(num_chips-1))
return blocks[read_chip_A].portA.read();
else
return 0;
else
return 0;
endmethod
endinterface
interface EBRPort portB;
method Action put(UInt#(3) chip_select, Bool write, ByteAddr addr, VRAMData data_in);
for (Integer i=0; i<num_chips; i=i+1)
blocks[i].portB.put(chip_select, write, addr, data_in);
if (write)
read_chip_B <= chip_select;
endmethod
method VRAMData read();
if (read_chip_B.ready)
if (read_chip_B <= fromInteger(num_chips-1))
return blocks[read_chip_B].portB.read();
else
return 0;
else
return 0;
endmethod
endinterface
endmodule
typedef struct {
VRAMAddr addr;
Maybe#(VRAMData) data;
} VRAMRequest deriving (Bits, Eq);
typedef struct {
VRAMData data;
} VRAMResponse deriving (Bits, Eq);
typedef Server#(VRAMRequest, VRAMResponse) VRAMServer;
typedef Client#(VRAMRequest, VRAMResponse) VRAMClient;
interface VRAM;
interface VRAMServer portA;
interface VRAMServer portB;
endinterface
module mkVRAM(Integer num_4kB_blocks, VRAM ifc);
if (num_4kB_blocks > 32)
error("maximum number of blocks is 32 (128KiB)");
UInt#(TAdd#(SizeOf#(VRAMAddr), 1)) max_request_addr = fromInteger((4096 * num_4kB_blocks));
function Tuple2#(ChipAddr, ByteAddr) split_addr(VRAMAddr a);
UInt#(TAdd#(SizeOf#(VRAMAddr), 1)) expanded = extend(a);
VRAMAddr wrapped = truncate(expanded % max_request_addr);
match {.chip, .off} = split(pack(wrapped));
return tuple2(unpack(chip), unpack(off));
endfunction
ByteRAM blocks[num_4kB_blocks];
for (Integer i=0; i<num_4kB_blocks; i=i+1)
blocks[i] <- mkByteRAM(0);
Reg#(Maybe#(ChipAddr)) inflight_A[2] <- mkCReg(2, tagged Invalid);
Reg#(Maybe#(ChipAddr)) inflight_B[2] <- mkCReg(2, tagged Invalid);
interface VRAMServer portA;
interface Put request;
method Action put(VRAMRequest req) if (inflight_A[1] matches tagged Invalid);
match {.chip, .off} = split_addr(req.addr);
blocks[chip].portA.put(0, isValid(req.data), off, fromMaybe(0, req.data));
if (!isValid(req.data))
inflight_A[1] <= tagged Valid chip;
endmethod
endinterface
interface Get response;
method ActionValue#(VRAMResponse) get() if (inflight_A[0] matches tagged Valid .chip);
inflight_A[0] <= tagged Invalid;
return VRAMResponse{data: blocks[chip].portA.read()};
endmethod
endinterface
endinterface
interface VRAMServer portB;
interface Put request;
method Action put(VRAMRequest req) if (inflight_B[1] matches tagged Invalid);
match {.chip, .off} = split_addr(req.addr);
blocks[chip].portB.put(0, isValid(req.data), off, fromMaybe(0, req.data));
if (!isValid(req.data))
inflight_B[1] <= tagged Valid chip;
endmethod
endinterface
interface Get response;
method ActionValue#(VRAMResponse) get() if (inflight_B[0] matches tagged Valid .chip);
inflight_B[0] <= tagged Invalid;
return VRAMResponse{data: blocks[chip].portB.read()};
endmethod
endinterface
endinterface
endmodule
endpackage