diff --git a/.gitignore b/.gitignore
index 9f2164b..9db2d5c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@
*.sasmout
*.lib
*.img
+*.mem
*.lsym
*.zip
go.sum
@@ -17,10 +18,10 @@ sine.pas
graph.pas
graph2.pas
chase.pas
-*.img
!runtime.s
**/tridoracpu.*/
rtl/arty-a7/mig_dram_0/_tmp
rtl/arty-a7/mig_dram_0/mig_dram_0
rtl/arty-a7/mig_dram_0/xil_txt.*
rtl/arty-a7/mig_dram_0/*.veo
+rtl/arty-a7/mig_dram_0/*.tcl
diff --git a/rtl/arty-a7/Arty-A7-35-Master.xdc b/rtl/arty-a7/Arty-A7-35-Master.xdc
new file mode 100644
index 0000000..c618478
--- /dev/null
+++ b/rtl/arty-a7/Arty-A7-35-Master.xdc
@@ -0,0 +1,218 @@
+## This file is a general .xdc for the Arty A7-35 Rev. D
+## To use it in a project:
+## - uncomment the lines corresponding to used pins
+## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project
+
+## Clock signal
+set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports clk]
+create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports clk]
+
+## Switches
+set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports sw0]
+set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports sw1]
+#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2]
+#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3]
+
+## RGB LEDs
+#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L18N_T2_35 Sch=led0_b
+#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L19N_T3_VREF_35 Sch=led0_g
+#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L19P_T3_35 Sch=led0_r
+#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1_b }]; #IO_L20P_T3_35 Sch=led1_b
+#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1_g }]; #IO_L21P_T3_DQS_35 Sch=led1_g
+#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1_r }]; #IO_L20N_T3_35 Sch=led1_r
+#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2_b }]; #IO_L21N_T3_DQS_35 Sch=led2_b
+#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2_g }]; #IO_L22N_T3_35 Sch=led2_g
+#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2_r }]; #IO_L22P_T3_35 Sch=led2_r
+#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3_b }]; #IO_L23P_T3_35 Sch=led3_b
+#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3_g }]; #IO_L24P_T3_35 Sch=led3_g
+#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3_r }]; #IO_L23N_T3_35 Sch=led3_r
+
+## LEDs
+set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports led0]
+set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports led1]
+set_property -dict {PACKAGE_PIN T9 IOSTANDARD LVCMOS33} [get_ports led2]
+set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports led3]
+
+## Buttons
+set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports btn0]
+#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn1 }]; #IO_L11P_T1_SRCC_16 Sch=btn[1]
+#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2]
+#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3]
+
+## Pmod Header JA
+set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports sd_cs_n]
+set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS33} [get_ports sd_mosi]
+set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS33} [get_ports sd_miso]
+set_property -dict {PACKAGE_PIN D12 IOSTANDARD LVCMOS33} [get_ports sd_sck]
+#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { sd_dat1 }]; #IO_L6N_T0_VREF_15 Sch=ja[7]
+#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { sd_dat2 }]; #IO_L10P_T1_AD11P_15 Sch=ja[8]
+set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports sd_cd]
+#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { sd_nc }]; #IO_25_15 Sch=ja[10]
+
+###Pmod Header JB
+set_property -dict {PACKAGE_PIN E15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[0]}]
+set_property -dict {PACKAGE_PIN E16 IOSTANDARD LVCMOS33} [get_ports {VGA_R[1]}]
+set_property -dict {PACKAGE_PIN D15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[2]}]
+set_property -dict {PACKAGE_PIN C15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[3]}]
+set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS33} [get_ports {VGA_B[0]}]
+set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {VGA_B[1]}]
+set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS33} [get_ports {VGA_B[2]}]
+set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {VGA_B[3]}]
+
+###Pmod Header JC
+set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {VGA_G[0]}]
+set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports {VGA_G[1]}]
+set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {VGA_G[2]}]
+set_property -dict {PACKAGE_PIN V11 IOSTANDARD LVCMOS33} [get_ports {VGA_G[3]}]
+set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVCMOS33} [get_ports VGA_HS_O]
+set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports VGA_VS_O]
+#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L23P_T3_A03_D19_14 Sch=jc_p[4]
+#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4]
+
+## Pmod Header JD
+#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L11N_T1_SRCC_35 Sch=jd[1]
+#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L12N_T1_MRCC_35 Sch=jd[2]
+#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L13P_T2_MRCC_35 Sch=jd[3]
+#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L13N_T2_MRCC_35 Sch=jd[4]
+#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L14P_T2_SRCC_35 Sch=jd[7]
+#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L14N_T2_SRCC_35 Sch=jd[8]
+#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15P_T2_DQS_35 Sch=jd[9]
+#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L15N_T2_DQS_35 Sch=jd[10]
+
+## USB-UART Interface
+set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS33} [get_ports uart_rxd_out]
+set_property -dict {PACKAGE_PIN A9 IOSTANDARD LVCMOS33} [get_ports uart_txd_in]
+
+## ChipKit Outer Digital Header
+#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0]
+#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io1 }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1]
+#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io2 }]; #IO_L8N_T1_D12_14 Sch=ck_io[2]
+#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io3 }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3]
+#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io4 }]; #IO_L5P_T0_D06_14 Sch=ck_io[4]
+#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io5 }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5]
+#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io6 }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6]
+#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io7 }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7]
+#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io8 }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8]
+#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io9 }]; #IO_L10P_T1_D14_14 Sch=ck_io[9]
+#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10]
+#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11]
+#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12]
+#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13]
+
+## ChipKit Inner Digital Header
+#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { ck_io26 }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26]
+#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { ck_io27 }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27]
+#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { ck_io28 }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28]
+#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { ck_io29 }]; #IO_25_14 Sch=ck_io[29]
+#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { ck_io30 }]; #IO_0_14 Sch=ck_io[30]
+#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { ck_io31 }]; #IO_L5N_T0_D07_14 Sch=ck_io[31]
+#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { ck_io32 }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32]
+#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_io33 }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33]
+#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io34 }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34]
+#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { ck_io35 }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35]
+#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { ck_io36 }]; #IO_L8P_T1_D11_14 Sch=ck_io[36]
+#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io37 }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37]
+#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { ck_io38 }]; #IO_L7N_T1_D10_14 Sch=ck_io[38]
+#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { ck_io39 }]; #IO_L7P_T1_D09_14 Sch=ck_io[39]
+#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io40 }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40]
+#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io41 }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41]
+
+## ChipKit Outer Analog Header - as Single-Ended Analog Inputs
+## NOTE: These ports can be used as single-ended analog inputs with voltages from 0-3.3V (ChipKit analog pins A0-A5) or as digital I/O.
+## WARNING: Do not use both sets of constraints at the same time!
+## NOTE: The following constraints should be used with the XADC IP core when using these ports as analog inputs.
+#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vaux4_n }]; #IO_L1N_T0_AD4N_35 Sch=ck_an_n[0] ChipKit pin=A0
+#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vaux4_p }]; #IO_L1P_T0_AD4P_35 Sch=ck_an_p[0] ChipKit pin=A0
+#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vaux5_n }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] ChipKit pin=A1
+#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vaux5_p }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] ChipKit pin=A1
+#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_n }]; #IO_L7N_T1_AD6N_35 Sch=ck_an_n[2] ChipKit pin=A2
+#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_p }]; #IO_L7P_T1_AD6P_35 Sch=ck_an_p[2] ChipKit pin=A2
+#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_n }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] ChipKit pin=A3
+#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_p }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] ChipKit pin=A3
+#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { vaux15_n }]; #IO_L10N_T1_AD15N_35 Sch=ck_an_n[4] ChipKit pin=A4
+#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { vaux15_p }]; #IO_L10P_T1_AD15P_35 Sch=ck_an_p[4] ChipKit pin=A4
+#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_n }]; #IO_L1N_T0_AD0N_15 Sch=ck_an_n[5] ChipKit pin=A5
+#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_p }]; #IO_L1P_T0_AD0P_15 Sch=ck_an_p[5] ChipKit pin=A5
+## ChipKit Outer Analog Header - as Digital I/O
+## NOTE: the following constraints should be used when using these ports as digital I/O.
+#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_a0 }]; #IO_0_35 Sch=ck_a[0] ChipKit pin=A0
+#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_a1 }]; #IO_L4P_T0_35 Sch=ck_a[1] ChipKit pin=A1
+#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_a2 }]; #IO_L4N_T0_35 Sch=ck_a[2] ChipKit pin=A2
+#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_a3 }]; #IO_L6P_T0_35 Sch=ck_a[3] ChipKit pin=A3
+#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_a4 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4] ChipKit pin=A4
+#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_a5 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5] ChipKit pin=A5
+
+## ChipKit Inner Analog Header - as Differential Analog Inputs
+## NOTE: These ports can be used as differential analog inputs with voltages from 0-1.0V (ChipKit Analog pins A6-A11) or as digital I/O.
+## WARNING: Do not use both sets of constraints at the same time!
+## NOTE: The following constraints should be used with the XADC core when using these ports as analog inputs.
+#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vaux12_p }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6
+#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vaux12_n }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7
+#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { vaux13_p }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8
+#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { vaux13_n }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9
+#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vaux14_p }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10
+#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vaux14_n }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11
+## ChipKit Inner Analog Header - as Digital I/O
+## NOTE: the following constraints should be used when using the inner analog header ports as digital I/O.
+#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { ck_io20 }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6
+#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { ck_io21 }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7
+#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { ck_io22 }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8
+#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { ck_io23 }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9
+#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { ck_io24 }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10
+#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { ck_io25 }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11
+
+## ChipKit SPI
+#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso
+#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi
+#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck
+#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss
+
+## ChipKit I2C
+#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl
+#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda
+#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup
+#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup
+
+## Misc. ChipKit Ports
+#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa
+set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports rst]
+
+## SMSC Ethernet PHY
+#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col
+#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs
+#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc
+#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio
+#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk
+#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L20P_T3_A20_15 Sch=eth_rstn
+#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_clk }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk
+#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_dv }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv
+#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0]
+#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1]
+#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2]
+#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3]
+#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr
+#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_clk }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk
+#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_en }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en
+#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0]
+#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1]
+#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2]
+#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3]
+
+## Quad SPI Flash
+#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs
+#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0]
+#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1]
+#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2]
+#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3]
+
+## Power Measurements
+#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2]
+#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2]
+#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1]
+#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1]
+#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9]
+#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9]
+#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10]
+#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10]
+
+set_property BITSTREAM.GENERAL.COMPRESS True [current_design]
diff --git a/rtl/arty-a7/Arty_C_mig.ucf b/rtl/arty-a7/Arty_C_mig.ucf
new file mode 100644
index 0000000..5a36c18
--- /dev/null
+++ b/rtl/arty-a7/Arty_C_mig.ucf
@@ -0,0 +1,48 @@
+NET "ddr3_dq[0]" LOC = "K5" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[1]" LOC = "L3" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[2]" LOC = "K3" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[3]" LOC = "L6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[4]" LOC = "M3" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[5]" LOC = "M1" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[6]" LOC = "L4" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[7]" LOC = "M2" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[8]" LOC = "V4" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[9]" LOC = "T5" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[10]" LOC = "U4" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[11]" LOC = "V5" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[12]" LOC = "V1" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[13]" LOC = "T3" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[14]" LOC = "U3" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dq[15]" LOC = "R3" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dm[0]" LOC = "L1" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dm[1]" LOC = "U1" | IOSTANDARD = SSTL135 ;
+NET "ddr3_dqs_p[0]" LOC = "N2" | IOSTANDARD = DIFF_SSTL135 ;
+NET "ddr3_dqs_n[0]" LOC = "N1" | IOSTANDARD = DIFF_SSTL135 ;
+NET "ddr3_dqs_p[1]" LOC = "U2" | IOSTANDARD = DIFF_SSTL135 ;
+NET "ddr3_dqs_n[1]" LOC = "V2" | IOSTANDARD = DIFF_SSTL135 ;
+NET "ddr3_addr[13]" LOC = "T8" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[12]" LOC = "T6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[11]" LOC = "U6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[10]" LOC = "R6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[9]" LOC = "V7" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[8]" LOC = "R8" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[7]" LOC = "U7" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[6]" LOC = "V6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[5]" LOC = "R7" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[4]" LOC = "N6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[3]" LOC = "T1" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[2]" LOC = "N4" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[1]" LOC = "M6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_addr[0]" LOC = "R2" | IOSTANDARD = SSTL135 ;
+NET "ddr3_ba[2]" LOC = "P2" | IOSTANDARD = SSTL135 ;
+NET "ddr3_ba[1]" LOC = "P4" | IOSTANDARD = SSTL135 ;
+NET "ddr3_ba[0]" LOC = "R1" | IOSTANDARD = SSTL135 ;
+NET "ddr3_ck_p[0]" LOC = "U9" | IOSTANDARD = DIFF_SSTL135 ;
+NET "ddr3_ck_n[0]" LOC = "V9" | IOSTANDARD = DIFF_SSTL135 ;
+NET "ddr3_ras_n" LOC = "P3" | IOSTANDARD = SSTL135 ;
+NET "ddr3_cas_n" LOC = "M4" | IOSTANDARD = SSTL135 ;
+NET "ddr3_we_n" LOC = "P5" | IOSTANDARD = SSTL135 ;
+NET "ddr3_reset_n" LOC = "K6" | IOSTANDARD = SSTL135 ;
+NET "ddr3_cke[0]" LOC = "N5" | IOSTANDARD = SSTL135 ;
+NET "ddr3_odt[0]" LOC = "R5" | IOSTANDARD = SSTL135 ;
+NET "ddr3_cs_n[0]" LOC = "U8" | IOSTANDARD = SSTL135 ;
diff --git a/rtl/arty-a7/mig_dram_0/mig_a.prj b/rtl/arty-a7/mig_dram_0/mig_a.prj
new file mode 100644
index 0000000..b263a25
--- /dev/null
+++ b/rtl/arty-a7/mig_dram_0/mig_a.prj
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+ mig_dram_0
+
+ 1
+
+ 1
+
+ OFF
+
+ 1024
+
+ ON
+
+ Enabled
+
+ xc7a35ti-csg324/-1L
+
+ 4.2
+
+ No Buffer
+
+ No Buffer
+
+ ACTIVE LOW
+
+ FALSE
+
+ 1
+
+ 50 Ohms
+
+ 0
+
+
+ DDR3_SDRAM/Components/MT41K128M16XX-15E
+ 3000
+ 1.8V
+ 4:1
+ 83.333
+ 0
+ 666
+ 1.000
+ 1
+ 1
+ 1
+ 1
+ 16
+ 1
+ 1
+ Disabled
+ Strict
+ 4
+ FALSE
+
+ 14
+ 10
+ 3
+ 1.35V
+ BANK_ROW_COLUMN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8 - Fixed
+ Sequential
+ 5
+ Normal
+ No
+ Slow Exit
+ Enable
+ RZQ/6
+ Disable
+ Enable
+ RZQ/6
+ 0
+ Disabled
+ Enabled
+ Output Buffer Enabled
+ Full Array
+ 5
+ Enabled
+ Normal
+ Dynamic ODT off
+ NATIVE
+
+
+
+
diff --git a/rtl/arty-a7/mig_dram_0/mig_b.prj b/rtl/arty-a7/mig_dram_0/mig_b.prj
new file mode 100644
index 0000000..b263a25
--- /dev/null
+++ b/rtl/arty-a7/mig_dram_0/mig_b.prj
@@ -0,0 +1,148 @@
+
+
+
+
+
+
+
+ mig_dram_0
+
+ 1
+
+ 1
+
+ OFF
+
+ 1024
+
+ ON
+
+ Enabled
+
+ xc7a35ti-csg324/-1L
+
+ 4.2
+
+ No Buffer
+
+ No Buffer
+
+ ACTIVE LOW
+
+ FALSE
+
+ 1
+
+ 50 Ohms
+
+ 0
+
+
+ DDR3_SDRAM/Components/MT41K128M16XX-15E
+ 3000
+ 1.8V
+ 4:1
+ 83.333
+ 0
+ 666
+ 1.000
+ 1
+ 1
+ 1
+ 1
+ 16
+ 1
+ 1
+ Disabled
+ Strict
+ 4
+ FALSE
+
+ 14
+ 10
+ 3
+ 1.35V
+ BANK_ROW_COLUMN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 8 - Fixed
+ Sequential
+ 5
+ Normal
+ No
+ Slow Exit
+ Enable
+ RZQ/6
+ Disable
+ Enable
+ RZQ/6
+ 0
+ Disabled
+ Enabled
+ Output Buffer Enabled
+ Full Array
+ 5
+ Enabled
+ Normal
+ Dynamic ODT off
+ NATIVE
+
+
+
+
diff --git a/rtl/arty-a7/mig_dram_0/mig_dram_0.xci b/rtl/arty-a7/mig_dram_0/mig_dram_0.xci
new file mode 100644
index 0000000..3da3694
--- /dev/null
+++ b/rtl/arty-a7/mig_dram_0/mig_dram_0.xci
@@ -0,0 +1,2876 @@
+
+
+ xilinx.com
+ xci
+ unknown
+ 1.0
+
+
+ mig_dram_0
+
+
+ 0
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 0
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+
+ 0
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ TDM
+ 8
+ false
+ 11
+ 11
+ true
+
+ true
+ 8
+
+ COMPONENTS
+ ROW_COLUMN_BANK
+ Single
+ 1250
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+
+
+
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ false
+ 100000000
+
+
+
+ 100000000
+ 0
+ 0
+ 0.000
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 0
+ 0
+ 0
+
+ 1
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 0
+ 1
+ 1
+ 1
+ 1
+ 1
+ 0.000
+ AXI4LITE
+ READ_WRITE
+ 0
+ 0
+ 0
+ 0
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 32
+ 32
+ 32
+ 4
+ 1048576
+ 32
+ 4
+ 1048576
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 100.0
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 1200.0
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ DIFF
+ FALSE
+ 0
+ 0
+ 28
+ 32
+ 32
+ 4
+ 1048576
+ 128
+ 2
+ 268435456
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ 28
+ 3
+ 1
+ 1
+ 1
+ 16
+ OFF
+ 2
+ 1
+ 2
+ 16
+ 1
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 4
+ 1
+ 8
+ 8
+ 2
+ OFF
+ 1
+ OFF
+ 83333333
+ FALSE
+ 8
+ 3
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 1
+ 1
+ 1
+ 8
+ OFF
+ 14
+ 1
+ 1
+ 1
+ 2
+ 1
+ DDR3
+ FALSE
+ 10.0
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ FALSE
+ 10
+ 666
+ 1
+ 0.000
+ ACTIVE_LOW
+ 29
+ 1
+ 8
+ 18
+ OFF
+ 1
+ NOBUF
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 1
+ 18
+ OFF
+ 1
+ 1
+ 1
+ 8
+ 1
+ 29
+ 1
+ 29
+ 2
+ 1
+ 18
+ 1
+ 1
+ NOBUF
+ INTERNAL
+ FALSE
+ 0
+ Custom
+ mig_dram_0
+ Custom
+ Custom
+ mig_b.prj
+ artix7
+ digilentinc.com:arty-a7-35:part0:1.0
+
+ xc7a35ti
+ csg324
+ VERILOG
+
+ MIXED
+ -1L
+
+ I
+ TRUE
+ TRUE
+ IP_Flow
+ 1
+ TRUE
+ .
+
+ .
+ 2020.1
+ OUT_OF_CONTEXT
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/rtl/arty-a7/sdspi_testbench_behav.wcfg b/rtl/arty-a7/sdspi_testbench_behav.wcfg
new file mode 100644
index 0000000..bb29917
--- /dev/null
+++ b/rtl/arty-a7/sdspi_testbench_behav.wcfg
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clk
+ clk
+
+
+ tx_data[7:0]
+ tx_data[7:0]
+
+
+ rx_data[7:0]
+ rx_data[7:0]
+
+
+ rx_shifter[7:0]
+ rx_shifter[7:0]
+
+
+ tx_shifter[7:0]
+ tx_shifter[7:0]
+
+
+ tx_fifo_out[7:0]
+ tx_fifo_out[7:0]
+
+
+ tx_fifo_rd_en
+ tx_fifo_rd_en
+
+
+ tx_fifo_wr_en
+ tx_fifo_wr_en
+
+
+ rx_fifo_wr_en
+ rx_fifo_wr_en
+
+
+ rx_bit_recvd
+ rx_bit_recvd
+
+
+ tail_x[4:0]
+ tail_x[4:0]
+
+
+ head_x[4:0]
+ head_x[4:0]
+
+
+ tx_ready
+ tx_ready
+
+
+ tx_empty
+ tx_empty
+
+
+ rx_avail
+ rx_avail
+
+
+ tx_write
+ tx_write
+
+
+ rx_read
+ rx_read
+
+
+ ctrl_write
+ ctrl_write
+
+
+ rx_filter_en
+ rx_filter_en
+
+
+ txrx_en
+ txrx_en
+
+
+ spiclk_div_wr
+ spiclk_div_wr
+
+
+ spi_clk_on
+ spi_clk_on
+
+
+ spiclk_f_en
+ spiclk_f_en
+
+
+ spi_clk_f_on
+ spi_clk_f_on
+
+
+ sd_cs_n
+ sd_cs_n
+ #DCDCDC
+ true
+
+
+ sd_mosi
+ sd_mosi
+ #00FFFF
+ true
+
+
+ sd_miso
+ sd_miso
+
+
+ sd_sck
+ sd_sck
+ #FFFF00
+ true
+
+
+ xcvr_on
+ xcvr_on
+
+
+ hphase_start
+ hphase_start
+ #F0E68C
+ true
+
+
+ clk_phase[1:0]
+ clk_phase[1:0]
+ #D2691E
+ true
+
+
+ running
+ running
+
+
+ xcvr_bitcount[3:0]
+ xcvr_bitcount[3:0]
+
+
+ spi_clk_count[6:0]
+ spi_clk_count[6:0]
+
+
+ spi_clk_div[6:0]
+ spi_clk_div[6:0]
+
+
diff --git a/rtl/arty-a7/testbench_behav1.wcfg b/rtl/arty-a7/testbench_behav1.wcfg
new file mode 100644
index 0000000..1a2bc03
--- /dev/null
+++ b/rtl/arty-a7/testbench_behav1.wcfg
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clk
+ clk
+
+
+ addr[31:0]
+ addr[31:0]
+
+
+ data_in[31:0]
+ data_in[31:0]
+
+
+ data_out[31:0]
+ data_out[31:0]
+
+
+ seq_state[1:0]
+ seq_state[1:0]
+
+
+ PC[31:0]
+ PC[31:0]
+
+
+ nPC[31:0]
+ nPC[31:0]
+
+
+ ins[15:0]
+ ins[15:0]
+ BINARYRADIX
+
+
+ ins_branch
+ ins_branch
+
+
+ ins_loadrel
+ ins_loadrel
+
+
+ X[31:0]
+ X[31:0]
+
+
+ nX[31:0]
+ nX[31:0]
+
+
+ FP[31:0]
+ FP[31:0]
+
+
+ pc_next_ins[31:0]
+ pc_next_ins[31:0]
+
+
+ mem_wait
+ mem_wait
+
+
+ ins_buf[15:0]
+ ins_buf[15:0]
+
+
diff --git a/rtl/arty-a7/tridoracpu.tcl b/rtl/arty-a7/tridoracpu.tcl
new file mode 100644
index 0000000..e18483e
--- /dev/null
+++ b/rtl/arty-a7/tridoracpu.tcl
@@ -0,0 +1,724 @@
+#*****************************************************************************************
+# Vivado (TM) v2020.1 (64-bit)
+#
+# tridoracpu.tcl: Tcl script for re-creating project 'tridoracpu'
+#
+# Generated by Vivado on Sat Sep 14 23:58:12 +0200 2024
+# IP Build 2902112 on Wed May 27 22:43:36 MDT 2020
+#
+# This file contains the Vivado Tcl commands for re-creating the project to the state*
+# when this script was generated. In order to re-create the project, please source this
+# file in the Vivado Tcl Shell.
+#
+# * Note that the runs in the created project will be configured the same way as the
+# original project, however they will not be launched automatically. To regenerate the
+# run results please launch the synthesis/implementation runs as needed.
+#
+#*****************************************************************************************
+# NOTE: In order to use this script for source control purposes, please make sure that the
+# following files are added to the source control system:-
+#
+# 1. This project restoration tcl script (tridoracpu.tcl) that was generated.
+#
+# 2. The following source(s) files that were local or imported into the original project.
+# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script)
+#
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/cpuclk.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/display_clock.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/mem.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stack.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stackcpu.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/vgafb.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/top.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/testbench.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/rom.mem"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_a.prj"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_b.prj"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/dram_bridge.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/bram_tdp.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/palette.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/irqctrl.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi_testbench.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_dram_0.xci"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sim_1/new/uart_tb.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/testbench_behav1.wcfg"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/sdspi_testbench_behav.wcfg"
+#
+# 3. The following remote source files that were added to the original project:-
+#
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/imports/verilog/uart.v"
+# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/constrs_1/imports/fpga/Arty-A7-35-Master.xdc"
+#
+#*****************************************************************************************
+
+#xhub::refresh_catalog [xhub::get_xstores xilinx_board_store]
+# this will take quite some time
+#xhub::install [xhub::get_xitems]
+
+# Set the reference directory for source file relative paths (by default the value is script directory path)
+set origin_dir "C:/Users/sebastian/develop/Tridora/rtl"
+
+# Oh come on, Xilinx, why?
+#set xilinx_board_store_dir "../../../../AppData/Roaming/Xilinx/Vivado/2020.1/xhub/board_store/xilinx_board_store"
+set xilinx_board_store_dir [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
+set_param board.repoPaths [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]]
+
+# Use origin directory path location variable, if specified in the tcl shell
+if { [info exists ::origin_dir_loc] } {
+ set origin_dir $::origin_dir_loc
+}
+
+# Set the project name
+set _xil_proj_name_ "tridoracpu"
+
+# Use project name variable, if specified in the tcl shell
+if { [info exists ::user_project_name] } {
+ set _xil_proj_name_ $::user_project_name
+}
+
+variable script_file
+set script_file "tridoracpu.tcl"
+
+# Help information for this script
+proc print_help {} {
+ variable script_file
+ puts "\nDescription:"
+ puts "Recreate a Vivado project from this script. The created project will be"
+ puts "functionally equivalent to the original project for which this script was"
+ puts "generated. The script contains commands for creating a project, filesets,"
+ puts "runs, adding/importing sources and setting properties on various objects.\n"
+ puts "Syntax:"
+ puts "$script_file"
+ puts "$script_file -tclargs \[--origin_dir \]"
+ puts "$script_file -tclargs \[--project_name \]"
+ puts "$script_file -tclargs \[--help\]\n"
+ puts "Usage:"
+ puts "Name Description"
+ puts "-------------------------------------------------------------------------"
+ puts "\[--origin_dir \] Determine source file paths wrt this path. Default"
+ puts " origin_dir path value is \".\", otherwise, the value"
+ puts " that was set with the \"-paths_relative_to\" switch"
+ puts " when this script was generated.\n"
+ puts "\[--project_name \] Create project with the specified name. Default"
+ puts " name is the name of the project from where this"
+ puts " script was generated.\n"
+ puts "\[--help\] Print help information for this script"
+ puts "-------------------------------------------------------------------------\n"
+ exit 0
+}
+
+if { $::argc > 0 } {
+ for {set i 0} {$i < $::argc} {incr i} {
+ set option [string trim [lindex $::argv $i]]
+ switch -regexp -- $option {
+ "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] }
+ "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] }
+ "--help" { print_help }
+ default {
+ if { [regexp {^-} $option] } {
+ puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n"
+ return 1
+ }
+ }
+ }
+ }
+}
+
+# Set the directory path for the original project from where this script was exported
+set orig_proj_dir "[file normalize "${origin_dir}/arty-a7"]"
+
+# Create project
+create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7a35ticsg324-1L
+
+# Set the directory path for the new project
+set proj_dir [get_property directory [current_project]]
+
+# Set project properties
+set obj [current_project]
+#set_property -name "board_part_repo_paths" -value "[file normalize "$xilinx_board_store_dir"]" -objects $obj
+set_property -name "board_part" -value "digilentinc.com:arty-a7-35:part0:1.0" -objects $obj
+set_property -name "default_lib" -value "xil_defaultlib" -objects $obj
+set_property -name "enable_vhdl_2008" -value "1" -objects $obj
+set_property -name "ip_cache_permissions" -value "read write" -objects $obj
+set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj
+set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj
+set_property -name "platform.board_id" -value "arty-a7-35" -objects $obj
+set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj
+set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj
+set_property -name "simulator_language" -value "Mixed" -objects $obj
+set_property -name "source_mgmt_mode" -value "DisplayOnly" -objects $obj
+set_property -name "webtalk.activehdl_export_sim" -value "4" -objects $obj
+set_property -name "webtalk.ies_export_sim" -value "4" -objects $obj
+set_property -name "webtalk.modelsim_export_sim" -value "4" -objects $obj
+set_property -name "webtalk.questa_export_sim" -value "4" -objects $obj
+set_property -name "webtalk.riviera_export_sim" -value "4" -objects $obj
+set_property -name "webtalk.vcs_export_sim" -value "4" -objects $obj
+set_property -name "webtalk.xsim_export_sim" -value "4" -objects $obj
+set_property -name "webtalk.xsim_launch_sim" -value "537" -objects $obj
+
+# Create 'sources_1' fileset (if not found)
+if {[string equal [get_filesets -quiet sources_1] ""]} {
+ create_fileset -srcset sources_1
+}
+
+# Set 'sources_1' fileset object
+set obj [get_filesets sources_1]
+set files [list \
+ [file normalize "${origin_dir}/src/uart.v"] \
+]
+add_files -norecurse -fileset $obj $files
+
+# Add local files from the original project (-no_copy_sources specified)
+set files [list \
+ [file normalize "${origin_dir}/src/cpuclk.v" ]\
+ [file normalize "${origin_dir}/src/display_clock.v" ]\
+ [file normalize "${origin_dir}/src/mem.v" ]\
+ [file normalize "${origin_dir}/src/stack.v" ]\
+ [file normalize "${origin_dir}/src/stackcpu.v" ]\
+ [file normalize "${origin_dir}/src/vgafb.v" ]\
+ [file normalize "${origin_dir}/src/top.v" ]\
+ [file normalize "${origin_dir}/src/testbench.v" ]\
+ [file normalize "${orig_proj_dir}/rom.mem" ]\
+ [file normalize "${orig_proj_dir}/mig_dram_0/mig_a.prj" ]\
+ [file normalize "${orig_proj_dir}/mig_dram_0/mig_b.prj" ]\
+ [file normalize "${origin_dir}/src/dram_bridge.v" ]\
+ [file normalize "${origin_dir}/src/sdspi.v" ]\
+ [file normalize "${origin_dir}/src/bram_tdp.v" ]\
+ [file normalize "${origin_dir}/src/palette.v" ]\
+ [file normalize "${origin_dir}/src/irqctrl.v" ]\
+ [file normalize "${origin_dir}/src/fifo.v" ]\
+ [file normalize "${origin_dir}/src/fifo_testbench.v" ]\
+ [file normalize "${origin_dir}/src/sdspi_testbench.v" ]\
+]
+set added_files [add_files -fileset sources_1 $files]
+
+# Set 'sources_1' fileset file properties for remote files
+set file "$origin_dir/src/uart.v"
+set file [file normalize $file]
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+
+# Set 'sources_1' fileset file properties for local files
+set file "src/cpuclk.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/display_clock.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "is_enabled" -value "0" -objects $file_obj
+
+set file "src/mem.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/stack.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/stackcpu.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/vgafb.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/top.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/testbench.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "" -objects $file_obj
+set_property -name "used_in_implementation" -value "0" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+set_property -name "used_in_synthesis" -value "0" -objects $file_obj
+
+set file "arty-a7/rom.mem"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "file_type" -value "Memory File" -objects $file_obj
+
+set file "arty-a7/mig_dram_0/mig_a.prj"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "scoped_to_cells" -value "mig_dram_0" -objects $file_obj
+
+set file "arty-a7/mig_dram_0/mig_b.prj"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "scoped_to_cells" -value "mig_dram_0" -objects $file_obj
+
+set file "src/dram_bridge.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/palette.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/irqctrl.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+set file "src/fifo_testbench.v"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "used_in" -value "" -objects $file_obj
+set_property -name "used_in_implementation" -value "0" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+set_property -name "used_in_synthesis" -value "0" -objects $file_obj
+
+
+# Set 'sources_1' fileset properties
+set obj [get_filesets sources_1]
+set_property -name "top" -value "top" -objects $obj
+set_property -name "top_auto_set" -value "0" -objects $obj
+
+# Set 'sources_1' fileset object
+set obj [get_filesets sources_1]
+# Add local files from the original project (-no_copy_sources specified)
+set files [list \
+ [file normalize "${orig_proj_dir}/mig_dram_0/mig_dram_0.xci" ]\
+]
+set added_files [add_files -fileset sources_1 $files]
+
+# Set 'sources_1' fileset file properties for remote files
+# None
+
+# Set 'sources_1' fileset file properties for local files
+set file "arty-a7/mig_dram_0/mig_dram_0.xci"
+set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]]
+set_property -name "generate_files_for_reference" -value "0" -objects $file_obj
+set_property -name "registered_with_manager" -value "1" -objects $file_obj
+if { ![get_property "is_locked" $file_obj] } {
+ set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj
+}
+set_property -name "used_in" -value "synthesis implementation" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+
+
+# Create 'constrs_1' fileset (if not found)
+if {[string equal [get_filesets -quiet constrs_1] ""]} {
+ create_fileset -constrset constrs_1
+}
+
+# Set 'constrs_1' fileset object
+set obj [get_filesets constrs_1]
+
+# Add/Import constrs file and set constrs file properties
+set file "[file normalize ${origin_dir}/arty-a7/Arty-A7-35-Master.xdc]"
+set file_added [add_files -norecurse -fileset $obj [list $file]]
+set file "$origin_dir/arty-a7/Arty-A7-35-Master.xdc"
+set file [file normalize $file]
+set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]]
+set_property -name "file_type" -value "XDC" -objects $file_obj
+
+# Set 'constrs_1' fileset properties
+set obj [get_filesets constrs_1]
+set_property -name "target_constrs_file" -value "$orig_proj_dir/Arty-A7-35-Master.xdc" -objects $obj
+set_property -name "target_ucf" -value "$orig_proj_dir/Arty-A7-35-Master.xdc" -objects $obj
+
+# Create 'sim_1' fileset (if not found)
+if {[string equal [get_filesets -quiet sim_1] ""]} {
+ create_fileset -simset sim_1
+}
+
+# Set 'sim_1' fileset object
+set obj [get_filesets sim_1]
+# Add local files from the original project (-no_copy_sources specified)
+set files [list \
+ [file normalize "${origin_dir}/src/uart_tb.v" ]\
+ [file normalize "${orig_proj_dir}/testbench_behav1.wcfg" ]\
+]
+set added_files [add_files -fileset sim_1 $files]
+
+# Set 'sim_1' fileset file properties for remote files
+# None
+
+# Set 'sim_1' fileset file properties for local files
+set file [file normalize "${origin_dir}/src/uart_tb.v"]
+set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]]
+set_property -name "used_in" -value "" -objects $file_obj
+set_property -name "used_in_implementation" -value "0" -objects $file_obj
+set_property -name "used_in_simulation" -value "0" -objects $file_obj
+set_property -name "used_in_synthesis" -value "0" -objects $file_obj
+
+
+# Set 'sim_1' fileset properties
+set obj [get_filesets sim_1]
+set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj
+set_property -name "nl.mode" -value "funcsim" -objects $obj
+set_property -name "top" -value "testbench" -objects $obj
+set_property -name "top_lib" -value "xil_defaultlib" -objects $obj
+
+# Create 'sim_fifo' fileset (if not found)
+if {[string equal [get_filesets -quiet sim_fifo] ""]} {
+ create_fileset -simset sim_fifo
+}
+
+# Set 'sim_fifo' fileset object
+set obj [get_filesets sim_fifo]
+# Add local files from the original project (-no_copy_sources specified)
+set files [list \
+ [file normalize "${origin_dir}/src/fifo.v" ]\
+ [file normalize "${origin_dir}/src/fifo_testbench.v" ]\
+]
+set added_files [add_files -fileset sim_fifo $files]
+
+# Set 'sim_fifo' fileset file properties for remote files
+# None
+
+# Set 'sim_fifo' fileset file properties for local files
+# None
+
+# Set 'sim_fifo' fileset properties
+set obj [get_filesets sim_fifo]
+set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj
+set_property -name "top" -value "fifo_testbench" -objects $obj
+set_property -name "top_auto_set" -value "0" -objects $obj
+
+# Create 'sim_sdspi' fileset (if not found)
+if {[string equal [get_filesets -quiet sim_sdspi] ""]} {
+ create_fileset -simset sim_sdspi
+}
+
+# Set 'sim_sdspi' fileset object
+set obj [get_filesets sim_sdspi]
+# Add local files from the original project (-no_copy_sources specified)
+set files [list \
+ [file normalize "${orig_proj_dir}/sdspi_testbench_behav.wcfg" ]\
+]
+set added_files [add_files -fileset sim_sdspi $files]
+
+# Set 'sim_sdspi' fileset file properties for remote files
+# None
+
+# Set 'sim_sdspi' fileset file properties for local files
+# None
+
+# Set 'sim_sdspi' fileset properties
+set obj [get_filesets sim_sdspi]
+set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj
+set_property -name "sim_mode" -value "post-synthesis" -objects $obj
+set_property -name "top" -value "sdspi_testbench" -objects $obj
+set_property -name "top_auto_set" -value "0" -objects $obj
+set_property -name "top_lib" -value "xil_defaultlib" -objects $obj
+set_property -name "xsim.simulate.runtime" -value "10ms" -objects $obj
+
+# Set 'utils_1' fileset object
+set obj [get_filesets utils_1]
+# Empty (no sources present)
+
+# Set 'utils_1' fileset properties
+set obj [get_filesets utils_1]
+
+# Create 'synth_1' run (if not found)
+if {[string equal [get_runs -quiet synth_1] ""]} {
+ create_run -name synth_1 -part xc7a35ticsg324-1L -flow {Vivado Synthesis 2020} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1
+} else {
+ set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1]
+ set_property flow "Vivado Synthesis 2020" [get_runs synth_1]
+}
+set obj [get_runs synth_1]
+set_property set_report_strategy_name 1 $obj
+set_property report_strategy {Vivado Synthesis Default Reports} $obj
+set_property set_report_strategy_name 0 $obj
+# Create 'synth_1_synth_report_utilization_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } {
+ create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1
+}
+set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0]
+if { $obj != "" } {
+
+}
+set obj [get_runs synth_1]
+set_property -name "needs_refresh" -value "1" -objects $obj
+set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj
+
+# set the current synth run
+current_run -synthesis [get_runs synth_1]
+
+# Create 'impl_1' run (if not found)
+if {[string equal [get_runs -quiet impl_1] ""]} {
+ create_run -name impl_1 -part xc7a35ticsg324-1L -flow {Vivado Implementation 2020} -strategy "Performance_RefinePlacement" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1
+} else {
+ set_property strategy "Performance_RefinePlacement" [get_runs impl_1]
+ set_property flow "Vivado Implementation 2020" [get_runs impl_1]
+}
+set obj [get_runs impl_1]
+set_property set_report_strategy_name 1 $obj
+set_property report_strategy {Vivado Implementation Default Reports} $obj
+set_property set_report_strategy_name 0 $obj
+# Create 'impl_1_init_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+set_property -name "options.max_paths" -value "10" -objects $obj
+
+}
+# Create 'impl_1_opt_report_drc_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } {
+ create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_opt_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+set_property -name "options.max_paths" -value "10" -objects $obj
+
+}
+# Create 'impl_1_power_opt_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+set_property -name "options.max_paths" -value "10" -objects $obj
+
+}
+# Create 'impl_1_place_report_io_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } {
+ create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_place_report_utilization_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } {
+ create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_place_report_control_sets_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } {
+ create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0]
+if { $obj != "" } {
+set_property -name "options.verbose" -value "1" -objects $obj
+
+}
+# Create 'impl_1_place_report_incremental_reuse_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } {
+ create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+
+}
+# Create 'impl_1_place_report_incremental_reuse_1' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } {
+ create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+
+}
+# Create 'impl_1_place_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+set_property -name "options.max_paths" -value "10" -objects $obj
+
+}
+# Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+set_property -name "options.max_paths" -value "10" -objects $obj
+
+}
+# Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "is_enabled" -value "0" -objects $obj
+set_property -name "options.max_paths" -value "10" -objects $obj
+
+}
+# Create 'impl_1_route_report_drc_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_route_report_methodology_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_route_report_power_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_route_report_route_status_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_route_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "options.max_paths" -value "10" -objects $obj
+
+}
+# Create 'impl_1_route_report_incremental_reuse_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_route_report_clock_utilization_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0]
+if { $obj != "" } {
+
+}
+# Create 'impl_1_route_report_bus_skew_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } {
+ create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0]
+if { $obj != "" } {
+set_property -name "options.warn_on_violation" -value "1" -objects $obj
+
+}
+# Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } {
+ create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0]
+if { $obj != "" } {
+set_property -name "options.max_paths" -value "10" -objects $obj
+set_property -name "options.warn_on_violation" -value "1" -objects $obj
+
+}
+# Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found)
+if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } {
+ create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1
+}
+set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0]
+if { $obj != "" } {
+set_property -name "options.warn_on_violation" -value "1" -objects $obj
+
+}
+set obj [get_runs impl_1]
+set_property -name "needs_refresh" -value "1" -objects $obj
+set_property -name "strategy" -value "Performance_RefinePlacement" -objects $obj
+set_property -name "steps.place_design.args.directive" -value "ExtraPostPlacementOpt" -objects $obj
+set_property -name "steps.phys_opt_design.args.directive" -value "Explore" -objects $obj
+set_property -name "steps.route_design.args.directive" -value "Explore" -objects $obj
+set_property -name "steps.write_bitstream.args.bin_file" -value "1" -objects $obj
+set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj
+set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj
+
+# set the current impl run
+current_run -implementation [get_runs impl_1]
+
+puts "INFO: Project created:${_xil_proj_name_}"
+# Create 'drc_1' gadget (if not found)
+if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} {
+create_dashboard_gadget -name {drc_1} -type drc
+}
+set obj [get_dashboard_gadgets [ list "drc_1" ] ]
+set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj
+
+# Create 'methodology_1' gadget (if not found)
+if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} {
+create_dashboard_gadget -name {methodology_1} -type methodology
+}
+set obj [get_dashboard_gadgets [ list "methodology_1" ] ]
+set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj
+
+# Create 'power_1' gadget (if not found)
+if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} {
+create_dashboard_gadget -name {power_1} -type power
+}
+set obj [get_dashboard_gadgets [ list "power_1" ] ]
+set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj
+
+# Create 'timing_1' gadget (if not found)
+if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} {
+create_dashboard_gadget -name {timing_1} -type timing
+}
+set obj [get_dashboard_gadgets [ list "timing_1" ] ]
+set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj
+
+# Create 'utilization_1' gadget (if not found)
+if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} {
+create_dashboard_gadget -name {utilization_1} -type utilization
+}
+set obj [get_dashboard_gadgets [ list "utilization_1" ] ]
+set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj
+set_property -name "run.step" -value "synth_design" -objects $obj
+set_property -name "run.type" -value "synthesis" -objects $obj
+
+# Create 'utilization_2' gadget (if not found)
+if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} {
+create_dashboard_gadget -name {utilization_2} -type utilization
+}
+set obj [get_dashboard_gadgets [ list "utilization_2" ] ]
+set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj
+
+move_dashboard_gadget -name {utilization_1} -row 0 -col 0
+move_dashboard_gadget -name {power_1} -row 1 -col 0
+move_dashboard_gadget -name {drc_1} -row 2 -col 0
+move_dashboard_gadget -name {timing_1} -row 0 -col 1
+move_dashboard_gadget -name {utilization_2} -row 1 -col 1
+move_dashboard_gadget -name {methodology_1} -row 2 -col 1
diff --git a/rtl/src/bram_tdp.v b/rtl/src/bram_tdp.v
new file mode 100644
index 0000000..9537b9c
--- /dev/null
+++ b/rtl/src/bram_tdp.v
@@ -0,0 +1,46 @@
+`timescale 1ns / 1ps
+// taken from https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/
+// modified for one read/write-port and one read-only-port,
+/// A parameterized, inferable, true dual-port, dual-clock block RAM in Verilog.
+
+module bram_tdp #(
+ parameter DATA = 72,
+ parameter ADDR = 10
+) (
+ // Port A
+ input wire a_clk,
+ input wire a_rd,
+ input wire a_wr,
+ input wire [ADDR-1:0] a_addr,
+ input wire [DATA-1:0] a_din,
+ output reg [DATA-1:0] a_dout,
+ // Port B
+ input wire b_clk,
+ input wire [ADDR-1:0] b_addr,
+ output reg [DATA-1:0] b_dout,
+ input wire b_rd
+);
+
+// Shared memory
+ reg [DATA-1:0] mem [(2**ADDR)-1:0];
+
+ wire a_en = a_rd || a_wr;
+
+// Port A
+always @(posedge a_clk) begin
+ if(a_en)
+ begin
+ if(a_wr)
+ mem[a_addr] <= a_din;
+ else if(a_rd)
+ a_dout <= mem[a_addr];
+ end
+end
+
+// Port B
+always @(posedge b_clk) begin
+ if(b_rd)
+ b_dout <= mem[b_addr];
+end
+
+endmodule
diff --git a/rtl/src/cpuclk.v b/rtl/src/cpuclk.v
new file mode 100644
index 0000000..613d85e
--- /dev/null
+++ b/rtl/src/cpuclk.v
@@ -0,0 +1,83 @@
+`timescale 1ns / 1ps
+
+module cpu_clkgen(
+ input wire rst,
+ input wire clk100,
+ output wire cpuclk,
+ output wire dram_refclk,
+ output wire pixclk,
+ output wire locked
+ );
+
+ wire cpuclk_pre, clk_fb, refclk_pre, pixclk_pre;
+
+ MMCME2_BASE #(
+ .BANDWIDTH("OPTIMIZED"), // Jitter programming (OPTIMIZED, HIGH, LOW)
+ .CLKFBOUT_MULT_F(10.0), // Multiply value for all CLKOUT (2.000-64.000).
+ .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB (-360.000-360.000).
+ .CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
+ // CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128)
+ .CLKOUT0_DIVIDE_F(12.0), // Divide amount for CLKOUT0 (1.000-128.000).
+ .CLKOUT1_DIVIDE(5),
+ .CLKOUT2_DIVIDE(40), // 40 = 25MHz pixel clock (should be 25.175MHz per spec) for 640x480
+ //.CLKOUT2_DIVIDE(25), // 25 = 40MHz pixel clock for 800x600
+ //.CLKOUT2_DIVIDE(15), // 15 = 66.66MHz pixel clock (should be 65.0Mhz per spec) for 1024x768
+ .CLKOUT3_DIVIDE(1),
+ .CLKOUT4_DIVIDE(1),
+ .CLKOUT5_DIVIDE(1),
+ .CLKOUT6_DIVIDE(1),
+ // CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99).
+ .CLKOUT0_DUTY_CYCLE(0.5),
+ .CLKOUT1_DUTY_CYCLE(0.5),
+ .CLKOUT2_DUTY_CYCLE(0.5),
+ .CLKOUT3_DUTY_CYCLE(0.5),
+ .CLKOUT4_DUTY_CYCLE(0.5),
+ .CLKOUT5_DUTY_CYCLE(0.5),
+ .CLKOUT6_DUTY_CYCLE(0.5),
+ // CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
+ .CLKOUT0_PHASE(0.0),
+ .CLKOUT1_PHASE(0.0),
+ .CLKOUT2_PHASE(0.0),
+ .CLKOUT3_PHASE(0.0),
+ .CLKOUT4_PHASE(0.0),
+ .CLKOUT5_PHASE(0.0),
+ .CLKOUT6_PHASE(0.0),
+ .CLKOUT4_CASCADE("FALSE"), // Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
+ .DIVCLK_DIVIDE(1), // Master division value (1-106)
+ .REF_JITTER1(0.010), // Reference input jitter in UI (0.000-0.999).
+ .STARTUP_WAIT("FALSE") // Delays DONE until MMCM is locked (FALSE, TRUE)
+ )
+
+ MMCME2_BASE_inst (
+ /* verilator lint_off PINCONNECTEMPTY */
+ // Clock Outputs: 1-bit (each) output: User configurable clock outputs
+ .CLKOUT0(cpuclk_pre), // 1-bit output: CLKOUT0
+ .CLKOUT0B(), // 1-bit output: Inverted CLKOUT0
+ .CLKOUT1(refclk_pre), // 1-bit output: CLKOUT1
+ .CLKOUT1B(), // 1-bit output: Inverted CLKOUT1
+ .CLKOUT2(pixclk_pre), // 1-bit output: CLKOUT2
+ .CLKOUT2B(), // 1-bit output: Inverted CLKOUT2
+ .CLKOUT3(), // 1-bit output: CLKOUT3
+ .CLKOUT3B(), // 1-bit output: Inverted CLKOUT3
+ .CLKOUT4(), // 1-bit output: CLKOUT4
+ .CLKOUT5(), // 1-bit output: CLKOUT5
+ .CLKOUT6(), // 1-bit output: CLKOUT6
+ // Feedback Clocks: 1-bit (each) output: Clock feedback ports
+ .CLKFBOUT(clk_fb), // 1-bit output: Feedback clock
+ .CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT
+ // Status Ports: 1-bit (each) output: MMCM status ports
+ .LOCKED(locked), // 1-bit output: LOCK
+ // Clock Inputs: 1-bit (each) input: Clock input
+ .CLKIN1(clk100), // 1-bit input: Clock
+ // Control Ports: 1-bit (each) input: MMCM control ports
+ .PWRDWN(), // 1-bit input: Power-down
+ /* verilator lint_on PINCONNECTEMPTY */
+ .RST(rst), // 1-bit input: Reset
+ // Feedback Clocks: 1-bit (each) input: Clock feedback ports
+ .CLKFBIN(clk_fb) // 1-bit input: Feedback clock
+ );
+
+ BUFG bufg_cpuclk(.I(cpuclk_pre), .O(cpuclk));
+ BUFG bufg_refclk(.I(refclk_pre), .O(dram_refclk));
+ BUFG bufg_pixclk(.I(pixclk_pre), .O(pixclk));
+endmodule
diff --git a/rtl/src/display_clock.v b/rtl/src/display_clock.v
new file mode 100644
index 0000000..898ef7a
--- /dev/null
+++ b/rtl/src/display_clock.v
@@ -0,0 +1,96 @@
+`timescale 1ns / 1ps
+`default_nettype none
+
+// Project F: Display Clocks
+// (C)2019 Will Green, Open source hardware released under the MIT License
+// Learn more at https://projectf.io
+
+// Defaults to 25.2 and 126 MHz for 640x480 at 60 Hz
+
+module display_clock #(
+ MULT_MASTER=31.5, // master clock multiplier (2.000-64.000)
+ DIV_MASTER=5, // master clock divider (1-106)
+ DIV_5X=5.0, // 5x clock divider (1-128)
+ DIV_1X=25, // 1x clock divider (1-128)
+ IN_PERIOD=10.0 // period of i_clk in ns (100 MHz = 10.0 ns)
+ )
+ (
+ input wire i_clk, // input clock
+ input wire i_rst, // reset (active high)
+ output wire o_clk_1x, // pixel clock
+ output wire o_clk_5x, // 5x clock for 10:1 DDR SerDes
+ output wire o_locked // clock locked? (active high)
+ );
+
+ wire clk_fb; // internal clock feedback
+ wire clk_1x_pre;
+ wire clk_5x_pre;
+
+ MMCME2_BASE #(
+ .BANDWIDTH("OPTIMIZED"), // Jitter programming (OPTIMIZED, HIGH, LOW)
+ .CLKFBOUT_MULT_F(MULT_MASTER), // Multiply value for all CLKOUT (2.000-64.000).
+ .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB (-360.000-360.000).
+ .CLKIN1_PERIOD(IN_PERIOD), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz).
+ // CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128)
+ .CLKOUT0_DIVIDE_F(DIV_5X), // Divide amount for CLKOUT0 (1.000-128.000).
+ .CLKOUT1_DIVIDE(DIV_1X),
+ .CLKOUT2_DIVIDE(1),
+ .CLKOUT3_DIVIDE(1),
+ .CLKOUT4_DIVIDE(1),
+ .CLKOUT5_DIVIDE(1),
+ .CLKOUT6_DIVIDE(1),
+ // CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99).
+ .CLKOUT0_DUTY_CYCLE(0.5),
+ .CLKOUT1_DUTY_CYCLE(0.5),
+ .CLKOUT2_DUTY_CYCLE(0.5),
+ .CLKOUT3_DUTY_CYCLE(0.5),
+ .CLKOUT4_DUTY_CYCLE(0.5),
+ .CLKOUT5_DUTY_CYCLE(0.5),
+ .CLKOUT6_DUTY_CYCLE(0.5),
+ // CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
+ .CLKOUT0_PHASE(0.0),
+ .CLKOUT1_PHASE(0.0),
+ .CLKOUT2_PHASE(0.0),
+ .CLKOUT3_PHASE(0.0),
+ .CLKOUT4_PHASE(0.0),
+ .CLKOUT5_PHASE(0.0),
+ .CLKOUT6_PHASE(0.0),
+ .CLKOUT4_CASCADE("FALSE"), // Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE)
+ .DIVCLK_DIVIDE(DIV_MASTER), // Master division value (1-106)
+ .REF_JITTER1(0.010), // Reference input jitter in UI (0.000-0.999).
+ .STARTUP_WAIT("FALSE") // Delays DONE until MMCM is locked (FALSE, TRUE)
+ )
+ MMCME2_BASE_inst (
+ /* verilator lint_off PINCONNECTEMPTY */
+ // Clock Outputs: 1-bit (each) output: User configurable clock outputs
+ .CLKOUT0(clk_5x_pre), // 1-bit output: CLKOUT0
+ .CLKOUT0B(), // 1-bit output: Inverted CLKOUT0
+ .CLKOUT1(clk_1x_pre), // 1-bit output: CLKOUT1
+ .CLKOUT1B(), // 1-bit output: Inverted CLKOUT1
+ .CLKOUT2(), // 1-bit output: CLKOUT2
+ .CLKOUT2B(), // 1-bit output: Inverted CLKOUT2
+ .CLKOUT3(), // 1-bit output: CLKOUT3
+ .CLKOUT3B(), // 1-bit output: Inverted CLKOUT3
+ .CLKOUT4(), // 1-bit output: CLKOUT4
+ .CLKOUT5(), // 1-bit output: CLKOUT5
+ .CLKOUT6(), // 1-bit output: CLKOUT6
+ // Feedback Clocks: 1-bit (each) output: Clock feedback ports
+ .CLKFBOUT(clk_fb), // 1-bit output: Feedback clock
+ .CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT
+ // Status Ports: 1-bit (each) output: MMCM status ports
+ .LOCKED(o_locked), // 1-bit output: LOCK
+ // Clock Inputs: 1-bit (each) input: Clock input
+ .CLKIN1(i_clk), // 1-bit input: Clock
+ // Control Ports: 1-bit (each) input: MMCM control ports
+ .PWRDWN(), // 1-bit input: Power-down
+ /* verilator lint_on PINCONNECTEMPTY */
+ .RST(i_rst), // 1-bit input: Reset
+ // Feedback Clocks: 1-bit (each) input: Clock feedback ports
+ .CLKFBIN(clk_fb) // 1-bit input: Feedback clock
+ );
+
+ // explicitly buffer output clocks
+ BUFG bufg_clk_pix(.I(clk_1x_pre), .O(o_clk_1x));
+ BUFG bufg_clk_pix_5x(.I(clk_5x_pre), .O(o_clk_5x));
+
+endmodule
\ No newline at end of file
diff --git a/rtl/src/dram_bridge.v b/rtl/src/dram_bridge.v
new file mode 100644
index 0000000..102a8cf
--- /dev/null
+++ b/rtl/src/dram_bridge.v
@@ -0,0 +1,165 @@
+`timescale 1ns / 1ps
+
+module dram_bridge #(ADDR_WIDTH = 32, WIDTH = 32)
+(
+ // local bus
+ input wire [ADDR_WIDTH-1:0] mem_addr,
+ output wire [WIDTH-1:0] mem_read_data,
+ input wire [WIDTH-1:0] mem_write_data,
+ input wire mem_read_enable,
+ input wire mem_write_enable,
+ output wire mem_wait,
+
+ input wire rst_n,
+ input wire dram_front_clk,
+ input wire dram_refclk,
+
+ // DDR3 SDRAM
+ inout wire [15:0] ddr3_dq,
+ inout wire [1:0] ddr3_dqs_n,
+ inout wire [1:0] ddr3_dqs_p,
+
+ output wire [13:0] ddr3_addr,
+ output wire [2:0] ddr3_ba,
+ output wire ddr3_ras_n,
+ output wire ddr3_cas_n,
+ output wire ddr3_we_n,
+ output wire ddr3_reset_n,
+ output wire [0:0] ddr3_ck_p,
+ output wire [0:0] ddr3_ck_n,
+ output wire [0:0] ddr3_cke,
+ output wire [0:0] ddr3_cs_n,
+ output wire [1:0] ddr3_dm,
+ output wire [0:0] ddr3_odt
+);
+
+ localparam DRAM_ADDR_WIDTH = 28, DRAM_DATA_WIDTH = 128, DRAM_MASK_WIDTH = 16;
+ wire [DRAM_ADDR_WIDTH-1:0] app_addr;
+ wire [2:0] app_cmd;
+ wire app_en;
+ wire app_rdy;
+ wire [DRAM_DATA_WIDTH-1:0] app_rd_data;
+ wire app_rd_data_end;
+ wire app_rd_data_valid;
+ wire [DRAM_DATA_WIDTH-1:0] app_wdf_data;
+ wire app_wdf_end;
+ wire [DRAM_MASK_WIDTH-1:0] app_wdf_mask;
+ wire app_wdf_rdy;
+ wire app_sr_active;
+ wire app_ref_ack;
+ wire app_zq_ack;
+ wire app_wdf_wren;
+ wire [11:0] device_temp;
+ wire ui_clk, ui_rst_sync;
+ wire init_calib_complete;
+
+ localparam CMD_READ = 3'b1;
+ localparam CMD_WRITE = 3'b0;
+
+ mig_dram_0 dram0(
+ // Inouts
+ .ddr3_dq(ddr3_dq),
+ .ddr3_dqs_n(ddr3_dqs_n),
+ .ddr3_dqs_p(ddr3_dqs_p),
+ // Outputs
+ .ddr3_addr(ddr3_addr),
+ .ddr3_ba(ddr3_ba),
+ .ddr3_ras_n(ddr3_ras_n),
+ .ddr3_cas_n(ddr3_cas_n),
+ .ddr3_we_n(ddr3_we_n),
+ .ddr3_reset_n(ddr3_reset_n),
+ .ddr3_ck_p(ddr3_ck_p),
+ .ddr3_ck_n(ddr3_ck_n),
+ .ddr3_cke(ddr3_cke),
+ .ddr3_cs_n(ddr3_cs_n),
+ .ddr3_dm(ddr3_dm),
+ .ddr3_odt(ddr3_odt),
+// Application interface ports
+ .app_addr (app_addr),
+ .app_cmd (app_cmd),
+ .app_en (app_en),
+ .app_wdf_data (app_wdf_data),
+ .app_wdf_mask (app_wdf_mask),
+ .app_wdf_end (app_wdf_end),
+ .app_wdf_wren (app_wdf_wren),
+ .app_rd_data (app_rd_data),
+ .app_rd_data_end (app_rd_data_end),
+ .app_rd_data_valid (app_rd_data_valid),
+ .app_rdy (app_rdy),
+ .app_wdf_rdy (app_wdf_rdy),
+ .app_sr_req (1'b0),
+ .app_ref_req (1'b0),
+ .app_zq_req (1'b0),
+ .app_sr_active (app_sr_active),
+ .app_ref_ack (app_ref_ack),
+ .app_zq_ack (app_zq_ack),
+ .ui_clk (ui_clk),
+ .ui_clk_sync_rst (ui_rst_sync),
+
+// System Clock Ports
+ .sys_clk_i (dram_front_clk),
+// Reference Clock Ports
+ .clk_ref_i (dram_refclk),
+ .device_temp (device_temp),
+ .init_calib_complete (init_calib_complete),
+ .sys_rst (rst_n)
+ );
+
+// reg [DRAM_DATA_WIDTH-1:0] read_cache;
+// reg [ADDR_WIDTH-1:0] cached_addr;
+// wire cache_hit = cached_addr == mem_addr;
+// wire [DRAM_DATA_WIDTH-1:0] read_data_wrapper = cache_hit ? read_cache : app_rd_data;
+
+ reg [WIDTH-1:0] read_buf;
+ reg read_inprogress = 0;
+
+ assign app_rd_data_end = 1'b1;
+ //assign app_wdf_mask = 16'b1111111111111100;
+
+ // addresses on the memory interface are aligned to 16 bytes
+ // and 28 bits wide (=256MB)
+ assign app_addr = { mem_addr[DRAM_ADDR_WIDTH:4], 4'b0000 };
+ //assign app_addr = { 28'b0 };
+
+ // select a word from the 128 bits transferred by the dram controller
+ // according to the lower bits of the address (ignoring bits 1:0)
+ wire [WIDTH-1:0] read_word;
+ wire [1:0] word_sel = mem_addr[3:2];
+
+ assign read_word = word_sel == 3'b11 ? app_rd_data[31:0] :
+ word_sel == 3'b10 ? app_rd_data[63:32] :
+ word_sel == 3'b01 ? app_rd_data[95:64] :
+ app_rd_data[127:96];
+
+ assign mem_read_data = app_rd_data_valid ? read_word : read_buf;
+
+ // set the write mask according to the lower bits of the address
+ // (ignoring bit 0)
+ assign app_wdf_mask = word_sel == 3'b11 ? 16'b1111111111110000 :
+ word_sel == 3'b10 ? 16'b1111111100001111 :
+ word_sel == 3'b01 ? 16'b1111000011111111 :
+ 16'b0000111111111111 ;
+
+ wire write_ready = mem_write_enable & app_wdf_rdy & app_rdy;
+ assign app_wdf_wren = mem_write_enable & write_ready;
+ assign app_wdf_end = mem_write_enable & write_ready;
+ assign app_wdf_data = { {4{mem_write_data}} };
+
+ assign mem_wait = (mem_read_enable & ~read_inprogress) |
+ (mem_write_enable & (~app_wdf_rdy | ~app_rdy)) |
+ (read_inprogress & ~app_rd_data_valid);
+
+ assign app_en = (mem_read_enable & ~read_inprogress) |
+ (mem_write_enable & write_ready);
+ assign app_cmd = mem_read_enable ? CMD_READ : CMD_WRITE;
+
+ always @(posedge dram_front_clk)
+ begin
+ if(mem_read_enable & ~read_inprogress & app_rdy)
+ read_inprogress <= 1;
+ if(read_inprogress & app_rd_data_valid)
+ read_inprogress <= 0;
+ if(mem_read_enable & app_rd_data_valid)
+ read_buf <= mem_read_data;
+ end
+endmodule
diff --git a/rtl/src/fifo.v b/rtl/src/fifo.v
new file mode 100644
index 0000000..16d9583
--- /dev/null
+++ b/rtl/src/fifo.v
@@ -0,0 +1,53 @@
+`timescale 1ns / 1ps
+
+// a simple fifo
+module fifo #(parameter DATA_WIDTH = 8, ADDR_WIDTH = 4)(
+ input wire clk,
+ input wire reset,
+ input wire wr_en,
+ input wire rd_en,
+ input wire [DATA_WIDTH-1:0] wr_data,
+ output wire [DATA_WIDTH-1:0] rd_data,
+ output wire wr_full,
+ output wire rd_empty
+ );
+
+ reg [DATA_WIDTH-1:0] mem [0:2**ADDR_WIDTH-1];
+ reg [ADDR_WIDTH:0] head_x = 0; // head and tail have one extra bit
+ reg [ADDR_WIDTH:0] tail_x = 0; // for detecting overflows
+ wire [ADDR_WIDTH-1:0] head = head_x[ADDR_WIDTH-1:0];
+ wire [ADDR_WIDTH-1:0] tail = tail_x[ADDR_WIDTH-1:0];
+
+ assign rd_data = mem[tail];
+ // the fifo is full when head and tail pointer are the same
+ // and the extra bits differ (a wraparound occured)
+ assign wr_full = (head == tail) && (head_x[ADDR_WIDTH] != tail_x[ADDR_WIDTH]);
+ // the fifo is empty when head and tail pointer are the same
+ // and the extra bits are the same (no wraparound)
+ assign rd_empty = (head == tail) && (head_x[ADDR_WIDTH] == tail_x[ADDR_WIDTH]);
+
+ // Writing to FIFO
+ always @(posedge clk) begin
+ if (reset)
+ head_x <= 0;
+ else if (wr_en)
+ begin
+ mem[head] <= wr_data;
+ // move head, possible wraparound
+ head_x <= head_x + 1'b1;
+ end
+ end
+
+ // Reading from FIFO
+ always @(posedge clk)
+ begin
+ if (reset)
+ tail_x <= 0;
+ else if (rd_en)
+ begin
+ // rd_data always has current tail data
+ // move tail, possible wraparound
+ tail_x <= tail_x + 1'b1;
+ end
+ end
+endmodule
\ No newline at end of file
diff --git a/rtl/src/fifo_testbench.v b/rtl/src/fifo_testbench.v
new file mode 100644
index 0000000..ccc29ee
--- /dev/null
+++ b/rtl/src/fifo_testbench.v
@@ -0,0 +1,116 @@
+`timescale 1ns / 1ns
+`default_nettype none
+
+module fifo_testbench();
+ // Test signals
+ reg clk = 0;
+ reg reset = 0;
+ reg wr_en = 0;
+ reg rd_en = 0;
+ reg [7:0] wr_data = 0;
+ wire [7:0] rd_data;
+ wire wr_full;
+ wire rd_empty;
+
+ parameter CLOCK_NS = 10;
+
+ // Unit Under Test
+ fifo #(
+ .DATA_WIDTH(8),
+ .ADDR_WIDTH(4)
+ ) UUT (
+ .clk(clk),
+ .reset(reset),
+ .wr_en(wr_en),
+ .rd_en(rd_en),
+ .rd_data(rd_data),
+ .wr_data(wr_data),
+ .wr_full(wr_full),
+ .rd_empty(rd_empty)
+ );
+
+ // testbench clock
+ always
+ #(CLOCK_NS/2) clk <= ~clk;
+
+ initial
+ begin
+ // issue reset
+ reset = 1'b1;
+ #10
+ reset = 1'b0;
+ #10
+
+ // Write two bytes
+ wr_data <= 8'hAB;
+ wr_en <= 1'b1;
+ #10;
+ wr_data <= 8'hCD;
+ wr_en <= 1'b1;
+ #10;
+ wr_en <= 1'b0;
+ #10
+
+ // read fifo tail
+ if (rd_data == 8'hAB)
+ $display("Pass - Byte 1");
+ else
+ $display("Failed - Byte 2");
+
+ // read/remove byte from tail
+ rd_en <= 1'b1;
+ #10
+ // check next byte
+ if (rd_data == 8'hCD)
+ $display("Pass - Byte 2");
+ else
+ $display("Failed - Byte 2");
+
+ // remove 2nd byte
+ rd_en <= 1'b1;
+ #10
+
+ rd_en <= 1'b0;
+ #10
+
+ // Write until full
+ rd_en <= 1'b0;
+ wr_en <= 1'b0;
+
+ for (integer i = 0; i < 16; i = i + 1) begin
+ wr_data <= i;
+ wr_en <= 1'b1;
+ #10;
+ end
+ wr_en <= 1'b0;
+
+ if (wr_full)
+ $display("Pass - Fifo full");
+ else
+ $display("Failed - Fifo full");
+
+
+ // read until empty
+ rd_en <= 1'b0;
+ wr_en <= 1'b0;
+
+ for (integer i = 0; i < 16; i = i + 1) begin
+ rd_en <= 1'b1;
+ #10;
+ end
+ rd_en <= 1'b0;
+
+ if (rd_empty)
+ $display("Pass - Fifo empty");
+ else
+ $display("Failed - Fifo empty");
+ $finish();
+ end
+
+ initial
+ begin
+ // Required to dump signals
+ $dumpfile("fifo_tb_dump.vcd");
+ $dumpvars(0);
+ end
+endmodule
diff --git a/rtl/src/irqctrl.v b/rtl/src/irqctrl.v
new file mode 100644
index 0000000..1a079bf
--- /dev/null
+++ b/rtl/src/irqctrl.v
@@ -0,0 +1,73 @@
+`timescale 1ns / 1ps
+
+module irqctrl #(IRQ_LINES = 2, IRQ_DELAY_WIDTH = 4) (
+ input wire clk,
+ input wire [IRQ_LINES-1:0] irq_in,
+ input wire cs,
+ input wire wr_en,
+ input wire irq_wr_seten,
+ output wire [IRQ_LINES-1:0] rd_data,
+ output wire irq_out
+ );
+
+ reg [IRQ_LINES-1:0] irq_status; // a 1 bit here means we have seen an interrupt on that line
+ reg [IRQ_LINES-1:0] irq_mask; // a bit in irq_status is only set if the corresponding bit in irq_mask is not set
+ // irq_mask is set from irq_status when an interrupt occurs (ie irq_out is set)
+
+ reg irq_enabled; // globally enable/disable irq_out
+ reg [IRQ_DELAY_WIDTH-1:0] irq_delay; // counter to delay irq_out for a few cycles
+ reg irq_delaying; // delay is active
+
+ wire irq_pending = (irq_status != 0);
+
+ assign rd_data = irq_mask;
+ assign irq_out = irq_enabled && irq_pending && !irq_delaying;
+
+ // irq_status and irq_pending flags
+ always @(posedge clk)
+ begin
+ if(irq_out) // when an interrupt is being signaled to the cpu,
+ irq_status <= 0; // clear irq status, status will be copied to irq_mask (see below)
+ else
+ if(irq_in != 0)
+ irq_status <= irq_status | (irq_in & ~irq_mask); // add active irq to irq_status
+ end
+
+ // irq mask
+ always @(posedge clk)
+ begin
+ if (cs && wr_en && irq_wr_seten) // when enabling interrupts, clear mask
+ irq_mask <= 0;
+ else
+ if(irq_out) // when signalling an interrupt, set mask from status
+ irq_mask <= irq_status;
+ end
+
+ // manage irq_enabled and irq_delay/irq_delaying
+ always @(posedge clk)
+ begin
+ if(cs && wr_en) // when writing to control register
+ begin
+ if(irq_wr_seten) // if wr_seten flag is set, enable interrupts and start delay
+ begin
+ irq_enabled <= 1;
+ irq_delaying <= 1;
+ irq_delay <= 1;
+ end
+ else
+ irq_enabled <= 0; // else disable interrupts
+ end
+ else if(irq_out) irq_enabled <= 0; // after sending interrupt to cpu, disable further interrupts
+
+ if(irq_delaying) // the delay gives the CPU a chance to return from an interrupt handler
+ begin // if an interrupt is triggered again right after re-enabling interrupts
+ if(irq_delay==0)
+ begin
+ irq_delay <= 1;
+ irq_delaying <= 0;
+ end
+ else
+ irq_delay <= irq_delay + 1;
+ end
+ end
+ endmodule
diff --git a/rtl/src/mem.v b/rtl/src/mem.v
new file mode 100644
index 0000000..954443a
--- /dev/null
+++ b/rtl/src/mem.v
@@ -0,0 +1,161 @@
+`timescale 1ns / 1ps
+//////////////////////////////////////////////////////////////////////////////////
+// Company:
+// Engineer:
+//
+// Create Date: 05.01.2021 21:53:41
+// Design Name:
+// Module Name: mem
+// Project Name:
+// Target Devices:
+// Tool Versions:
+// Description:
+//
+// Dependencies:
+//
+// Revision:
+// Revision 0.01 - File Created
+// Additional Comments:
+//
+//////////////////////////////////////////////////////////////////////////////////
+
+// 32 bit wide rom with byte addressing (address bits 1-0 are ignored)
+module rom32 #(parameter ADDR_WIDTH = 11, DATA_WIDTH = 32)
+(
+ input wire clk,
+ input wire [ADDR_WIDTH-1:0] addr,
+ output reg [DATA_WIDTH-1:0] data_out,
+ input wire read_enable
+ );
+
+ wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 0
+ reg [DATA_WIDTH-1:0] rom [0:(2**(ADDR_WIDTH-2))-1];
+
+ initial begin
+ $readmemb("C:\\Users\\sebastian\\develop\\fpga\\vdumbcpu\\rom.mem", rom);
+ end
+
+ always @(posedge clk) data_out <= rom[internal_addr];
+
+endmodule
+
+module ram32 #(parameter ADDR_WIDTH = 16, DATA_WIDTH = 32)
+
+(
+ input wire clk,
+ input wire [ADDR_WIDTH-1:0] addr,
+ output reg [DATA_WIDTH-1:0] data_out,
+ input wire read_enable,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire write_enable
+ );
+
+ reg [DATA_WIDTH-1:0] ram [0:(2**(ADDR_WIDTH-2))-1]; // 32bit words with byte addressing
+ wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 1-0
+
+ always @(posedge clk)
+ begin
+ if(read_enable)
+ data_out <= ram[internal_addr];
+ if(write_enable)
+ ram[internal_addr] <= data_in;
+ end
+endmodule
+
+module mem #(parameter ADDR_WIDTH = 32,
+ parameter DATA_WIDTH = 32)
+(
+ input wire clk, rst_n,
+ input wire [ADDR_WIDTH-1:0] addr,
+ output wire [DATA_WIDTH-1:0] data_out,
+ input wire read_enable,
+ input wire [DATA_WIDTH-1:0] data_in,
+ input wire write_enable,
+ output wire io_enable,
+ input wire [DATA_WIDTH-1:0] io_rd_data,
+ output wire mem_wait,
+
+ output wire [ADDR_WIDTH-1:0] dram_addr,
+ input wire [DATA_WIDTH-1:0] dram_read_data,
+ output wire [DATA_WIDTH-1:0] dram_write_data,
+ output wire dram_read_enable,
+ output wire dram_write_enable,
+ input wire dram_wait
+ );
+
+ wire [DATA_WIDTH-1:0] ram_out, rom_out, dram_out;
+
+ // address map:
+ // ROM $0000 - $07FF 2K
+ // IO $0800 - $0FFF 2K
+ // RAM1 $1000 - $FFFF 60K
+ // RAM2 $10000 - $FFFFFFFF ~4GB
+
+ wire ram_cs = addr[ADDR_WIDTH-1:12] != { {(ADDR_WIDTH-12){1'b0}}};
+ wire ram1_cs = ram_cs && (addr[ADDR_WIDTH-1:16] == { {(ADDR_WIDTH-16){1'b0}}});
+ wire ram2_cs = ram_cs && !ram1_cs;
+ wire rom_cs = !ram_cs && addr[11] == 1'b0;
+ wire io_cs = !ram_cs && addr[11] == 1'b1;
+
+ assign io_enable = io_cs;
+
+ wire ram_read = ram1_cs && read_enable;
+ wire ram_write = ram1_cs && write_enable;
+ wire rom_read = rom_cs && read_enable;
+
+ reg [DATA_WIDTH-1:0] data_buf;
+
+ localparam SEL_RAM1 = 0;
+ localparam SEL_RAM2 = 1;
+ localparam SEL_ROM = 2;
+ localparam SEL_IO = 3;
+ localparam SEL_ERR = 4;
+
+ reg [1:0] out_sel;
+
+ // test
+ reg [1:0] wait_state;
+
+ ram32 #(.ADDR_WIDTH(16)) ram0 // 64KB RAM
+ (
+ .clk(clk),
+ .addr(addr[15:0]),
+ .data_out(ram_out),
+ .read_enable(ram_read),
+ .data_in(data_in),
+ .write_enable(ram_write)
+ );
+
+ rom32 #(.ADDR_WIDTH(11)) rom0 // 2KB ROM
+ (
+ .clk(clk),
+ .addr(addr[10:0]),
+ .data_out(rom_out),
+ .read_enable(rom_read)
+ );
+
+ assign dram_out = dram_read_data;
+ assign dram_addr = addr;
+ assign dram_write_data = data_in;
+ assign dram_read_enable = ram2_cs & read_enable;
+ assign dram_write_enable = ram2_cs & write_enable;
+
+ assign data_out = (out_sel == SEL_RAM1 ) ? ram_out :
+ (out_sel == SEL_RAM2 ) ? dram_out :
+ (out_sel == SEL_ROM ) ? rom_out :
+ (out_sel == SEL_IO ) ? io_rd_data :
+ data_buf;
+
+ assign mem_wait = ram2_cs && dram_wait;
+
+ always @(posedge clk)
+ begin
+ data_buf <= data_out;
+ if(read_enable) out_sel <=
+ ram1_cs ? SEL_RAM1 :
+ ram2_cs ? SEL_RAM2:
+ rom_cs ? SEL_ROM :
+ io_cs ? SEL_IO :
+ SEL_ERR;
+ end
+endmodule
diff --git a/rtl/src/palette.v b/rtl/src/palette.v
new file mode 100644
index 0000000..d076453
--- /dev/null
+++ b/rtl/src/palette.v
@@ -0,0 +1,28 @@
+`timescale 1ns / 1ps
+// taken from https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/
+// modified for one read/write-port and one read-only-port,
+/// A parameterized, inferable, true dual-port, dual-clock block RAM in Verilog.
+
+module palette #(
+ parameter SLOTS_WIDTH = 4, COLOR_WIDTH = 12
+) (
+ input wire wr_clk,
+ input wire rd_clk,
+ input wire wr_en,
+ input wire [SLOTS_WIDTH-1:0] wr_slot,
+ input wire [COLOR_WIDTH-1:0] wr_data,
+ input wire [SLOTS_WIDTH-1:0] rd_slot,
+ output wire [COLOR_WIDTH-1:0] rd_data
+);
+
+// Shared memory
+ reg [COLOR_WIDTH-1:0] colors [(2**SLOTS_WIDTH)-1:0];
+
+ assign rd_data = colors[rd_slot];
+
+ always @(posedge wr_clk) begin
+ if(wr_en) colors[wr_slot] <= wr_data;
+ end
+
+endmodule
+
diff --git a/rtl/src/sdspi.v b/rtl/src/sdspi.v
new file mode 100644
index 0000000..7141288
--- /dev/null
+++ b/rtl/src/sdspi.v
@@ -0,0 +1,372 @@
+`timescale 1ns / 1ps
+
+
+// Every spi_clk_div cpu clock cycles the spi clock line is inverted.
+// So a spi clock cycle is 2*spi_clk_div cpu clock cycles.
+// spi_clk_count counts the cpu cycles from spi_clk_div down to zero.
+// The resulting spi clock frequency is:
+// (cpu clock freq) / ((sclk_count + 1) * 2)
+// So for a 83.33 MHz cpu clock, we get
+// spi_clk_div = 10: 83.333 / 22 = 3.788 MHz
+// spi_clk_div = 124: 83.333 / 250 = 333.33 KHz
+
+
+module sdspi(
+ input wire clk, // bus clock
+ input wire reset,
+
+ input wire[7:0] tx_data, // data to transmit
+ output wire[7:0] rx_data, // data received
+ output wire tx_ready, // ready to write a data byte
+ output wire tx_empty, // transmitter fifo is empty
+ output wire rx_avail, // a byte has been received
+ output wire rx_ovr, // receiver overrun
+ input wire tx_write, // write strobe
+ input wire rx_read, // read strobe (clears rx_ovr)
+
+ output wire card_detect, // true is card is present
+ output wire card_changed, // card_detect signal has changed
+ output wire card_busy, // card is busy (MISO/DO is 0)
+
+ input wire ctrl_write, // set the following flags
+ input wire rx_filter_en, // set to discard received $FF bytes
+ input wire txrx_en, // enable transmitter and receiver
+ input wire spiclk_f_en, // enable spi clock without cs
+ input wire spiclk_div_wr, // set clock divider via tx_data
+
+ // PMOD connections
+ output wire sd_cs_n,
+ output reg sd_mosi,
+ input wire sd_miso,
+ output wire sd_sck,
+ input wire sd_cd
+ );
+
+ localparam CLKPHASE_0A = 2'b00;
+ localparam CLKPHASE_0B = 2'b01;
+ localparam CLKPHASE_1A = 2'b10;
+ localparam CLKPHASE_1B = 2'b11;
+ reg [1:0] clk_phase;
+
+ reg xcvr_on; // if turned off, the rest of the current byte
+ // will still transmitted, and until then "running"
+ // will be 1
+ (* KEEP *)
+ reg running; // transmitting/receiving a byte (maybe a dummy byte)
+
+ (* KEEP *) reg [3:0] xcvr_bitcount; // number of bits left of the current byte
+
+ reg [7:0] tx_shifter;
+ wire tx_fifo_wr_en;
+ reg tx_fifo_rd_en;
+ wire tx_fifo_full;
+ wire tx_fifo_empty;
+ wire [7:0] tx_fifo_out;
+
+ reg [7:0] rx_shifter;
+ reg rx_filter;
+ reg rx_fifo_wr_en;
+ wire rx_fifo_rd_en;
+ wire rx_fifo_full;
+ wire rx_fifo_empty;
+ wire [7:0] rx_fifo_out;
+
+ reg rx_bit_recvd; // this flag signals a received bit
+
+ reg rx_overrun; // byte received when rx fifo is full
+
+ reg c_changed;
+ reg c_cs;
+
+ reg spi_clk; // the spi clock signal
+ reg spi_clk_on; // enable clock, either via init mode or by xcvr_on
+ reg spi_clk_f_on; // init clock mode, i.e. start clock but no tx/rx
+ reg [6:0] spi_clk_count; // counting cpu clock ticks
+ reg [6:0] spi_clk_div; // tick counter for spi clock phases
+ wire spi_clk_count_z = (spi_clk_count == 7'b0);
+ reg hphase_start; // start of a spi clock half-phase
+
+ assign tx_ready = !tx_fifo_full;
+ assign tx_empty = tx_fifo_empty;
+ assign rx_avail = !rx_fifo_empty;
+ assign rx_ovr = rx_overrun;
+ assign rx_data = rx_fifo_out;
+
+ assign card_busy = (sd_miso == 0);
+ assign card_changed = c_changed;
+
+ assign sd_sck = spi_clk;
+ assign sd_cs_n = ~c_cs;
+
+ assign card_detect = sd_cd;
+
+ fifo #(.ADDR_WIDTH(4)) tx_fifo(clk, reset,
+ tx_fifo_wr_en, tx_fifo_rd_en,
+ tx_data, tx_fifo_out,
+ tx_fifo_full,
+ tx_fifo_empty
+ );
+
+ fifo #(.ADDR_WIDTH(8)) rx_fifo(clk, reset,
+ rx_fifo_wr_en, rx_fifo_rd_en,
+ rx_shifter, rx_fifo_out,
+ rx_fifo_full,
+ rx_fifo_empty
+ );
+
+ // spi clock
+ always @(posedge clk)
+ begin
+ if(reset)
+ begin
+ spi_clk <= 1; // CLK is high when inactive
+ spi_clk_on <= 0;
+ spi_clk_count <= 0;
+ end
+ else if(spi_clk_on)
+ begin
+
+ // set spi_clk at start of every half-phase
+ if(hphase_start)
+ case(clk_phase)
+ CLKPHASE_0A: spi_clk <= 1'b0;
+ CLKPHASE_0B: spi_clk <= 1'b0;
+ CLKPHASE_1A: spi_clk <= 1'b1;
+ CLKPHASE_1B: spi_clk <= 1'b1;
+ endcase
+
+ if(spi_clk_count_z)
+ begin
+ spi_clk_count <= spi_clk_div;
+ clk_phase <= clk_phase + 2'b1;
+ end
+ else
+ spi_clk_count <= spi_clk_count - 7'd1;
+ end
+
+ // start the clock if needed
+ if( (spi_clk_on == 0) && (running || spi_clk_f_on))
+ begin
+ spi_clk_on <= 1;
+ spi_clk_count <= spi_clk_div;
+ clk_phase <= CLKPHASE_1A;
+ end
+
+ // turn off the clock if transceiver not running
+ // and the force-clock-on flag is not set
+ if( (spi_clk_on == 1) && (!running && !spi_clk_f_on))
+ begin
+ spi_clk_on <= 0;
+ spi_clk <= 1'b1;
+ end
+ end
+
+ // half-phase-start flag trails spi_clk_count_z by one tick
+ always @(posedge clk)
+ begin
+ if(reset)
+ hphase_start <= 0;
+ else
+ hphase_start <= spi_clk_on && spi_clk_count_z;
+ end
+
+ // handle the force clock enable flag
+ always @(posedge clk)
+ begin
+ if (reset)
+ spi_clk_f_on <= 0;
+ else
+ if (ctrl_write)
+ spi_clk_f_on <= spiclk_f_en;
+ end
+
+ // clock divider
+ always @(posedge clk)
+ begin
+ if (spiclk_div_wr) spi_clk_div <= tx_data[6:0];
+ end
+
+ // card_changed flag
+ always @(posedge clk)
+ begin
+ if(sd_cd)
+ c_changed <= 1;
+ else if(ctrl_write || reset)
+ c_changed <= 0;
+ end
+
+ // cs signal
+ always @(posedge clk)
+ begin
+ if(hphase_start && clk_phase == CLKPHASE_0A || !running)
+ c_cs <= running;
+ end
+
+ // transmitter
+ always @(posedge clk)
+ begin
+ if(reset)
+ begin
+ // ???? we start the bitcount at 1 because we start
+ // at the second clock phase where the bitcount
+ // is decremented and the next byte gets loaded
+ xcvr_bitcount <= 0;
+
+ tx_shifter <= 8'b1;
+ xcvr_on <= 0;
+ sd_mosi <= 1;
+ tx_fifo_rd_en <= 0;
+ end
+ else
+ begin
+ // handle a control write to disable the transceiver
+ if(ctrl_write && !txrx_en && xcvr_on)
+ xcvr_on <= 0;
+ // a byte might still be in transit, so
+ // we do not disable the transceiver
+ // immediately (see "handle running status" below)
+ else
+ // handle control write to enable the transceiver
+ if(ctrl_write && txrx_en && !running)
+ begin
+ xcvr_on <= 1;
+ xcvr_bitcount <= 0;
+ // next clock phase must be 1B when starting the transceiver,
+ // so that the first byte is loaded into the shifter then
+ tx_shifter <= 8'b11111111;
+ // in case the transceiver is enabled, but no data is in the fifo,
+ // initialize the shifter with $FF
+ end
+ else
+ // handle clock phases
+ if (running)
+ begin
+ if(hphase_start)
+ case(clk_phase)
+ // set mosi signal at start of clock pulse
+ CLKPHASE_0A: sd_mosi <= tx_shifter[7];
+ CLKPHASE_0B: ;
+ CLKPHASE_1A: begin // shift at rising clock
+ tx_shifter <= tx_shifter << 1;
+ xcvr_bitcount <= xcvr_bitcount - 1;
+ end
+ CLKPHASE_1B: begin // in the middle of the high clock pulse,
+ // fetch the next byte if there are no bits
+ // left in the shift register
+ if (xcvr_bitcount == 0)
+ begin
+ if(!tx_fifo_empty)
+ begin
+ tx_shifter <= tx_fifo_out;
+ tx_fifo_rd_en <= 1;
+ end
+ else
+ tx_shifter <= 8'b11111111;
+ xcvr_bitcount <= 8;
+ end
+ else
+ tx_fifo_rd_en <= 0;
+ end
+ endcase
+ else
+ tx_fifo_rd_en <= 0;
+ end
+ end
+ end
+
+ // handle data write
+ assign tx_fifo_wr_en = tx_write && !tx_fifo_full;
+
+ // Enable fifo read signal if fifo is not empty.
+ // The data at the fifo tail is always available at
+ // rx_data, the read signal just moves the tail pointer
+ // forward.
+ assign rx_fifo_rd_en = rx_read && !rx_fifo_empty;
+
+ // receiver
+ always @(posedge clk)
+ begin
+ if(reset)
+ begin
+ rx_bit_recvd <= 0;
+ rx_shifter <= 8'b11111111;
+ rx_fifo_wr_en <= 0;
+ rx_filter <= 0;
+ rx_overrun <= 0;
+ end
+ else
+ begin
+ // handle a control write
+ if(ctrl_write)
+ begin
+ rx_filter <= rx_filter_en;
+ rx_overrun <= 0;
+ if(txrx_en && !running)
+ rx_shifter <= 8'b0;
+ end
+
+ if (running && hphase_start)
+ case(clk_phase)
+ CLKPHASE_0A: ;
+ CLKPHASE_0B: ;
+ CLKPHASE_1A: ;
+ CLKPHASE_1B: begin // in the middle of the high clock pulse,
+ // sample MISO and put into shift register
+ // and shift at the same time
+ rx_shifter <= { rx_shifter[6:0],sd_miso};
+ rx_bit_recvd <= 1;
+ end
+ endcase
+
+ if (rx_bit_recvd && !sd_cs_n && clk_phase == CLKPHASE_1B)
+ begin
+ rx_bit_recvd <= 0;
+
+ // if a complete byte was received, bitcount will be
+ // 8 because the transmitter has already loaded the next byte
+ // at this half-phase
+ if (xcvr_bitcount == 8)
+ begin
+ // discard $FF bytes if filter is enabled
+ if(!rx_filter || rx_shifter != 8'b11111111)
+ begin
+ if(rx_fifo_full) // discard received byte if fifo is full
+ rx_overrun <= 1; // and set overrun flag
+ else
+ rx_fifo_wr_en <= 1; // otherwise, enable fifo write strobe,
+ // fifo will take data from rx_shifter
+ end
+
+ // turn off filter if a byte != $FF was received
+ if (rx_filter && rx_shifter != 8'b11111111)
+ rx_filter <= 0;
+ end
+ end
+ else
+ rx_fifo_wr_en <= 0;
+
+ end
+ end
+
+ // handle running status
+ // (especially keep transmitter running when there are still bits left to be
+ // transmitted)
+ always@(posedge clk)
+ begin
+ if (reset)
+ running <= 0;
+ else
+ begin
+ // if we want to turn the transceiver on, set running flag
+ if (!running && xcvr_on)
+ running <= 1;
+
+ // when running and a byte has been transmitted,
+ // check if we should turn the transceiver off
+ if (running && hphase_start && xcvr_bitcount==0)
+ if(clk_phase == CLKPHASE_1B)
+ if (!xcvr_on)
+ running <= 0;
+ end
+ end
+endmodule
diff --git a/rtl/src/sdspi_testbench.v b/rtl/src/sdspi_testbench.v
new file mode 100644
index 0000000..a4113fb
--- /dev/null
+++ b/rtl/src/sdspi_testbench.v
@@ -0,0 +1,199 @@
+`timescale 1ns / 1ns
+`default_nettype none
+
+module sdspi_testbench();
+ parameter CLOCK_NS = 10;
+ integer i,j;
+
+ reg[7:0] rx_testdata[0:3];
+ reg[7:0] read_data;
+
+ // Test signals
+ reg clk = 0;
+ reg reset = 0;
+
+ reg[7:0] tx_data = 0;
+ wire[7:0] rx_data;
+ wire tx_ready;
+ wire tx_empty;
+ wire rx_avail;
+ wire rx_ovr;
+ reg tx_write = 0;
+ reg rx_read = 0;
+
+ wire card_detect;
+ wire card_changed;
+ wire card_busy;
+
+ reg ctrl_write = 0;
+ reg rx_filter_en = 0;
+ reg txrx_en = 0;
+ reg spiclk_f_en = 0;
+ reg spiclk_div_wr = 0;
+
+ // PMOD connections
+ wire sd_cs_n;
+ wire sd_mosi;
+ reg sd_miso = 1;
+ wire sd_sck;
+ reg sd_cd = 1;
+
+ // Unit Under Test
+ sdspi UUT (
+ .clk(clk),
+ .reset(reset),
+ .tx_data(tx_data),
+ .rx_data(rx_data),
+ .tx_ready(tx_ready),
+ .tx_empty(tx_empty),
+ .rx_avail(rx_avail),
+ .rx_ovr(rx_ovr),
+ .tx_write(tx_write),
+ .rx_read(rx_read),
+ .card_detect(card_detect),
+ .card_changed(card_changed),
+ .card_busy(card_busy),
+ .ctrl_write(ctrl_write),
+ .rx_filter_en(rx_filter_en),
+ .txrx_en(txrx_en),
+ .spiclk_f_en(spiclk_f_en),
+ .spiclk_div_wr(spiclk_div_wr),
+ .sd_cs_n(sd_cs_n),
+ .sd_mosi(sd_mosi),
+ .sd_miso(sd_miso),
+ .sd_sck(sd_sck),
+ .sd_cd(sd_cd)
+ );
+
+ // testbench clock
+ always
+ #(CLOCK_NS/2) clk <= ~clk;
+
+ initial
+ begin
+ rx_testdata[0] <= 'hFF;
+ rx_testdata[1] <= 'hFF;
+ rx_testdata[2] <= 'hCA;
+ rx_testdata[3] <= 'hFE;
+
+ // issue reset
+ reset = 1'b1;
+ #10
+ reset = 1'b0;
+ #10
+
+ // set clock divider
+ tx_data <= 3;
+ spiclk_div_wr <= 1'b1;
+ #10
+ spiclk_div_wr <= 1'b0;
+ #10
+
+ // Card initialization phase,
+ // cycle the clock at least 74 times
+ // while cs is off and mosi is high .
+ // we do 32 cycles
+ spiclk_f_en <= 1'b1;
+ ctrl_write <= 1'b1;
+ #10
+ spiclk_f_en <= 1'b0;
+ ctrl_write <= 1'b0;
+ #10
+ for (i=0; i<32*16; i = i + 1)
+ #10;
+ spiclk_f_en <= 1'b0;
+ ctrl_write <= 1'b1;
+ #10
+ ctrl_write <= 1'b0;
+ #10
+ for (i=0; i<32*16; i = i + 1)
+ #10;
+
+ // Write two bytes
+ tx_data <= 8'hAB;
+ tx_write <= 1'b1;
+ #10;
+ tx_data <= 8'hCD;
+ tx_write <= 1'b1;
+ #10;
+ tx_write <= 1'b0;
+ #10
+
+ // start transceiver, enable rx_filter
+ txrx_en <= 1'b1;
+ rx_filter_en <= 1'b1;
+ ctrl_write <= 1'b1;
+ #10
+ txrx_en <= 1'b0;
+ rx_filter_en <= 1'b0;
+ ctrl_write <= 1'b0;
+
+ for (i = 0; i < 2048; i = i + 1)
+ begin
+ if (!sd_cs_n && (i % 16)==15) sd_miso <= rx_testdata[(i/(16*8)) % 4][7 - (i/16 % 8)];
+ #10;
+ end
+ tx_write <= 1'b0;
+ #10
+
+ // read from rx fifo
+ read_data <= rx_data;
+ #10
+ $display("read data 1: %02h", read_data);
+
+
+ // strobe rx_read to go to next byte
+ rx_read <= 1'b1;
+ #10 // one cycle to transfer the data
+ rx_read <= 1'b0;
+ #10 // we need this extra cycle for the fifo tail to move
+
+ read_data <= rx_data;
+ #10
+ $display("read data 2: %02h", read_data);
+
+ // strobe rx_read to go to next byte
+ rx_read <= 1'b1;
+ #10
+ rx_read <= 1'b0;
+ #10 // we need this extra cycle for the fifo tail to move
+
+ read_data <= rx_data;
+ #10
+ $display("read data 3: %02h", read_data);
+
+
+ // set flag to turn transceiver off
+ txrx_en <= 1'b0;
+ ctrl_write <= 1'b1;
+ #10
+ ctrl_write <= 1'b0;
+ #10;
+
+ // wait for the transceiver to actually turn off
+ for (i=0; i<32*16; i = i + 1)
+ #10;
+
+ #10
+ // clear rx fifo
+ for(i=0; i<14; i = i + 1)
+ begin
+ $display("clear fifo data %02h", rx_data);
+ rx_read <= 1'b1;
+ #10
+ rx_read <= 1'b0;
+ #10
+ #10
+ #10; // simulate the four cycles of an instruction
+ end
+
+ $finish();
+ end
+
+ initial
+ begin
+ // Required to dump signals
+ $dumpfile("sdspi_tb_dump.vcd");
+ $dumpvars(0);
+ end
+endmodule
diff --git a/rtl/src/stack.v b/rtl/src/stack.v
new file mode 100644
index 0000000..965c070
--- /dev/null
+++ b/rtl/src/stack.v
@@ -0,0 +1,42 @@
+`timescale 1ns / 1ps
+//////////////////////////////////////////////////////////////////////////////////
+// Company:
+// Engineer:
+//
+// Create Date: 17.01.2021 20:59:29
+// Design Name:
+// Module Name: stack
+// Project Name:
+// Target Devices:
+// Tool Versions:
+// Description:
+//
+// Dependencies:
+//
+// Revision:
+// Revision 0.01 - File Created
+// Additional Comments:
+//
+//////////////////////////////////////////////////////////////////////////////////
+
+
+module stack
+ #(parameter ADDR_WIDTH=4, DATA_WIDTH=16)
+ (
+ input wire clk,
+ input wire [ADDR_WIDTH-1:0] rd_addr,
+ input wire [ADDR_WIDTH-1:0] wr_addr,
+ input wire wr_enable,
+ output wire [DATA_WIDTH-1:0] rd_data,
+ input wire [DATA_WIDTH-1:0] wr_data
+ );
+
+ reg [DATA_WIDTH-1:0] stack[0:2**ADDR_WIDTH-1];
+
+ always @(posedge clk)
+ begin
+ if(wr_enable) stack[wr_addr] <= wr_data;
+ end
+
+ assign rd_data = stack[rd_addr];
+endmodule
diff --git a/rtl/src/stackcpu.v b/rtl/src/stackcpu.v
new file mode 100644
index 0000000..c65ae4e
--- /dev/null
+++ b/rtl/src/stackcpu.v
@@ -0,0 +1,427 @@
+`timescale 1ns / 1ps
+//////////////////////////////////////////////////////////////////////////////////
+
+module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32,
+ WORDSIZE = 4, WORDSIZE_SHIFT = 2) (
+ input wire clk,
+ input wire rst,
+
+ input wire irq,
+
+ output reg [ADDR_WIDTH-1:0] addr,
+ input wire [WIDTH-1:0] data_in,
+ output wire read_enable,
+ output wire [WIDTH-1:0] data_out,
+ output wire write_enable,
+ input wire mem_wait,
+
+ output wire led1,
+ output wire led2,
+ output wire led3,
+
+ output wire [WIDTH-1:0] debug_out1,
+ output wire [WIDTH-1:0] debug_out2,
+ output wire [WIDTH-1:0] debug_out3,
+ output wire [WIDTH-1:0] debug_out4,
+ output wire [WIDTH-1:0] debug_out5,
+ output wire [WIDTH-1:0] debug_out6
+ );
+
+ localparam EVAL_STACK_INDEX_WIDTH = 6;
+
+ wire reset = !rst;
+
+ (* KEEP *) reg [1:0] seq_state;
+ localparam FETCH = 2'b00; localparam DECODE = 2'b01; localparam EXEC = 2'b10; localparam MEM = 2'b11;
+
+ (* KEEP*) reg [WIDTH-1:0] X, nX;
+ wire [WIDTH-1:0] Y;
+ (* KEEP *) reg [WIDTH-1:0] PC, nPC;
+ reg [WIDTH-1:0] RP, nRP;
+ reg [WIDTH-1:0] FP, BP;
+ reg [WIDTH-1:0] IV,IR;
+
+ wire [WIDTH-1:0] pc_next_ins = PC + 2;
+
+ reg [EVAL_STACK_INDEX_WIDTH-1:0] ESP, nESP;
+ reg stack_write;
+
+ reg irq_pending;
+
+ // eval stack
+ stack #(.ADDR_WIDTH(EVAL_STACK_INDEX_WIDTH), .DATA_WIDTH(WIDTH)) estack (
+ .clk(clk),
+ .rd_addr(ESP),
+ .wr_addr(nESP),
+ .wr_enable(stack_write),
+ .rd_data(Y),
+ .wr_data(X)
+ );
+
+ reg [15:0] ins;
+
+ wire [WIDTH-1:0] operand;
+
+ // decoded instructions
+ wire ins_loadrel;
+ wire ins_load;
+ wire ins_loadc;
+ wire ins_store;
+ wire ins_aluop;
+ wire ins_ext;
+ wire ins_xfer;
+ wire ins_branch;
+ wire ins_cbranch;
+
+ // decoded extended instructions
+ wire ins_mem, ins_loadi, ins_storei;
+ wire ins_fpadj;
+ wire ins_reg, ins_loadreg, ins_storereg;
+ wire ins_reg_fp, ins_reg_bp, ins_reg_rp;
+ wire ins_reg_iv, ins_reg_ir;
+ wire ins_reg_esp;
+ wire loadstore_base;
+ wire cbranch_n;
+
+ wire xfer_x2p, xfer_r2p, xfer_p2r;
+ wire [1:0] xfer_rs;
+
+ wire [3:0] aluop;
+ wire [1:0] aluop_sd;
+ wire aluop_x2y, aluop_ext;
+
+ wire cmp_i, cmp_e, cmp_l;
+
+ wire mem_read;
+ wire mem_write;
+
+ wire x_is_zero;
+ // wire [WIDTH-1:0] y_plus_operand = Y + operand;
+
+ wire x_equals_y = X == Y;
+ wire y_lessthan_x = $signed(Y) < $signed(X);
+ wire yx_unsigned_less = Y < X;
+
+ reg [WIDTH-1:0] mem_write_data;
+
+ wire mem_read_enable, mem_write_enable;
+
+ assign read_enable = mem_read_enable;
+ assign data_out = mem_write_data;
+ assign write_enable = mem_write_enable;
+
+ // debug output ------------------------------------------------------------------------------------
+ assign led1 = reset;
+ assign led2 = ins_loadc;
+ assign led3 = ins_branch;
+// assign debug_out1 = { mem_read_enable, mem_write_enable, x_is_zero,
+// ins_branch, ins_aluop, y_lessthan_x, x_equals_y, {7{1'b0}}, seq_state};
+// assign debug_out2 = data_in;
+// assign debug_out3 = nX;
+// assign debug_out4 = nPC;
+// assign debug_out5 = ins;
+// assign debug_out6 = IV;
+ //--------------------------------------------------------------------------------------------------
+
+ // instruction decoding
+ assign ins_branch = (ins[15:13] == 3'b000);
+ assign ins_aluop = (ins[15:13] == 3'b001);
+ assign ins_store = (ins[15:13] == 3'b010);
+ assign ins_xfer = (ins[15:13] == 3'b011);
+ assign ins_load = (ins[15:13] == 3'b100);
+ assign ins_cbranch = (ins[15:13] == 3'b101);
+ assign ins_loadc = (ins[15:13] == 3'b110);
+ assign ins_ext = (ins[15:13] == 3'b111);
+
+ // sub-decode LOAD/STORE
+ assign loadstore_base = ins[0];
+
+ // sub-decode CBRANCH
+ assign cbranch_n = ins[0];
+
+ // sub-decode XFER
+ assign xfer_x2p = ins[0];
+ assign xfer_r2p = ins[7];
+ assign xfer_p2r = ins[6];
+ assign xfer_rs = ins[9:8];
+
+ // sub-decode OP
+ assign aluop = ins[12:9];
+ assign aluop_x2y = ins[6];
+ assign aluop_sd = ins[5:4];
+ assign aluop_ext = ins[7];
+
+ // sub-decode OP.CMP
+ assign cmp_i = ins[2];
+ assign cmp_e = ins[1];
+ assign cmp_l = ins[0];
+
+ assign x_is_zero = X == {WIDTH{1'b0}};
+
+ // decode extended instructions
+ assign ins_reg = (ins_ext && ins[12:10] == 3'b000);
+ assign ins_mem = (ins_ext && ins[12:10] == 3'b001);
+ assign ins_loadi = (ins_mem && ins[9] == 1'b0);
+ assign ins_storei = (ins_mem && ins[9] == 1'b1);
+ assign ins_fpadj = (ins_ext && ins[12:10] == 3'b011);
+ assign ins_loadrel= (ins_ext && ins[12:10] == 3'b101);
+
+ // sub-decode LOADREG/STOREREG
+ assign ins_loadreg = (ins_reg && ins[9] == 1'b0);
+ assign ins_storereg = (ins_reg && ins[9] == 1'b1);
+ assign ins_reg_fp = (ins_reg && ins[3:0] == 4'b0000);
+ assign ins_reg_bp = (ins_reg && ins[3:0] == 4'b0001);
+ assign ins_reg_rp = (ins_reg && ins[3:0] == 4'b0010);
+ assign ins_reg_iv = (ins_reg && ins[3:0] == 4'b0011);
+ assign ins_reg_ir = (ins_reg && ins[3:0] == 4'b0100);
+ assign ins_reg_esp = (ins_reg && ins[3:0] == 4'b0101);
+
+ assign mem_read = ins_loadi || ins_load || ins_loadrel || (ins_xfer && xfer_r2p);
+ assign mem_write = ins_storei || ins_store || (ins_xfer && xfer_p2r);
+
+ assign mem_read_enable = (seq_state == FETCH) || (seq_state == EXEC && mem_read);
+ assign mem_write_enable = (seq_state == MEM && mem_write);
+
+ initial
+ begin
+ PC <= 0; nPC <= 0; seq_state <= MEM;
+ ESP <= -1; nESP <= -1;
+ addr <= 0;
+ FP <= 0; BP <= 0; RP <= 0; nRP <= 0;
+ IV <= 0; IR <= 0;
+ irq_pending <= 0;
+ end
+
+ // instruction sequencer
+ always @(posedge clk)
+ begin
+ if(reset)
+ seq_state <= MEM;
+ else if(mem_wait == 1'b0)
+ case(seq_state)
+ FETCH: seq_state <= DECODE;
+ DECODE: seq_state <= EXEC;
+ EXEC: seq_state <= MEM;
+ MEM: seq_state <= FETCH;
+ default: seq_state <= FETCH;
+ endcase
+ end
+
+ // operand register
+ assign operand =
+ (ins_load || ins_store || ins_branch || ins_cbranch) ?
+ { {(WIDTH-13){ins[12]}}, ins[12:1], 1'b0 }
+ : (ins_loadc) ? { {(WIDTH-13){ins[12]}}, ins[12:0] } // sign extend
+ : (ins_aluop || ins_mem) ?
+ { {(WIDTH-4){1'b0}}, ins[3:0] }
+ : (ins_loadrel) ? { {(WIDTH-10){1'b0}}, ins[9:0] }
+ : (ins_fpadj) ? { {(WIDTH-10){ins[9]}}, ins[9:0] } // sign extend
+ : { {WIDTH{1'b0}} };
+
+ // program counter
+ always @(posedge clk)
+ begin
+ if(reset) nPC <= 0;
+ else
+ case(seq_state)
+ EXEC:
+ if(ins_xfer && xfer_x2p) nPC <= X;
+ else if(ins_branch || (ins_cbranch && (x_is_zero != cbranch_n))) nPC <= PC + operand;
+ else nPC <= pc_next_ins;
+ MEM:
+ if(ins_xfer && xfer_r2p) nPC <= data_in;
+ else if(irq_pending) nPC <= IV;
+ endcase
+ end
+
+ // return stack pointer
+ always @*
+ begin
+ if(seq_state == EXEC || seq_state == DECODE || seq_state == MEM)
+ begin
+ if (ins_xfer) nRP <= RP +
+ ({ {(ADDR_WIDTH-3){xfer_rs[1]}},xfer_rs} << WORDSIZE_SHIFT);
+ // sign extend xfer_rs and multiply by word size
+ else if (ins_storereg && ins_reg_rp) nRP <= X;
+ else nRP <= RP;
+ end
+ else nRP <= nRP;
+ end
+
+ // instruction fetch
+ // depending on bit 1 of the PC, read either the upper or lower half word as an instruction
+ always @* if(seq_state == DECODE) ins <= PC[1] ? data_in[15:0] : data_in[31:16];
+
+ // RAM read/write
+ always @(posedge clk)
+ begin
+ if(reset)
+ begin
+ addr <= 0;
+ mem_write_data <= 0;
+ end
+ else
+ case(seq_state)
+ DECODE:
+ if(ins_load || ins_store) // read from address in BP/FP + offset
+ addr <= operand + ( loadstore_base ? BP: FP);
+ else if (ins_loadi) // read from address in X
+ addr <= X;
+ else if (ins_storei) // write to address in Y
+ addr <= Y;
+ else if (ins_loadrel) // read from address next to current instruction
+ addr <= PC + operand;
+ else if (ins_xfer && xfer_r2p) // read from return stack
+ addr <= RP; // use the current RP
+ else if (ins_xfer && xfer_p2r) // write to return stack
+ addr <= nRP; // use the new RP
+ EXEC:
+ begin
+ if (ins_store)
+ mem_write_data <= X;
+ else if (ins_storei)
+ mem_write_data <= X;
+ else if (ins_xfer && xfer_p2r)
+ mem_write_data <= pc_next_ins;
+ else
+ mem_write_data <= 0;
+ end
+ MEM:
+ if(!mem_wait) // do not change the address if mem_wait is active
+ begin
+ if(ins_xfer && xfer_r2p) addr <= data_in; // on RET take addr for next instruction from the data we just read from mem
+ else addr <= irq_pending ? IV : nPC; // prepare fetch cycle
+ end
+ endcase
+ end
+
+ // X/ToS-Register
+ always @(posedge clk)
+ begin
+ if(reset) nX <= 0;
+ else
+ case(seq_state)
+ // default: nX <= X;
+ FETCH, DECODE:;
+ EXEC:
+ if(ins_loadc) nX <= operand;
+ else if(ins_cbranch || ins_store || ins_storereg || (ins_xfer && xfer_x2p)) nX <= Y;
+ else if(ins_storei) nX <= Y + operand;
+ else if(ins_loadreg && ins_reg_fp) nX <= FP;
+ else if(ins_loadreg && ins_reg_bp) nX <= BP;
+ else if(ins_loadreg && ins_reg_rp) nX <= RP;
+ else if(ins_loadreg && ins_reg_iv) nX <= IV;
+ else if(ins_loadreg && ins_reg_ir) nX <= IR;
+ else if(ins_loadreg && ins_reg_esp) nX <= ESP;
+ else if(ins_aluop)
+ begin
+ case(aluop)
+ 4'b0000: nX = X + Y; // ADD
+ 4'b0001: nX = Y - X; // SUB
+ 4'b0010: nX = ~X; // NOT
+ 4'b0011: nX = X & Y; // AND
+ 4'b0100: nX = X | Y; // OR
+ 4'b0101: nX = X ^ Y; // XOR
+ 4'b0110: nX = // CMP
+ cmp_i ^ ((cmp_e && x_equals_y) || (cmp_l && y_lessthan_x));
+ 4'b0111: nX = Y; // Y
+ 4'b1000: nX = aluop_ext ? X >>> 1 : X >> 1; // SHR
+ 4'b1001: nX = operand[1] ? X << 2 : X << 1; // SHL
+ 4'b1010: nX = X + operand; // INC
+ 4'b1011: nX = X - operand; // DEC
+ 4'b1100: nX = // CMPU
+ cmp_i ^ ((cmp_e && x_equals_y) || (cmp_l && yx_unsigned_less));
+ // 4'b1101: nX = X[7:0] << ((3 - Y[1:0]) << 3); // BPLC
+ 4'b1101: nX = Y[1:0] == 0 ? { X[7:0], 24'b0 } :
+ Y[1:0] == 1 ? { 8'b0, X[7:0], 16'b0 } :
+ Y[1:0] == 2 ? { 16'b0, X[7:0], 8'b0 } :
+ { 24'b0, X[7:0]}; // BPLC
+ 4'b1110: nX = { X[23:16], X[15:8], X[7:0], X[31:24] }; // BROT
+ 4'b1111: nX = { 24'b0, Y[1:0] == 0 ? X[31:24] : Y[1:0] == 1 ? X[23:16] :
+ Y[1:0] == 2 ? X[15: 8] : X[7:0] }; // BSEL
+// 4'b1110: nX = X * Y; // MUL
+// 4'b1111: nX = X / Y; // DIV
+ default: nX = X;
+ endcase
+ end
+ MEM:
+ if (ins_loadi || ins_load || ins_loadrel)
+ nX = data_in;
+ endcase
+ end
+
+ // estack movement
+ wire [EVAL_STACK_INDEX_WIDTH-1:0] delta =
+ ((ins_load || ins_loadc || ins_loadreg || ins_loadrel)) ? 1
+ : ((ins_aluop || ins_loadi || ins_storei || ins_xfer)) ?
+ { {(EVAL_STACK_INDEX_WIDTH-2){aluop_sd[1]}},aluop_sd} // sign extend
+ : ((ins_store || ins_cbranch || ins_xfer || ins_storereg)) ? -1
+ : 0;
+
+
+ always @*
+ begin
+ if(reset)
+ nESP <= 0;
+ else
+ if(seq_state == EXEC)
+ begin
+ nESP = ESP + delta;
+ end
+ end
+
+ always @(posedge clk)
+ begin
+ // when to write (old) X back to stack (new Y)
+ // stack write is a reg so it is 1 in the next cycle i.e. MEM state
+ stack_write <= (seq_state == EXEC &&
+ (ins_load || ins_loadc || ins_loadrel || ins_loadreg
+ || ((ins_loadi || ins_storei || ins_aluop) && aluop_x2y)));
+ end
+
+ // FP register
+ always @(posedge clk)
+ begin
+ if(seq_state == EXEC)
+ begin
+ if(ins_fpadj) FP <= FP + operand;
+ else if(ins_storereg && ins_reg_fp) FP <= X;
+ end
+ end
+
+ // BP register
+ always @(posedge clk) if(seq_state == EXEC && ins_storereg && ins_reg_bp) BP <= X;
+
+ // IV register
+ always @(posedge clk)
+ begin
+ if(reset)
+ IV <= 0;
+ else if(seq_state == EXEC && ins_storereg && ins_reg_iv)
+ IV <= X;
+ end
+
+ // IR register
+ always @(posedge clk)
+ begin
+ if(seq_state == MEM && irq_pending) IR <= nPC; // use nPC as interrupt return addr
+ end
+
+ // process irq
+ always @(posedge clk)
+ begin
+ if(seq_state == MEM && irq_pending && !(ins_xfer & xfer_r2p)) // in FETCH state, clear irq_pending.
+ irq_pending <= 0;
+ else
+ irq_pending <= irq_pending || irq; // else set irq_pending when irq is high
+ end
+
+ // advance CPU state
+ always @ (posedge clk)
+ begin
+ if(reset)
+ { PC, X, ESP, RP } <= { {WIDTH{1'b0}}, {WIDTH{1'b0}}, {WIDTH{1'b0}}, {WIDTH{1'b0}} };
+ else if(seq_state == FETCH)
+ { PC, X, ESP, RP } <= { nPC, nX, nESP, nRP};
+ end
+endmodule
diff --git a/rtl/src/testbench.v b/rtl/src/testbench.v
new file mode 100644
index 0000000..8d26bb4
--- /dev/null
+++ b/rtl/src/testbench.v
@@ -0,0 +1,54 @@
+`timescale 1ns/1ps
+`default_nettype none
+
+module testbench();
+ reg clk;
+ reg rst_n;
+ wire btn0;
+ wire sw0;
+ wire sw1;
+ wire led0;
+ wire led1;
+ wire led2;
+ wire led3;
+ wire uart_txd_in;
+ wire uart_rxd_out;
+
+ wire [15:0] ddr3_dq;
+ wire [1:0] ddr3_dqs_n;
+ wire [1:0] ddr3_dqs_p;
+ wire [13:0] ddr3_addr;
+ wire [2:0] ddr3_ba;
+ wire ddr3_ras_n;
+ wire ddr3_cas_n;
+ wire ddr3_we_n;
+ wire ddr3_reset_n;
+ wire [0:0] ddr3_ck_p;
+ wire [0:0] ddr3_ck_n;
+ wire [0:0] ddr3_cke;
+ wire [0:0] ddr3_cs_n;
+ wire [1:0] ddr3_dm;
+ wire [0:0] ddr3_odt;
+
+ integer t;
+
+ top top0(clk, rst_n, btn0, sw0,sw1, led0, led1, led2, led3, uart_txd_in, uart_rxd_out,
+ ddr3_dq, ddr3_dqs_n, ddr3_dqs_p, ddr3_addr, ddr3_ba, ddr3_ras_n, ddr3_cas_n,
+ ddr3_we_n, ddr3_reset_n, ddr3_ck_p, ddr3_ck_n, ddr3_cke, ddr3_cs_n, ddr3_dm, ddr3_odt);
+
+ initial begin
+ clk = 1;
+ t = 0;
+ rst_n = 0;
+ end
+
+ always #5.0 clk = ~clk;
+
+ always @(posedge clk) begin
+ t <= t + 1;
+ if (t == 2)
+ rst_n = 1;
+ if (t == 400)
+ $finish;
+ end
+endmodule
diff --git a/rtl/src/top.v b/rtl/src/top.v
new file mode 100644
index 0000000..e79d611
--- /dev/null
+++ b/rtl/src/top.v
@@ -0,0 +1,288 @@
+`timescale 1ns / 1ps
+// either define clock as clk (100MHz on Arty)
+// or as clk_1hz for debugging
+
+`define clock cpuclk
+`define clkfreq 83333333
+//`define clock clk
+//`define clkfreq 100000000
+//`define clock clk_1hz
+`define ENABLE_VGAFB
+`define ENABLE_MICROSD
+
+module top(
+ input wire clk,
+ input wire rst,
+ input wire btn0,
+ input wire sw0,
+ input wire sw1,
+ output wire led0,
+ output wire led1,
+ output wire led2,
+ output wire led3,
+ input wire uart_txd_in,
+ output wire uart_rxd_out,
+
+ // DDR3 SDRAM
+ inout wire [15:0] ddr3_dq,
+ inout wire [1:0] ddr3_dqs_n,
+ inout wire [1:0] ddr3_dqs_p,
+
+ output wire [13:0] ddr3_addr,
+ output wire [2:0] ddr3_ba,
+ output wire ddr3_ras_n,
+ output wire ddr3_cas_n,
+ output wire ddr3_we_n,
+ output wire ddr3_reset_n,
+ output wire [0:0] ddr3_ck_p,
+ output wire [0:0] ddr3_ck_n,
+ output wire [0:0] ddr3_cke,
+ output wire [0:0] ddr3_cs_n,
+ output wire [1:0] ddr3_dm,
+ output wire [0:0] ddr3_odt
+
+`ifdef ENABLE_VGAFB
+ ,
+ output wire [3:0] VGA_R,
+ output wire [3:0] VGA_G,
+ output wire [3:0] VGA_B,
+
+ output wire VGA_HS_O,
+ output wire VGA_VS_O
+`endif
+
+`ifdef ENABLE_MICROSD
+ ,
+ output wire sd_cs_n,
+ output wire sd_mosi,
+ input wire sd_miso,
+ output wire sd_sck,
+ input wire sd_cd
+`endif
+);
+
+ reg clk_1hz;
+ reg [31:0] counter;
+
+ localparam ADDR_WIDTH = 32, WIDTH = 32,
+ ROMADDR_WIDTH = 11, IOADDR_WIDTH = 11, IOADDR_SEL = 4;
+
+ wire [ADDR_WIDTH-1:0] mem_addr;
+ wire [WIDTH-1:0] mem_read_data;
+ wire [WIDTH-1:0] mem_write_data;
+ (* KEEP *) wire mem_wait;
+
+ (* KEEP *) wire mem_read_enable;
+ (* KEEP *) wire mem_write_enable;
+ (* KEEP *) wire io_enable;
+ wire [WIDTH-1:0] io_rd_data;
+ wire [IOADDR_SEL-1:0] io_slot = mem_addr[IOADDR_WIDTH-1:IOADDR_WIDTH-IOADDR_SEL];
+
+ wire irq;
+
+ // assign led0 = mem_wait;
+
+ wire [WIDTH-1:0] debug_data1, debug_data2,
+ debug_data3, debug_data4,
+ debug_data5, debug_data6;
+
+ assign led0 = debug_data6[0];
+
+ wire cpuclk, cpuclk_locked;
+ wire dram_refclk200;
+ wire pixclk;
+ cpu_clkgen cpuclk_0(~rst, clk, cpuclk, dram_refclk200, pixclk, cpuclk_locked);
+
+ // DRAM --------------------------------------------------------------------------
+ wire [ADDR_WIDTH-1:0] dram_addr;
+ wire [WIDTH-1:0] dram_read_data, dram_write_data;
+ wire dram_read_enable, dram_write_enable, dram_wait;
+
+ dram_bridge dram_bridge0 (dram_addr,
+ dram_read_data, dram_write_data, dram_read_enable, dram_write_enable, dram_wait,
+ rst, cpuclk, dram_refclk200,
+ ddr3_dq, ddr3_dqs_n, ddr3_dqs_p, ddr3_addr,
+ ddr3_ba, ddr3_ras_n, ddr3_cas_n, ddr3_we_n,
+ ddr3_reset_n, ddr3_ck_p, ddr3_ck_n, ddr3_cke,
+ ddr3_cs_n, ddr3_dm, ddr3_odt);
+
+ mem #(.ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(WIDTH)) mem0(
+ .clk(`clock), .rst_n(rst), .addr(mem_addr),
+ .data_out(mem_read_data), .read_enable(mem_read_enable),
+ .data_in(mem_write_data), .write_enable(mem_write_enable),
+ .io_enable(io_enable),
+ .io_rd_data(io_rd_data),
+ .mem_wait(mem_wait),
+ .dram_addr(dram_addr),
+ .dram_read_data(dram_read_data),
+ .dram_write_data(dram_write_data),
+ .dram_read_enable(dram_read_enable),
+ .dram_write_enable(dram_write_enable),
+ .dram_wait(dram_wait)
+ );
+
+`ifdef ENABLE_VGAFB
+ localparam FB_ADDR_WIDTH = 14;
+ wire [FB_ADDR_WIDTH-1:0] fb_rd_addr;
+ wire [FB_ADDR_WIDTH-1:0] fb_wr_addr;
+ wire [WIDTH-1:0] fb_rd_data;
+ wire [WIDTH-1:0] fb_wr_data;
+ wire fb_rd_en, fb_wr_en;
+
+ wire fb_cs_en = io_enable && (io_slot == 2);
+
+ assign fb_rd_en = fb_cs_en && mem_read_enable;
+ assign fb_wr_en = fb_cs_en && mem_write_enable;
+ assign fb_wr_data = mem_write_data;
+
+ vgafb vgafb0(`clock, pixclk, rst,
+ mem_addr[3:0], fb_rd_data, fb_wr_data,
+ fb_rd_en, fb_wr_en,
+ VGA_HS_O, VGA_VS_O, VGA_R, VGA_G, VGA_B);
+`endif
+
+ // SPI SD card controller -------------------------------------------------------------------
+`ifdef ENABLE_MICROSD
+ wire [7:0] spi_tx_data;
+ (*KEEP*) wire [7:0] spi_rx_data;
+ wire spi_tx_ready; // ready to transmit new data
+ wire spi_tx_empty; // tx fifo is empty
+ wire spi_rx_avail; // a byte has been received
+ wire spi_rx_ovr; // receiver overrun
+ wire spi_tx_write; // write strobe
+ wire spi_rx_read; // read strobe (clears rx_avail)
+
+ wire spi_card_detect; // true is card is present
+ wire spi_card_changed; // card_detect signal has changed
+ wire spi_card_busy; // card is busy (MISO/DO is 0)
+
+ wire spi_ctrl_write; // set the following flags
+ wire spi_rx_filter_en; // set to wait for start bit (1-to-0) when receiving
+ wire spi_txrx_en; // enable transmitter and receiver
+ wire spi_sclk_f_en; // enable spi clock without transceiver
+ wire spi_sclk_div_wr; // set clock divider from tx_data
+
+ wire spi_cs; // cs signal for spi controller
+ wire [WIDTH-1:0] spi_rd_data;
+
+ assign spi_cs = io_enable && (io_slot == 1);
+
+ // spi read data: [ 0,...,0,cd,cc,cb,tr,te,ra,ro,d,d,d,d,d,d,d,d ]
+ // cd = card detect, cc = card changed, cb = card busy,
+ // tr = transmitter ready, te = tx fifo empty,
+ // ra = received byte available, ro = receive overrun, d = received byte
+ assign spi_rd_data =
+ { {WIDTH-15{1'b0}}, spi_card_detect, spi_card_changed, spi_card_busy,
+ spi_tx_ready, spi_tx_empty,
+ spi_rx_avail, spi_rx_ovr, spi_rx_data };
+
+ // spi write data: [ 0,...,0,CW,CF,Cx,Cc,Cd,DR,DW,d,d,d,d,d,d,d,d ]
+ // CW = control write, CF = enable receive filter, Cx = enable transceiver,
+ // Cc = force spi clock on, Cd = write clock divider,
+ // DR = read acknowledge, DW = data write, d = byte to be sent
+ assign spi_ctrl_write = spi_cs && mem_write_enable && mem_write_data[14];
+ assign spi_rx_filter_en = mem_write_data[13];
+ assign spi_txrx_en = mem_write_data[12];
+ assign spi_sclk_f_en = mem_write_data[11];
+ assign spi_sclk_div_wr = spi_cs && mem_write_enable && mem_write_data[10];
+ assign spi_rx_read = mem_write_data[9];
+ assign spi_tx_write = spi_cs && mem_write_enable && mem_write_data[8];
+ assign spi_tx_data = mem_write_data[7:0];
+
+ sdspi sdspi0(.clk(`clock), .reset(~rst),
+ .tx_data(spi_tx_data), .rx_data(spi_rx_data),
+ .tx_ready(spi_tx_ready), .tx_empty(spi_tx_empty),
+ .rx_avail(spi_rx_avail), .rx_ovr(spi_rx_ovr),
+ .tx_write(spi_tx_write), .rx_read(spi_rx_read),
+ .card_detect(spi_card_detect), .card_changed(spi_card_changed), .card_busy(spi_card_busy),
+ // ctrl_write is used with rx_filter_en, txrx_en and spiclk_f_en
+ .ctrl_write(spi_ctrl_write),
+ .rx_filter_en(spi_rx_filter_en), .txrx_en(spi_txrx_en), .spiclk_f_en(spi_sclk_f_en),
+ //
+ .spiclk_div_wr(spi_sclk_div_wr),
+ .sd_cs_n(sd_cs_n),
+ .sd_mosi(sd_mosi), .sd_miso(sd_miso), .sd_sck(sd_sck), .sd_cd(sd_cd));
+`endif
+
+ // UART -----------------------------------------------------------------------
+
+ // uart write data: [ 0, 0, 0, 0, 0, T, C, 0, c, c, c, c, c, c, c, c ]
+ // T = transmit enable, C = receiver clear, c = 8-bit-character
+ // uart read data: [ 0, 0, 0, 0, 0, 0, A, B, c, c, c, c, c, c, c, c ]
+ // A = char available, B = tx busy, c = 8-bit-character
+ wire uart_cs = io_enable && (io_slot == 0);
+ wire uart_tx_en = uart_cs && mem_write_enable && mem_write_data[10];
+ wire uart_rx_clear = uart_cs && mem_write_enable && mem_write_data[9];
+ wire uart_rx_avail;
+ wire uart_rx_busy, uart_tx_busy;
+ wire uart_err;
+ wire [7:0] uart_rx_data;
+ wire [7:0] uart_tx_data;
+ wire [31:0] uart_baud = 32'd115200;
+ wire [WIDTH-1:0] uart_rd_data;
+
+ assign uart_tx_data = mem_write_data[7:0];
+ assign uart_rd_data = { {WIDTH-10{1'b1}}, uart_rx_avail, uart_tx_busy, uart_rx_data };
+
+ reg timer_tick;
+ reg[23:0] tick_count;
+ wire [1:0] irq_in = { timer_tick, uart_rx_avail };
+ wire [1:0] irqc_rd_data0;
+ wire [WIDTH-1:0] irqc_rd_data = { tick_count, 6'b0, irqc_rd_data0 };
+ wire irqc_seten = mem_write_data[7];
+ wire irqc_cs = io_enable && (io_slot == 3);
+
+ assign io_rd_data = (io_slot == 0) ? uart_rd_data :
+ `ifdef ENABLE_MICROSD
+ (io_slot == 1) ? spi_rd_data :
+ `endif
+ `ifdef ENABLE_VGAFB
+ (io_slot == 2) ? fb_rd_data :
+ `endif
+ (io_slot == 3) ? irqc_rd_data:
+
+ -1;
+
+ buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst,
+ uart_baud,
+ uart_txd_in, uart_rxd_out,
+ uart_rx_clear, uart_tx_en,
+ uart_rx_avail, uart_tx_busy,
+ uart_tx_data, uart_rx_data);
+
+ // CPU -----------------------------------------------------------------
+ stackcpu cpu0(.clk(`clock), .rst(rst), .irq(irq),
+ .addr(mem_addr),
+ .data_in(mem_read_data), .read_enable(mem_read_enable),
+ .data_out(mem_write_data), .write_enable(mem_write_enable),
+ .mem_wait(mem_wait),
+ .led1(led1), .led2(led2), .led3(led3),
+ .debug_out1(debug_data1),
+ .debug_out2(debug_data2),
+ .debug_out3(debug_data3),
+ .debug_out4(debug_data4),
+ .debug_out5(debug_data5),
+ .debug_out6(debug_data6));
+
+ // Interrupt Controller
+ irqctrl irqctrl0(`clock, irq_in, irqc_cs, mem_write_enable,
+ irqc_seten, irqc_rd_data0,
+ irq);
+
+ // count clock ticks
+ // generate interrupt every 20nth of a second
+ always @ (posedge `clock)
+ begin
+ counter <= counter + 1;
+ if (counter >= (`clkfreq/20))
+ begin
+ counter <= 0;
+ timer_tick <= 1;
+ tick_count <= tick_count + 1'b1;
+ end
+ else
+ begin
+ timer_tick <= 0;
+ end
+ end
+endmodule
diff --git a/rtl/src/uart.v b/rtl/src/uart.v
new file mode 100644
index 0000000..fec26a3
--- /dev/null
+++ b/rtl/src/uart.v
@@ -0,0 +1,262 @@
+/*
+Copyright (c) 2010-2020, James Bowman
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+* Neither the name of swapforth nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+`default_nettype none
+//`define def_clkfreq 100000000
+`define def_clkfreq 83333333
+
+module baudgen(
+ input wire clk,
+ input wire resetq,
+ input wire [31:0] baud,
+ input wire restart,
+ output wire ser_clk);
+ parameter CLKFREQ = `def_clkfreq;
+
+ wire [38:0] aclkfreq = CLKFREQ;
+ reg [38:0] d;
+ wire [38:0] dInc = d[38] ? ({4'd0, baud}) : (({4'd0, baud}) - aclkfreq);
+ wire [38:0] dN = restart ? 0 : (d + dInc);
+ wire fastclk = ~d[38];
+ assign ser_clk = fastclk;
+
+ always @(negedge resetq or posedge clk)
+ begin
+ if (!resetq) begin
+ d <= 0;
+ end else begin
+ d <= dN;
+ end
+ end
+endmodule
+
+/*
+
+-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+----
+ | | | | | | | | | | | |
+ |start| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |stop1|stop2|
+ | | | | | | | | | | | ? |
+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+ +
+
+*/
+
+module uart(
+ input wire clk, // System clock
+ input wire resetq,
+
+ // Outputs
+ output wire uart_busy, // High means UART is transmitting
+ output reg uart_tx, // UART transmit wire
+ // Inputs
+ input wire [31:0] baud,
+ input wire uart_wr_i, // Raise to transmit byte
+ input wire [7:0] uart_dat_i // 8-bit data
+);
+ parameter CLKFREQ = `def_clkfreq;
+
+ reg [3:0] bitcount;
+ reg [8:0] shifter;
+
+ assign uart_busy = |bitcount;
+ wire sending = |bitcount;
+
+ wire ser_clk;
+
+ wire starting = uart_wr_i & ~uart_busy;
+ baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
+ .clk(clk),
+ .resetq(resetq),
+ .baud(baud),
+ .restart(1'b0),
+ .ser_clk(ser_clk));
+
+ always @(negedge resetq or posedge clk)
+ begin
+ if (!resetq) begin
+ uart_tx <= 1;
+ bitcount <= 0;
+ shifter <= 0;
+ end else begin
+ if (starting) begin
+ shifter <= { uart_dat_i[7:0], 1'b0 };
+ bitcount <= 1 + 8 + 1;
+ end
+
+ if (sending & ser_clk) begin
+ { shifter, uart_tx } <= { 1'b1, shifter };
+ bitcount <= bitcount - 4'd1;
+ end
+ end
+ end
+
+endmodule
+
+module rxuart(
+ input wire clk,
+ input wire resetq,
+ input wire [31:0] baud,
+ input wire uart_rx, // UART recv wire
+ input wire rd, // read strobe
+ output wire valid, // has data
+ output wire [7:0] data); // data
+ parameter CLKFREQ = `def_clkfreq;
+
+ reg [4:0] bitcount;
+ reg [7:0] shifter;
+
+ // On starting edge, wait 3 half-bits then sample, and sample every 2 bits thereafter
+
+ wire idle = &bitcount;
+ wire sample;
+ reg [2:0] hh = 3'b111;
+ wire [2:0] hhN = {hh[1:0], uart_rx};
+ wire startbit = idle & (hhN[2:1] == 2'b10);
+ wire [7:0] shifterN = sample ? {hh[1], shifter[7:1]} : shifter;
+
+ wire ser_clk;
+ baudgen #(.CLKFREQ(CLKFREQ)) _baudgen(
+ .clk(clk),
+ .baud({baud[30:0], 1'b0}),
+ .resetq(resetq),
+ .restart(startbit),
+ .ser_clk(ser_clk));
+
+ assign valid = (bitcount == 18);
+ reg [4:0] bitcountN;
+ always @*
+ if (startbit)
+ bitcountN = 0;
+ else if (!idle & !valid & ser_clk)
+ bitcountN = bitcount + 5'd1;
+ else if (valid & rd)
+ bitcountN = 5'b11111;
+ else
+ bitcountN = bitcount;
+
+ // 3,5,7,9,11,13,15,17
+ assign sample = (bitcount > 2) & bitcount[0] & !valid & ser_clk;
+ assign data = shifter;
+
+ always @(negedge resetq or posedge clk)
+ begin
+ if (!resetq) begin
+ hh <= 3'b111;
+ bitcount <= 5'b11111;
+ shifter <= 0;
+ end else begin
+ hh <= hhN;
+ bitcount <= bitcountN;
+ shifter <= shifterN;
+ end
+ end
+endmodule
+
+module fifo_rxuart(
+ input wire clk,
+ input wire resetq,
+ input wire [31:0] baud,
+ input wire uart_rx, // UART recv wire
+ input wire rd, // read strobe
+ output wire valid, // has data
+ output wire [7:0] data); // data
+ parameter CLKFREQ = `def_clkfreq;
+
+ localparam ADDR_WIDTH = 6;
+ localparam DATA_WIDTH = 8;
+
+ reg fifo_wr_en;
+ (*KEEP*) wire fifo_rd_en, fifo_full, fifo_empty;
+ wire [DATA_WIDTH-1:0] fifo_wr_data, fifo_rd_data;
+ (*KEEP*) wire rx_avail;
+
+ assign valid = !fifo_empty;
+ assign data = fifo_rd_data;
+ assign fifo_rd_en = rd;
+
+ fifo #(.ADDR_WIDTH(ADDR_WIDTH)) rx_fifo(clk, ~resetq,
+ fifo_wr_en, fifo_rd_en,
+ fifo_wr_data, fifo_rd_data,
+ fifo_full,
+ fifo_empty
+ );
+
+ rxuart #(.CLKFREQ(CLKFREQ)) _rx (
+ .clk(clk),
+ .resetq(resetq),
+ .baud(baud),
+ .uart_rx(uart_rx),
+ .rd(fifo_wr_en), // strobe read signal on fifo write
+ .valid(rx_avail),
+ .data(fifo_wr_data));
+
+ always @(posedge clk)
+ begin
+ if (!resetq)
+ fifo_wr_en <= 0;
+ else if(!fifo_wr_en && rx_avail) // ILA shows fifo_wr_en stays 0 ??
+ fifo_wr_en <= 1; // pulse fifo_wr_en for one clock
+ else // rx_avail goes zero one clock later
+ fifo_wr_en <= 0;
+ end
+endmodule
+
+module buart(
+ input wire clk,
+ input wire resetq,
+ input wire [31:0] baud,
+ input wire rx, // recv wire
+ output wire tx, // xmit wire
+ input wire rd, // read strobe
+ input wire wr, // write strobe
+ output wire valid, // has recv data
+ output wire busy, // is transmitting
+ input wire [7:0] tx_data,
+ output wire [7:0] rx_data // data
+);
+ parameter CLKFREQ = `def_clkfreq;
+
+ fifo_rxuart #(.CLKFREQ(CLKFREQ)) _rx (
+ .clk(clk),
+ .resetq(resetq),
+ .baud(baud),
+ .uart_rx(rx),
+ .rd(rd),
+ .valid(valid),
+ .data(rx_data));
+ uart #(.CLKFREQ(CLKFREQ)) _tx (
+ .clk(clk),
+ .resetq(resetq),
+ .baud(baud),
+ .uart_busy(busy),
+ .uart_tx(tx),
+ .uart_wr_i(wr),
+ .uart_dat_i(tx_data));
+endmodule
diff --git a/rtl/src/uart_tb.v b/rtl/src/uart_tb.v
new file mode 100644
index 0000000..7f794a2
--- /dev/null
+++ b/rtl/src/uart_tb.v
@@ -0,0 +1,100 @@
+//////////////////////////////////////////////////////////////////////
+// File Downloaded from http://www.nandland.com
+//////////////////////////////////////////////////////////////////////
+
+// This testbench will exercise both the UART Tx and Rx.
+// It sends out byte 0xAB over the transmitter
+// It then exercises the receive by receiving byte 0x3F
+`timescale 1ns/10ps
+
+module uart_tb ();
+
+ // Testbench uses a 10 MHz clock
+ // Want to interface to 115200 baud UART
+ // 10000000 / 115200 = 87 Clocks Per Bit.
+ parameter c_CLOCK_PERIOD_NS = 100;
+ parameter c_CLKS_PER_BIT = 87;
+ parameter c_BIT_PERIOD = 8600;
+
+ reg r_Clock = 0;
+ reg r_Tx_DV = 0;
+ wire w_Tx_Done;
+ reg [7:0] r_Tx_Byte = 0;
+ reg r_Rx_Serial = 1;
+ wire [7:0] w_Rx_Byte;
+
+
+ // Takes in input byte and serializes it
+ task UART_WRITE_BYTE;
+ input [7:0] i_Data;
+ integer ii;
+ begin
+
+ // Send Start Bit
+ r_Rx_Serial <= 1'b0;
+ #(c_BIT_PERIOD);
+ #1000;
+
+
+ // Send Data Byte
+ for (ii=0; ii<8; ii=ii+1)
+ begin
+ r_Rx_Serial <= i_Data[ii];
+ #(c_BIT_PERIOD);
+ end
+
+ // Send Stop Bit
+ r_Rx_Serial <= 1'b1;
+ #(c_BIT_PERIOD);
+ end
+ endtask // UART_WRITE_BYTE
+
+
+ uart_rx #(.CLKS_PER_BIT(c_CLKS_PER_BIT)) UART_RX_INST
+ (.i_Clock(r_Clock),
+ .i_Rx_Serial(r_Rx_Serial),
+ .o_Rx_DV(),
+ .o_Rx_Byte(w_Rx_Byte)
+ );
+
+ uart_tx #(.CLKS_PER_BIT(c_CLKS_PER_BIT)) UART_TX_INST
+ (.i_Clock(r_Clock),
+ .i_Tx_DV(r_Tx_DV),
+ .i_Tx_Byte(r_Tx_Byte),
+ .o_Tx_Active(),
+ .o_Tx_Serial(),
+ .o_Tx_Done(w_Tx_Done)
+ );
+
+
+ always
+ #(c_CLOCK_PERIOD_NS/2) r_Clock <= !r_Clock;
+
+
+ // Main Testing:
+ initial
+ begin
+
+ // Tell UART to send a command (exercise Tx)
+ @(posedge r_Clock);
+ @(posedge r_Clock);
+ r_Tx_DV <= 1'b1;
+ r_Tx_Byte <= 8'hAB;
+ @(posedge r_Clock);
+ r_Tx_DV <= 1'b0;
+ @(posedge w_Tx_Done);
+
+ // Send a command to the UART (exercise Rx)
+ @(posedge r_Clock);
+ UART_WRITE_BYTE(8'h3F);
+ @(posedge r_Clock);
+
+ // Check that the correct command was received
+ if (w_Rx_Byte == 8'h3F)
+ $display("Test Passed - Correct Byte Received");
+ else
+ $display("Test Failed - Incorrect Byte Received");
+
+ end
+
+endmodule
\ No newline at end of file
diff --git a/rtl/src/vgafb.v b/rtl/src/vgafb.v
new file mode 100644
index 0000000..4e8d668
--- /dev/null
+++ b/rtl/src/vgafb.v
@@ -0,0 +1,292 @@
+`timescale 1ns / 1ps
+`default_nettype none
+
+// Project F: Display Timings
+// (C)2019 Will Green, Open Source Hardware released under the MIT License
+// Learn more at https://projectf.io
+
+//128K video memory is not enough for 640x480x4
+`define RES_640_400
+//`define RES_1024_768
+
+module display_timings #(
+ H_RES=640, // horizontal resolution (pixels)
+ V_RES=480, // vertical resolution (lines)
+ H_FP=16, // horizontal front porch
+ H_SYNC=96, // horizontal sync
+ H_BP=48, // horizontal back porch
+ V_FP=10, // vertical front porch
+ V_SYNC=2, // vertical sync
+ V_BP=33, // vertical back porch
+ H_POL=0, // horizontal sync polarity (0:neg, 1:pos)
+ V_POL=0 // vertical sync polarity (0:neg, 1:pos)
+ )
+ (
+ input wire i_pix_clk, // pixel clock
+ input wire i_rst, // reset: restarts frame (active high)
+ output wire o_hs, // horizontal sync
+ output wire o_vs, // vertical sync
+ output wire o_de, // display enable: high during active video
+ output wire o_frame, // high for one tick at the start of each frame
+ output wire o_scanline, // high for one tick at the start of each scanline
+ output reg o_vblank, // high during vertical blank phase
+ output reg signed [15:0] o_sx, // horizontal beam position (including blanking)
+ output reg signed [15:0] o_sy // vertical beam position (including blanking)
+ );
+
+ // Horizontal: sync, active, and pixels
+ localparam signed H_STA = 0 - H_FP - H_SYNC - H_BP; // horizontal start
+ localparam signed HS_STA = H_STA + H_FP; // sync start
+ localparam signed HS_END = HS_STA + H_SYNC; // sync end
+ localparam signed HA_STA = 0; // active start
+ localparam signed HA_END = H_RES - 1; // active end
+
+ // Vertical: sync, active, and pixels
+ localparam signed V_STA = 0 - V_FP - V_SYNC - V_BP; // vertical start
+ localparam signed VS_STA = V_STA + V_FP; // sync start
+ localparam signed VS_END = VS_STA + V_SYNC; // sync end
+ localparam signed VA_STA = 0; // active start
+ localparam signed VA_END = V_RES - 1; // active end
+
+ // generate sync signals with correct polarity
+ assign o_hs = H_POL ? (o_sx > HS_STA && o_sx <= HS_END)
+ : ~(o_sx > HS_STA && o_sx <= HS_END);
+ assign o_vs = V_POL ? (o_sy > VS_STA && o_sy <= VS_END)
+ : ~(o_sy > VS_STA && o_sy <= VS_END);
+
+ // display enable: high during active period
+ assign o_de = (o_sx >= 0 && o_sy >= 0);
+
+ // o_frame: high for one tick at the start of each frame
+ assign o_frame = (o_sy == V_STA && o_sx == H_STA);
+ // o_scanline: high for one tick at the start of each visible scanline
+ assign o_scanline = (o_sy >= VA_STA) && (o_sy <= VA_END) && (o_sx == H_STA);
+
+ always @(posedge i_pix_clk)
+ begin
+ if(o_frame) o_vblank <= 1;
+ else if (o_de) o_vblank <= 0;
+ end
+
+ always @ (posedge i_pix_clk)
+ begin
+ if (i_rst) // reset to start of frame
+ begin
+ o_sx <= H_STA;
+ o_sy <= V_STA;
+ end
+ else
+ begin
+ if (o_sx == HA_END) // end of line
+ begin
+ o_sx <= H_STA;
+ if (o_sy == VA_END) // end of frame
+ o_sy <= V_STA;
+ else
+ o_sy <= o_sy + 16'sh1;
+ end
+ else
+ o_sx <= o_sx + 16'sh1;
+ end
+ end
+endmodule
+
+// Project F: Display Controller VGA Demo
+// (C)2020 Will Green, Open source hardware released under the MIT License
+// Learn more at https://projectf.io
+
+// This demo requires the following Verilog modules:
+// * display_clocks
+// * display_timings
+// * test_card_simple or another test card
+
+module vgafb #(VMEM_ADDR_WIDTH = 15, VMEM_DATA_WIDTH = 32) (
+ input wire cpu_clk, // cpu clock
+ input wire CLK, // pixel clock
+ input wire RST_BTN, // reset button
+ input wire[3:0] reg_sel, // register select/address
+ output wire [VMEM_DATA_WIDTH-1:0] rd_data,
+ input wire [VMEM_DATA_WIDTH-1:0] wr_data,
+ input wire rd_en,
+ input wire wr_en,
+
+ output wire VGA_HS, // horizontal sync output
+ output wire VGA_VS, // vertical sync output
+ output wire [3:0] VGA_R, // 4-bit VGA red output
+ output wire [3:0] VGA_G, // 4-bit VGA green output
+ output wire [3:0] VGA_B // 4-bit VGA blue output
+ );
+
+ localparam BITS_PER_PIXEL = 4; localparam MAX_SHIFT_COUNT = 7;
+ localparam REG_RD_ADDR = 0; localparam REG_WR_ADDR = 1; localparam REG_VMEM = 2;
+ localparam REG_PAL_SLOT = 3; localparam REG_PAL_DATA = 4;
+ localparam REG_CTL = 5;
+
+ localparam COLOR_WIDTH = 12;
+ localparam PALETTE_WIDTH = 4;
+
+ // Display Clocks
+ wire pix_clk = CLK; // pixel clock
+ wire clk_lock = 1; // clock locked?
+
+ wire vmem_rd_en;
+ wire vmem_wr_en;
+ wire [VMEM_DATA_WIDTH-1:0] vmem_rd_data;
+ reg [VMEM_ADDR_WIDTH-1:0] cpu_rd_addr;
+ reg [VMEM_ADDR_WIDTH-1:0] cpu_wr_addr;
+ reg [VMEM_ADDR_WIDTH-1:0] pix_addr;
+ wire [VMEM_DATA_WIDTH-1:0] pix_data;
+ wire pix_rd;
+ wire [VMEM_DATA_WIDTH-1:0] status;
+
+ assign vmem_rd_en = rd_en;
+ assign vmem_wr_en = (reg_sel == REG_VMEM) && wr_en;
+ assign rd_data = (reg_sel == REG_VMEM) ? vmem_rd_data :
+ (reg_sel == REG_RD_ADDR) ? cpu_rd_addr :
+ (reg_sel == REG_WR_ADDR) ? cpu_wr_addr :
+ (reg_sel == REG_CTL) ? status :
+ 32'hFFFFFFFF;
+
+ wire [VMEM_ADDR_WIDTH-1:0] cpu_addr = vmem_wr_en ? cpu_wr_addr : cpu_rd_addr;
+
+ bram_tdp #(.DATA(VMEM_DATA_WIDTH),.ADDR(VMEM_ADDR_WIDTH)) vram0 (
+ .a_rd(vmem_rd_en), .a_clk(cpu_clk),
+ .a_wr(vmem_wr_en), .a_addr(cpu_addr), .a_din(wr_data),
+ .a_dout(vmem_rd_data),
+ .b_clk(pix_clk), .b_addr(pix_addr), .b_dout(pix_data),
+ .b_rd(pix_rd)
+ );
+
+ wire palette_wr_en = (reg_sel == REG_PAL_DATA) && wr_en;
+ reg [PALETTE_WIDTH-1:0] palette_wr_slot;
+ wire [COLOR_WIDTH-1:0] color_data;
+
+ palette palette0(.wr_clk(cpu_clk), .rd_clk(pix_clk), .wr_en(palette_wr_en),
+ .wr_slot(palette_wr_slot), .wr_data(wr_data[COLOR_WIDTH-1:0]),
+ .rd_slot(pixel[3:0]), .rd_data(color_data));
+
+ // Display Timings
+ wire signed [15:0] sx; // horizontal screen position (signed)
+ wire signed [15:0] sy; // vertical screen position (signed)
+ wire h_sync; // horizontal sync
+ wire v_sync; // vertical sync
+ wire de; // display enable
+ wire frame; // frame start
+ wire scanline; // scanline start
+ wire vblank; // vertical blank
+ reg vblank_buf; // vertical blank in cpu clock domain
+
+ display_timings #( // 640x480 800x600 1280x720 1920x1080
+`ifdef RES_1024_768
+ .H_RES(1024), // 640 800 1280 1920
+ .V_RES(768), // 480 600 720 1080
+ .H_FP(24), // 16 40 110 88
+ .H_SYNC(136), // 96 128 40 44
+ .H_BP(160), // 48 88 220 148
+ .V_FP(3), // 10 1 5 4
+ .V_SYNC(6), // 2 4 5 5
+ .V_BP(29), // 33 23 20 36
+ .H_POL(0), // 0 1 1 1
+ .V_POL(0) // 0 1 1 1
+ `endif
+ `ifdef RES_640_400
+ .H_RES(640),
+ .V_RES(400),
+ .H_FP(16),
+ .H_SYNC(96),
+ .H_BP(48),
+ .V_FP(12),
+ .V_SYNC(2),
+ .V_BP(35),
+ .H_POL(0),
+ .V_POL(1)
+ `endif
+ )
+ display_timings_inst (
+ .i_pix_clk(CLK),
+ .i_rst(!RST_BTN),
+ .o_hs(h_sync),
+ .o_vs(v_sync),
+ .o_de(de),
+ .o_frame(frame),
+ .o_scanline(scanline),
+ .o_vblank(vblank),
+ .o_sx(sx),
+ .o_sy(sy)
+ );
+
+ wire [7:0] red;
+ wire [7:0] green;
+ wire [7:0] blue;
+
+ reg [VMEM_DATA_WIDTH-1:0] shifter;
+ reg [4:0] shift_count;
+
+ // delayed frame signal for pix_rd
+ reg frame_d;
+
+ assign pix_rd = frame_d || scanline || (shift_count == 2);
+
+ assign status = { 4'b0001, {(VMEM_DATA_WIDTH-5){1'b0}}, vblank_buf};
+
+ wire [BITS_PER_PIXEL-1:0] pixel = shifter[VMEM_DATA_WIDTH-1:VMEM_DATA_WIDTH-BITS_PER_PIXEL];
+
+ always @(posedge pix_clk) frame_d <= frame;
+
+ always @(posedge cpu_clk) vblank_buf <= vblank;
+
+ always @(posedge cpu_clk)
+ begin
+ if(wr_en)
+ begin
+ case(reg_sel)
+ REG_RD_ADDR: cpu_rd_addr <= wr_data;
+ REG_WR_ADDR: cpu_wr_addr <= wr_data;
+ REG_VMEM: cpu_wr_addr <= cpu_wr_addr + 1; // auto-increment write addr on write
+ REG_PAL_SLOT: palette_wr_slot <= wr_data[3:0];
+ endcase
+ end
+ else
+ if(rd_en && reg_sel == REG_VMEM) cpu_rd_addr <= cpu_rd_addr + 1; // auto-increment read addr on read
+ end
+
+ always @(posedge pix_clk)
+ begin
+ if(scanline || shift_count == MAX_SHIFT_COUNT) // before start of a line
+ begin // or at the end of a word, reset shifter with pixel data
+ shift_count <= 0;
+ shifter <= pix_data;
+ end
+ else if(de)
+ begin
+ shift_count <= shift_count + 1;
+ shifter <= shifter << BITS_PER_PIXEL;
+ end
+
+ if(frame) // at start of frame, reset pixel pointer
+ pix_addr <= 0;
+ else if(shift_count == 1) // after the first pixel, increment address
+ pix_addr <= pix_addr + 1;
+ end
+
+// Hard-Coded RGBI palette
+// // Pixel = { red, green, blue, intensity }
+// assign red = pixel[3] ? pixel[0] ? 255 : 127: 0;
+// assign green = pixel[2] ? pixel[0] ? 255 : 127: 0;
+// assign blue = pixel[1] ? pixel[0] ? 255 : 127: 0;
+
+// // VGA Output
+// // VGA Pmod is 12-bit so we take the upper nibble of each colour
+// assign VGA_HS = h_sync;
+// assign VGA_VS = v_sync;
+// assign VGA_R = de ? red[7:4] : 4'b0;
+// assign VGA_G = de ? green[7:4] : 4'b0;
+// assign VGA_B = de ? blue[7:4] : 4'b0;
+
+ // 12 bit RGB palette
+ assign VGA_HS = h_sync;
+ assign VGA_VS = v_sync;
+ assign VGA_R = de ? color_data[11:8] : 4'b0;
+ assign VGA_G = de ? color_data[7:4] : 4'b0;
+ assign VGA_B = de ? color_data[3:0] : 4'b0;
+endmodule