From 3ac8fa14fd75ce2a9ad28f668d7a2676e881a40f Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Thu, 28 Nov 2024 15:42:36 +0100 Subject: [PATCH 01/17] adjusting for R6, wip --- .gitignore | 16 +- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 382 +++++++++++++++++++ hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 468 +++++++++++++++++++++++ vhdl/hw/MEGA65/MEGA65_R6.vhd | 512 ++++++++++++++++++++++++++ vhdl/hw/MEGA65/drivers/hyperram.vhdl | 154 +------- vhdl/hw/MEGA65/hyperram_ctl.vhd | 21 +- vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd | 7 +- 7 files changed, 1382 insertions(+), 178 deletions(-) create mode 100644 hw/xilinx/MEGA65-R6/Vivado/mega65.xdc create mode 100644 hw/xilinx/MEGA65-R6/Vivado/mega65.xpr create mode 100644 vhdl/hw/MEGA65/MEGA65_R6.vhd diff --git a/.gitignore b/.gitignore index 46c117d7..2fa008cb 100644 --- a/.gitignore +++ b/.gitignore @@ -21,15 +21,15 @@ hw/xilinx/MEGA65/ISE/iseconfig hw/xilinx/MEGA65/ISE/webtalk_impact.xml hw/xilinx/MEGA65/ISE/mega65.ipf hw/xilinx/MEGA65/ISE/mega65_xdb -hw/xilinx/MEGA65/Vivado/*.jou -hw/xilinx/MEGA65/Vivado/*.str -hw/xilinx/MEGA65/Vivado/*.cache -hw/xilinx/MEGA65/Vivado/*.hw -hw/xilinx/MEGA65/Vivado/*.ip_user_files -hw/xilinx/MEGA65/Vivado/*.runs -hw/xilinx/MEGA65/Vivado/.Xil +hw/xilinx/MEGA65*/Vivado/*.jou +hw/xilinx/MEGA65*/Vivado/*.str +hw/xilinx/MEGA65*/Vivado/*.cache +hw/xilinx/MEGA65*/Vivado/*.hw +hw/xilinx/MEGA65*/Vivado/*.ip_user_files +hw/xilinx/MEGA65*/Vivado/*.runs +hw/xilinx/MEGA65*/Vivado/.Xil +hw/xilinx/MEGA65*/Vivado/MEGA65.sim hw/xilinx/MEGA65 -hw/xilinx/MEGA65/Vivado/MEGA65.sim impact.xsl impact_impact.xwbt assembler/qasm diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc new file mode 100644 index 00000000..a226761e --- /dev/null +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -0,0 +1,382 @@ +## MiSTer2MEGA framework pin mapping +## +## Done by MJoergen and sy2002 in 2023 and licensed under GPL v3 + +################################ +## Pin to signal mapping +################################ + +# Onboard crystal oscillator = 100 MHz +set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {CLK}]; # CLOCK_FPGA_MRCC + +# Reset button on the side of the machine +set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports {RESET_N}]; # RESET + +# USB-RS232 Interface +set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {UART_RXD}]; # DBG_UART_RX +set_property -dict {PACKAGE_PIN L13 IOSTANDARD LVCMOS33} [get_ports {UART_TXD}]; # DBG_UART_TX + +# VGA via VDAC. U3 = ADV7125BCPZ170 +set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {vdac_blank_n_o}]; # VDAC_BLANK_N +set_property -dict {PACKAGE_PIN AA9 IOSTANDARD LVCMOS33} [get_ports {vdac_clk_o}]; # VDAC_CLK +set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports {vdac_psave_n_o}]; # VDAC_PSAVE_N +set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {vdac_sync_n_o}]; # VDAC_SYNC_N +set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[0]}]; # B0 +set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[1]}]; # B1 +set_property -dict {PACKAGE_PIN AB12 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[2]}]; # B2 +set_property -dict {PACKAGE_PIN AA11 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[3]}]; # B3 +set_property -dict {PACKAGE_PIN AB11 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[4]}]; # B4 +set_property -dict {PACKAGE_PIN Y11 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[5]}]; # B5 +set_property -dict {PACKAGE_PIN AB10 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[6]}]; # B6 +set_property -dict {PACKAGE_PIN AA10 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[7]}]; # B7 +set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[0]}]; # G0 +set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[1]}]; # G1 +set_property -dict {PACKAGE_PIN AA15 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[2]}]; # G2 +set_property -dict {PACKAGE_PIN AB15 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[3]}]; # G3 +set_property -dict {PACKAGE_PIN Y13 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[4]}]; # G4 +set_property -dict {PACKAGE_PIN AA14 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[5]}]; # G5 +set_property -dict {PACKAGE_PIN AA13 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[6]}]; # G6 +set_property -dict {PACKAGE_PIN AB13 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[7]}]; # G7 +set_property -dict {PACKAGE_PIN W12 IOSTANDARD LVCMOS33} [get_ports {VGA_HS}]; # HSYNC +set_property -dict {PACKAGE_PIN U15 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[0]}]; # R0 +set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[1]}]; # R1 +set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[2]}]; # R2 +set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[3]}]; # R3 +set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[4]}]; # R4 +set_property -dict {PACKAGE_PIN AB17 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[5]}]; # R5 +set_property -dict {PACKAGE_PIN AA16 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[6]}]; # R6 +set_property -dict {PACKAGE_PIN AB16 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[7]}]; # R7 +set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports {vga_scl_io}]; # VGA_SCL +set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {vga_sda_io}]; # VGA_SDA +set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports {VGA_VS}]; # VSYNC + +# HDMI output. U10 = PTN3363BSMP +# I2C address 0x40. +set_property -dict {PACKAGE_PIN Y1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_n_o}]; # TXC_N +set_property -dict {PACKAGE_PIN W1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_p_o}]; # TXC_P +set_property -dict {PACKAGE_PIN AB1 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[0]}]; # TX0_N +set_property -dict {PACKAGE_PIN AB2 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[1]}]; # TX1_N +set_property -dict {PACKAGE_PIN AB5 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[2]}]; # TX2_N +set_property -dict {PACKAGE_PIN AA1 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[0]}]; # TX0_P +set_property -dict {PACKAGE_PIN AB3 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[1]}]; # TX1_P +set_property -dict {PACKAGE_PIN AA5 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[2]}]; # TX2_P +set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {hdmi_hiz_en_o}]; # HIZ_EN +set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {hdmi_hpd_i}]; # HPD_A +set_property -dict {PACKAGE_PIN AB7 IOSTANDARD LVCMOS33} [get_ports {hdmi_scl_io}]; # SCL_A +set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS33} [get_ports {hdmi_sda_io}]; # SDA_A +set_property -dict {PACKAGE_PIN AB8 IOSTANDARD LVCMOS33} [get_ports {hdmi_ls_oe_n_o}]; # LS_OE + +# MEGA65 Keyboard +set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {kb_io0_o}]; # KB_IO1 +set_property -dict {PACKAGE_PIN A13 IOSTANDARD LVCMOS33} [get_ports {kb_io1_o}]; # KB_IO2 +set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS33} [get_ports {kb_io2_i}]; # KB_IO3 +set_property -dict {PACKAGE_PIN E13 IOSTANDARD LVCMOS33} [get_ports {kb_tck_o}]; # KB_TCK +set_property -dict {PACKAGE_PIN E14 IOSTANDARD LVCMOS33} [get_ports {kb_tdo_i}]; # KB_TDO +set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS33} [get_ports {kb_tms_o}]; # KB_TMS +set_property -dict {PACKAGE_PIN D15 IOSTANDARD LVCMOS33} [get_ports {kb_tdi_o}]; # KB_TDI +set_property -dict {PACKAGE_PIN B13 IOSTANDARD LVCMOS33} [get_ports {kb_jtagen_o}]; # KB_JTAGEN + +# Micro SD Connector (external slot at back of the cover) +set_property -dict {PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {sd_cd_i}]; # SD_CD +set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33} [get_ports {SD_CLK}]; # SD_CLK +set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {SD_MISO}]; # SD_D0 +set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {SD_MOSI}]; # SD_CMD +set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {SD_RESET}]; # SD_D3 +set_property -dict {PACKAGE_PIN H3 IOSTANDARD LVCMOS33} [get_ports {sd_d1_i}]; # SD_D1 +set_property -dict {PACKAGE_PIN J1 IOSTANDARD LVCMOS33} [get_ports {sd_d2_i}]; # SD_D2 + +# SD Connector (this is the slot at the bottom side of the case under the cover) +set_property -dict {PACKAGE_PIN D17 IOSTANDARD LVCMOS33} [get_ports {sd2_cd_i}]; # SD2_CD +set_property -dict {PACKAGE_PIN B17 IOSTANDARD LVCMOS33} [get_ports {sd2_clk_o}]; # SD2_CLK +set_property -dict {PACKAGE_PIN B18 IOSTANDARD LVCMOS33} [get_ports {sd2_miso_i}]; # SD2_D0 +set_property -dict {PACKAGE_PIN B16 IOSTANDARD LVCMOS33} [get_ports {sd2_mosi_o}]; # SD2_CMD +set_property -dict {PACKAGE_PIN B15 IOSTANDARD LVCMOS33} [get_ports {sd2_reset_o}]; # SD2_D3 +set_property -dict {PACKAGE_PIN C17 IOSTANDARD LVCMOS33} [get_ports {sd2_wp_i}]; # SD2_WP +set_property -dict {PACKAGE_PIN C18 IOSTANDARD LVCMOS33} [get_ports {sd2_d1_i}]; # SD2_D1 +set_property -dict {PACKAGE_PIN C19 IOSTANDARD LVCMOS33} [get_ports {sd2_d2_i}]; # SD2_D2 + +# Audio DAC. U37 = AK4432VT +# I2C address: 0x19. +set_property -dict {PACKAGE_PIN D16 IOSTANDARD LVCMOS33} [get_ports {audio_mclk_o}]; # AUDIO_MCLK +set_property -dict {PACKAGE_PIN E19 IOSTANDARD LVCMOS33} [get_ports {audio_bick_o}]; # AUDIO_BCLK +set_property -dict {PACKAGE_PIN E16 IOSTANDARD LVCMOS33} [get_ports {audio_sdti_o}]; # AUDIO_SDATA +set_property -dict {PACKAGE_PIN F19 IOSTANDARD LVCMOS33} [get_ports {audio_lrclk_o}]; # AUDIO_LRCLK +set_property -dict {PACKAGE_PIN F18 IOSTANDARD LVCMOS33} [get_ports {audio_pdn_n_o}]; # nSD_AUDIO +set_property -dict {PACKAGE_PIN F4 IOSTANDARD LVCMOS33} [get_ports {audio_i2cfil_o}]; # AUDIO1 +set_property -dict {PACKAGE_PIN L6 IOSTANDARD LVCMOS33} [get_ports {audio_scl_io}]; # AUDIO2 +set_property -dict {PACKAGE_PIN W9 IOSTANDARD LVCMOS33} [get_ports {audio_sda_io}]; # AUDIO3 + +# Joystick +set_property -dict {PACKAGE_PIN F16 IOSTANDARD LVCMOS33} [get_ports {fa_down_n_i}]; # FA_DOWN +set_property -dict {PACKAGE_PIN E17 IOSTANDARD LVCMOS33} [get_ports {fa_fire_n_i}]; # FA_FIRE +set_property -dict {PACKAGE_PIN F14 IOSTANDARD LVCMOS33} [get_ports {fa_left_n_i}]; # FA_LEFT +set_property -dict {PACKAGE_PIN F13 IOSTANDARD LVCMOS33} [get_ports {fa_right_n_i}]; # FA_RIGHT +set_property -dict {PACKAGE_PIN C14 IOSTANDARD LVCMOS33} [get_ports {fa_up_n_i}]; # FA_UP +set_property -dict {PACKAGE_PIN P17 IOSTANDARD LVCMOS33} [get_ports {fb_down_n_i}]; # FB_DOWN +set_property -dict {PACKAGE_PIN F15 IOSTANDARD LVCMOS33} [get_ports {fb_fire_n_i}]; # FB_FIRE +set_property -dict {PACKAGE_PIN F21 IOSTANDARD LVCMOS33} [get_ports {fb_left_n_i}]; # FB_LEFT +set_property -dict {PACKAGE_PIN C15 IOSTANDARD LVCMOS33} [get_ports {fb_right_n_i}]; # FB_RIGHT +set_property -dict {PACKAGE_PIN W19 IOSTANDARD LVCMOS33} [get_ports {fb_up_n_i}]; # FB_UP + +# Paddles +set_property -dict {PACKAGE_PIN H22 IOSTANDARD LVCMOS33} [get_ports {paddle_drain_o}]; # Pulse-discharge +set_property -dict {PACKAGE_PIN H13 IOSTANDARD LVCMOS33} [get_ports {paddle_i[0]}]; # CP0 +set_property -dict {PACKAGE_PIN G15 IOSTANDARD LVCMOS33} [get_ports {paddle_i[1]}]; # CP1 +set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS33} [get_ports {paddle_i[2]}]; # CP2 +set_property -dict {PACKAGE_PIN J22 IOSTANDARD LVCMOS33} [get_ports {paddle_i[3]}]; # CP3 + +# HyperRAM. U29 = IS66WVH8M8DBLL-100B1LI +set_property -dict {PACKAGE_PIN D22 IOSTANDARD LVCMOS33} [get_ports {hr_clk_p_o}]; # H_CLK +set_property -dict {PACKAGE_PIN C22 IOSTANDARD LVCMOS33} [get_ports {hr_cs0}]; # CS0 +set_property -dict {PACKAGE_PIN A21 IOSTANDARD LVCMOS33} [get_ports {hr_d[0]}]; # DQ0 +set_property -dict {PACKAGE_PIN D21 IOSTANDARD LVCMOS33} [get_ports {hr_d[1]}]; # DQ1 +set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {hr_d[2]}]; # DQ2 +set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {hr_d[3]}]; # DQ3 +set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {hr_d[4]}]; # DQ4 +set_property -dict {PACKAGE_PIN A19 IOSTANDARD LVCMOS33} [get_ports {hr_d[5]}]; # DQ5 +set_property -dict {PACKAGE_PIN E21 IOSTANDARD LVCMOS33} [get_ports {hr_d[6]}]; # DQ6 +set_property -dict {PACKAGE_PIN E22 IOSTANDARD LVCMOS33} [get_ports {hr_d[7]}]; # DQ7 +set_property -dict {PACKAGE_PIN B22 IOSTANDARD LVCMOS33} [get_ports {hr_reset_o}]; # H_RES +set_property -dict {PACKAGE_PIN B21 IOSTANDARD LVCMOS33} [get_ports {hr_rwds_io}]; # RWDS +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_reset_o}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_cs0}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_clk_p_o}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_d_io[*]}]; +set_property -dict {PULLTYPE PULLDOWN SLEW FAST DRIVE 16} [get_ports {hr_rwds_io}]; + +# CBM-488/IEC serial port +set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {iec_atn_n_o}]; # F_SER_ATN +set_property -dict {PACKAGE_PIN AA21 IOSTANDARD LVCMOS33} [get_ports {iec_clk_en_n_o}]; # F_SER_CLK_EN. Active low +set_property -dict {PACKAGE_PIN Y18 IOSTANDARD LVCMOS33} [get_ports {iec_clk_n_i}]; # F_SER_CLK_I +set_property -dict {PACKAGE_PIN Y19 IOSTANDARD LVCMOS33} [get_ports {iec_clk_n_o}]; # F_SER_CLK_O +set_property -dict {PACKAGE_PIN Y21 IOSTANDARD LVCMOS33} [get_ports {iec_data_en_n_o}]; # F_SER_DATA_EN. Active low +set_property -dict {PACKAGE_PIN AB22 IOSTANDARD LVCMOS33} [get_ports {iec_data_n_i}]; # F_SER_DATA_I +set_property -dict {PACKAGE_PIN Y22 IOSTANDARD LVCMOS33} [get_ports {iec_data_n_o}]; # F_SER_DATA_O +set_property -dict {PACKAGE_PIN AB21 IOSTANDARD LVCMOS33} [get_ports {iec_reset_n_o}]; # F_SER_RESET +set_property -dict {PACKAGE_PIN AB20 IOSTANDARD LVCMOS33} [get_ports {iec_srq_en_n_o}]; # F_SER_SRQ_EN. Active low +set_property -dict {PACKAGE_PIN AA18 IOSTANDARD LVCMOS33} [get_ports {iec_srq_n_i}]; # F_SER_SRQ_I +set_property -dict {PACKAGE_PIN U20 IOSTANDARD LVCMOS33} [get_ports {iec_srq_n_o}]; # F_SER_SRQ_O +set_property -dict {PULLUP TRUE} [get_ports {iec_clk_n_i}]; +set_property -dict {PULLUP TRUE} [get_ports {iec_data_n_i}]; + +# C64 Expansion Port (aka Cartridge Port) +set_property -dict {PACKAGE_PIN V17 IOSTANDARD LVCMOS33} [get_ports {cart_phi2_o}]; # F_C64_O2 +set_property -dict {PACKAGE_PIN AA19 IOSTANDARD LVCMOS33} [get_ports {cart_dotclock_o}]; # F_C64_CLOCK +set_property -dict {PACKAGE_PIN P15 IOSTANDARD LVCMOS33} [get_ports {cart_dma_i}]; # F_C64_DMA +set_property -dict {PACKAGE_PIN T20 IOSTANDARD LVCMOS33} [get_ports {cart_reset_oe_n_o}]; # F_C64_RESET_EN +set_property -dict {PACKAGE_PIN N14 IOSTANDARD LVCMOS33} [get_ports {cart_reset_io}]; # F_C64_RESET +set_property -dict {PACKAGE_PIN L15 IOSTANDARD LVCMOS33} [get_ports {cart_game_oe_n_o}]; # F_C64_GAME_EN +set_property -dict {PACKAGE_PIN W22 IOSTANDARD LVCMOS33} [get_ports {cart_game_io}]; #_F_C64_GAME +set_property -dict {PACKAGE_PIN M16 IOSTANDARD LVCMOS33} [get_ports {cart_exrom_oe_n_o}]; # F_C64_EXROM_EN +set_property -dict {PACKAGE_PIN R19 IOSTANDARD LVCMOS33} [get_ports {cart_exrom_io}]; # F_C64_EXROM +set_property -dict {PACKAGE_PIN F20 IOSTANDARD LVCMOS33} [get_ports {cart_nmi_oe_n_o}]; # F_C64_NMI_EN +set_property -dict {PACKAGE_PIN W17 IOSTANDARD LVCMOS33} [get_ports {cart_nmi_io}]; # F_C64_NMI +set_property -dict {PACKAGE_PIN H14 IOSTANDARD LVCMOS33} [get_ports {cart_irq_oe_n_o}]; # F_C64_IRQ_EN +set_property -dict {PACKAGE_PIN P14 IOSTANDARD LVCMOS33} [get_ports {cart_irq_io}]; # F_C64_IRQ +set_property -dict {PACKAGE_PIN G18 IOSTANDARD LVCMOS33} [get_ports {cart_ctrl_en_o}]; # F_CTRL_EN +set_property -dict {PACKAGE_PIN U17 IOSTANDARD LVCMOS33} [get_ports {cart_ctrl_dir_o}]; # F_CTRL_DIR +set_property -dict {PACKAGE_PIN N13 IOSTANDARD LVCMOS33} [get_ports {cart_ba_io}]; # F_C64_BA +set_property -dict {PACKAGE_PIN R18 IOSTANDARD LVCMOS33} [get_ports {cart_rw_io}]; # F_C64_RW +set_property -dict {PACKAGE_PIN N15 IOSTANDARD LVCMOS33} [get_ports {cart_io1_io}]; # F_C64_IO1 +set_property -dict {PACKAGE_PIN AA20 IOSTANDARD LVCMOS33} [get_ports {cart_io2_io}]; # F_C64_IO2 +set_property -dict {PACKAGE_PIN T16 IOSTANDARD LVCMOS33} [get_ports {cart_romh_oe_n_o}]; # F_C64_ROMH_DIR +set_property -dict {PACKAGE_PIN T18 IOSTANDARD LVCMOS33} [get_ports {cart_romh_io}]; # F_C64_ROMH +set_property -dict {PACKAGE_PIN U16 IOSTANDARD LVCMOS33} [get_ports {cart_roml_oe_n_o}]; # F_C64_ROML_DIR +set_property -dict {PACKAGE_PIN AB18 IOSTANDARD LVCMOS33} [get_ports {cart_roml_io}]; # F_C64_ROML +set_property -dict {PACKAGE_PIN T21 IOSTANDARD LVCMOS33} [get_ports {cart_en_o}]; # EXP_SLOT_EN +set_property -dict {PACKAGE_PIN L19 IOSTANDARD LVCMOS33} [get_ports {cart_addr_en_o}]; # F_ADDR_EN +set_property -dict {PACKAGE_PIN L18 IOSTANDARD LVCMOS33} [get_ports {cart_haddr_dir_o}]; # F_HADDR_DIR +set_property -dict {PACKAGE_PIN L21 IOSTANDARD LVCMOS33} [get_ports {cart_laddr_dir_o}]; # F_LADDR_DIR +set_property -dict {PACKAGE_PIN K19 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[0]}]; # F_C64_A0 +set_property -dict {PACKAGE_PIN K18 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[1]}]; # F_C64_A1 +set_property -dict {PACKAGE_PIN K21 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[2]}]; # F_C64_A2 +set_property -dict {PACKAGE_PIN M22 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[3]}]; # F_C64_A3 +set_property -dict {PACKAGE_PIN L20 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[4]}]; # F_C64_A4 +set_property -dict {PACKAGE_PIN J20 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[5]}]; # F_C64_A5 +set_property -dict {PACKAGE_PIN J21 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[6]}]; # F_C64_A6 +set_property -dict {PACKAGE_PIN K22 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[7]}]; # F_C64_A7 +set_property -dict {PACKAGE_PIN H17 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[8]}]; # F_C64_A8 +set_property -dict {PACKAGE_PIN H20 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[9]}]; # F_C64_A9 +set_property -dict {PACKAGE_PIN G20 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[10]}]; # F_C64_A10 +set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[11]}]; # F_C64_A11 +set_property -dict {PACKAGE_PIN H19 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[12]}]; # F_C64_A12 +set_property -dict {PACKAGE_PIN M20 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[13]}]; # F_C64_A13 +set_property -dict {PACKAGE_PIN N22 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[14]}]; # F_C64_A14 +set_property -dict {PACKAGE_PIN H18 IOSTANDARD LVCMOS33} [get_ports {cart_a_io[15]}]; # F_C64_A15 +set_property -dict {PACKAGE_PIN U21 IOSTANDARD LVCMOS33} [get_ports {cart_data_en_o}]; # F_DATA_EN +set_property -dict {PACKAGE_PIN V22 IOSTANDARD LVCMOS33} [get_ports {cart_data_dir_o}]; # F_DATA_DIR +set_property -dict {PACKAGE_PIN P16 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[0]}]; # F_C64_D0 +set_property -dict {PACKAGE_PIN R17 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[1]}]; # F_C64_D1 +set_property -dict {PACKAGE_PIN P20 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[2]}]; # F_C64_D2 +set_property -dict {PACKAGE_PIN R16 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[3]}]; # F_C64_D3 +set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[4]}]; # F_C64_D4 +set_property -dict {PACKAGE_PIN V18 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[5]}]; # F_C64_D5 +set_property -dict {PACKAGE_PIN W20 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[6]}]; # F_C64_D6 +set_property -dict {PACKAGE_PIN W21 IOSTANDARD LVCMOS33} [get_ports {cart_d_io[7]}]; # F_C64_D7 + +# I2C bus +# U32 = PCA9655EMTTXG. Address 0x40. I/O expander. +# U12 = MP8869SGL-Z. Address 0x61. DC/DC Converter. +# U14 = MP8869SGL-Z. Address 0x67. DC/DC Converter. +set_property -dict {PACKAGE_PIN N18 IOSTANDARD LVCMOS33} [get_ports {i2c_scl_io}]; # I2C_SCL +set_property -dict {PACKAGE_PIN P19 IOSTANDARD LVCMOS33} [get_ports {i2c_sda_io}]; # I2C_SDA + +# Debug. Also used to control output to joystick ?? +set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS33} [get_ports {fa_fire_n_o}]; # DBG0 = FA_FIRE_O +set_property -dict {PACKAGE_PIN G16 IOSTANDARD LVCMOS33} [get_ports {fa_up_n_o}]; # DBG1 = FA_UP_O +set_property -dict {PACKAGE_PIN K13 IOSTANDARD LVCMOS33} [get_ports {fa_left_n_o}]; # DBG2 = FA_LEFT_O +set_property -dict {PACKAGE_PIN K14 IOSTANDARD LVCMOS33} [get_ports {fa_down_n_o}]; # DBG3 = FA_DOWN_O +set_property -dict {PACKAGE_PIN N20 IOSTANDARD LVCMOS33} [get_ports {fb_up_n_o}]; # DBG4 = FB_UP_O +set_property -dict {PACKAGE_PIN L16 IOSTANDARD LVCMOS33} [get_ports {fa_right_n_o}]; # DBG5 = FA_RIGHT_O +set_property -dict {PACKAGE_PIN M18 IOSTANDARD LVCMOS33} [get_ports {fb_down_n_o}]; # DBG6 = FB_DOWN_O +set_property -dict {PACKAGE_PIN N19 IOSTANDARD LVCMOS33} [get_ports {fb_fire_n_o}]; # DBG7 = FB_FIRE_O +set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports {fb_right_n_o}]; # DBG8 = FB_RIGHT_O +set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {fb_left_n_o}]; # DBG9 = FB_LEFT_O +set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports {dbg_11_io}]; # DBG11 + +# SMSC Ethernet PHY. U4 = KSZ8081RNDCA +set_property -dict {PACKAGE_PIN L4 IOSTANDARD LVCMOS33} [get_ports {eth_clock_o}]; # ETH_CLK +set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {eth_led2_o}]; # ETH_LED2 +set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports {eth_mdc_o}]; # ETH_MDC +set_property -dict {PACKAGE_PIN L5 IOSTANDARD LVCMOS33} [get_ports {eth_mdio_io}]; # ETH_MDIO +set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVCMOS33} [get_ports {eth_reset_o}]; # ETH-RST +set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[0]}]; # ETH_RX_D0 +set_property -dict {PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[1]}]; # ETH_RX_D1 +set_property -dict {PACKAGE_PIN K4 IOSTANDARD LVCMOS33} [get_ports {eth_rxdv_i}]; # ETH_CRS_DV +set_property -dict {PACKAGE_PIN M6 IOSTANDARD LVCMOS33} [get_ports {eth_rxer_i}]; # ETH_RXER +set_property -dict {PACKAGE_PIN L3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[0]}]; # ETH_TX_D0 +set_property -dict {PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[1]}]; # ETH_TX_D1 +set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {eth_txen_o}]; # ETH_TX_EN +set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txd_o[*]}]; +set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txen_o}]; +set_property -dict {SLEW FAST} [get_ports {eth_clock_o}]; + +# FDC interface +set_property -dict {PACKAGE_PIN P6 IOSTANDARD LVCMOS33} [get_ports {f_density_o}]; # F_REDWC +set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {f_diskchanged_i}]; # F_DSCKCHG +set_property -dict {PACKAGE_PIN M2 IOSTANDARD LVCMOS33} [get_ports {f_index_i}]; # F_INDEX +set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports {f_motora_o}]; # F_MOTEA +set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {f_motorb_o}]; # F_MOTEB +set_property -dict {PACKAGE_PIN P1 IOSTANDARD LVCMOS33} [get_ports {f_rdata_i}]; # F_RDATA1 +set_property -dict {PACKAGE_PIN N5 IOSTANDARD LVCMOS33} [get_ports {f_selecta_o}]; # F_DRVSA +set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {f_selectb_o}]; # F_DRVSB +set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {f_side1_o}]; # F_SIDE1 +set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {f_stepdir_o}]; # F_DIR +set_property -dict {PACKAGE_PIN M3 IOSTANDARD LVCMOS33} [get_ports {f_step_o}]; # F_STEP +set_property -dict {PACKAGE_PIN N2 IOSTANDARD LVCMOS33} [get_ports {f_track0_i}]; # F_TRCK0 +set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {f_wdata_o}]; # F_WDATE +set_property -dict {PACKAGE_PIN N3 IOSTANDARD LVCMOS33} [get_ports {f_wgate_o}]; # F_WGATE +set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {f_writeprotect_i}]; # F_WPT + +# I2C bus for on-board peripherals +# U36. 24AA025E48T. Address 0x50. 2K Serial EEPROM. +# U38. RV-3032-C7. Address 0x51. Real-Time Clock Module. +# U39. 24LC128. Address 0x56. 128K CMOS Serial EEPROM. +set_property -dict {PACKAGE_PIN A15 IOSTANDARD LVCMOS33} [get_ports {fpga_scl_io}]; # FPGA_SCL +set_property -dict {PACKAGE_PIN A16 IOSTANDARD LVCMOS33} [get_ports {fpga_sda_io}]; # FPGA_SDA + +# Connected to J18. +set_property -dict {PACKAGE_PIN G21 IOSTANDARD LVCMOS33} [get_ports {grove_scl_io}]; # Grove_SCL0 +set_property -dict {PACKAGE_PIN G22 IOSTANDARD LVCMOS33} [get_ports {grove_sda_io}]; # Grove_SDA0 + +# Joystick power supply +set_property -dict {PACKAGE_PIN D19 IOSTANDARD LVCMOS33} [get_ports {joystick_5v_disable_o}]; # EN_5V_JOY_N +set_property -dict {PACKAGE_PIN D20 IOSTANDARD LVCMOS33} [get_ports {joystick_5v_powergood_i}]; # 5V_JOY_PG + +# On board LEDs +set_property -dict {PACKAGE_PIN V19 IOSTANDARD LVCMOS33} [get_ports {led_g_n_o}]; # LED_G +set_property -dict {PACKAGE_PIN U22 IOSTANDARD LVCMOS33} [get_ports {led_o}]; # ULED +set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports {led_r_n_o}]; # LED_R + +# Pmod Header +set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[0]}]; # B16_L17_P +set_property -dict {PACKAGE_PIN E1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[1]}]; # B35_L3_P +set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[2]}]; # B35_L2_P +set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[3]}]; # B35_L1_P +set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[0]}]; # B35_L5_N +set_property -dict {PACKAGE_PIN D1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[1]}]; # B35_L3_N +set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[2]}]; # B35_L2_N +set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[3]}]; # B35_L1_N +set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[0]}]; # B35_L4_P +set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[1]}]; # B35_L4_N +set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[2]}]; # B35_L12_N +set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[3]}]; # B35_L10_P +set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[0]}]; # B35_L6_P +set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[1]}]; # B35_L6_N +set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[2]}]; # B35_L12_P +set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[3]}]; # B35_L10_N +set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {pmod1_en_o}]; # PMOD1_EN +set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {pmod1_flag_i}]; # PMOD1_FLG +set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {pmod2_en_o}]; # PMOD2_EN +set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports {pmod2_flag_i}]; # PMOD2_FLG + +# Quad SPI Flash. U5 = S25FL512SAGBHIS10 +set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports {qspicsn_o}]; # SPI-CS +set_property -dict {PACKAGE_PIN P22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[0]}]; # SPI-DQ0 +set_property -dict {PACKAGE_PIN R22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[1]}]; # SPI-DQ1 +set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[2]}]; # SPI-DQ2 +set_property -dict {PACKAGE_PIN R21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[3]}]; # SPI-DQ3 +set_property -dict {PULLUP TRUE} [get_ports {qspidb_io[*]}]; + +# SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL +set_property -dict {PACKAGE_PIN T4 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[0]}]; # SDRAM_A0 +set_property -dict {PACKAGE_PIN R2 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[1]}]; # SDRAM_A1 +set_property -dict {PACKAGE_PIN R3 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[2]}]; # SDRAM_A2 +set_property -dict {PACKAGE_PIN T3 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[3]}]; # SDRAM_A3 +set_property -dict {PACKAGE_PIN Y4 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[4]}]; # SDRAM_A4 +set_property -dict {PACKAGE_PIN W6 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[5]}]; # SDRAM_A5 +set_property -dict {PACKAGE_PIN W4 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[6]}]; # SDRAM_A6 +set_property -dict {PACKAGE_PIN U7 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[7]}]; # SDRAM_A7 +set_property -dict {PACKAGE_PIN AA8 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[8]}]; # SDRAM_A8 +set_property -dict {PACKAGE_PIN Y2 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[9]}]; # SDRAM_A9 +set_property -dict {PACKAGE_PIN R6 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[10]}]; # SDRAM_A10 +set_property -dict {PACKAGE_PIN Y7 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[11]}]; # SDRAM_A11 +set_property -dict {PACKAGE_PIN Y9 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[12]}]; # SDRAM_A12 +set_property -dict {PACKAGE_PIN U3 IOSTANDARD LVCMOS33} [get_ports {sdram_ba_o[0]}]; # SDRAM_BA0 +set_property -dict {PACKAGE_PIN R4 IOSTANDARD LVCMOS33} [get_ports {sdram_ba_o[1]}]; # SDRAM_BA1 +set_property -dict {PACKAGE_PIN V3 IOSTANDARD LVCMOS33} [get_ports {sdram_cas_n_o}]; # SDRAM_CAS# +set_property -dict {PACKAGE_PIN U5 IOSTANDARD LVCMOS33} [get_ports {sdram_cke_o}]; # SDRAM_CKE +set_property -dict {PACKAGE_PIN V8 IOSTANDARD LVCMOS33} [get_ports {sdram_clk_o}]; # SDRAM_CLK +set_property -dict {PACKAGE_PIN G3 IOSTANDARD LVCMOS33} [get_ports {sdram_cs_n_o}]; # SDRAM_CS# +set_property -dict {PACKAGE_PIN V5 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[0]}]; # SDRAM_DQ0 +set_property -dict {PACKAGE_PIN AA4 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[10]}]; # SDRAM_DQ10 +set_property -dict {PACKAGE_PIN V7 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[11]}]; # SDRAM_DQ11 +set_property -dict {PACKAGE_PIN AA6 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[12]}]; # SDRAM_DQ12 +set_property -dict {PACKAGE_PIN W5 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[13]}]; # SDRAM_DQ13 +set_property -dict {PACKAGE_PIN AB6 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[14]}]; # SDRAM_DQ14 +set_property -dict {PACKAGE_PIN Y3 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[15]}]; # SDRAM_DQ15 +set_property -dict {PACKAGE_PIN T1 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[1]}]; # SDRAM_DQ1 +set_property -dict {PACKAGE_PIN V4 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[2]}]; # SDRAM_DQ2 +set_property -dict {PACKAGE_PIN U2 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[3]}]; # SDRAM_DQ3 +set_property -dict {PACKAGE_PIN V2 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[4]}]; # SDRAM_DQ4 +set_property -dict {PACKAGE_PIN U1 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[5]}]; # SDRAM_DQ5 +set_property -dict {PACKAGE_PIN U6 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[6]}]; # SDRAM_DQ6 +set_property -dict {PACKAGE_PIN T6 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[7]}]; # SDRAM_DQ7 +set_property -dict {PACKAGE_PIN W7 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[8]}]; # SDRAM_DQ8 +set_property -dict {PACKAGE_PIN AA3 IOSTANDARD LVCMOS33} [get_ports {sdram_dq_io[9]}]; # SDRAM_DQ9 +set_property -dict {PACKAGE_PIN Y6 IOSTANDARD LVCMOS33} [get_ports {sdram_dqmh_o}]; # SDRAM_DQMH +set_property -dict {PACKAGE_PIN W2 IOSTANDARD LVCMOS33} [get_ports {sdram_dqml_o}]; # SDRAM_DQML +set_property -dict {PACKAGE_PIN T5 IOSTANDARD LVCMOS33} [get_ports {sdram_ras_n_o}]; # SDRAM_RAS# +set_property -dict {PACKAGE_PIN G1 IOSTANDARD LVCMOS33} [get_ports {sdram_we_n_o}]; # SDRAM_WE# +set_property -dict {PULLUP FALSE SLEW FAST DRIVE 16} [get_ports {sdram_*}]; + + +################################ +## PLACEMENT CONSTRAINTS +################################ + +# Place Keyboard close to I/O pins +create_pblock pblock_m65driver +add_cells_to_pblock pblock_m65driver [get_cells [list framework_inst/m2m_keyb_inst/mega65kbd_to_matrix_inst]] +resize_pblock pblock_m65driver -add {SLICE_X0Y225:SLICE_X7Y243} + +# Place SD card controller in the middle between the left and right FPGA boundary because the output ports are at the opposide edges +create_pblock pblock_sdcard +add_cells_to_pblock pblock_sdcard [get_cells [list framework_inst/qnice_wrapper_inst/qnice_inst/sd_card]] +resize_pblock pblock_sdcard -add {SLICE_X66Y178:SLICE_X99Y193} + +# Place phase-shifted VGA output registers near the actual output buffers +create_pblock pblock_vga +add_cells_to_pblock pblock_vga [get_cells [list framework_inst/av_pipeline_inst/analog_pipeline_inst/VGA_OUT_PHASE_SHIFTED.*]] +resize_pblock pblock_vga -add SLICE_X0Y75:SLICE_X5Y99 + diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr new file mode 100644 index 00000000..6fa3a394 --- /dev/null +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default_dashboard + + + diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd new file mode 100644 index 00000000..c512484e --- /dev/null +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -0,0 +1,512 @@ +---------------------------------------------------------------------------------- +-- MEGA65 port of QNICE-FGA +-- +-- Top Module for synthesizing the whole machine +-- +-- done on-again-off-again in 2015, 2016 by sy2002 +-- MEGA65 port done in April to August 2020 by sy2002 +---------------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +use work.env1_globals.all; + +library UNISIM; +use UNISIM.VCOMPONENTS.ALL; + +entity MEGA65 is +port ( + CLK : in std_logic; -- 100 MHz clock + RESET_N : in std_logic; -- CPU reset button + + -- serial communication (rxd, txd only; rts/cts are not available) + -- 115.200 baud, 8-N-1 + UART_RXD : in std_logic; -- receive data + UART_TXD : out std_logic; -- send data + + -- VGA + VGA_RED : out std_logic_vector(7 downto 0); + VGA_GREEN : out std_logic_vector(7 downto 0); + VGA_BLUE : out std_logic_vector(7 downto 0); + VGA_HS : out std_logic; + VGA_VS : out std_logic; + + -- VDAC + vdac_clk : out std_logic; + vdac_sync_n : out std_logic; + vdac_blank_n : out std_logic; + + -- MEGA65 smart keyboard controller + kb_io0 : out std_logic; -- clock to keyboard + kb_io1 : out std_logic; -- data output to keyboard + kb_io2 : in std_logic; -- data input from keyboard + + -- SD Card + SD_RESET : out std_logic; + SD_CLK : out std_logic; + SD_MOSI : out std_logic; + SD_MISO : in std_logic; + + -- Built-in HyperRAM + hr_d : inout unsigned(7 downto 0); -- Data/Address + hr_rwds : inout std_logic; -- RW Data strobe + hr_reset : out std_logic; -- Active low RESET line to HyperRAM + hr_clk_p : out std_logic; + hr_cs0 : out std_logic +); +end entity MEGA65; + +architecture beh of MEGA65 is + +-- CPU control signals +signal cpu_addr : std_logic_vector(15 downto 0); +signal cpu_data_in : std_logic_vector(15 downto 0); +signal cpu_data_out : std_logic_vector(15 downto 0); +signal cpu_data_dir : std_logic; +signal cpu_data_valid : std_logic; +signal cpu_wait_for_data : std_logic; +signal cpu_halt : std_logic; +signal cpu_ins_cnt_strobe : std_logic; +signal cpu_int_n : std_logic; +signal cpu_igrant_n : std_logic; + +-- MMIO control signals +signal rom_enable : std_logic; +signal rom_busy : std_logic; +signal rom_data_out : std_logic_vector(15 downto 0); +signal ram_enable : std_logic; +signal ram_busy : std_logic; +signal ram_data_out : std_logic_vector(15 downto 0); +signal pore_rom_enable : std_logic; +signal pore_rom_busy : std_logic; +signal pore_rom_data_out : std_logic_vector(15 downto 0); +signal til_reg0_enable : std_logic; +signal til_reg1_enable : std_logic; +signal switch_reg_enable : std_logic; +signal switch_data_out : std_logic_vector(15 downto 0); +signal kbd_en : std_logic; +signal kbd_we : std_logic; +signal kbd_reg : std_logic_vector(1 downto 0); +signal kbd_data_out : std_logic_vector(15 downto 0); +signal tin_en : std_logic; +signal tin_we : std_logic; +signal tin_reg : std_logic_vector(2 downto 0); +signal timer_data_out : std_logic_vector(15 downto 0); +signal vga_en : std_logic; +signal vga_we : std_logic; +signal vga_reg : std_logic_vector(3 downto 0); +signal vga_data_out : std_logic_vector(15 downto 0); +signal uart_en : std_logic; +signal uart_we : std_logic; +signal uart_reg : std_logic_vector(1 downto 0); +signal uart_data_out : std_logic_vector(15 downto 0); +signal uart_cpu_ws : std_logic; +signal cyc_en : std_logic; +signal cyc_we : std_logic; +signal cyc_reg : std_logic_vector(1 downto 0); +signal cyc_data_out : std_logic_vector(15 downto 0); +signal ins_en : std_logic; +signal ins_we : std_logic; +signal ins_reg : std_logic_vector(1 downto 0); +signal ins_data_out : std_logic_vector(15 downto 0); +signal eae_en : std_logic; +signal eae_we : std_logic; +signal eae_reg : std_logic_vector(2 downto 0); +signal eae_data_out : std_logic_vector(15 downto 0); +signal sd_en : std_logic; +signal sd_we : std_logic; +signal sd_reg : std_logic_vector(2 downto 0); +signal sd_data_out : std_logic_vector(15 downto 0); +signal hram_en : std_logic; +signal hram_we : std_logic; +signal hram_reg : std_logic_vector(3 downto 0); +signal hram_data_out : std_logic_vector(15 downto 0); +signal hram_cpu_ws : std_logic; + +signal reset_pre_pore : std_logic; +signal reset_post_pore : std_logic; + +-- VGA control signals +signal vga_r : std_logic; +signal vga_g : std_logic; +signal vga_b : std_logic; +signal vga_hsync : std_logic; +signal vga_vsync : std_logic; + +-- 50 MHz as long as we did not solve the timing issues of the register file +signal SLOW_CLOCK : std_logic := '0'; + +-- Pixelclock and fast clock for HRAM +signal CLK1x : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase +signal CLK2x : std_logic; -- 4x SLOW_CLOCK = 200 MHz +signal clk25MHz : std_logic; -- 25.175 MHz pixelclock for 640x480 @ 60 Hz +signal pll_locked_main : std_logic; +signal clk_fb_main : std_logic; + +-- combined pre- and post pore reset +signal reset_ctl : std_logic; + +-- enable displaying of address bus on system halt, if switch 2 is on +signal i_til_reg0_enable : std_logic; +signal i_til_data_in : std_logic_vector(15 downto 0); + +-- emulate the switches on the Nexys4 dev board to toggle VGA and PS/2 +signal SWITCHES : std_logic_vector(15 downto 0); + +begin + + -- Merge data outputs from all devices into a single data input to the CPU. + -- This requires that all devices output 0's when not selected. + cpu_data_in <= pore_rom_data_out or + rom_data_out or + ram_data_out or + switch_data_out or + kbd_data_out or + vga_data_out or + uart_data_out or + timer_data_out or + cyc_data_out or + ins_data_out or + eae_data_out or + sd_data_out or + hram_data_out; + + clk_main: mmcme2_base + generic map + ( + clkin1_period => 10.0, -- 100 MHz (10 ns) + clkfbout_mult_f => 8.0, -- 800 MHz common multiply + divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range + clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but actual value is 25.197 MHz + clkout1_divide => 8, -- 100 MHz /8 + clkout2_divide => 16, -- 50 MHz /16 + clkout3_divide => 4 -- 200 MHz /4 + ) + port map + ( + pwrdwn => '0', + rst => '0', + clkin1 => CLK, + clkfbin => clk_fb_main, + clkfbout => clk_fb_main, + clkout0 => clk25MHz, -- pixelclock + clkout1 => CLK1x, -- 100 MHz + clkout2 => SLOW_CLOCK, -- 50 MHz + clkout3 => CLK2x, -- 200 MHz + locked => pll_locked_main + ); + + -- QNICE CPU + cpu : entity work.QNICE_CPU + port map ( + CLK => SLOW_CLOCK, + RESET => reset_ctl, + WAIT_FOR_DATA => cpu_wait_for_data, + ADDR => cpu_addr, + DATA_IN => cpu_data_in, + DATA_OUT => cpu_data_out, + DATA_DIR => cpu_data_dir, + DATA_VALID => cpu_data_valid, + HALT => cpu_halt, + INS_CNT_STROBE => cpu_ins_cnt_strobe, + INT_N => cpu_int_n, + IGRANT_N => cpu_igrant_n + ); + + -- ROM: up to 64kB consisting of up to 32.000 16 bit words + rom : entity work.BROM + generic map ( + FILE_NAME => ROM_FILE + ) + port map ( + clk => SLOW_CLOCK, + ce => rom_enable, + address => cpu_addr(14 downto 0), + data => rom_data_out, + busy => rom_busy + ); + + -- RAM: up to 64kB consisting of up to 32.000 16 bit words + ram : entity work.BRAM + port map ( + clk => SLOW_CLOCK, + ce => ram_enable, + address => cpu_addr(14 downto 0), + we => cpu_data_dir, + data_i => cpu_data_out, + data_o => ram_data_out, + busy => ram_busy + ); + + -- PORE ROM: Power On & Reset Execution ROM + -- contains code that is executed during power on and/or during reset + -- MMIO is managing the PORE process + pore_rom : entity work.BROM + generic map ( + FILE_NAME => PORE_ROM_FILE + ) + port map ( + clk => SLOW_CLOCK, + ce => pore_rom_enable, + address => cpu_addr(14 downto 0), + data => pore_rom_data_out, + busy => pore_rom_busy + ); + + -- VGA: 80x40 textmode VGA adaptor + vga_screen : entity work.vga_textmode + port map ( + reset => reset_ctl, + clk25MHz => clk25MHz, + clk50MHz => SLOW_CLOCK, + R => vga_r, + G => vga_g, + B => vga_b, + hsync => vga_hsync, + vsync => vga_vsync, + hdmi_de => open, + en => vga_en, + we => vga_we, + reg => vga_reg, + data_in => cpu_data_out, + data_out => vga_data_out + ); + + -- special UART with FIFO that can be directly connected to the CPU bus + uart : entity work.bus_uart + generic map ( + DIVISOR => UART_DIVISOR + ) + port map ( + clk => SLOW_CLOCK, + reset => reset_ctl, + rx => UART_RXD, + tx => UART_TXD, + rts => '0', + cts => open, + uart_en => uart_en, + uart_we => uart_we, + uart_reg => uart_reg, + uart_cpu_ws => uart_cpu_ws, + cpu_data_in => cpu_data_out, + cpu_data_out => uart_data_out + ); + + -- MEGA65 keyboard + kbd : entity work.keyboard + generic map ( + clk_freq => 50000000 + ) + port map ( + clk => SLOW_CLOCK, + reset => reset_ctl, + kb_io0 => kb_io0, + kb_io1 => kb_io1, + kb_io2 => kb_io2, + kbd_en => kbd_en, + kbd_we => kbd_we, + kbd_reg => kbd_reg, + cpu_data_in => cpu_data_out, + cpu_data_out => kbd_data_out, + stdinout => SWITCHES(1 downto 0) + ); + + timer_interrupt : entity work.timer_module + generic map ( + CLK_FREQ => 50000000 + ) + port map ( + clk => SLOW_CLOCK, + reset => reset_ctl, + int_n_out => cpu_int_n, + grant_n_in => cpu_igrant_n, + int_n_in => '1', -- no more devices to in Daisy Chain: 1=no interrupt + grant_n_out => open, -- ditto: open=grant goes nowhere + en => tin_en, + we => tin_we, + reg => tin_reg, + data_in => cpu_data_out, + data_out => timer_data_out + ); + + -- cycle counter + cyc : entity work.cycle_counter + port map ( + clk => SLOW_CLOCK, + impulse => '1', + reset => reset_ctl, + en => cyc_en, + we => cyc_we, + reg => cyc_reg, + data_in => cpu_data_out, + data_out => cyc_data_out + ); + + -- instruction counter + ins : entity work.cycle_counter + port map ( + clk => SLOW_CLOCK, + impulse => cpu_ins_cnt_strobe, + reset => reset_ctl, + en => ins_en, + we => ins_we, + reg => ins_reg, + data_in => cpu_data_out, + data_out => ins_data_out + ); + + -- EAE - Extended Arithmetic Element (32-bit multiplication, division, modulo) + eae_inst : entity work.eae + port map ( + clk => SLOW_CLOCK, + reset => reset_ctl, + en => eae_en, + we => eae_we, + reg => eae_reg, + data_in => cpu_data_out, + data_out => eae_data_out + ); + + -- SD Card + sd_card : entity work.sdcard + port map ( + clk => SLOW_CLOCK, + reset => reset_ctl, + en => sd_en, + we => sd_we, + reg => sd_reg, + data_in => cpu_data_out, + data_out => sd_data_out, + sd_reset => SD_RESET, + sd_clk => SD_CLK, + sd_mosi => SD_MOSI, + sd_miso => SD_MISO + ); + + -- HyperRAM + HRAM : entity work.hyperram_ctl + port map ( + clk => SLOW_CLOCK, + clk2x => CLK1x, + clk4x => CLK2x, + reset => reset_ctl, + hram_en => hram_en, + hram_we => hram_we, + hram_reg => hram_reg, + hram_cpu_ws => hram_cpu_ws, + data_in => cpu_data_out, + data_out => hram_data_out, + hr_d => hr_d, + hr_rwds => hr_rwds, + hr_reset => hr_reset, + hr_clk_p => hr_clk_p, + hr_cs0 => hr_cs0 + ); + + -- memory mapped i/o controller + mmio_controller : entity work.mmio_mux + generic map ( + GD_TIL => false, -- no support for TIL leds on MEGA65 + GD_SWITCHES => true, -- we emulate the switch register as described in doc/README.md + GD_HRAM => true -- support HyperRAM + ) + port map ( + HW_RESET => not RESET_N, + CLK => SLOW_CLOCK, -- @TODO change debouncer bitsize when going to 100 MHz + addr => cpu_addr, + data_dir => cpu_data_dir, + data_valid => cpu_data_valid, + cpu_wait_for_data => cpu_wait_for_data, + cpu_halt => cpu_halt, + cpu_igrant_n => cpu_igrant_n, + rom_enable => rom_enable, + rom_busy => rom_busy, + ram_enable => ram_enable, + ram_busy => ram_busy, + pore_rom_enable => pore_rom_enable, + pore_rom_busy => pore_rom_busy, + switch_reg_enable => switch_reg_enable, + kbd_en => kbd_en, + kbd_we => kbd_we, + kbd_reg => kbd_reg, + tin_en => tin_en, + tin_we => tin_we, + tin_reg => tin_reg, + vga_en => vga_en, + vga_we => vga_we, + vga_reg => vga_reg, + uart_en => uart_en, + uart_we => uart_we, + uart_reg => uart_reg, + uart_cpu_ws => uart_cpu_ws, + cyc_en => cyc_en, + cyc_we => cyc_we, + cyc_reg => cyc_reg, + ins_en => ins_en, + ins_we => ins_we, + ins_reg => ins_reg, + eae_en => eae_en, + eae_we => eae_we, + eae_reg => eae_reg, + sd_en => sd_en, + sd_we => sd_we, + sd_reg => sd_reg, + hram_en => hram_en, + hram_we => hram_we, + hram_reg => hram_reg, + hram_cpu_ws => hram_cpu_ws, + + -- no TIL leds on the MEGA65 , + til_reg0_enable => open, + til_reg1_enable => open, + + reset_pre_pore => reset_pre_pore, + reset_post_pore => reset_post_pore + ); + + -- emulate the toggle switches as described in doc/README.md + switch_driver : process(switch_reg_enable, SWITCHES) + begin + if switch_reg_enable = '1' then + switch_data_out <= SWITCHES; + else + switch_data_out <= (others => '0'); + end if; + end process; + + video_signal_latches : process(clk25MHz) + begin + if rising_edge(clk25MHz) then + -- VGA: wire the simplified color system of the VGA component to the VGA outputs + VGA_RED <= vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r; + VGA_GREEN <= vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g; + VGA_BLUE <= vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b; + + -- VGA horizontal and vertical sync + VGA_HS <= vga_hsync; + VGA_VS <= vga_vsync; + end if; + end process; + + -- make the VDAC output the image + vdac_sync_n <= '0'; + vdac_blank_n <= '1'; + + -- Fix of the Vivado induced "blurry VGA screen": + -- As of the time writing this (June 2020): it is absolutely unclear for me, why I need to + -- invert the phase of the vdac_clk when use Vivado 2019.2. When using ISE 14.7, it works + -- fine without the phase shift. + vdac_clk <= not clk25MHz; + + -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard + -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) + -- bit #1: use UART AS STDOUT (0) / use VGA as STDOUT (1) + SWITCHES(15 downto 2) <= "00000000000000"; + + -- generate the general reset signal + reset_ctl <= '1' when (reset_pre_pore = '1' or reset_post_pore = '1' or pll_locked_main = '0') else '0'; + +end architecture beh; + diff --git a/vhdl/hw/MEGA65/drivers/hyperram.vhdl b/vhdl/hw/MEGA65/drivers/hyperram.vhdl index a9ba47b6..8c3912b5 100644 --- a/vhdl/hw/MEGA65/drivers/hyperram.vhdl +++ b/vhdl/hw/MEGA65/drivers/hyperram.vhdl @@ -71,16 +71,7 @@ entity hyperram is hr_reset : out std_logic := '1'; -- Active low RESET line to HyperRAM hr_clk_n : out std_logic := '0'; hr_clk_p : out std_logic := '1'; - - hr2_d : inout unsigned(7 downto 0) := (others => 'Z'); -- Data/Address - hr2_rwds : inout std_logic := 'Z'; -- RW Data strobe - hr2_reset : out std_logic := '1'; -- Active low RESET line to HyperRAM - hr2_clk_n : out std_logic := '0'; - hr2_clk_p : out std_logic := '1'; - - - hr_cs0 : out std_logic := '1'; - hr_cs1 : out std_logic := '1' + hr_cs0 : out std_logic := '1' ); end hyperram; @@ -229,7 +220,6 @@ architecture gothic of hyperram is signal hr_reset_int : std_logic := '1'; signal hr_rwds_int : std_logic := '0'; signal hr_cs0_int : std_logic := '0'; - signal hr_cs1_int : std_logic := '0'; signal hr_clk_p_int : std_logic := '0'; signal hr_clk_n_int : std_logic := '0'; @@ -1281,78 +1271,45 @@ begin case clock_status_vector is -- Slow clock rate, no phase shift when "00000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00010" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00011" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00100" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "00101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "00110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "00111" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; -- Slow clock rate, with phase shift = bring forward tick by 1/2 a cycle when "01000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "01001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "01010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01011" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01100" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01110" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "01111" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; -- Fast clock rate, no phase shift when "10000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "10011" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "10100" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10101" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "10111" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; -- Fast clock rate, with phase shift when "11000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "11001" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11011" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "11100" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "11101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; - hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11111" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; when others => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; - hr2_clk_p <= '0'; hr2_clk_n <= '1'; end case; end if; @@ -1730,12 +1687,10 @@ begin -- Make sure we don't abort a read so quickly, that we allow -- glitching of clock line with clock phase shifting hr_cs0 <= '1'; - hr_cs1 <= '1'; state <= Idle; when Idle => report "Tristating hr_d"; hr_d <= (others => 'Z'); - hr2_d <= (others => 'Z'); read_request_held <= '0'; write_request_held <= '0'; @@ -1783,7 +1738,6 @@ begin if rwr_counter /= to_unsigned(0,8) then rwr_counter <= rwr_counter - 1; hr_d <= x"bb"; - hr2_d <= x"bb"; end if; if rwr_counter = to_unsigned(1,8) then rwr_waiting <= '0'; @@ -2040,7 +1994,6 @@ begin -- Release CS line between transactions report "Releasing hyperram CS lines"; hr_cs0 <= '1'; - hr_cs1 <= '1'; end if; when StartBackgroundWrite => @@ -2162,10 +2115,8 @@ begin report "hr_command = $" & to_hstring(hr_command); -- Call HyperRAM to attention hr_cs0 <= not hyperram0_select; - hr_cs1 <= not (hyperram1_select or first_transaction); hr_rwds <= 'Z'; - hr2_rwds <= 'Z'; -- Prepare for reading block data is_block_read <= false; @@ -2271,7 +2222,6 @@ begin & ", countdown = " & integer'image(countdown); hr_d <= hr_command(47 downto 40); - hr2_d <= hr_command(47 downto 40); hr_command(47 downto 8) <= hr_command(39 downto 0); -- Also shift out config register values, if required @@ -2298,9 +2248,7 @@ begin if countdown = 3 and (config_reg_write='0' or ram_reading_held='1') then extra_latency <= hr_rwds; - if (hr_rwds='1' and hyperram0_select='1') - or (hr2_rwds='1' and hyperram1_select='1') - then + if (hr_rwds='1' and hyperram0_select='1') then report "Applying extra latency"; end if; end if; @@ -2320,10 +2268,8 @@ begin report "Writing command"; -- Call HyperRAM to attention hr_cs0 <= not hyperram0_select; - hr_cs1 <= not (hyperram1_select or first_transaction); hr_rwds <= 'Z'; - hr2_rwds <= 'Z'; hr_clk_phaseshift <= write_byte_phase; @@ -2335,7 +2281,6 @@ begin -- & ", cs0= " & std_logic'image(hr_cs0); hr_d <= hr_command(47 downto 40); - hr2_d <= hr_command(47 downto 40); hr_command(47 downto 8) <= hr_command(39 downto 0); -- Also shift out config register values, if required @@ -2353,11 +2298,8 @@ begin if countdown = 3 and (config_reg_write='0' or ram_reading_held='1') then if hyperram0_select='1' then extra_latency <= hr_rwds; - else - extra_latency <= hr2_rwds; end if; - if (hr_rwds='1' and hyperram0_select='1') - or (hr2_rwds='1' and hyperram1_select='1') then + if (hr_rwds='1' and hyperram0_select='1') then report "Applying extra latency"; end if; end if; @@ -2487,9 +2429,7 @@ begin -- Begin write mask pre-amble if ram_reading_held = '0' and countdown = 2 then hr_rwds <= '0'; - hr2_rwds <= '0'; hr_d <= x"BE"; -- "before" data byte - hr2_d <= x"BE"; -- "before" data byte end if; if countdown /= 0 then @@ -2529,7 +2469,6 @@ begin & ", valids= " & to_string(background_write_valids) & ", background words left = " & integer'image(background_write_count); hr_d <= background_write_data(0); - hr2_d <= background_write_data(0); background_write_data(0) <= background_write_data(1); background_write_data(1) <= background_write_data(2); background_write_data(2) <= background_write_data(3); @@ -2540,7 +2479,6 @@ begin background_write_data(7) <= x"00"; hr_rwds <= not background_write_valids(0); - hr2_rwds <= not background_write_valids(0); background_write_valids(0 to 6) <= background_write_valids(1 to 7); background_write_valids(7) <= '0'; @@ -2553,9 +2491,7 @@ begin -- okay, as they are only supported with the cache and -- write-collecting, anyway. hr_d <= ram_wdata; - hr2_d <= ram_wdata; hr_rwds <= hyperram_access_address(0) xor write_byte_phase; - hr2_rwds <= hyperram_access_address(0) xor write_byte_phase; end if; -- Write byte @@ -2564,11 +2500,9 @@ begin if write_byte_phase = '0' and hyperram_access_address(0)='1' then report "Masking even byte"; hr_d <= x"ee"; -- even "masked" data byte - hr2_d <= x"ee"; -- even "masked" data byte elsif write_byte_phase = '1' and hyperram_access_address(0)='0' then report "Masking odd byte"; hr_d <= x"0d"; -- odd "masked" data byte - hr2_d <= x"0d"; -- odd "masked" data byte end if; if background_write_count /= 0 then background_write_count <= background_write_count - 1; @@ -2743,9 +2677,7 @@ begin -- Begin write mask pre-amble if ram_reading_held = '0' and countdown = 2 then hr_rwds <= '0'; - hr2_rwds <= '0'; hr_d <= x"BE"; -- "before" data byte - hr2_d <= x"BE"; -- "before" data byte end if; if countdown /= 0 then @@ -2784,7 +2716,6 @@ begin & ", valids= " & to_string(background_write_valids) & ", background words left = " & integer'image(background_write_count); hr_d <= background_write_data(0); - hr2_d <= background_write_data(0); background_write_data(0) <= background_write_data(1); background_write_data(1) <= background_write_data(2); @@ -2796,7 +2727,6 @@ begin background_write_data(7) <= x"00"; hr_rwds <= not background_write_valids(0); - hr2_rwds <= not background_write_valids(0); background_write_valids(0 to 6) <= background_write_valids(1 to 7); background_write_valids(7) <= '0'; else @@ -2804,9 +2734,7 @@ begin -- okay, as they are only supported with the cache and -- write-collecting, anyway. hr_d <= ram_wdata; - hr2_d <= ram_wdata; hr_rwds <= hyperram_access_address(0) xor write_byte_phase; - hr2_rwds <= hyperram_access_address(0) xor write_byte_phase; end if; -- Finish resetting write collectors when chaining @@ -2828,10 +2756,8 @@ begin if background_write='0' then if write_byte_phase = '0' and hyperram_access_address(0)='1' then hr_d <= x"ee"; -- even "masked" data byte - hr2_d <= x"ee"; -- even "masked" data byte elsif write_byte_phase = '1' and hyperram_access_address(0)='0' then hr_d <= x"0d"; -- odd "masked" data byte - hr2_d <= x"0d"; -- odd "masked" data byte end if; if background_write_count /= 0 then background_write_count <= background_write_count - 1; @@ -2876,11 +2802,8 @@ begin when HyperRAMFinishWriting => -- Mask writing from here on. hr_cs0 <= '1'; - hr_cs1 <= '1'; hr_rwds <= 'Z'; - hr2_rwds <= 'Z'; hr_d <= x"FA"; -- "after" data byte - hr2_d <= x"FA"; -- "after" data byte hr_clk_phaseshift <= write_phase_shift; report "clk_queue <= '00'"; rwr_counter <= rwr_delay; @@ -2889,10 +2812,8 @@ begin state <= Idle; when HyperRAMReadWait => hr_rwds <= 'Z'; - hr2_rwds <= 'Z'; report "Presenting tri-state on hr_d"; hr_d <= (others => 'Z'); - hr2_d <= (others => 'Z'); if countdown_is_zero = '0' then countdown <= countdown - 1; end if; @@ -3016,8 +2937,6 @@ begin if hyperram0_select='1' then last_rwds <= hr_rwds; - else - last_rwds <= hr2_rwds; end if; -- HyperRAM drives RWDS basically to follow the clock. -- But first valid data is when RWDS goes high, so we have to @@ -3025,9 +2944,7 @@ begin -- report "DISPATCH watching for data: rwds=" & std_logic'image(hr_rwds) & ", clock=" & std_logic'image(hr_clock) -- & ", rwds seen=" & std_logic'image(hr_rwds_high_seen); - if ((hr_rwds='1') and (hyperram0_select='1')) - or ((hr2_rwds='1') and (hyperram1_select='1')) - then + if ((hr_rwds='1') and (hyperram0_select='1')) then hr_rwds_high_seen <= '1'; -- if hr_rwds_high_seen = '0' then -- report "DISPATCH saw hr_rwds go high at start of data stream"; @@ -3035,9 +2952,7 @@ begin else hr_rwds_high_seen <= '0'; end if; - if (((hr_rwds='1') and (hyperram0_select='1')) - or ((hr2_rwds='1') and (hyperram1_select='1'))) - or (hr_rwds_high_seen='1') then + if ((hr_rwds='1') and (hyperram0_select='1')) or (hr_rwds_high_seen='1') then -- Data has arrived: Latch either odd or even byte -- as required. report "DISPATCH Saw read data = $" & to_hstring(hr_d); @@ -3049,9 +2964,6 @@ begin if hyperram0_select='1' then block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) <= hr_d; - else - block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) - <= hr2_d; end if; show_block := true; end if; @@ -3060,8 +2972,6 @@ begin if is_vic_fetch then if hyperram0_select='1' then viciv_data_buffer(to_integer(byte_phase)) <= hr_d; - else - viciv_data_buffer(to_integer(byte_phase)) <= hr2_d; end if; -- We load the data here 2x faster than it is sent to the VIC-IV -- so we can start transmitting immediately, to minimise latency @@ -3075,8 +2985,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; - else - cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; elsif hyperram_access_address_matches_cache_row1 = '1' then @@ -3085,8 +2993,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; - else - cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; elsif random_bits(1) = '0' then @@ -3099,8 +3005,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; - else - cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; else @@ -3113,8 +3017,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; - else - cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; end if; @@ -3136,23 +3038,12 @@ begin if to_integer(byte_phase) = (to_integer(hyperram_access_address(2 downto 0))+0) and is_expected_to_respond and (not is_vic_fetch) then if hyperram0_select='1' then - report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d) - & ", hyperram0_select="& std_logic'image(hyperram0_select) - & ", hyperram1_select="& std_logic'image(hyperram1_select); + report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d) & ", hyperram0_select=" & std_logic'image(hyperram0_select) & ", hyperram1_select=" & std_logic'image(hyperram1_select); if rdata_16en='1' and byte_phase(0)='1' then rdata_hi <= hr_d; else rdata <= hr_d; end if; - else - report "DISPATCH: Returning freshly read data = $" & to_hstring(hr2_d) - & ", hyperram0_select="& std_logic'image(hyperram0_select) - & ", hyperram1_select="& std_logic'image(hyperram1_select); - if rdata_16en='1' and byte_phase(0)='1' then - rdata_hi <= hr2_d; - else - rdata <= hr2_d; - end if; end if; report "hr_return='1'"; report "hr_return='0'"; @@ -3171,7 +3062,6 @@ begin last_request_toggle <= request_toggle; state <= Idle; hr_cs0 <= '1'; - hr_cs1 <= '1'; hr_clk_phaseshift <= write_phase_shift; if is_block_read then block_valid <= '1'; @@ -3184,15 +3074,11 @@ begin end if; when HyperRAMReadWaitSlow => hr_rwds <= 'Z'; - hr2_rwds <= 'Z'; report "Presenting tri-state on hr_d"; hr_d <= (others => 'Z'); - hr2_d <= (others => 'Z'); if hyperram0_select='1' then hr_d_last <= hr_d; - else - hr_d_last <= hr2_d; end if; pause_phase <= not pause_phase; @@ -3255,8 +3141,6 @@ begin if hyperram0_select='1' then last_rwds <= hr_rwds; - else - last_rwds <= hr2_rwds; end if; -- HyperRAM drives RWDS basically to follow the clock. -- But first valid data is when RWDS goes high, so we have to @@ -3264,7 +3148,7 @@ begin -- report "DISPATCH watching for data: rwds=" & std_logic'image(hr_rwds) & ", clock=" & std_logic'image(hr_clock) -- & ", rwds seen=" & std_logic'image(hr_rwds_high_seen); - if ((hr_rwds='1') and (hyperram0_select='1')) or ((hr2_rwds='1') and (hyperram1_select='1')) + if (hr_rwds='1') and (hyperram0_select='1') then hr_rwds_high_seen <= '1'; else @@ -3273,7 +3157,7 @@ begin -- report "DISPATCH saw hr_rwds go high at start of data stream"; -- end if; end if; - if (((hr_rwds='1') and (hyperram0_select='1')) or ((hr2_rwds='1') and (hyperram1_select='1'))) + if ((hr_rwds='1') and (hyperram0_select='1')) or (hr_rwds_high_seen='1') then -- Data has arrived: Latch either odd or even byte -- as required. @@ -3286,9 +3170,6 @@ begin if hyperram0_select='1' then block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) <= hr_d; - else - block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) - <= hr2_d; end if; show_block := true; end if; @@ -3297,8 +3178,6 @@ begin if is_vic_fetch then if hyperram0_select='1' then viciv_data_buffer(to_integer(byte_phase)) <= hr_d; - else - viciv_data_buffer(to_integer(byte_phase)) <= hr2_d; end if; -- We load the data here 2x faster than it is sent to the VIC-IV -- so we can start transmitting immediately, to minimise latency @@ -3312,8 +3191,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; - else - cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; elsif hyperram_access_address_matches_cache_row1 = '1' then @@ -3322,8 +3199,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; - else - cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; elsif random_bits(1) = '0' then @@ -3336,8 +3211,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; - else - cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; else @@ -3350,8 +3223,6 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; - else - cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; end if; @@ -3377,10 +3248,6 @@ begin if hyperram0_select='1' then report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d); rdata <= hr_d; - else - report "DISPATCH: Returning freshly read data = $" & to_hstring(hr2_d) - & ", byte_phase=" & integer'image(to_integer(byte_phase)); - rdata <= hr2_d; end if; report "hr_return='1'"; report "hr_return='0'"; @@ -3394,10 +3261,6 @@ begin if hyperram0_select='1' then report "DISPATCH: Returning freshly read high-byte data = $" & to_hstring(hr_d); rdata_hi <= hr_d; - else - report "DISPATCH: Returning freshly read data = $" & to_hstring(hr2_d) - & ", byte_phase=" & integer'image(to_integer(byte_phase)); - rdata_hi <= hr2_d; end if; report "hr_return='1'"; report "hr_return='0'"; @@ -3416,7 +3279,6 @@ begin report "returning to idle"; state <= Idle; hr_cs0 <= '1'; - hr_cs1 <= '1'; hr_clk_phaseshift <= write_phase_shift; else byte_phase <= byte_phase + 1; diff --git a/vhdl/hw/MEGA65/hyperram_ctl.vhd b/vhdl/hw/MEGA65/hyperram_ctl.vhd index c11b1c14..0e2f913f 100644 --- a/vhdl/hw/MEGA65/hyperram_ctl.vhd +++ b/vhdl/hw/MEGA65/hyperram_ctl.vhd @@ -39,12 +39,7 @@ port( hr_rwds : inout std_logic; -- RW Data strobe hr_reset : out std_logic; -- Active low RESET line to HyperRAM hr_clk_p : out std_logic; - hr2_d : inout unsigned(7 downto 0); -- Data/Address - hr2_rwds : inout std_logic; -- RW Data strobe - hr2_reset : out std_logic; -- Active low RESET line to HyperRAM - hr2_clk_p : out std_logic; - hr_cs0 : out std_logic; - hr_cs1 : out std_logic + hr_cs0 : out std_logic ); end hyperram_ctl; @@ -79,12 +74,7 @@ component hyperram is hr_rwds : inout std_logic; hr_reset : out std_logic; hr_clk_p : out std_logic; - hr2_d : inout unsigned(7 downto 0); - hr2_rwds : inout std_logic; - hr2_reset : out std_logic; - hr2_clk_p : out std_logic; - hr_cs0 : out std_logic; - hr_cs1 : out std_logic + hr_cs0 : out std_logic ); end component; @@ -151,12 +141,7 @@ begin hr_rwds => hr_rwds, hr_reset => hr_reset, hr_clk_p => hr_clk_p, - hr2_d => hr2_d, - hr2_rwds => hr2_rwds, - hr2_reset => hr2_reset, - hr2_clk_p => hr2_clk_p, - hr_cs0 => hr_cs0, - hr_cs1 => hr_cs1 + hr_cs0 => hr_cs0 ); fsm_advance_state : process(clk, reset) diff --git a/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd b/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd index 75f59807..c69b6674 100644 --- a/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd +++ b/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd @@ -171,12 +171,7 @@ begin hr_rwds => hr_rwds, hr_reset => hr_reset, hr_clk_p => hr_clk_p, - hr2_d => hr2_d, - hr2_rwds => hr2_rwds, - hr2_reset => hr2_reset, - hr2_clk_p => hr2_clk_p, - hr_cs0 => hr_cs0, - hr_cs1 => hr_cs1 + hr_cs0 => hr_cs0 ); -- memory mapped i/o controller From 2be8c675836933f2eec9c46fdf2159666314f965 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Fri, 29 Nov 2024 19:09:29 +0100 Subject: [PATCH 02/17] bit stream generates, reset works, vga signal present yet screen is blank --- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 18 +++++++++--------- pore/boot_message_mega65.txt | 4 +--- vhdl/hw/MEGA65/MEGA65_R6.vhd | 4 ++-- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc index a226761e..ff7e3142 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -17,10 +17,10 @@ set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {UART_RXD}] set_property -dict {PACKAGE_PIN L13 IOSTANDARD LVCMOS33} [get_ports {UART_TXD}]; # DBG_UART_TX # VGA via VDAC. U3 = ADV7125BCPZ170 -set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {vdac_blank_n_o}]; # VDAC_BLANK_N -set_property -dict {PACKAGE_PIN AA9 IOSTANDARD LVCMOS33} [get_ports {vdac_clk_o}]; # VDAC_CLK +set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {vdac_blank_n}]; # VDAC_BLANK_N +set_property -dict {PACKAGE_PIN AA9 IOSTANDARD LVCMOS33} [get_ports {vdac_clk}]; # VDAC_CLK set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports {vdac_psave_n_o}]; # VDAC_PSAVE_N -set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {vdac_sync_n_o}]; # VDAC_SYNC_N +set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {vdac_sync_n}]; # VDAC_SYNC_N set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[0]}]; # B0 set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[1]}]; # B1 set_property -dict {PACKAGE_PIN AB12 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[2]}]; # B2 @@ -67,9 +67,9 @@ set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS33} [get_ports {hdmi_sda_i set_property -dict {PACKAGE_PIN AB8 IOSTANDARD LVCMOS33} [get_ports {hdmi_ls_oe_n_o}]; # LS_OE # MEGA65 Keyboard -set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {kb_io0_o}]; # KB_IO1 -set_property -dict {PACKAGE_PIN A13 IOSTANDARD LVCMOS33} [get_ports {kb_io1_o}]; # KB_IO2 -set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS33} [get_ports {kb_io2_i}]; # KB_IO3 +set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {kb_io0}]; # KB_IO1 +set_property -dict {PACKAGE_PIN A13 IOSTANDARD LVCMOS33} [get_ports {kb_io1}]; # KB_IO2 +set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS33} [get_ports {kb_io2}]; # KB_IO3 set_property -dict {PACKAGE_PIN E13 IOSTANDARD LVCMOS33} [get_ports {kb_tck_o}]; # KB_TCK set_property -dict {PACKAGE_PIN E14 IOSTANDARD LVCMOS33} [get_ports {kb_tdo_i}]; # KB_TDO set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS33} [get_ports {kb_tms_o}]; # KB_TMS @@ -126,7 +126,7 @@ set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS33} [get_ports {paddle_i[2 set_property -dict {PACKAGE_PIN J22 IOSTANDARD LVCMOS33} [get_ports {paddle_i[3]}]; # CP3 # HyperRAM. U29 = IS66WVH8M8DBLL-100B1LI -set_property -dict {PACKAGE_PIN D22 IOSTANDARD LVCMOS33} [get_ports {hr_clk_p_o}]; # H_CLK +set_property -dict {PACKAGE_PIN D22 IOSTANDARD LVCMOS33} [get_ports {hr_clk_p}]; # H_CLK set_property -dict {PACKAGE_PIN C22 IOSTANDARD LVCMOS33} [get_ports {hr_cs0}]; # CS0 set_property -dict {PACKAGE_PIN A21 IOSTANDARD LVCMOS33} [get_ports {hr_d[0]}]; # DQ0 set_property -dict {PACKAGE_PIN D21 IOSTANDARD LVCMOS33} [get_ports {hr_d[1]}]; # DQ1 @@ -136,8 +136,8 @@ set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {hr_d[4]}]; set_property -dict {PACKAGE_PIN A19 IOSTANDARD LVCMOS33} [get_ports {hr_d[5]}]; # DQ5 set_property -dict {PACKAGE_PIN E21 IOSTANDARD LVCMOS33} [get_ports {hr_d[6]}]; # DQ6 set_property -dict {PACKAGE_PIN E22 IOSTANDARD LVCMOS33} [get_ports {hr_d[7]}]; # DQ7 -set_property -dict {PACKAGE_PIN B22 IOSTANDARD LVCMOS33} [get_ports {hr_reset_o}]; # H_RES -set_property -dict {PACKAGE_PIN B21 IOSTANDARD LVCMOS33} [get_ports {hr_rwds_io}]; # RWDS +set_property -dict {PACKAGE_PIN B22 IOSTANDARD LVCMOS33} [get_ports {hr_reset}]; # H_RES +set_property -dict {PACKAGE_PIN B21 IOSTANDARD LVCMOS33} [get_ports {hr_rwds}]; # RWDS set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_reset_o}]; set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_cs0}]; set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_clk_p_o}]; diff --git a/pore/boot_message_mega65.txt b/pore/boot_message_mega65.txt index 3ce2498c..8fba060d 100644 --- a/pore/boot_message_mega65.txt +++ b/pore/boot_message_mega65.txt @@ -1,7 +1,5 @@ PORE$NEWLINE .ASCII_W "\n\n" -; PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 [WIP] [only 16 regbnks] by sy2002 in July 2020 (GIT #" - ; PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 V1.6 [BETA/WIP] by sy2002 in July 2020 (GIT #" -PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 Version 1.6 by sy2002 in September 2020 (GIT # \ No newline at end of file +PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 Version 1.6 by sy2002 - testing ... (GIT # \ No newline at end of file diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index c512484e..2c9d7099 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -410,10 +410,10 @@ begin generic map ( GD_TIL => false, -- no support for TIL leds on MEGA65 GD_SWITCHES => true, -- we emulate the switch register as described in doc/README.md - GD_HRAM => true -- support HyperRAM + GD_HRAM => false -- support HyperRAM ) port map ( - HW_RESET => not RESET_N, + HW_RESET => RESET_N, CLK => SLOW_CLOCK, -- @TODO change debouncer bitsize when going to 100 MHz addr => cpu_addr, data_dir => cpu_data_dir, From 212462740b83f09ec684a7c259917463e79fe295 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Fri, 29 Nov 2024 19:51:41 +0100 Subject: [PATCH 03/17] hram re-enabled --- vhdl/hw/MEGA65/MEGA65_R6.vhd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index 2c9d7099..5a445584 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -410,7 +410,7 @@ begin generic map ( GD_TIL => false, -- no support for TIL leds on MEGA65 GD_SWITCHES => true, -- we emulate the switch register as described in doc/README.md - GD_HRAM => false -- support HyperRAM + GD_HRAM => true -- support HyperRAM ) port map ( HW_RESET => RESET_N, From 6498232df8d5a9205fd6a0da853edd2a0cf38a21 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Mon, 2 Dec 2024 21:08:52 +0100 Subject: [PATCH 04/17] QMON starts, VGA screen appears yet auto-adjustment isn't able to catch it properly --- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 167 +++++++++---------- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 3 +- vhdl/hw/MEGA65/MEGA65_R6.vhd | 231 +++++++++++++++++++++----- 3 files changed, 279 insertions(+), 122 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc index ff7e3142..47c5d8ca 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -52,19 +52,19 @@ set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports {VGA_VS}]; # HDMI output. U10 = PTN3363BSMP # I2C address 0x40. -set_property -dict {PACKAGE_PIN Y1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_n_o}]; # TXC_N -set_property -dict {PACKAGE_PIN W1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_p_o}]; # TXC_P -set_property -dict {PACKAGE_PIN AB1 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[0]}]; # TX0_N -set_property -dict {PACKAGE_PIN AB2 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[1]}]; # TX1_N -set_property -dict {PACKAGE_PIN AB5 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[2]}]; # TX2_N -set_property -dict {PACKAGE_PIN AA1 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[0]}]; # TX0_P -set_property -dict {PACKAGE_PIN AB3 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[1]}]; # TX1_P -set_property -dict {PACKAGE_PIN AA5 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[2]}]; # TX2_P -set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {hdmi_hiz_en_o}]; # HIZ_EN -set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {hdmi_hpd_i}]; # HPD_A -set_property -dict {PACKAGE_PIN AB7 IOSTANDARD LVCMOS33} [get_ports {hdmi_scl_io}]; # SCL_A -set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS33} [get_ports {hdmi_sda_io}]; # SDA_A -set_property -dict {PACKAGE_PIN AB8 IOSTANDARD LVCMOS33} [get_ports {hdmi_ls_oe_n_o}]; # LS_OE +#set_property -dict {PACKAGE_PIN Y1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_n_o}]; # TXC_N +#set_property -dict {PACKAGE_PIN W1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_p_o}]; # TXC_P +#set_property -dict {PACKAGE_PIN AB1 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[0]}]; # TX0_N +#set_property -dict {PACKAGE_PIN AB2 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[1]}]; # TX1_N +#set_property -dict {PACKAGE_PIN AB5 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[2]}]; # TX2_N +#set_property -dict {PACKAGE_PIN AA1 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[0]}]; # TX0_P +#set_property -dict {PACKAGE_PIN AB3 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[1]}]; # TX1_P +#set_property -dict {PACKAGE_PIN AA5 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[2]}]; # TX2_P +#set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {hdmi_hiz_en_o}]; # HIZ_EN +#set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {hdmi_hpd_i}]; # HPD_A +#set_property -dict {PACKAGE_PIN AB7 IOSTANDARD LVCMOS33} [get_ports {hdmi_scl_io}]; # SCL_A +#set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS33} [get_ports {hdmi_sda_io}]; # SDA_A +#set_property -dict {PACKAGE_PIN AB8 IOSTANDARD LVCMOS33} [get_ports {hdmi_ls_oe_n_o}]; # LS_OE # MEGA65 Keyboard set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {kb_io0}]; # KB_IO1 @@ -138,11 +138,11 @@ set_property -dict {PACKAGE_PIN E21 IOSTANDARD LVCMOS33} [get_ports {hr_d[6]}]; set_property -dict {PACKAGE_PIN E22 IOSTANDARD LVCMOS33} [get_ports {hr_d[7]}]; # DQ7 set_property -dict {PACKAGE_PIN B22 IOSTANDARD LVCMOS33} [get_ports {hr_reset}]; # H_RES set_property -dict {PACKAGE_PIN B21 IOSTANDARD LVCMOS33} [get_ports {hr_rwds}]; # RWDS -set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_reset_o}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_reset}]; set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_cs0}]; -set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_clk_p_o}]; -set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_d_io[*]}]; -set_property -dict {PULLTYPE PULLDOWN SLEW FAST DRIVE 16} [get_ports {hr_rwds_io}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_clk_p}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_d[*]}]; +set_property -dict {PULLTYPE PULLDOWN SLEW FAST DRIVE 16} [get_ports {hr_rwds}]; # CBM-488/IEC serial port set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {iec_atn_n_o}]; # F_SER_ATN @@ -232,41 +232,41 @@ set_property -dict {PACKAGE_PIN M18 IOSTANDARD LVCMOS33} [get_ports {fb_down_n_ set_property -dict {PACKAGE_PIN N19 IOSTANDARD LVCMOS33} [get_ports {fb_fire_n_o}]; # DBG7 = FB_FIRE_O set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports {fb_right_n_o}]; # DBG8 = FB_RIGHT_O set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {fb_left_n_o}]; # DBG9 = FB_LEFT_O -set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports {dbg_11_io}]; # DBG11 +#set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports {dbg_11_io}]; # DBG11 # SMSC Ethernet PHY. U4 = KSZ8081RNDCA -set_property -dict {PACKAGE_PIN L4 IOSTANDARD LVCMOS33} [get_ports {eth_clock_o}]; # ETH_CLK -set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {eth_led2_o}]; # ETH_LED2 -set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports {eth_mdc_o}]; # ETH_MDC -set_property -dict {PACKAGE_PIN L5 IOSTANDARD LVCMOS33} [get_ports {eth_mdio_io}]; # ETH_MDIO -set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVCMOS33} [get_ports {eth_reset_o}]; # ETH-RST -set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[0]}]; # ETH_RX_D0 -set_property -dict {PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[1]}]; # ETH_RX_D1 -set_property -dict {PACKAGE_PIN K4 IOSTANDARD LVCMOS33} [get_ports {eth_rxdv_i}]; # ETH_CRS_DV -set_property -dict {PACKAGE_PIN M6 IOSTANDARD LVCMOS33} [get_ports {eth_rxer_i}]; # ETH_RXER -set_property -dict {PACKAGE_PIN L3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[0]}]; # ETH_TX_D0 -set_property -dict {PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[1]}]; # ETH_TX_D1 -set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {eth_txen_o}]; # ETH_TX_EN -set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txd_o[*]}]; -set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txen_o}]; -set_property -dict {SLEW FAST} [get_ports {eth_clock_o}]; +#set_property -dict {PACKAGE_PIN L4 IOSTANDARD LVCMOS33} [get_ports {eth_clock_o}]; # ETH_CLK +#set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {eth_led2_o}]; # ETH_LED2 +#set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports {eth_mdc_o}]; # ETH_MDC +#set_property -dict {PACKAGE_PIN L5 IOSTANDARD LVCMOS33} [get_ports {eth_mdio_io}]; # ETH_MDIO +#set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVCMOS33} [get_ports {eth_reset_o}]; # ETH-RST +#set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[0]}]; # ETH_RX_D0 +#set_property -dict {PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[1]}]; # ETH_RX_D1 +#set_property -dict {PACKAGE_PIN K4 IOSTANDARD LVCMOS33} [get_ports {eth_rxdv_i}]; # ETH_CRS_DV +#set_property -dict {PACKAGE_PIN M6 IOSTANDARD LVCMOS33} [get_ports {eth_rxer_i}]; # ETH_RXER +#set_property -dict {PACKAGE_PIN L3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[0]}]; # ETH_TX_D0 +#set_property -dict {PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[1]}]; # ETH_TX_D1 +#set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {eth_txen_o}]; # ETH_TX_EN +#set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txd_o[*]}]; +#set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txen_o}]; +#set_property -dict {SLEW FAST} [get_ports {eth_clock_o}]; # FDC interface -set_property -dict {PACKAGE_PIN P6 IOSTANDARD LVCMOS33} [get_ports {f_density_o}]; # F_REDWC -set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {f_diskchanged_i}]; # F_DSCKCHG -set_property -dict {PACKAGE_PIN M2 IOSTANDARD LVCMOS33} [get_ports {f_index_i}]; # F_INDEX -set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports {f_motora_o}]; # F_MOTEA -set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {f_motorb_o}]; # F_MOTEB -set_property -dict {PACKAGE_PIN P1 IOSTANDARD LVCMOS33} [get_ports {f_rdata_i}]; # F_RDATA1 -set_property -dict {PACKAGE_PIN N5 IOSTANDARD LVCMOS33} [get_ports {f_selecta_o}]; # F_DRVSA -set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {f_selectb_o}]; # F_DRVSB -set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {f_side1_o}]; # F_SIDE1 -set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {f_stepdir_o}]; # F_DIR -set_property -dict {PACKAGE_PIN M3 IOSTANDARD LVCMOS33} [get_ports {f_step_o}]; # F_STEP -set_property -dict {PACKAGE_PIN N2 IOSTANDARD LVCMOS33} [get_ports {f_track0_i}]; # F_TRCK0 -set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {f_wdata_o}]; # F_WDATE -set_property -dict {PACKAGE_PIN N3 IOSTANDARD LVCMOS33} [get_ports {f_wgate_o}]; # F_WGATE -set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {f_writeprotect_i}]; # F_WPT +#set_property -dict {PACKAGE_PIN P6 IOSTANDARD LVCMOS33} [get_ports {f_density_o}]; # F_REDWC +#set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {f_diskchanged_i}]; # F_DSCKCHG +#set_property -dict {PACKAGE_PIN M2 IOSTANDARD LVCMOS33} [get_ports {f_index_i}]; # F_INDEX +#set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports {f_motora_o}]; # F_MOTEA +#set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {f_motorb_o}]; # F_MOTEB +#set_property -dict {PACKAGE_PIN P1 IOSTANDARD LVCMOS33} [get_ports {f_rdata_i}]; # F_RDATA1 +#set_property -dict {PACKAGE_PIN N5 IOSTANDARD LVCMOS33} [get_ports {f_selecta_o}]; # F_DRVSA +#set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {f_selectb_o}]; # F_DRVSB +#set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {f_side1_o}]; # F_SIDE1 +#set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {f_stepdir_o}]; # F_DIR +#set_property -dict {PACKAGE_PIN M3 IOSTANDARD LVCMOS33} [get_ports {f_step_o}]; # F_STEP +#set_property -dict {PACKAGE_PIN N2 IOSTANDARD LVCMOS33} [get_ports {f_track0_i}]; # F_TRCK0 +#set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {f_wdata_o}]; # F_WDATE +#set_property -dict {PACKAGE_PIN N3 IOSTANDARD LVCMOS33} [get_ports {f_wgate_o}]; # F_WGATE +#set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {f_writeprotect_i}]; # F_WPT # I2C bus for on-board peripherals # U36. 24AA025E48T. Address 0x50. 2K Serial EEPROM. @@ -289,34 +289,34 @@ set_property -dict {PACKAGE_PIN U22 IOSTANDARD LVCMOS33} [get_ports {led_o}]; set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports {led_r_n_o}]; # LED_R # Pmod Header -set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[0]}]; # B16_L17_P -set_property -dict {PACKAGE_PIN E1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[1]}]; # B35_L3_P -set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[2]}]; # B35_L2_P -set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[3]}]; # B35_L1_P -set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[0]}]; # B35_L5_N -set_property -dict {PACKAGE_PIN D1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[1]}]; # B35_L3_N -set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[2]}]; # B35_L2_N -set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[3]}]; # B35_L1_N -set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[0]}]; # B35_L4_P -set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[1]}]; # B35_L4_N -set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[2]}]; # B35_L12_N -set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[3]}]; # B35_L10_P -set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[0]}]; # B35_L6_P -set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[1]}]; # B35_L6_N -set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[2]}]; # B35_L12_P -set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[3]}]; # B35_L10_N -set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {pmod1_en_o}]; # PMOD1_EN -set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {pmod1_flag_i}]; # PMOD1_FLG -set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {pmod2_en_o}]; # PMOD2_EN -set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports {pmod2_flag_i}]; # PMOD2_FLG +#set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[0]}]; # B16_L17_P +#set_property -dict {PACKAGE_PIN E1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[1]}]; # B35_L3_P +#set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[2]}]; # B35_L2_P +#set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[3]}]; # B35_L1_P +#set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[0]}]; # B35_L5_N +#set_property -dict {PACKAGE_PIN D1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[1]}]; # B35_L3_N +#set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[2]}]; # B35_L2_N +#set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[3]}]; # B35_L1_N +#set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[0]}]; # B35_L4_P +#set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[1]}]; # B35_L4_N +#set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[2]}]; # B35_L12_N +#set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[3]}]; # B35_L10_P +#set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[0]}]; # B35_L6_P +#set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[1]}]; # B35_L6_N +#set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[2]}]; # B35_L12_P +#set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[3]}]; # B35_L10_N +#set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {pmod1_en_o}]; # PMOD1_EN +#set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {pmod1_flag_i}]; # PMOD1_FLG +#set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {pmod2_en_o}]; # PMOD2_EN +#set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports {pmod2_flag_i}]; # PMOD2_FLG # Quad SPI Flash. U5 = S25FL512SAGBHIS10 -set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports {qspicsn_o}]; # SPI-CS -set_property -dict {PACKAGE_PIN P22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[0]}]; # SPI-DQ0 -set_property -dict {PACKAGE_PIN R22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[1]}]; # SPI-DQ1 -set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[2]}]; # SPI-DQ2 -set_property -dict {PACKAGE_PIN R21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[3]}]; # SPI-DQ3 -set_property -dict {PULLUP TRUE} [get_ports {qspidb_io[*]}]; +#set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports {qspicsn_o}]; # SPI-CS +#set_property -dict {PACKAGE_PIN P22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[0]}]; # SPI-DQ0 +#set_property -dict {PACKAGE_PIN R22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[1]}]; # SPI-DQ1 +#set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[2]}]; # SPI-DQ2 +#set_property -dict {PACKAGE_PIN R21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[3]}]; # SPI-DQ3 +#set_property -dict {PULLUP TRUE} [get_ports {qspidb_io[*]}]; # SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL set_property -dict {PACKAGE_PIN T4 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[0]}]; # SDRAM_A0 @@ -366,17 +366,16 @@ set_property -dict {PULLUP FALSE SLEW FAST DRIVE 16} [get_ports {sdram_*}]; ################################ # Place Keyboard close to I/O pins -create_pblock pblock_m65driver -add_cells_to_pblock pblock_m65driver [get_cells [list framework_inst/m2m_keyb_inst/mega65kbd_to_matrix_inst]] -resize_pblock pblock_m65driver -add {SLICE_X0Y225:SLICE_X7Y243} +#create_pblock pblock_m65driver +#add_cells_to_pblock pblock_m65driver [get_cells [list framework_inst/m2m_keyb_inst/mega65kbd_to_matrix_inst]] +#resize_pblock pblock_m65driver -add {SLICE_X0Y225:SLICE_X7Y243} # Place SD card controller in the middle between the left and right FPGA boundary because the output ports are at the opposide edges -create_pblock pblock_sdcard -add_cells_to_pblock pblock_sdcard [get_cells [list framework_inst/qnice_wrapper_inst/qnice_inst/sd_card]] -resize_pblock pblock_sdcard -add {SLICE_X66Y178:SLICE_X99Y193} +#create_pblock pblock_sdcard +#add_cells_to_pblock pblock_sdcard [get_cells [list framework_inst/qnice_wrapper_inst/qnice_inst/sd_card]] +#resize_pblock pblock_sdcard -add {SLICE_X66Y178:SLICE_X99Y193} # Place phase-shifted VGA output registers near the actual output buffers -create_pblock pblock_vga -add_cells_to_pblock pblock_vga [get_cells [list framework_inst/av_pipeline_inst/analog_pipeline_inst/VGA_OUT_PHASE_SHIFTED.*]] -resize_pblock pblock_vga -add SLICE_X0Y75:SLICE_X5Y99 - +#create_pblock pblock_vga +#add_cells_to_pblock pblock_vga [get_cells [list framework_inst/av_pipeline_inst/analog_pipeline_inst/VGA_OUT_PHASE_SHIFTED.*]] +#resize_pblock pblock_vga -add SLICE_X0Y75:SLICE_X5Y99 \ No newline at end of file diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index 6fa3a394..a3dac685 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -298,9 +298,10 @@ - + + diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index 5a445584..da0882ba 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -18,43 +18,200 @@ use UNISIM.VCOMPONENTS.ALL; entity MEGA65 is port ( - CLK : in std_logic; -- 100 MHz clock - RESET_N : in std_logic; -- CPU reset button - - -- serial communication (rxd, txd only; rts/cts are not available) - -- 115.200 baud, 8-N-1 - UART_RXD : in std_logic; -- receive data - UART_TXD : out std_logic; -- send data - - -- VGA - VGA_RED : out std_logic_vector(7 downto 0); - VGA_GREEN : out std_logic_vector(7 downto 0); - VGA_BLUE : out std_logic_vector(7 downto 0); - VGA_HS : out std_logic; - VGA_VS : out std_logic; - - -- VDAC - vdac_clk : out std_logic; - vdac_sync_n : out std_logic; - vdac_blank_n : out std_logic; - - -- MEGA65 smart keyboard controller - kb_io0 : out std_logic; -- clock to keyboard - kb_io1 : out std_logic; -- data output to keyboard - kb_io2 : in std_logic; -- data input from keyboard - - -- SD Card - SD_RESET : out std_logic; - SD_CLK : out std_logic; - SD_MOSI : out std_logic; - SD_MISO : in std_logic; - - -- Built-in HyperRAM - hr_d : inout unsigned(7 downto 0); -- Data/Address - hr_rwds : inout std_logic; -- RW Data strobe - hr_reset : out std_logic; -- Active low RESET line to HyperRAM - hr_clk_p : out std_logic; - hr_cs0 : out std_logic + CLK : in std_logic; -- 100 MHz clock + RESET_N : in std_logic; -- CPU reset button + + -- serial communication (rxd, txd only; rts/cts are not available) + -- 115.200 baud, 8-N-1 + UART_RXD : in std_logic; -- receive data + UART_TXD : out std_logic; -- send data + + -- VGA + VGA_RED : out std_logic_vector(7 downto 0); + VGA_GREEN : out std_logic_vector(7 downto 0); + VGA_BLUE : out std_logic_vector(7 downto 0); + VGA_HS : out std_logic; + VGA_VS : out std_logic; + + -- VDAC + vga_scl_io : inout std_logic; + vga_sda_io : inout std_logic; + vdac_clk : out std_logic; + vdac_sync_n : out std_logic; + vdac_blank_n : out std_logic; + vdac_psave_n_o : out std_logic; + + -- HDMI. U10 = PTN3363BSMP + -- I2C address 0x40 + /* + tmds_data_p_o : out std_logic_vector(2 downto 0); + tmds_data_n_o : out std_logic_vector(2 downto 0); + tmds_clk_p_o : out std_logic; + tmds_clk_n_o : out std_logic; + hdmi_hiz_en_o : out std_logic; -- Connect to U10.HIZ_EN + hdmi_ls_oe_n_o : out std_logic; -- Connect to U10.OE# + hdmi_hpd_i : in std_logic; -- Connect to U10.HPD_SOURCE + hdmi_scl_io : inout std_logic; -- Connect to U10.SCL_SOURCE + hdmi_sda_io : inout std_logic; -- Connect to U10.SDA_SOURCE + */ + + -- MEGA65 smart keyboard controller + kb_io0 : out std_logic; -- clock to keyboard + kb_io1 : out std_logic; -- data output to keyboard + kb_io2 : in std_logic; -- data input from keyboard + kb_tck_o : out std_logic; + kb_tdo_i : in std_logic; + kb_tms_o : out std_logic; + kb_tdi_o : out std_logic; + kb_jtagen_o : out std_logic; + + -- SD Card + SD_RESET : out std_logic; + SD_CLK : out std_logic; + SD_MOSI : out std_logic; + SD_MISO : in std_logic; + sd_cd_i : in std_logic; + sd_d1_i : in std_logic; + sd_d2_i : in std_logic; + + -- SD Connector (this is the slot at the bottom side of the case under the cover) + sd2_reset_o : out std_logic; + sd2_clk_o : out std_logic; + sd2_mosi_o : out std_logic; + sd2_miso_i : in std_logic; + sd2_cd_i : in std_logic; + sd2_wp_i : in std_logic; + sd2_d1_i : in std_logic; + sd2_d2_i : in std_logic; + + -- Audio DAC. U37 = AK4432VT + -- I2C address 0x19 + audio_mclk_o : out std_logic; -- Master Clock Input Pin, 12.288 MHz + audio_bick_o : out std_logic; -- Audio Serial Data Clock Pin, 3.072 MHz + audio_sdti_o : out std_logic; -- Audio Serial Data Input Pin, 16-bit LSB justified + audio_lrclk_o : out std_logic; -- Input Channel Clock Pin, 48.0 kHz + audio_pdn_n_o : out std_logic; -- Power-Down & Reset Pin + audio_i2cfil_o : out std_logic; -- I2C Interface Mode Select Pin + audio_scl_io : inout std_logic; -- Control Data Clock Input Pin + audio_sda_io : inout std_logic; -- Control Data Input/Output Pin + + -- Joysticks and Paddles + fa_up_n_i : in std_logic; + fa_down_n_i : in std_logic; + fa_left_n_i : in std_logic; + fa_right_n_i : in std_logic; + fa_fire_n_i : in std_logic; + fa_fire_n_o : out std_logic; -- 0: Drive pin low (output). 1: Leave pin floating (input) + fa_up_n_o : out std_logic; + fa_left_n_o : out std_logic; + fa_down_n_o : out std_logic; + fa_right_n_o : out std_logic; + fb_up_n_i : in std_logic; + fb_down_n_i : in std_logic; + fb_left_n_i : in std_logic; + fb_right_n_i : in std_logic; + fb_fire_n_i : in std_logic; + fb_up_n_o : out std_logic; + fb_down_n_o : out std_logic; + fb_fire_n_o : out std_logic; + fb_right_n_o : out std_logic; + fb_left_n_o : out std_logic; + + -- Joystick power supply + joystick_5v_disable_o : out std_logic; -- 1: Disable 5V power supply to joysticks + joystick_5v_powergood_i : in std_logic; + + paddle_i : in std_logic_vector(3 downto 0); + paddle_drain_o : out std_logic; + + -- Built-in HyperRAM + hr_d : inout unsigned(7 downto 0); -- Data/Address + hr_rwds : inout std_logic; -- RW Data strobe + hr_reset : out std_logic; -- Active low RESET line to HyperRAM + hr_clk_p : out std_logic; + hr_cs0 : out std_logic; + + -- I2C bus + -- U32 = PCA9655EMTTXG. Address 0x40. I/O expander. + -- U12 = MP8869SGL-Z. Address 0x61. DC/DC Converter. + -- U14 = MP8869SGL-Z. Address 0x67. DC/DC Converter. + i2c_scl_io : inout std_logic; + i2c_sda_io : inout std_logic; + + -- CBM-488/IEC serial port + iec_reset_n_o : out std_logic; + iec_atn_n_o : out std_logic; + iec_clk_en_n_o : out std_logic; + iec_clk_n_i : in std_logic; + iec_clk_n_o : out std_logic; + iec_data_en_n_o : out std_logic; + iec_data_n_i : in std_logic; + iec_data_n_o : out std_logic; + iec_srq_en_n_o : out std_logic; + iec_srq_n_i : in std_logic; + iec_srq_n_o : out std_logic; + + -- C64 Expansion Port (aka Cartridge Port) + cart_phi2_o : out std_logic; + cart_dotclock_o : out std_logic; + cart_dma_i : in std_logic; + cart_reset_oe_n_o : out std_logic; + cart_reset_io : inout std_logic; + cart_game_oe_n_o : out std_logic; + cart_game_io : inout std_logic; + cart_exrom_oe_n_o : out std_logic; + cart_exrom_io : inout std_logic; + cart_nmi_oe_n_o : out std_logic; + cart_nmi_io : inout std_logic; + cart_irq_oe_n_o : out std_logic; + cart_irq_io : inout std_logic; + cart_ctrl_en_o : out std_logic; + cart_ctrl_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_ba_io : inout std_logic; + cart_rw_io : inout std_logic; + cart_io1_io : inout std_logic; + cart_io2_io : inout std_logic; + cart_romh_oe_n_o : out std_logic; + cart_romh_io : inout std_logic; + cart_roml_oe_n_o : out std_logic; + cart_roml_io : inout std_logic; + cart_en_o : out std_logic; + cart_addr_en_o : out std_logic; + cart_haddr_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_laddr_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_a_io : inout unsigned(15 downto 0); + cart_data_en_o : out std_logic; + cart_data_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_d_io : inout unsigned(7 downto 0); + + -- I2C bus for on-board peripherals + -- U36. 24AA025E48T. Address 0x50. 2K Serial EEPROM. + -- U38. RV-3032-C7. Address 0x51. Real-Time Clock Module. + -- U39. 24LC128. Address 0x56. 128K CMOS Serial EEPROM. + fpga_sda_io : inout std_logic; + fpga_scl_io : inout std_logic; + + -- Connected to J18 + grove_sda_io : inout std_logic; + grove_scl_io : inout std_logic; + + -- On board LEDs + led_g_n_o : out std_logic; + led_r_n_o : out std_logic; + led_o : out std_logic; + + -- SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL + sdram_clk_o : out std_logic; + sdram_cke_o : out std_logic; + sdram_ras_n_o : out std_logic; + sdram_cas_n_o : out std_logic; + sdram_we_n_o : out std_logic; + sdram_cs_n_o : out std_logic; + sdram_ba_o : out std_logic_vector(1 downto 0); + sdram_a_o : out std_logic_vector(12 downto 0); + sdram_dqml_o : out std_logic; + sdram_dqmh_o : out std_logic; + sdram_dq_io : inout std_logic_vector(15 downto 0) ); end entity MEGA65; From 78f3472e46d93bfd26b118e1ea848f6df55d073e Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Tue, 3 Dec 2024 18:24:13 +0100 Subject: [PATCH 05/17] working R6 version --- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 132 +-- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 8 +- vhdl/hw/MEGA65/MEGA65_R6.vhd | 1255 +++++++++++++------------ 3 files changed, 718 insertions(+), 677 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc index 47c5d8ca..57bbd9a4 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -7,69 +7,69 @@ ################################ # Onboard crystal oscillator = 100 MHz -set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {CLK}]; # CLOCK_FPGA_MRCC +set_property -dict {PACKAGE_PIN V13 IOSTANDARD LVCMOS33} [get_ports {clk_i}]; # CLOCK_FPGA_MRCC # Reset button on the side of the machine -set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports {RESET_N}]; # RESET +set_property -dict {PACKAGE_PIN J19 IOSTANDARD LVCMOS33} [get_ports {reset_button_i}]; # RESET # USB-RS232 Interface -set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {UART_RXD}]; # DBG_UART_RX -set_property -dict {PACKAGE_PIN L13 IOSTANDARD LVCMOS33} [get_ports {UART_TXD}]; # DBG_UART_TX +set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports {uart_rxd_i}]; # DBG_UART_RX +set_property -dict {PACKAGE_PIN L13 IOSTANDARD LVCMOS33} [get_ports {uart_txd_o}]; # DBG_UART_TX # VGA via VDAC. U3 = ADV7125BCPZ170 -set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {vdac_blank_n}]; # VDAC_BLANK_N -set_property -dict {PACKAGE_PIN AA9 IOSTANDARD LVCMOS33} [get_ports {vdac_clk}]; # VDAC_CLK +set_property -dict {PACKAGE_PIN W11 IOSTANDARD LVCMOS33} [get_ports {vdac_blank_n_o}]; # VDAC_BLANK_N +set_property -dict {PACKAGE_PIN AA9 IOSTANDARD LVCMOS33} [get_ports {vdac_clk_o}]; # VDAC_CLK set_property -dict {PACKAGE_PIN W16 IOSTANDARD LVCMOS33} [get_ports {vdac_psave_n_o}]; # VDAC_PSAVE_N -set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {vdac_sync_n}]; # VDAC_SYNC_N -set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[0]}]; # B0 -set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[1]}]; # B1 -set_property -dict {PACKAGE_PIN AB12 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[2]}]; # B2 -set_property -dict {PACKAGE_PIN AA11 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[3]}]; # B3 -set_property -dict {PACKAGE_PIN AB11 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[4]}]; # B4 -set_property -dict {PACKAGE_PIN Y11 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[5]}]; # B5 -set_property -dict {PACKAGE_PIN AB10 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[6]}]; # B6 -set_property -dict {PACKAGE_PIN AA10 IOSTANDARD LVCMOS33} [get_ports {VGA_BLUE[7]}]; # B7 -set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[0]}]; # G0 -set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[1]}]; # G1 -set_property -dict {PACKAGE_PIN AA15 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[2]}]; # G2 -set_property -dict {PACKAGE_PIN AB15 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[3]}]; # G3 -set_property -dict {PACKAGE_PIN Y13 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[4]}]; # G4 -set_property -dict {PACKAGE_PIN AA14 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[5]}]; # G5 -set_property -dict {PACKAGE_PIN AA13 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[6]}]; # G6 -set_property -dict {PACKAGE_PIN AB13 IOSTANDARD LVCMOS33} [get_ports {VGA_GREEN[7]}]; # G7 -set_property -dict {PACKAGE_PIN W12 IOSTANDARD LVCMOS33} [get_ports {VGA_HS}]; # HSYNC -set_property -dict {PACKAGE_PIN U15 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[0]}]; # R0 -set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[1]}]; # R1 -set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[2]}]; # R2 -set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[3]}]; # R3 -set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[4]}]; # R4 -set_property -dict {PACKAGE_PIN AB17 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[5]}]; # R5 -set_property -dict {PACKAGE_PIN AA16 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[6]}]; # R6 -set_property -dict {PACKAGE_PIN AB16 IOSTANDARD LVCMOS33} [get_ports {VGA_RED[7]}]; # R7 +set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {vdac_sync_n_o}]; # VDAC_SYNC_N +set_property -dict {PACKAGE_PIN W10 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[0]}]; # B0 +set_property -dict {PACKAGE_PIN Y12 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[1]}]; # B1 +set_property -dict {PACKAGE_PIN AB12 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[2]}]; # B2 +set_property -dict {PACKAGE_PIN AA11 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[3]}]; # B3 +set_property -dict {PACKAGE_PIN AB11 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[4]}]; # B4 +set_property -dict {PACKAGE_PIN Y11 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[5]}]; # B5 +set_property -dict {PACKAGE_PIN AB10 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[6]}]; # B6 +set_property -dict {PACKAGE_PIN AA10 IOSTANDARD LVCMOS33} [get_ports {vga_blue_o[7]}]; # B7 +set_property -dict {PACKAGE_PIN Y14 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[0]}]; # G0 +set_property -dict {PACKAGE_PIN W14 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[1]}]; # G1 +set_property -dict {PACKAGE_PIN AA15 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[2]}]; # G2 +set_property -dict {PACKAGE_PIN AB15 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[3]}]; # G3 +set_property -dict {PACKAGE_PIN Y13 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[4]}]; # G4 +set_property -dict {PACKAGE_PIN AA14 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[5]}]; # G5 +set_property -dict {PACKAGE_PIN AA13 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[6]}]; # G6 +set_property -dict {PACKAGE_PIN AB13 IOSTANDARD LVCMOS33} [get_ports {vga_green_o[7]}]; # G7 +set_property -dict {PACKAGE_PIN W12 IOSTANDARD LVCMOS33} [get_ports {vga_hs_o}]; # HSYNC +set_property -dict {PACKAGE_PIN U15 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[0]}]; # R0 +set_property -dict {PACKAGE_PIN V15 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[1]}]; # R1 +set_property -dict {PACKAGE_PIN T14 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[2]}]; # R2 +set_property -dict {PACKAGE_PIN Y17 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[3]}]; # R3 +set_property -dict {PACKAGE_PIN Y16 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[4]}]; # R4 +set_property -dict {PACKAGE_PIN AB17 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[5]}]; # R5 +set_property -dict {PACKAGE_PIN AA16 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[6]}]; # R6 +set_property -dict {PACKAGE_PIN AB16 IOSTANDARD LVCMOS33} [get_ports {vga_red_o[7]}]; # R7 set_property -dict {PACKAGE_PIN W15 IOSTANDARD LVCMOS33} [get_ports {vga_scl_io}]; # VGA_SCL set_property -dict {PACKAGE_PIN T15 IOSTANDARD LVCMOS33} [get_ports {vga_sda_io}]; # VGA_SDA -set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports {VGA_VS}]; # VSYNC +set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports {vga_vs_o}]; # VSYNC # HDMI output. U10 = PTN3363BSMP # I2C address 0x40. -#set_property -dict {PACKAGE_PIN Y1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_n_o}]; # TXC_N -#set_property -dict {PACKAGE_PIN W1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_p_o}]; # TXC_P -#set_property -dict {PACKAGE_PIN AB1 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[0]}]; # TX0_N -#set_property -dict {PACKAGE_PIN AB2 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[1]}]; # TX1_N -#set_property -dict {PACKAGE_PIN AB5 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[2]}]; # TX2_N -#set_property -dict {PACKAGE_PIN AA1 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[0]}]; # TX0_P -#set_property -dict {PACKAGE_PIN AB3 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[1]}]; # TX1_P -#set_property -dict {PACKAGE_PIN AA5 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[2]}]; # TX2_P -#set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {hdmi_hiz_en_o}]; # HIZ_EN -#set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {hdmi_hpd_i}]; # HPD_A -#set_property -dict {PACKAGE_PIN AB7 IOSTANDARD LVCMOS33} [get_ports {hdmi_scl_io}]; # SCL_A -#set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS33} [get_ports {hdmi_sda_io}]; # SDA_A -#set_property -dict {PACKAGE_PIN AB8 IOSTANDARD LVCMOS33} [get_ports {hdmi_ls_oe_n_o}]; # LS_OE +set_property -dict {PACKAGE_PIN Y1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_n_o}]; # TXC_N +set_property -dict {PACKAGE_PIN W1 IOSTANDARD TMDS_33} [get_ports {tmds_clk_p_o}]; # TXC_P +set_property -dict {PACKAGE_PIN AB1 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[0]}]; # TX0_N +set_property -dict {PACKAGE_PIN AB2 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[1]}]; # TX1_N +set_property -dict {PACKAGE_PIN AB5 IOSTANDARD TMDS_33} [get_ports {tmds_data_n_o[2]}]; # TX2_N +set_property -dict {PACKAGE_PIN AA1 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[0]}]; # TX0_P +set_property -dict {PACKAGE_PIN AB3 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[1]}]; # TX1_P +set_property -dict {PACKAGE_PIN AA5 IOSTANDARD TMDS_33} [get_ports {tmds_data_p_o[2]}]; # TX2_P +set_property -dict {PACKAGE_PIN M15 IOSTANDARD LVCMOS33} [get_ports {hdmi_hiz_en_o}]; # HIZ_EN +set_property -dict {PACKAGE_PIN Y8 IOSTANDARD LVCMOS33} [get_ports {hdmi_hpd_i}]; # HPD_A +set_property -dict {PACKAGE_PIN AB7 IOSTANDARD LVCMOS33} [get_ports {hdmi_scl_io}]; # SCL_A +set_property -dict {PACKAGE_PIN V9 IOSTANDARD LVCMOS33} [get_ports {hdmi_sda_io}]; # SDA_A +set_property -dict {PACKAGE_PIN AB8 IOSTANDARD LVCMOS33} [get_ports {hdmi_ls_oe_n_o}]; # LS_OE # MEGA65 Keyboard -set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {kb_io0}]; # KB_IO1 -set_property -dict {PACKAGE_PIN A13 IOSTANDARD LVCMOS33} [get_ports {kb_io1}]; # KB_IO2 -set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS33} [get_ports {kb_io2}]; # KB_IO3 +set_property -dict {PACKAGE_PIN A14 IOSTANDARD LVCMOS33} [get_ports {kb_io0_o}]; # KB_IO1 +set_property -dict {PACKAGE_PIN A13 IOSTANDARD LVCMOS33} [get_ports {kb_io1_o}]; # KB_IO2 +set_property -dict {PACKAGE_PIN C13 IOSTANDARD LVCMOS33} [get_ports {kb_io2_i}]; # KB_IO3 set_property -dict {PACKAGE_PIN E13 IOSTANDARD LVCMOS33} [get_ports {kb_tck_o}]; # KB_TCK set_property -dict {PACKAGE_PIN E14 IOSTANDARD LVCMOS33} [get_ports {kb_tdo_i}]; # KB_TDO set_property -dict {PACKAGE_PIN D14 IOSTANDARD LVCMOS33} [get_ports {kb_tms_o}]; # KB_TMS @@ -126,23 +126,23 @@ set_property -dict {PACKAGE_PIN J14 IOSTANDARD LVCMOS33} [get_ports {paddle_i[2 set_property -dict {PACKAGE_PIN J22 IOSTANDARD LVCMOS33} [get_ports {paddle_i[3]}]; # CP3 # HyperRAM. U29 = IS66WVH8M8DBLL-100B1LI -set_property -dict {PACKAGE_PIN D22 IOSTANDARD LVCMOS33} [get_ports {hr_clk_p}]; # H_CLK -set_property -dict {PACKAGE_PIN C22 IOSTANDARD LVCMOS33} [get_ports {hr_cs0}]; # CS0 -set_property -dict {PACKAGE_PIN A21 IOSTANDARD LVCMOS33} [get_ports {hr_d[0]}]; # DQ0 -set_property -dict {PACKAGE_PIN D21 IOSTANDARD LVCMOS33} [get_ports {hr_d[1]}]; # DQ1 -set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {hr_d[2]}]; # DQ2 -set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {hr_d[3]}]; # DQ3 -set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {hr_d[4]}]; # DQ4 -set_property -dict {PACKAGE_PIN A19 IOSTANDARD LVCMOS33} [get_ports {hr_d[5]}]; # DQ5 -set_property -dict {PACKAGE_PIN E21 IOSTANDARD LVCMOS33} [get_ports {hr_d[6]}]; # DQ6 -set_property -dict {PACKAGE_PIN E22 IOSTANDARD LVCMOS33} [get_ports {hr_d[7]}]; # DQ7 -set_property -dict {PACKAGE_PIN B22 IOSTANDARD LVCMOS33} [get_ports {hr_reset}]; # H_RES -set_property -dict {PACKAGE_PIN B21 IOSTANDARD LVCMOS33} [get_ports {hr_rwds}]; # RWDS -set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_reset}]; -set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_cs0}]; -set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_clk_p}]; -set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_d[*]}]; -set_property -dict {PULLTYPE PULLDOWN SLEW FAST DRIVE 16} [get_ports {hr_rwds}]; +set_property -dict {PACKAGE_PIN D22 IOSTANDARD LVCMOS33} [get_ports {hr_clk_p_o}]; # H_CLK +set_property -dict {PACKAGE_PIN C22 IOSTANDARD LVCMOS33} [get_ports {hr_cs0_o}]; # CS0 +set_property -dict {PACKAGE_PIN A21 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[0]}]; # DQ0 +set_property -dict {PACKAGE_PIN D21 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[1]}]; # DQ1 +set_property -dict {PACKAGE_PIN C20 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[2]}]; # DQ2 +set_property -dict {PACKAGE_PIN A20 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[3]}]; # DQ3 +set_property -dict {PACKAGE_PIN B20 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[4]}]; # DQ4 +set_property -dict {PACKAGE_PIN A19 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[5]}]; # DQ5 +set_property -dict {PACKAGE_PIN E21 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[6]}]; # DQ6 +set_property -dict {PACKAGE_PIN E22 IOSTANDARD LVCMOS33} [get_ports {hr_d_io[7]}]; # DQ7 +set_property -dict {PACKAGE_PIN B22 IOSTANDARD LVCMOS33} [get_ports {hr_reset_o}]; # H_RES +set_property -dict {PACKAGE_PIN B21 IOSTANDARD LVCMOS33} [get_ports {hr_rwds_io}]; # RWDS +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_reset_o}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_cs0_o}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_clk_p_o}]; +set_property -dict {PULLTYPE {} SLEW FAST DRIVE 16} [get_ports {hr_d_io[*]}]; +set_property -dict {PULLTYPE PULLDOWN SLEW FAST DRIVE 16} [get_ports {hr_rwds_io}]; # CBM-488/IEC serial port set_property -dict {PACKAGE_PIN N17 IOSTANDARD LVCMOS33} [get_ports {iec_atn_n_o}]; # F_SER_ATN diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index a3dac685..1e0cd601 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -409,7 +409,9 @@ - + + Vivado Synthesis Defaults + @@ -419,7 +421,9 @@ - + + Default settings for Implementation. + diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index da0882ba..033b7b55 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -7,663 +7,700 @@ -- MEGA65 port done in April to August 2020 by sy2002 ---------------------------------------------------------------------------------- -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.NUMERIC_STD.ALL; +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; -use work.env1_globals.all; +library unisim; +use unisim.vcomponents.all; -library UNISIM; -use UNISIM.VCOMPONENTS.ALL; +use work.env1_globals.all; entity MEGA65 is -port ( - CLK : in std_logic; -- 100 MHz clock - RESET_N : in std_logic; -- CPU reset button - - -- serial communication (rxd, txd only; rts/cts are not available) - -- 115.200 baud, 8-N-1 - UART_RXD : in std_logic; -- receive data - UART_TXD : out std_logic; -- send data - - -- VGA - VGA_RED : out std_logic_vector(7 downto 0); - VGA_GREEN : out std_logic_vector(7 downto 0); - VGA_BLUE : out std_logic_vector(7 downto 0); - VGA_HS : out std_logic; - VGA_VS : out std_logic; - - -- VDAC + port ( + clk_i : in std_logic; -- Onboard crystal oscillator = 100 MHz + reset_button_i : in std_logic; -- Reset button on the side of the machine, active high + + -- USB-RS232 Interface + uart_rxd_i : in std_logic; + uart_txd_o : out std_logic; + + -- VGA via VDAC. U3 = ADV7125BCPZ170 + vga_red_o : out std_logic_vector(7 downto 0); + vga_green_o : out std_logic_vector(7 downto 0); + vga_blue_o : out std_logic_vector(7 downto 0); + vga_hs_o : out std_logic; + vga_vs_o : out std_logic; vga_scl_io : inout std_logic; - vga_sda_io : inout std_logic; - vdac_clk : out std_logic; - vdac_sync_n : out std_logic; - vdac_blank_n : out std_logic; + vga_sda_io : inout std_logic; + vdac_clk_o : out std_logic; + vdac_sync_n_o : out std_logic; + vdac_blank_n_o : out std_logic; vdac_psave_n_o : out std_logic; -- HDMI. U10 = PTN3363BSMP -- I2C address 0x40 - /* - tmds_data_p_o : out std_logic_vector(2 downto 0); - tmds_data_n_o : out std_logic_vector(2 downto 0); - tmds_clk_p_o : out std_logic; - tmds_clk_n_o : out std_logic; - hdmi_hiz_en_o : out std_logic; -- Connect to U10.HIZ_EN - hdmi_ls_oe_n_o : out std_logic; -- Connect to U10.OE# - hdmi_hpd_i : in std_logic; -- Connect to U10.HPD_SOURCE - hdmi_scl_io : inout std_logic; -- Connect to U10.SCL_SOURCE - hdmi_sda_io : inout std_logic; -- Connect to U10.SDA_SOURCE - */ + + tmds_data_p_o : out std_logic_vector(2 downto 0); + tmds_data_n_o : out std_logic_vector(2 downto 0); + tmds_clk_p_o : out std_logic; + tmds_clk_n_o : out std_logic; + hdmi_hiz_en_o : out std_logic; -- Connect to U10.HIZ_EN + hdmi_ls_oe_n_o : out std_logic; -- Connect to U10.OE# + hdmi_hpd_i : in std_logic; -- Connect to U10.HPD_SOURCE + hdmi_scl_io : inout std_logic; -- Connect to U10.SCL_SOURCE + hdmi_sda_io : inout std_logic; -- Connect to U10.SDA_SOURCE -- MEGA65 smart keyboard controller - kb_io0 : out std_logic; -- clock to keyboard - kb_io1 : out std_logic; -- data output to keyboard - kb_io2 : in std_logic; -- data input from keyboard - kb_tck_o : out std_logic; - kb_tdo_i : in std_logic; - kb_tms_o : out std_logic; - kb_tdi_o : out std_logic; - kb_jtagen_o : out std_logic; - + kb_io0_o : out std_logic; -- clock to keyboard + kb_io1_o : out std_logic; -- data output to keyboard + kb_io2_i : in std_logic; -- data input from keyboard + kb_tck_o : out std_logic; + kb_tdo_i : in std_logic; + kb_tms_o : out std_logic; + kb_tdi_o : out std_logic; + kb_jtagen_o : out std_logic; + -- SD Card - SD_RESET : out std_logic; - SD_CLK : out std_logic; - SD_MOSI : out std_logic; - SD_MISO : in std_logic; - sd_cd_i : in std_logic; - sd_d1_i : in std_logic; - sd_d2_i : in std_logic; - + SD_RESET : out std_logic; + SD_CLK : out std_logic; + SD_MOSI : out std_logic; + SD_MISO : in std_logic; + sd_cd_i : in std_logic; + sd_d1_i : in std_logic; + sd_d2_i : in std_logic; + -- SD Connector (this is the slot at the bottom side of the case under the cover) - sd2_reset_o : out std_logic; - sd2_clk_o : out std_logic; - sd2_mosi_o : out std_logic; - sd2_miso_i : in std_logic; - sd2_cd_i : in std_logic; - sd2_wp_i : in std_logic; - sd2_d1_i : in std_logic; - sd2_d2_i : in std_logic; - + sd2_reset_o : out std_logic; + sd2_clk_o : out std_logic; + sd2_mosi_o : out std_logic; + sd2_miso_i : in std_logic; + sd2_cd_i : in std_logic; + sd2_wp_i : in std_logic; + sd2_d1_i : in std_logic; + sd2_d2_i : in std_logic; + -- Audio DAC. U37 = AK4432VT -- I2C address 0x19 - audio_mclk_o : out std_logic; -- Master Clock Input Pin, 12.288 MHz - audio_bick_o : out std_logic; -- Audio Serial Data Clock Pin, 3.072 MHz - audio_sdti_o : out std_logic; -- Audio Serial Data Input Pin, 16-bit LSB justified - audio_lrclk_o : out std_logic; -- Input Channel Clock Pin, 48.0 kHz - audio_pdn_n_o : out std_logic; -- Power-Down & Reset Pin - audio_i2cfil_o : out std_logic; -- I2C Interface Mode Select Pin - audio_scl_io : inout std_logic; -- Control Data Clock Input Pin - audio_sda_io : inout std_logic; -- Control Data Input/Output Pin - + audio_mclk_o : out std_logic; -- Master Clock Input Pin, 12.288 MHz + audio_bick_o : out std_logic; -- Audio Serial Data Clock Pin, 3.072 MHz + audio_sdti_o : out std_logic; -- Audio Serial Data Input Pin, 16-bit LSB justified + audio_lrclk_o : out std_logic; -- Input Channel Clock Pin, 48.0 kHz + audio_pdn_n_o : out std_logic; -- Power-Down & Reset Pin + audio_i2cfil_o : out std_logic; -- I2C Interface Mode Select Pin + audio_scl_io : inout std_logic; -- Control Data Clock Input Pin + audio_sda_io : inout std_logic; -- Control Data Input/Output Pin + -- Joysticks and Paddles - fa_up_n_i : in std_logic; - fa_down_n_i : in std_logic; - fa_left_n_i : in std_logic; - fa_right_n_i : in std_logic; - fa_fire_n_i : in std_logic; - fa_fire_n_o : out std_logic; -- 0: Drive pin low (output). 1: Leave pin floating (input) - fa_up_n_o : out std_logic; - fa_left_n_o : out std_logic; - fa_down_n_o : out std_logic; - fa_right_n_o : out std_logic; - fb_up_n_i : in std_logic; - fb_down_n_i : in std_logic; - fb_left_n_i : in std_logic; - fb_right_n_i : in std_logic; - fb_fire_n_i : in std_logic; - fb_up_n_o : out std_logic; - fb_down_n_o : out std_logic; - fb_fire_n_o : out std_logic; - fb_right_n_o : out std_logic; - fb_left_n_o : out std_logic; - + fa_up_n_i : in std_logic; + fa_down_n_i : in std_logic; + fa_left_n_i : in std_logic; + fa_right_n_i : in std_logic; + fa_fire_n_i : in std_logic; + fa_fire_n_o : out std_logic; -- 0: Drive pin low (output). 1: Leave pin floating (input) + fa_up_n_o : out std_logic; + fa_left_n_o : out std_logic; + fa_down_n_o : out std_logic; + fa_right_n_o : out std_logic; + fb_up_n_i : in std_logic; + fb_down_n_i : in std_logic; + fb_left_n_i : in std_logic; + fb_right_n_i : in std_logic; + fb_fire_n_i : in std_logic; + fb_up_n_o : out std_logic; + fb_down_n_o : out std_logic; + fb_fire_n_o : out std_logic; + fb_right_n_o : out std_logic; + fb_left_n_o : out std_logic; + -- Joystick power supply - joystick_5v_disable_o : out std_logic; -- 1: Disable 5V power supply to joysticks - joystick_5v_powergood_i : in std_logic; - - paddle_i : in std_logic_vector(3 downto 0); - paddle_drain_o : out std_logic; - - -- Built-in HyperRAM - hr_d : inout unsigned(7 downto 0); -- Data/Address - hr_rwds : inout std_logic; -- RW Data strobe - hr_reset : out std_logic; -- Active low RESET line to HyperRAM - hr_clk_p : out std_logic; - hr_cs0 : out std_logic; - + joystick_5v_disable_o : out std_logic; -- 1: Disable 5V power supply to joysticks + joystick_5v_powergood_i : in std_logic; + + paddle_i : in std_logic_vector(3 downto 0); + paddle_drain_o : out std_logic; + + -- HyperRAM. U29 = IS66WVH8M8DBLL-100B1LI + hr_d_io : inout unsigned(7 downto 0); -- Data/Address + hr_rwds_io : inout std_logic; -- RW Data strobe + hr_reset_o : out std_logic; -- Active low RESET line to HyperRAM + hr_clk_p_o : out std_logic; + hr_cs0_o : out std_logic; + -- I2C bus -- U32 = PCA9655EMTTXG. Address 0x40. I/O expander. -- U12 = MP8869SGL-Z. Address 0x61. DC/DC Converter. -- U14 = MP8869SGL-Z. Address 0x67. DC/DC Converter. - i2c_scl_io : inout std_logic; - i2c_sda_io : inout std_logic; - + i2c_scl_io : inout std_logic; + i2c_sda_io : inout std_logic; + -- CBM-488/IEC serial port - iec_reset_n_o : out std_logic; - iec_atn_n_o : out std_logic; - iec_clk_en_n_o : out std_logic; - iec_clk_n_i : in std_logic; - iec_clk_n_o : out std_logic; - iec_data_en_n_o : out std_logic; - iec_data_n_i : in std_logic; - iec_data_n_o : out std_logic; - iec_srq_en_n_o : out std_logic; - iec_srq_n_i : in std_logic; - iec_srq_n_o : out std_logic; + iec_reset_n_o : out std_logic; + iec_atn_n_o : out std_logic; + iec_clk_en_n_o : out std_logic; + iec_clk_n_i : in std_logic; + iec_clk_n_o : out std_logic; + iec_data_en_n_o : out std_logic; + iec_data_n_i : in std_logic; + iec_data_n_o : out std_logic; + iec_srq_en_n_o : out std_logic; + iec_srq_n_i : in std_logic; + iec_srq_n_o : out std_logic; -- C64 Expansion Port (aka Cartridge Port) - cart_phi2_o : out std_logic; - cart_dotclock_o : out std_logic; - cart_dma_i : in std_logic; - cart_reset_oe_n_o : out std_logic; - cart_reset_io : inout std_logic; - cart_game_oe_n_o : out std_logic; - cart_game_io : inout std_logic; - cart_exrom_oe_n_o : out std_logic; - cart_exrom_io : inout std_logic; - cart_nmi_oe_n_o : out std_logic; - cart_nmi_io : inout std_logic; - cart_irq_oe_n_o : out std_logic; - cart_irq_io : inout std_logic; - cart_ctrl_en_o : out std_logic; - cart_ctrl_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA - cart_ba_io : inout std_logic; - cart_rw_io : inout std_logic; - cart_io1_io : inout std_logic; - cart_io2_io : inout std_logic; - cart_romh_oe_n_o : out std_logic; - cart_romh_io : inout std_logic; - cart_roml_oe_n_o : out std_logic; - cart_roml_io : inout std_logic; - cart_en_o : out std_logic; - cart_addr_en_o : out std_logic; - cart_haddr_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA - cart_laddr_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA - cart_a_io : inout unsigned(15 downto 0); - cart_data_en_o : out std_logic; - cart_data_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA - cart_d_io : inout unsigned(7 downto 0); - + cart_phi2_o : out std_logic; + cart_dotclock_o : out std_logic; + cart_dma_i : in std_logic; + cart_reset_oe_n_o : out std_logic; + cart_reset_io : inout std_logic; + cart_game_oe_n_o : out std_logic; + cart_game_io : inout std_logic; + cart_exrom_oe_n_o : out std_logic; + cart_exrom_io : inout std_logic; + cart_nmi_oe_n_o : out std_logic; + cart_nmi_io : inout std_logic; + cart_irq_oe_n_o : out std_logic; + cart_irq_io : inout std_logic; + cart_ctrl_en_o : out std_logic; + cart_ctrl_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_ba_io : inout std_logic; + cart_rw_io : inout std_logic; + cart_io1_io : inout std_logic; + cart_io2_io : inout std_logic; + cart_romh_oe_n_o : out std_logic; + cart_romh_io : inout std_logic; + cart_roml_oe_n_o : out std_logic; + cart_roml_io : inout std_logic; + cart_en_o : out std_logic; + cart_addr_en_o : out std_logic; + cart_haddr_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_laddr_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_a_io : inout unsigned(15 downto 0); + cart_data_en_o : out std_logic; + cart_data_dir_o : out std_logic; -- =1 means FPGA->Port, =0 means Port->FPGA + cart_d_io : inout unsigned(7 downto 0); + -- I2C bus for on-board peripherals -- U36. 24AA025E48T. Address 0x50. 2K Serial EEPROM. -- U38. RV-3032-C7. Address 0x51. Real-Time Clock Module. -- U39. 24LC128. Address 0x56. 128K CMOS Serial EEPROM. - fpga_sda_io : inout std_logic; - fpga_scl_io : inout std_logic; - + fpga_sda_io : inout std_logic; + fpga_scl_io : inout std_logic; + -- Connected to J18 - grove_sda_io : inout std_logic; - grove_scl_io : inout std_logic; - + grove_sda_io : inout std_logic; + grove_scl_io : inout std_logic; + -- On board LEDs - led_g_n_o : out std_logic; - led_r_n_o : out std_logic; - led_o : out std_logic; - - -- SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL - sdram_clk_o : out std_logic; - sdram_cke_o : out std_logic; - sdram_ras_n_o : out std_logic; - sdram_cas_n_o : out std_logic; - sdram_we_n_o : out std_logic; - sdram_cs_n_o : out std_logic; - sdram_ba_o : out std_logic_vector(1 downto 0); - sdram_a_o : out std_logic_vector(12 downto 0); - sdram_dqml_o : out std_logic; - sdram_dqmh_o : out std_logic; - sdram_dq_io : inout std_logic_vector(15 downto 0) -); + led_g_n_o : out std_logic; + led_r_n_o : out std_logic; + led_o : out std_logic; + + -- SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL + sdram_clk_o : out std_logic; + sdram_cke_o : out std_logic; + sdram_ras_n_o : out std_logic; + sdram_cas_n_o : out std_logic; + sdram_we_n_o : out std_logic; + sdram_cs_n_o : out std_logic; + sdram_ba_o : out std_logic_vector(1 downto 0); + sdram_a_o : out std_logic_vector(12 downto 0); + sdram_dqml_o : out std_logic; + sdram_dqmh_o : out std_logic; + sdram_dq_io : inout std_logic_vector(15 downto 0) + ); end entity MEGA65; architecture beh of MEGA65 is --- CPU control signals -signal cpu_addr : std_logic_vector(15 downto 0); -signal cpu_data_in : std_logic_vector(15 downto 0); -signal cpu_data_out : std_logic_vector(15 downto 0); -signal cpu_data_dir : std_logic; -signal cpu_data_valid : std_logic; -signal cpu_wait_for_data : std_logic; -signal cpu_halt : std_logic; -signal cpu_ins_cnt_strobe : std_logic; -signal cpu_int_n : std_logic; -signal cpu_igrant_n : std_logic; - --- MMIO control signals -signal rom_enable : std_logic; -signal rom_busy : std_logic; -signal rom_data_out : std_logic_vector(15 downto 0); -signal ram_enable : std_logic; -signal ram_busy : std_logic; -signal ram_data_out : std_logic_vector(15 downto 0); -signal pore_rom_enable : std_logic; -signal pore_rom_busy : std_logic; -signal pore_rom_data_out : std_logic_vector(15 downto 0); -signal til_reg0_enable : std_logic; -signal til_reg1_enable : std_logic; -signal switch_reg_enable : std_logic; -signal switch_data_out : std_logic_vector(15 downto 0); -signal kbd_en : std_logic; -signal kbd_we : std_logic; -signal kbd_reg : std_logic_vector(1 downto 0); -signal kbd_data_out : std_logic_vector(15 downto 0); -signal tin_en : std_logic; -signal tin_we : std_logic; -signal tin_reg : std_logic_vector(2 downto 0); -signal timer_data_out : std_logic_vector(15 downto 0); -signal vga_en : std_logic; -signal vga_we : std_logic; -signal vga_reg : std_logic_vector(3 downto 0); -signal vga_data_out : std_logic_vector(15 downto 0); -signal uart_en : std_logic; -signal uart_we : std_logic; -signal uart_reg : std_logic_vector(1 downto 0); -signal uart_data_out : std_logic_vector(15 downto 0); -signal uart_cpu_ws : std_logic; -signal cyc_en : std_logic; -signal cyc_we : std_logic; -signal cyc_reg : std_logic_vector(1 downto 0); -signal cyc_data_out : std_logic_vector(15 downto 0); -signal ins_en : std_logic; -signal ins_we : std_logic; -signal ins_reg : std_logic_vector(1 downto 0); -signal ins_data_out : std_logic_vector(15 downto 0); -signal eae_en : std_logic; -signal eae_we : std_logic; -signal eae_reg : std_logic_vector(2 downto 0); -signal eae_data_out : std_logic_vector(15 downto 0); -signal sd_en : std_logic; -signal sd_we : std_logic; -signal sd_reg : std_logic_vector(2 downto 0); -signal sd_data_out : std_logic_vector(15 downto 0); -signal hram_en : std_logic; -signal hram_we : std_logic; -signal hram_reg : std_logic_vector(3 downto 0); -signal hram_data_out : std_logic_vector(15 downto 0); -signal hram_cpu_ws : std_logic; - -signal reset_pre_pore : std_logic; -signal reset_post_pore : std_logic; - --- VGA control signals -signal vga_r : std_logic; -signal vga_g : std_logic; -signal vga_b : std_logic; -signal vga_hsync : std_logic; -signal vga_vsync : std_logic; - --- 50 MHz as long as we did not solve the timing issues of the register file -signal SLOW_CLOCK : std_logic := '0'; - --- Pixelclock and fast clock for HRAM -signal CLK1x : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase -signal CLK2x : std_logic; -- 4x SLOW_CLOCK = 200 MHz -signal clk25MHz : std_logic; -- 25.175 MHz pixelclock for 640x480 @ 60 Hz -signal pll_locked_main : std_logic; -signal clk_fb_main : std_logic; - --- combined pre- and post pore reset -signal reset_ctl : std_logic; - --- enable displaying of address bus on system halt, if switch 2 is on -signal i_til_reg0_enable : std_logic; -signal i_til_data_in : std_logic_vector(15 downto 0); - --- emulate the switches on the Nexys4 dev board to toggle VGA and PS/2 -signal SWITCHES : std_logic_vector(15 downto 0); + -- CPU control signals + signal cpu_addr : std_logic_vector(15 downto 0); + signal cpu_data_in : std_logic_vector(15 downto 0); + signal cpu_data_out : std_logic_vector(15 downto 0); + signal cpu_data_dir : std_logic; + signal cpu_data_valid : std_logic; + signal cpu_wait_for_data : std_logic; + signal cpu_halt : std_logic; + signal cpu_ins_cnt_strobe : std_logic; + signal cpu_int_n : std_logic; + signal cpu_igrant_n : std_logic; + + -- MMIO control signals + signal rom_enable : std_logic; + signal rom_busy : std_logic; + signal rom_data_out : std_logic_vector(15 downto 0); + signal ram_enable : std_logic; + signal ram_busy : std_logic; + signal ram_data_out : std_logic_vector(15 downto 0); + signal pore_rom_enable : std_logic; + signal pore_rom_busy : std_logic; + signal pore_rom_data_out : std_logic_vector(15 downto 0); + signal til_reg0_enable : std_logic; + signal til_reg1_enable : std_logic; + signal switch_reg_enable : std_logic; + signal switch_data_out : std_logic_vector(15 downto 0); + signal kbd_en : std_logic; + signal kbd_we : std_logic; + signal kbd_reg : std_logic_vector(1 downto 0); + signal kbd_data_out : std_logic_vector(15 downto 0); + signal tin_en : std_logic; + signal tin_we : std_logic; + signal tin_reg : std_logic_vector(2 downto 0); + signal timer_data_out : std_logic_vector(15 downto 0); + signal vga_en : std_logic; + signal vga_we : std_logic; + signal vga_reg : std_logic_vector(3 downto 0); + signal vga_data_out : std_logic_vector(15 downto 0); + signal uart_en : std_logic; + signal uart_we : std_logic; + signal uart_reg : std_logic_vector(1 downto 0); + signal uart_data_out : std_logic_vector(15 downto 0); + signal uart_cpu_ws : std_logic; + signal cyc_en : std_logic; + signal cyc_we : std_logic; + signal cyc_reg : std_logic_vector(1 downto 0); + signal cyc_data_out : std_logic_vector(15 downto 0); + signal ins_en : std_logic; + signal ins_we : std_logic; + signal ins_reg : std_logic_vector(1 downto 0); + signal ins_data_out : std_logic_vector(15 downto 0); + signal eae_en : std_logic; + signal eae_we : std_logic; + signal eae_reg : std_logic_vector(2 downto 0); + signal eae_data_out : std_logic_vector(15 downto 0); + signal sd_en : std_logic; + signal sd_we : std_logic; + signal sd_reg : std_logic_vector(2 downto 0); + signal sd_data_out : std_logic_vector(15 downto 0); + signal hram_en : std_logic; + signal hram_we : std_logic; + signal hram_reg : std_logic_vector(3 downto 0); + signal hram_data_out : std_logic_vector(15 downto 0); + signal hram_cpu_ws : std_logic; + + signal reset_pre_pore : std_logic; + signal reset_post_pore : std_logic; + + -- VGA control signals + signal vga_r : std_logic; + signal vga_g : std_logic; + signal vga_b : std_logic; + signal vga_hsync : std_logic; + signal vga_vsync : std_logic; + + -- 50 MHz as long as we did not solve the timing issues of the register file + signal SLOW_CLOCK : std_logic := '0'; + + -- Pixelclock and fast clock for HRAM + signal CLK1x : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase + signal CLK2x : std_logic; -- 4x SLOW_CLOCK = 200 MHz + signal clk25MHz : std_logic; -- 25.175 MHz pixelclock for 640x480 @ 60 Hz + signal pll_locked_main : std_logic; + signal clk_fb_main : std_logic; + + -- combined pre- and post pore reset + signal reset_ctl : std_logic; + + -- enable displaying of address bus on system halt, if switch 2 is on + signal i_til_reg0_enable : std_logic; + signal i_til_data_in : std_logic_vector(15 downto 0); + + -- emulate the switches on the Nexys4 dev board to toggle VGA and PS/2 + signal SWITCHES : std_logic_vector(15 downto 0); begin - -- Merge data outputs from all devices into a single data input to the CPU. - -- This requires that all devices output 0's when not selected. - cpu_data_in <= pore_rom_data_out or - rom_data_out or - ram_data_out or - switch_data_out or - kbd_data_out or - vga_data_out or - uart_data_out or - timer_data_out or - cyc_data_out or - ins_data_out or - eae_data_out or - sd_data_out or - hram_data_out; - - clk_main: mmcme2_base + -- Merge data outputs from all devices into a single data input to the CPU. + -- This requires that all devices output 0's when not selected. + cpu_data_in <= pore_rom_data_out or + rom_data_out or + ram_data_out or + switch_data_out or + kbd_data_out or + vga_data_out or + uart_data_out or + timer_data_out or + cyc_data_out or + ins_data_out or + eae_data_out or + sd_data_out or + hram_data_out; + + -- Due to a bug in the R5/R6 boards, the cartridge port needs to be enabled for joystick port 2 to work + cart_en_o <= '1'; + + -- dummy HDMI differential output + + hdmi_hiz_en_o <= 'L'; + hdmi_ls_oe_n_o <= 'H'; + hdmi_scl_io <= 'Z'; + hdmi_sda_io <= 'Z'; + + tmds_data_obufds : for i in 0 to 2 generate + begin + tmds_data_obufds_bit : obufds + port map ( + i => 'L', + o => tmds_data_p_o(i), + ob => tmds_data_n_o(i) + ); + end generate tmds_data_obufds; + + tmds_clk_obufds : obufds + port map ( + i => 'L', + o => tmds_clk_p_o, + ob => tmds_clk_n_o + ); + + clk_main : mmcme2_base generic map ( - clkin1_period => 10.0, -- 100 MHz (10 ns) - clkfbout_mult_f => 8.0, -- 800 MHz common multiply - divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range - clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but actual value is 25.197 MHz - clkout1_divide => 8, -- 100 MHz /8 - clkout2_divide => 16, -- 50 MHz /16 - clkout3_divide => 4 -- 200 MHz /4 + clkin1_period => 10.0, -- 100 MHz (10 ns) + clkfbout_mult_f => 8.0, -- 800 MHz common multiply + divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range + clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but actual value is 25.197 MHz + clkout1_divide => 8, -- 100 MHz /8 + clkout2_divide => 16, -- 50 MHz /16 + clkout3_divide => 4 -- 200 MHz /4 ) port map ( pwrdwn => '0', rst => '0', - clkin1 => CLK, + clkin1 => clk_i, clkfbin => clk_fb_main, clkfbout => clk_fb_main, - clkout0 => clk25MHz, -- pixelclock - clkout1 => CLK1x, -- 100 MHz - clkout2 => SLOW_CLOCK, -- 50 MHz - clkout3 => CLK2x, -- 200 MHz + clkout0 => clk25MHz, -- pixelclock + clkout1 => CLK1x, -- 100 MHz + clkout2 => SLOW_CLOCK, -- 50 MHz + clkout3 => CLK2x, -- 200 MHz locked => pll_locked_main ); - -- QNICE CPU - cpu : entity work.QNICE_CPU - port map ( - CLK => SLOW_CLOCK, - RESET => reset_ctl, - WAIT_FOR_DATA => cpu_wait_for_data, - ADDR => cpu_addr, - DATA_IN => cpu_data_in, - DATA_OUT => cpu_data_out, - DATA_DIR => cpu_data_dir, - DATA_VALID => cpu_data_valid, - HALT => cpu_halt, - INS_CNT_STROBE => cpu_ins_cnt_strobe, - INT_N => cpu_int_n, - IGRANT_N => cpu_igrant_n - ); - - -- ROM: up to 64kB consisting of up to 32.000 16 bit words - rom : entity work.BROM - generic map ( - FILE_NAME => ROM_FILE - ) - port map ( - clk => SLOW_CLOCK, - ce => rom_enable, - address => cpu_addr(14 downto 0), - data => rom_data_out, - busy => rom_busy - ); - - -- RAM: up to 64kB consisting of up to 32.000 16 bit words - ram : entity work.BRAM - port map ( - clk => SLOW_CLOCK, - ce => ram_enable, - address => cpu_addr(14 downto 0), - we => cpu_data_dir, - data_i => cpu_data_out, - data_o => ram_data_out, - busy => ram_busy - ); - - -- PORE ROM: Power On & Reset Execution ROM - -- contains code that is executed during power on and/or during reset - -- MMIO is managing the PORE process - pore_rom : entity work.BROM - generic map ( - FILE_NAME => PORE_ROM_FILE - ) - port map ( - clk => SLOW_CLOCK, - ce => pore_rom_enable, - address => cpu_addr(14 downto 0), - data => pore_rom_data_out, - busy => pore_rom_busy - ); - - -- VGA: 80x40 textmode VGA adaptor - vga_screen : entity work.vga_textmode - port map ( - reset => reset_ctl, - clk25MHz => clk25MHz, - clk50MHz => SLOW_CLOCK, - R => vga_r, - G => vga_g, - B => vga_b, - hsync => vga_hsync, - vsync => vga_vsync, - hdmi_de => open, - en => vga_en, - we => vga_we, - reg => vga_reg, - data_in => cpu_data_out, - data_out => vga_data_out - ); - - -- special UART with FIFO that can be directly connected to the CPU bus - uart : entity work.bus_uart - generic map ( - DIVISOR => UART_DIVISOR - ) - port map ( - clk => SLOW_CLOCK, - reset => reset_ctl, - rx => UART_RXD, - tx => UART_TXD, - rts => '0', - cts => open, - uart_en => uart_en, - uart_we => uart_we, - uart_reg => uart_reg, - uart_cpu_ws => uart_cpu_ws, - cpu_data_in => cpu_data_out, - cpu_data_out => uart_data_out - ); - - -- MEGA65 keyboard - kbd : entity work.keyboard - generic map ( - clk_freq => 50000000 - ) - port map ( - clk => SLOW_CLOCK, - reset => reset_ctl, - kb_io0 => kb_io0, - kb_io1 => kb_io1, - kb_io2 => kb_io2, - kbd_en => kbd_en, - kbd_we => kbd_we, - kbd_reg => kbd_reg, - cpu_data_in => cpu_data_out, - cpu_data_out => kbd_data_out, - stdinout => SWITCHES(1 downto 0) - ); - - timer_interrupt : entity work.timer_module - generic map ( - CLK_FREQ => 50000000 - ) - port map ( - clk => SLOW_CLOCK, - reset => reset_ctl, - int_n_out => cpu_int_n, - grant_n_in => cpu_igrant_n, - int_n_in => '1', -- no more devices to in Daisy Chain: 1=no interrupt - grant_n_out => open, -- ditto: open=grant goes nowhere - en => tin_en, - we => tin_we, - reg => tin_reg, - data_in => cpu_data_out, - data_out => timer_data_out - ); - - -- cycle counter - cyc : entity work.cycle_counter - port map ( - clk => SLOW_CLOCK, - impulse => '1', - reset => reset_ctl, - en => cyc_en, - we => cyc_we, - reg => cyc_reg, - data_in => cpu_data_out, - data_out => cyc_data_out - ); - - -- instruction counter - ins : entity work.cycle_counter - port map ( - clk => SLOW_CLOCK, - impulse => cpu_ins_cnt_strobe, - reset => reset_ctl, - en => ins_en, - we => ins_we, - reg => ins_reg, - data_in => cpu_data_out, - data_out => ins_data_out - ); - - -- EAE - Extended Arithmetic Element (32-bit multiplication, division, modulo) - eae_inst : entity work.eae - port map ( - clk => SLOW_CLOCK, - reset => reset_ctl, - en => eae_en, - we => eae_we, - reg => eae_reg, - data_in => cpu_data_out, - data_out => eae_data_out - ); - - -- SD Card - sd_card : entity work.sdcard - port map ( - clk => SLOW_CLOCK, - reset => reset_ctl, - en => sd_en, - we => sd_we, - reg => sd_reg, - data_in => cpu_data_out, - data_out => sd_data_out, - sd_reset => SD_RESET, - sd_clk => SD_CLK, - sd_mosi => SD_MOSI, - sd_miso => SD_MISO - ); - - -- HyperRAM - HRAM : entity work.hyperram_ctl - port map ( - clk => SLOW_CLOCK, - clk2x => CLK1x, - clk4x => CLK2x, - reset => reset_ctl, - hram_en => hram_en, - hram_we => hram_we, - hram_reg => hram_reg, - hram_cpu_ws => hram_cpu_ws, - data_in => cpu_data_out, - data_out => hram_data_out, - hr_d => hr_d, - hr_rwds => hr_rwds, - hr_reset => hr_reset, - hr_clk_p => hr_clk_p, - hr_cs0 => hr_cs0 - ); - - -- memory mapped i/o controller - mmio_controller : entity work.mmio_mux - generic map ( - GD_TIL => false, -- no support for TIL leds on MEGA65 - GD_SWITCHES => true, -- we emulate the switch register as described in doc/README.md - GD_HRAM => true -- support HyperRAM - ) - port map ( - HW_RESET => RESET_N, - CLK => SLOW_CLOCK, -- @TODO change debouncer bitsize when going to 100 MHz - addr => cpu_addr, - data_dir => cpu_data_dir, - data_valid => cpu_data_valid, - cpu_wait_for_data => cpu_wait_for_data, - cpu_halt => cpu_halt, - cpu_igrant_n => cpu_igrant_n, - rom_enable => rom_enable, - rom_busy => rom_busy, - ram_enable => ram_enable, - ram_busy => ram_busy, - pore_rom_enable => pore_rom_enable, - pore_rom_busy => pore_rom_busy, - switch_reg_enable => switch_reg_enable, - kbd_en => kbd_en, - kbd_we => kbd_we, - kbd_reg => kbd_reg, - tin_en => tin_en, - tin_we => tin_we, - tin_reg => tin_reg, - vga_en => vga_en, - vga_we => vga_we, - vga_reg => vga_reg, - uart_en => uart_en, - uart_we => uart_we, - uart_reg => uart_reg, - uart_cpu_ws => uart_cpu_ws, - cyc_en => cyc_en, - cyc_we => cyc_we, - cyc_reg => cyc_reg, - ins_en => ins_en, - ins_we => ins_we, - ins_reg => ins_reg, - eae_en => eae_en, - eae_we => eae_we, - eae_reg => eae_reg, - sd_en => sd_en, - sd_we => sd_we, - sd_reg => sd_reg, - hram_en => hram_en, - hram_we => hram_we, - hram_reg => hram_reg, - hram_cpu_ws => hram_cpu_ws, - - -- no TIL leds on the MEGA65 , - til_reg0_enable => open, - til_reg1_enable => open, - - reset_pre_pore => reset_pre_pore, - reset_post_pore => reset_post_pore - ); - - -- emulate the toggle switches as described in doc/README.md - switch_driver : process(switch_reg_enable, SWITCHES) - begin - if switch_reg_enable = '1' then - switch_data_out <= SWITCHES; - else - switch_data_out <= (others => '0'); - end if; - end process; - - video_signal_latches : process(clk25MHz) - begin - if rising_edge(clk25MHz) then - -- VGA: wire the simplified color system of the VGA component to the VGA outputs - VGA_RED <= vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r; - VGA_GREEN <= vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g; - VGA_BLUE <= vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b; - - -- VGA horizontal and vertical sync - VGA_HS <= vga_hsync; - VGA_VS <= vga_vsync; - end if; - end process; - - -- make the VDAC output the image - vdac_sync_n <= '0'; - vdac_blank_n <= '1'; - - -- Fix of the Vivado induced "blurry VGA screen": - -- As of the time writing this (June 2020): it is absolutely unclear for me, why I need to - -- invert the phase of the vdac_clk when use Vivado 2019.2. When using ISE 14.7, it works - -- fine without the phase shift. - vdac_clk <= not clk25MHz; - - -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard - -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) - -- bit #1: use UART AS STDOUT (0) / use VGA as STDOUT (1) - SWITCHES(15 downto 2) <= "00000000000000"; - - -- generate the general reset signal - reset_ctl <= '1' when (reset_pre_pore = '1' or reset_post_pore = '1' or pll_locked_main = '0') else '0'; + -- QNICE CPU + cpu : entity work.QNICE_CPU + port map + ( + CLK => SLOW_CLOCK, + RESET => reset_ctl, + WAIT_FOR_DATA => cpu_wait_for_data, + ADDR => cpu_addr, + DATA_IN => cpu_data_in, + DATA_OUT => cpu_data_out, + DATA_DIR => cpu_data_dir, + DATA_VALID => cpu_data_valid, + HALT => cpu_halt, + INS_CNT_STROBE => cpu_ins_cnt_strobe, + INT_N => cpu_int_n, + IGRANT_N => cpu_igrant_n + ); + + -- ROM: up to 64kB consisting of up to 32.000 16 bit words + rom : entity work.BROM + generic map( + FILE_NAME => ROM_FILE + ) + port map + ( + clk => SLOW_CLOCK, + ce => rom_enable, + address => cpu_addr(14 downto 0), + data => rom_data_out, + busy => rom_busy + ); + + -- RAM: up to 64kB consisting of up to 32.000 16 bit words + ram : entity work.BRAM + port map + ( + clk => SLOW_CLOCK, + ce => ram_enable, + address => cpu_addr(14 downto 0), + we => cpu_data_dir, + data_i => cpu_data_out, + data_o => ram_data_out, + busy => ram_busy + ); + + -- PORE ROM: Power On & Reset Execution ROM + -- contains code that is executed during power on and/or during reset + -- MMIO is managing the PORE process + pore_rom : entity work.BROM + generic map( + FILE_NAME => PORE_ROM_FILE + ) + port map + ( + clk => SLOW_CLOCK, + ce => pore_rom_enable, + address => cpu_addr(14 downto 0), + data => pore_rom_data_out, + busy => pore_rom_busy + ); + + -- VGA: 80x40 textmode VGA adaptor + vga_screen : entity work.vga_textmode + port map + ( + reset => reset_ctl, + clk25MHz => clk25MHz, + clk50MHz => SLOW_CLOCK, + R => vga_r, + G => vga_g, + B => vga_b, + hsync => vga_hsync, + vsync => vga_vsync, + hdmi_de => open, + en => vga_en, + we => vga_we, + reg => vga_reg, + data_in => cpu_data_out, + data_out => vga_data_out + ); + + -- special UART with FIFO that can be directly connected to the CPU bus + uart : entity work.bus_uart + generic map( + DIVISOR => UART_DIVISOR + ) + port map + ( + clk => SLOW_CLOCK, + reset => reset_ctl, + rx => uart_rxd_i, + tx => uart_txd_o, + rts => '0', + cts => open, + uart_en => uart_en, + uart_we => uart_we, + uart_reg => uart_reg, + uart_cpu_ws => uart_cpu_ws, + cpu_data_in => cpu_data_out, + cpu_data_out => uart_data_out + ); + + -- MEGA65 keyboard + kbd : entity work.keyboard + generic map( + clk_freq => 50000000 + ) + port map + ( + clk => SLOW_CLOCK, + reset => reset_ctl, + kb_io0 => kb_io0_o, + kb_io1 => kb_io1_o, + kb_io2 => kb_io2_i, + kbd_en => kbd_en, + kbd_we => kbd_we, + kbd_reg => kbd_reg, + cpu_data_in => cpu_data_out, + cpu_data_out => kbd_data_out, + stdinout => SWITCHES(1 downto 0) + ); + + timer_interrupt : entity work.timer_module + generic map( + CLK_FREQ => 50000000 + ) + port map + ( + clk => SLOW_CLOCK, + reset => reset_ctl, + int_n_out => cpu_int_n, + grant_n_in => cpu_igrant_n, + int_n_in => '1', -- no more devices to in Daisy Chain: 1=no interrupt + grant_n_out => open, -- ditto: open=grant goes nowhere + en => tin_en, + we => tin_we, + reg => tin_reg, + data_in => cpu_data_out, + data_out => timer_data_out + ); + + -- cycle counter + cyc : entity work.cycle_counter + port map + ( + clk => SLOW_CLOCK, + impulse => '1', + reset => reset_ctl, + en => cyc_en, + we => cyc_we, + reg => cyc_reg, + data_in => cpu_data_out, + data_out => cyc_data_out + ); + + -- instruction counter + ins : entity work.cycle_counter + port map + ( + clk => SLOW_CLOCK, + impulse => cpu_ins_cnt_strobe, + reset => reset_ctl, + en => ins_en, + we => ins_we, + reg => ins_reg, + data_in => cpu_data_out, + data_out => ins_data_out + ); + + -- EAE - Extended Arithmetic Element (32-bit multiplication, division, modulo) + eae_inst : entity work.eae + port map + ( + clk => SLOW_CLOCK, + reset => reset_ctl, + en => eae_en, + we => eae_we, + reg => eae_reg, + data_in => cpu_data_out, + data_out => eae_data_out + ); + + -- SD Card + sd_card : entity work.sdcard + port map + ( + clk => SLOW_CLOCK, + reset => reset_ctl, + en => sd_en, + we => sd_we, + reg => sd_reg, + data_in => cpu_data_out, + data_out => sd_data_out, + sd_reset => SD_RESET, + sd_clk => SD_CLK, + sd_mosi => SD_MOSI, + sd_miso => SD_MISO + ); + + -- HyperRAM + HRAM : entity work.hyperram_ctl + port map + ( + clk => SLOW_CLOCK, + clk2x => CLK1x, + clk4x => CLK2x, + reset => reset_ctl, + hram_en => hram_en, + hram_we => hram_we, + hram_reg => hram_reg, + hram_cpu_ws => hram_cpu_ws, + data_in => cpu_data_out, + data_out => hram_data_out, + hr_d => hr_d_io, + hr_rwds => hr_rwds_io, + hr_reset => hr_reset_o, + hr_clk_p => hr_clk_p_o, + hr_cs0 => hr_cs0_o + ); + + -- memory mapped i/o controller + mmio_controller : entity work.mmio_mux + generic map( + GD_TIL => false, -- no support for TIL leds on MEGA65 + GD_SWITCHES => true, -- we emulate the switch register as described in doc/README.md + GD_HRAM => true -- support HyperRAM + ) + port map + ( + HW_RESET => reset_button_i, + CLK => SLOW_CLOCK, -- @TODO change debouncer bitsize when going to 100 MHz + addr => cpu_addr, + data_dir => cpu_data_dir, + data_valid => cpu_data_valid, + cpu_wait_for_data => cpu_wait_for_data, + cpu_halt => cpu_halt, + cpu_igrant_n => cpu_igrant_n, + rom_enable => rom_enable, + rom_busy => rom_busy, + ram_enable => ram_enable, + ram_busy => ram_busy, + pore_rom_enable => pore_rom_enable, + pore_rom_busy => pore_rom_busy, + switch_reg_enable => switch_reg_enable, + kbd_en => kbd_en, + kbd_we => kbd_we, + kbd_reg => kbd_reg, + tin_en => tin_en, + tin_we => tin_we, + tin_reg => tin_reg, + vga_en => vga_en, + vga_we => vga_we, + vga_reg => vga_reg, + uart_en => uart_en, + uart_we => uart_we, + uart_reg => uart_reg, + uart_cpu_ws => uart_cpu_ws, + cyc_en => cyc_en, + cyc_we => cyc_we, + cyc_reg => cyc_reg, + ins_en => ins_en, + ins_we => ins_we, + ins_reg => ins_reg, + eae_en => eae_en, + eae_we => eae_we, + eae_reg => eae_reg, + sd_en => sd_en, + sd_we => sd_we, + sd_reg => sd_reg, + hram_en => hram_en, + hram_we => hram_we, + hram_reg => hram_reg, + hram_cpu_ws => hram_cpu_ws, + + -- no TIL leds on the MEGA65 , + til_reg0_enable => open, + til_reg1_enable => open, + + reset_pre_pore => reset_pre_pore, + reset_post_pore => reset_post_pore + ); + + -- emulate the toggle switches as described in doc/README.md + switch_driver : process (switch_reg_enable, SWITCHES) + begin + if switch_reg_enable = '1' then + switch_data_out <= SWITCHES; + else + switch_data_out <= (others => '0'); + end if; + end process; + + video_signal_latches : process (clk25MHz) + begin + if rising_edge(clk25MHz) then + -- VGA: wire the simplified color system of the VGA component to the VGA outputs + vga_red_o <= vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r; + vga_green_o <= vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g; + vga_blue_o <= vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b; + + -- VGA horizontal and vertical sync + vga_hs_o <= vga_hsync; + vga_vs_o <= vga_vsync; + end if; + end process; + + -- make the VDAC output the image + vdac_sync_n_o <= '0'; + vdac_blank_n_o <= '1'; + + -- Fix of the Vivado induced "blurry VGA screen": + -- As of the time writing this (June 2020): it is absolutely unclear for me, why I need to + -- invert the phase of the vdac_clk when use Vivado 2019.2. When using ISE 14.7, it works + -- fine without the phase shift. + vdac_clk_o <= not clk25MHz; + + -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard + -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) + -- bit #1: use UART AS STDOUT (0) / use VGA as STDOUT (1) + SWITCHES(15 downto 2) <= "00000000000000"; + + -- generate the general reset signal + reset_ctl <= '1' when (reset_pre_pore = '1' or reset_post_pore = '1' or pll_locked_main = '0') else + '0'; end architecture beh; - From 863bc558d2f192c9a44ee068074d65140ca900ee Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Tue, 3 Dec 2024 18:41:35 +0100 Subject: [PATCH 06/17] create separate r6 versions of certain files --- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 6 +- vhdl/hw/MEGA65/drivers/hyperram.vhdl | 154 +- vhdl/hw/MEGA65/drivers/hyperram_r6.vhdl | 3294 +++++++++++++++++++++++ vhdl/hw/MEGA65/hyperram_ctl.vhd | 21 +- vhdl/hw/MEGA65/hyperram_ctl_r6.vhd | 346 +++ vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd | 7 +- vhdl/hw/MEGA65/sim/sim_hram_dbg_r6.vhd | 247 ++ 7 files changed, 4060 insertions(+), 15 deletions(-) create mode 100644 vhdl/hw/MEGA65/drivers/hyperram_r6.vhdl create mode 100644 vhdl/hw/MEGA65/hyperram_ctl_r6.vhd create mode 100644 vhdl/hw/MEGA65/sim/sim_hram_dbg_r6.vhd diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index 1e0cd601..ee240aee 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -195,7 +195,7 @@ - + @@ -258,7 +258,7 @@ - + @@ -365,7 +365,7 @@ - + diff --git a/vhdl/hw/MEGA65/drivers/hyperram.vhdl b/vhdl/hw/MEGA65/drivers/hyperram.vhdl index 8c3912b5..a9ba47b6 100644 --- a/vhdl/hw/MEGA65/drivers/hyperram.vhdl +++ b/vhdl/hw/MEGA65/drivers/hyperram.vhdl @@ -71,7 +71,16 @@ entity hyperram is hr_reset : out std_logic := '1'; -- Active low RESET line to HyperRAM hr_clk_n : out std_logic := '0'; hr_clk_p : out std_logic := '1'; - hr_cs0 : out std_logic := '1' + + hr2_d : inout unsigned(7 downto 0) := (others => 'Z'); -- Data/Address + hr2_rwds : inout std_logic := 'Z'; -- RW Data strobe + hr2_reset : out std_logic := '1'; -- Active low RESET line to HyperRAM + hr2_clk_n : out std_logic := '0'; + hr2_clk_p : out std_logic := '1'; + + + hr_cs0 : out std_logic := '1'; + hr_cs1 : out std_logic := '1' ); end hyperram; @@ -220,6 +229,7 @@ architecture gothic of hyperram is signal hr_reset_int : std_logic := '1'; signal hr_rwds_int : std_logic := '0'; signal hr_cs0_int : std_logic := '0'; + signal hr_cs1_int : std_logic := '0'; signal hr_clk_p_int : std_logic := '0'; signal hr_clk_n_int : std_logic := '0'; @@ -1271,45 +1281,78 @@ begin case clock_status_vector is -- Slow clock rate, no phase shift when "00000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00010" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00011" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "00100" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "00101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "00110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "00111" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; -- Slow clock rate, with phase shift = bring forward tick by 1/2 a cycle when "01000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "01001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "01010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01011" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01100" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "01110" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "01111" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; -- Fast clock rate, no phase shift when "10000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "10011" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "10100" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10101" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "10110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "10111" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; -- Fast clock rate, with phase shift when "11000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "11001" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11011" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "11100" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when "11101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + hr2_clk_p <= '1'; hr2_clk_n <= '0'; when "11111" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; when others => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + hr2_clk_p <= '0'; hr2_clk_n <= '1'; end case; end if; @@ -1687,10 +1730,12 @@ begin -- Make sure we don't abort a read so quickly, that we allow -- glitching of clock line with clock phase shifting hr_cs0 <= '1'; + hr_cs1 <= '1'; state <= Idle; when Idle => report "Tristating hr_d"; hr_d <= (others => 'Z'); + hr2_d <= (others => 'Z'); read_request_held <= '0'; write_request_held <= '0'; @@ -1738,6 +1783,7 @@ begin if rwr_counter /= to_unsigned(0,8) then rwr_counter <= rwr_counter - 1; hr_d <= x"bb"; + hr2_d <= x"bb"; end if; if rwr_counter = to_unsigned(1,8) then rwr_waiting <= '0'; @@ -1994,6 +2040,7 @@ begin -- Release CS line between transactions report "Releasing hyperram CS lines"; hr_cs0 <= '1'; + hr_cs1 <= '1'; end if; when StartBackgroundWrite => @@ -2115,8 +2162,10 @@ begin report "hr_command = $" & to_hstring(hr_command); -- Call HyperRAM to attention hr_cs0 <= not hyperram0_select; + hr_cs1 <= not (hyperram1_select or first_transaction); hr_rwds <= 'Z'; + hr2_rwds <= 'Z'; -- Prepare for reading block data is_block_read <= false; @@ -2222,6 +2271,7 @@ begin & ", countdown = " & integer'image(countdown); hr_d <= hr_command(47 downto 40); + hr2_d <= hr_command(47 downto 40); hr_command(47 downto 8) <= hr_command(39 downto 0); -- Also shift out config register values, if required @@ -2248,7 +2298,9 @@ begin if countdown = 3 and (config_reg_write='0' or ram_reading_held='1') then extra_latency <= hr_rwds; - if (hr_rwds='1' and hyperram0_select='1') then + if (hr_rwds='1' and hyperram0_select='1') + or (hr2_rwds='1' and hyperram1_select='1') + then report "Applying extra latency"; end if; end if; @@ -2268,8 +2320,10 @@ begin report "Writing command"; -- Call HyperRAM to attention hr_cs0 <= not hyperram0_select; + hr_cs1 <= not (hyperram1_select or first_transaction); hr_rwds <= 'Z'; + hr2_rwds <= 'Z'; hr_clk_phaseshift <= write_byte_phase; @@ -2281,6 +2335,7 @@ begin -- & ", cs0= " & std_logic'image(hr_cs0); hr_d <= hr_command(47 downto 40); + hr2_d <= hr_command(47 downto 40); hr_command(47 downto 8) <= hr_command(39 downto 0); -- Also shift out config register values, if required @@ -2298,8 +2353,11 @@ begin if countdown = 3 and (config_reg_write='0' or ram_reading_held='1') then if hyperram0_select='1' then extra_latency <= hr_rwds; + else + extra_latency <= hr2_rwds; end if; - if (hr_rwds='1' and hyperram0_select='1') then + if (hr_rwds='1' and hyperram0_select='1') + or (hr2_rwds='1' and hyperram1_select='1') then report "Applying extra latency"; end if; end if; @@ -2429,7 +2487,9 @@ begin -- Begin write mask pre-amble if ram_reading_held = '0' and countdown = 2 then hr_rwds <= '0'; + hr2_rwds <= '0'; hr_d <= x"BE"; -- "before" data byte + hr2_d <= x"BE"; -- "before" data byte end if; if countdown /= 0 then @@ -2469,6 +2529,7 @@ begin & ", valids= " & to_string(background_write_valids) & ", background words left = " & integer'image(background_write_count); hr_d <= background_write_data(0); + hr2_d <= background_write_data(0); background_write_data(0) <= background_write_data(1); background_write_data(1) <= background_write_data(2); background_write_data(2) <= background_write_data(3); @@ -2479,6 +2540,7 @@ begin background_write_data(7) <= x"00"; hr_rwds <= not background_write_valids(0); + hr2_rwds <= not background_write_valids(0); background_write_valids(0 to 6) <= background_write_valids(1 to 7); background_write_valids(7) <= '0'; @@ -2491,7 +2553,9 @@ begin -- okay, as they are only supported with the cache and -- write-collecting, anyway. hr_d <= ram_wdata; + hr2_d <= ram_wdata; hr_rwds <= hyperram_access_address(0) xor write_byte_phase; + hr2_rwds <= hyperram_access_address(0) xor write_byte_phase; end if; -- Write byte @@ -2500,9 +2564,11 @@ begin if write_byte_phase = '0' and hyperram_access_address(0)='1' then report "Masking even byte"; hr_d <= x"ee"; -- even "masked" data byte + hr2_d <= x"ee"; -- even "masked" data byte elsif write_byte_phase = '1' and hyperram_access_address(0)='0' then report "Masking odd byte"; hr_d <= x"0d"; -- odd "masked" data byte + hr2_d <= x"0d"; -- odd "masked" data byte end if; if background_write_count /= 0 then background_write_count <= background_write_count - 1; @@ -2677,7 +2743,9 @@ begin -- Begin write mask pre-amble if ram_reading_held = '0' and countdown = 2 then hr_rwds <= '0'; + hr2_rwds <= '0'; hr_d <= x"BE"; -- "before" data byte + hr2_d <= x"BE"; -- "before" data byte end if; if countdown /= 0 then @@ -2716,6 +2784,7 @@ begin & ", valids= " & to_string(background_write_valids) & ", background words left = " & integer'image(background_write_count); hr_d <= background_write_data(0); + hr2_d <= background_write_data(0); background_write_data(0) <= background_write_data(1); background_write_data(1) <= background_write_data(2); @@ -2727,6 +2796,7 @@ begin background_write_data(7) <= x"00"; hr_rwds <= not background_write_valids(0); + hr2_rwds <= not background_write_valids(0); background_write_valids(0 to 6) <= background_write_valids(1 to 7); background_write_valids(7) <= '0'; else @@ -2734,7 +2804,9 @@ begin -- okay, as they are only supported with the cache and -- write-collecting, anyway. hr_d <= ram_wdata; + hr2_d <= ram_wdata; hr_rwds <= hyperram_access_address(0) xor write_byte_phase; + hr2_rwds <= hyperram_access_address(0) xor write_byte_phase; end if; -- Finish resetting write collectors when chaining @@ -2756,8 +2828,10 @@ begin if background_write='0' then if write_byte_phase = '0' and hyperram_access_address(0)='1' then hr_d <= x"ee"; -- even "masked" data byte + hr2_d <= x"ee"; -- even "masked" data byte elsif write_byte_phase = '1' and hyperram_access_address(0)='0' then hr_d <= x"0d"; -- odd "masked" data byte + hr2_d <= x"0d"; -- odd "masked" data byte end if; if background_write_count /= 0 then background_write_count <= background_write_count - 1; @@ -2802,8 +2876,11 @@ begin when HyperRAMFinishWriting => -- Mask writing from here on. hr_cs0 <= '1'; + hr_cs1 <= '1'; hr_rwds <= 'Z'; + hr2_rwds <= 'Z'; hr_d <= x"FA"; -- "after" data byte + hr2_d <= x"FA"; -- "after" data byte hr_clk_phaseshift <= write_phase_shift; report "clk_queue <= '00'"; rwr_counter <= rwr_delay; @@ -2812,8 +2889,10 @@ begin state <= Idle; when HyperRAMReadWait => hr_rwds <= 'Z'; + hr2_rwds <= 'Z'; report "Presenting tri-state on hr_d"; hr_d <= (others => 'Z'); + hr2_d <= (others => 'Z'); if countdown_is_zero = '0' then countdown <= countdown - 1; end if; @@ -2937,6 +3016,8 @@ begin if hyperram0_select='1' then last_rwds <= hr_rwds; + else + last_rwds <= hr2_rwds; end if; -- HyperRAM drives RWDS basically to follow the clock. -- But first valid data is when RWDS goes high, so we have to @@ -2944,7 +3025,9 @@ begin -- report "DISPATCH watching for data: rwds=" & std_logic'image(hr_rwds) & ", clock=" & std_logic'image(hr_clock) -- & ", rwds seen=" & std_logic'image(hr_rwds_high_seen); - if ((hr_rwds='1') and (hyperram0_select='1')) then + if ((hr_rwds='1') and (hyperram0_select='1')) + or ((hr2_rwds='1') and (hyperram1_select='1')) + then hr_rwds_high_seen <= '1'; -- if hr_rwds_high_seen = '0' then -- report "DISPATCH saw hr_rwds go high at start of data stream"; @@ -2952,7 +3035,9 @@ begin else hr_rwds_high_seen <= '0'; end if; - if ((hr_rwds='1') and (hyperram0_select='1')) or (hr_rwds_high_seen='1') then + if (((hr_rwds='1') and (hyperram0_select='1')) + or ((hr2_rwds='1') and (hyperram1_select='1'))) + or (hr_rwds_high_seen='1') then -- Data has arrived: Latch either odd or even byte -- as required. report "DISPATCH Saw read data = $" & to_hstring(hr_d); @@ -2964,6 +3049,9 @@ begin if hyperram0_select='1' then block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) <= hr_d; + else + block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) + <= hr2_d; end if; show_block := true; end if; @@ -2972,6 +3060,8 @@ begin if is_vic_fetch then if hyperram0_select='1' then viciv_data_buffer(to_integer(byte_phase)) <= hr_d; + else + viciv_data_buffer(to_integer(byte_phase)) <= hr2_d; end if; -- We load the data here 2x faster than it is sent to the VIC-IV -- so we can start transmitting immediately, to minimise latency @@ -2985,6 +3075,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; + else + cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; elsif hyperram_access_address_matches_cache_row1 = '1' then @@ -2993,6 +3085,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; + else + cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; elsif random_bits(1) = '0' then @@ -3005,6 +3099,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; + else + cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; else @@ -3017,6 +3113,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; + else + cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; end if; @@ -3038,12 +3136,23 @@ begin if to_integer(byte_phase) = (to_integer(hyperram_access_address(2 downto 0))+0) and is_expected_to_respond and (not is_vic_fetch) then if hyperram0_select='1' then - report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d) & ", hyperram0_select=" & std_logic'image(hyperram0_select) & ", hyperram1_select=" & std_logic'image(hyperram1_select); + report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d) + & ", hyperram0_select="& std_logic'image(hyperram0_select) + & ", hyperram1_select="& std_logic'image(hyperram1_select); if rdata_16en='1' and byte_phase(0)='1' then rdata_hi <= hr_d; else rdata <= hr_d; end if; + else + report "DISPATCH: Returning freshly read data = $" & to_hstring(hr2_d) + & ", hyperram0_select="& std_logic'image(hyperram0_select) + & ", hyperram1_select="& std_logic'image(hyperram1_select); + if rdata_16en='1' and byte_phase(0)='1' then + rdata_hi <= hr2_d; + else + rdata <= hr2_d; + end if; end if; report "hr_return='1'"; report "hr_return='0'"; @@ -3062,6 +3171,7 @@ begin last_request_toggle <= request_toggle; state <= Idle; hr_cs0 <= '1'; + hr_cs1 <= '1'; hr_clk_phaseshift <= write_phase_shift; if is_block_read then block_valid <= '1'; @@ -3074,11 +3184,15 @@ begin end if; when HyperRAMReadWaitSlow => hr_rwds <= 'Z'; + hr2_rwds <= 'Z'; report "Presenting tri-state on hr_d"; hr_d <= (others => 'Z'); + hr2_d <= (others => 'Z'); if hyperram0_select='1' then hr_d_last <= hr_d; + else + hr_d_last <= hr2_d; end if; pause_phase <= not pause_phase; @@ -3141,6 +3255,8 @@ begin if hyperram0_select='1' then last_rwds <= hr_rwds; + else + last_rwds <= hr2_rwds; end if; -- HyperRAM drives RWDS basically to follow the clock. -- But first valid data is when RWDS goes high, so we have to @@ -3148,7 +3264,7 @@ begin -- report "DISPATCH watching for data: rwds=" & std_logic'image(hr_rwds) & ", clock=" & std_logic'image(hr_clock) -- & ", rwds seen=" & std_logic'image(hr_rwds_high_seen); - if (hr_rwds='1') and (hyperram0_select='1') + if ((hr_rwds='1') and (hyperram0_select='1')) or ((hr2_rwds='1') and (hyperram1_select='1')) then hr_rwds_high_seen <= '1'; else @@ -3157,7 +3273,7 @@ begin -- report "DISPATCH saw hr_rwds go high at start of data stream"; -- end if; end if; - if ((hr_rwds='1') and (hyperram0_select='1')) + if (((hr_rwds='1') and (hyperram0_select='1')) or ((hr2_rwds='1') and (hyperram1_select='1'))) or (hr_rwds_high_seen='1') then -- Data has arrived: Latch either odd or even byte -- as required. @@ -3170,6 +3286,9 @@ begin if hyperram0_select='1' then block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) <= hr_d; + else + block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) + <= hr2_d; end if; show_block := true; end if; @@ -3178,6 +3297,8 @@ begin if is_vic_fetch then if hyperram0_select='1' then viciv_data_buffer(to_integer(byte_phase)) <= hr_d; + else + viciv_data_buffer(to_integer(byte_phase)) <= hr2_d; end if; -- We load the data here 2x faster than it is sent to the VIC-IV -- so we can start transmitting immediately, to minimise latency @@ -3191,6 +3312,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; + else + cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; elsif hyperram_access_address_matches_cache_row1 = '1' then @@ -3199,6 +3322,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; + else + cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; elsif random_bits(1) = '0' then @@ -3211,6 +3336,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row0_data(to_integer(byte_phase)) <= hr_d; + else + cache_row0_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache0 := true; else @@ -3223,6 +3350,8 @@ begin report "hr_sample='0'"; if hyperram0_select='1' then cache_row1_data(to_integer(byte_phase)) <= hr_d; + else + cache_row1_data(to_integer(byte_phase)) <= hr2_d; end if; show_cache1 := true; end if; @@ -3248,6 +3377,10 @@ begin if hyperram0_select='1' then report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d); rdata <= hr_d; + else + report "DISPATCH: Returning freshly read data = $" & to_hstring(hr2_d) + & ", byte_phase=" & integer'image(to_integer(byte_phase)); + rdata <= hr2_d; end if; report "hr_return='1'"; report "hr_return='0'"; @@ -3261,6 +3394,10 @@ begin if hyperram0_select='1' then report "DISPATCH: Returning freshly read high-byte data = $" & to_hstring(hr_d); rdata_hi <= hr_d; + else + report "DISPATCH: Returning freshly read data = $" & to_hstring(hr2_d) + & ", byte_phase=" & integer'image(to_integer(byte_phase)); + rdata_hi <= hr2_d; end if; report "hr_return='1'"; report "hr_return='0'"; @@ -3279,6 +3416,7 @@ begin report "returning to idle"; state <= Idle; hr_cs0 <= '1'; + hr_cs1 <= '1'; hr_clk_phaseshift <= write_phase_shift; else byte_phase <= byte_phase + 1; diff --git a/vhdl/hw/MEGA65/drivers/hyperram_r6.vhdl b/vhdl/hw/MEGA65/drivers/hyperram_r6.vhdl new file mode 100644 index 00000000..8c3912b5 --- /dev/null +++ b/vhdl/hw/MEGA65/drivers/hyperram_r6.vhdl @@ -0,0 +1,3294 @@ +-- Original MEGA65 keyboard driver file by Paul Gardner-Stephen +-- see README.md for details and license +-- +-- Modified for QNICE-FPGA by sy2002 in August 2020 + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; + +package cache_row_type is +type cache_row_t is array (0 to 7) of unsigned(7 downto 0); +end package cache_row_type; + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use ieee.numeric_std.all; +use Std.TextIO.all; + +use work.cache_row_type.all; + +entity hyperram is + generic ( in_simulation : in boolean := false); + Port ( pixelclock : in STD_LOGIC; -- For slow devices bus interface is + -- actually on pixelclock to reduce latencies + -- Also pixelclock is the natural clock speed we apply to the HyperRAM. + clock163 : in std_logic; -- Used for fast clock for HyperRAM + clock325 : in std_logic; -- Used for fast clock for HyperRAM SERDES units + + -- Simple counter for number of requests received + request_counter : out std_logic := '0'; + + read_request : in std_logic; + write_request : in std_logic; + address : in unsigned(26 downto 0); + wdata : in unsigned(7 downto 0); + + -- Optional 16-bit interface (for Amiga core use) + -- (That it is optional, is why the write_en is inverted for the + -- low-byte). + -- 16-bit transactions MUST occur on an even numbered address, or + -- else expect odd and horrible things to happen. + wdata_hi : in unsigned(7 downto 0) := x"00"; + wen_hi : in std_logic := '0'; + wen_lo : in std_logic := '1'; + rdata_hi : out unsigned(7 downto 0); + rdata_16en : in std_logic := '0'; -- set this high to be able + -- to read 16-bit values + + rdata : out unsigned(7 downto 0); + + data_ready_strobe : out std_logic := '0'; + busy : out std_logic := '0'; + + -- Export current cache line for speeding up reads from slow_devices controller + -- by skipping the need to hand us the request and get the response back. + current_cache_line : out cache_row_t := (others => (others => '0')); + current_cache_line_address : inout unsigned(26 downto 3) := (others => '0'); + current_cache_line_valid : out std_logic := '0'; + expansionram_current_cache_line_next_toggle : in std_logic := '0'; + + -- Allow VIC-IV to request lines of data also. + -- We then pump it out byte-by-byte when ready + -- VIC-IV can address only 512KB at a time, so we have a banking register + viciv_addr : in unsigned(18 downto 3) := (others => '0'); + viciv_request_toggle : in std_logic := '0'; + viciv_data_out : out unsigned(7 downto 0) := x"00"; + viciv_data_strobe : out std_logic := '0'; + + hr_d : inout unsigned(7 downto 0) := (others => 'Z'); -- Data/Address + hr_rwds : inout std_logic := 'Z'; -- RW Data strobe + hr_reset : out std_logic := '1'; -- Active low RESET line to HyperRAM + hr_clk_n : out std_logic := '0'; + hr_clk_p : out std_logic := '1'; + hr_cs0 : out std_logic := '1' + ); +end hyperram; + +architecture gothic of hyperram is + + type state_t is ( + StartupDelay, + ReadAbort, + Idle, + ReadSetup, + WriteSetup, + HyperRAMOutputCommand, + HyperRAMDoWrite, + HyperRAMOutputCommandSlow, + StartBackgroundWrite, + HyperRAMDoWriteSlow, + HyperRAMFinishWriting, + HyperRAMReadWaitSlow, + HyperRAMReadWait + ); + + -- How many clock ticks need to expire between transactions to satisfy T_RWR + -- of hyperrram for the T_RWR 40ns delay. + -- We can also subtract one cycle for the time it takes to pull CS low, and then + -- two more for the clocks before the critical moment, and one more for time + -- covered by various latencies in the system (including clock 1/2 cycle delay). + -- This effectively gets us down to 45ns. Taking another cycle would leave us + -- at only 38.7ns, which is a bit too short. + -- This gives us an effective 8-byte write latency of ~132ns = ~7.5MHz. + -- For read it is ~143ns = 6.99MHz, which might just be a whisker too slow + -- for MiniMig. By reading only 4 bytes instead of 8, this would allow getting + -- back down to ~120 -- 132ns, which should be enough. + -- Actually, all of that is a bit moot, since it seems that we just have to apply + -- some trial and error to get it right. 1 seems right with the current settings. + signal rwr_delay : unsigned(7 downto 0) := to_unsigned(1,8); + signal rwr_counter : unsigned(7 downto 0) := (others => '0'); + signal rwr_waiting : std_logic := '0'; + + signal current_cache_line_drive : cache_row_t := (others => (others => '0')); + signal current_cache_line_address_drive : unsigned(26 downto 3) := (others => '0'); + signal current_cache_line_valid_drive : std_logic := '0'; + + signal last_current_cache_next_toggle : std_logic := '0'; + + signal state : state_t := StartupDelay; + signal busy_internal : std_logic := '1'; + signal hr_command : unsigned(47 downto 0); + + signal hr_d_last : unsigned(7 downto 0); + + -- Used to assert CS line on BOTH hyperRAM modules at the same time + -- when doing the initial configuration register write. + signal first_transaction : std_logic := '1'; + + -- Initial transaction is config register write + signal config_reg_write : std_logic := '1'; + signal ram_address : unsigned(26 downto 0) := + "010000000000001000000000000"; -- = bottom 27 bits of x"A001000"; + signal ram_wdata : unsigned(7 downto 0) := x"00"; + signal ram_wdata_hi : unsigned(7 downto 0) := x"00"; + signal ram_wdata_enlo : std_logic := '0'; + signal ram_wdata_enhi : std_logic := '0'; + signal ram_reading : std_logic := '0'; + signal ram_reading_held : std_logic := '0'; + + signal ram_reading_drive : std_logic := '0'; + signal ram_address_drive : unsigned(26 downto 0) := + "010000000000001000000000000"; -- = bottom 27 bits of x"A001000"; + signal ram_wdata_drive : unsigned(7 downto 0) := x"00"; + signal ram_wdata_hi_drive : unsigned(7 downto 0) := x"00"; + signal ram_wdata_enlo_drive : std_logic := '0'; + signal ram_wdata_enhi_drive : std_logic := '0'; + signal cache_row0_address_matches_ram_address : std_logic := '0'; + signal cache_row1_address_matches_ram_address : std_logic := '0'; + signal ram_address_matches_current_cache_line_address : std_logic := '0'; + signal address_matches_hyperram_access_address_block : std_logic := '0'; + signal write_collect0_address_matches_write_collect1_address_plus_1 : std_logic := '0'; + + -- We want to set config register 0 to $ffe6, to enable variable latency + -- and 3 cycles instead of 6 for latency. This speeds up writing almost 2x. + -- But at 80MHz instead of 40MHz bus, we have to increase the latency from + -- 3 to 4 cycles to satisfy the 40ns minimum time requirement. + -- This also sets the drive strength to the maximum, to get cleaner faster + -- clock transitions. This fixes checkerboard read errors at 80MHz. + + signal conf_buf0 : unsigned(7 downto 0) := x"ff"; + signal conf_buf1 : unsigned(7 downto 0) := x"f6"; + signal conf_buf0_in : unsigned(7 downto 0) := x"ff"; + signal conf_buf1_in : unsigned(7 downto 0) := x"f6"; + signal conf_buf0_set : std_logic := '0'; + signal conf_buf1_set : std_logic := '0'; + signal last_conf_buf0_set : std_logic := '0'; + signal last_conf_buf1_set : std_logic := '0'; + + -- 4 is correct for the part we have in the MEGA65, after we have set the + -- config register to minimise latency. + signal write_latency : unsigned(7 downto 0) := to_unsigned(5,8); + -- And the matching extra latency is 5 + signal extra_write_latency : unsigned(7 downto 0) := to_unsigned(7,8); + + -- And for the 2nd trap-door hyperram. + -- That module from 1BitSquared uses a different brand of hyperram + -- and seems to have different timing. + signal write_latency2 : unsigned(7 downto 0) := to_unsigned(3,8); + signal extra_write_latency2 : unsigned(7 downto 0) := to_unsigned(1,8); + + + -- Control optimisations for hyperram access + -- Enabling the cache MOSTLY works, but there is some cache coherency bug(s) + -- when writing. These are currently being investigated. + signal cache_enabled : boolean := true; + signal block_read_enable : std_logic := '1'; -- enable 32 byte read block fetching + signal flag_prefetch : std_logic := '1'; -- enable/disable prefetch of read + -- blocks + signal enable_current_cache_line : std_logic := '1'; + + -- These three must be off for reliable operation on current PCBs + signal fast_cmd_mode : std_logic := '0'; + signal fast_read_mode : std_logic := '0'; + signal fast_write_mode : std_logic := '0'; + + signal read_phase_shift : std_logic := '0'; + signal write_phase_shift : std_logic := '1'; + + signal countdown : integer range 0 to 63 := 0; + signal countdown_is_zero : std_logic := '1'; + signal extra_latency : std_logic := '0'; + signal countdown_timeout : std_logic := '0'; + + signal pause_phase : std_logic := '0'; + signal hr_clock : std_logic := '0'; + + signal data_ready_toggle : std_logic := '0'; + signal last_data_ready_toggle : std_logic := '0'; + signal data_ready_strobe_hold : std_logic := '0'; + + signal request_toggle : std_logic := '0'; + signal request_accepted : std_logic := '0'; + signal last_request_toggle : std_logic := '0'; + + signal byte_phase : unsigned(5 downto 0) := to_unsigned(0,6); + signal write_byte_phase : std_logic := '0'; + + signal hr_ddr : std_logic := '0'; + signal hr_rwds_ddr : std_logic := '0'; + signal hr_reset_int : std_logic := '1'; + signal hr_rwds_int : std_logic := '0'; + signal hr_cs0_int : std_logic := '0'; + signal hr_clk_p_int : std_logic := '0'; + signal hr_clk_n_int : std_logic := '0'; + + signal cycle_count : integer := 0; + + -- Have a tiny little cache to reduce latency + -- 8 byte cache rows, where we indicate the validity of + -- each byte. + signal cache_row0_valids : std_logic_vector(0 to 7) := (others => '0'); + signal cache_row0_address : unsigned(23 downto 0) := (others => '1'); + signal cache_row0_data : cache_row_t := ( others => x"00" ); + + signal cache_row1_valids : std_logic_vector(0 to 7) := (others => '0'); + signal cache_row1_address : unsigned(23 downto 0) := (others => '1'); + signal cache_row1_data : cache_row_t := ( others => x"00" ); + + -- Collect writes together to hide write latency + signal write_collect0_dispatchable : std_logic := '0'; + signal write_collect0_address : unsigned(26 downto 3) := (others => '0'); + signal write_collect0_valids : std_logic_vector(0 to 7) := (others => '0'); + signal write_collect0_data : cache_row_t := ( others => x"00" ); + signal write_collect0_toolate : std_logic := '0'; -- Set when its too late to + -- add more bytes to the write. + signal write_collect0_flushed : std_logic := '1'; + + signal write_collect1_dispatchable : std_logic := '0'; + signal write_collect1_address : unsigned(26 downto 3) := (others => '0'); + signal write_collect1_valids : std_logic_vector(0 to 7) := (others => '0'); + signal write_collect1_data : cache_row_t := ( others => x"00" ); + signal write_collect1_toolate : std_logic := '0'; -- Set when its too late to + -- add more bytes to the write. + signal write_collect1_flushed : std_logic := '1'; + + + type block_t is array (0 to 3) of cache_row_t; + signal block_data : block_t := (others => (others => x"00")); + signal block_address : unsigned(26 downto 5); + signal block_valid : std_logic := '0'; + signal is_block_read : boolean := false; + signal is_prefetch : boolean := false; + signal is_expected_to_respond : boolean := false; + signal ram_prefetch : boolean := false; + signal ram_normalfetch : boolean := false; + + signal current_cache_line_new_address : unsigned(26 downto 3) := (others => '0'); + signal current_cache_line_update : cache_row_t := (others => (others => '0')); + signal current_cache_line_update_address : unsigned(26 downto 3) := (others => '0'); + signal current_cache_line_update_all : std_logic := '0'; + signal current_cache_line_update_flags : std_logic_vector(0 to 7) := (others => '0'); + signal last_current_cache_line_update_all : std_logic := '0'; + signal last_current_cache_line_update_flags : std_logic_vector(0 to 7) := (others => '0'); + + signal current_cache_line_matches_block : std_logic := '0'; + signal current_cache_line_plus_1_matches_block : std_logic := '0'; + signal hyperram_access_address_matches_cache_row0 : std_logic := '0'; + signal hyperram_access_address_matches_cache_row1 : std_logic := '0'; + + signal cache_row_update_toggle : std_logic := '0'; + signal last_cache_row_update_toggle : std_logic := '0'; + signal cache_row_update_address : unsigned(26 downto 3) := (others => '0'); + signal cache_row_update_byte : integer range 0 to 7 := 0; + signal cache_row_update_value : unsigned(7 downto 0) := x"00"; + signal cache_row_update_value_hi : unsigned(7 downto 0) := x"00"; + signal cache_row_update_lo : std_logic := '0'; + signal cache_row_update_hi : std_logic := '0'; + + signal last_rwds : std_logic := '0'; + + signal fake_data_ready_strobe : std_logic := '0'; + signal fake_rdata : unsigned(7 downto 0) := x"00"; + signal fake_rdata_hi : unsigned(7 downto 0) := x"00"; + + signal request_counter_int : std_logic := '0'; + + + signal hr_rwds_high_seen : std_logic := '0'; + + signal random_bits : unsigned(7 downto 0) := x"00"; + + signal write_blocked : std_logic := '0'; + + signal background_write : std_logic := '0'; + signal background_write_source : std_logic := '0'; + signal background_write_valids : std_logic_vector(0 to 7) := x"00"; + signal background_write_data : cache_row_t := (others => (others => '0')); + signal background_write_count : integer range 0 to 7 := 0; + signal background_write_next_address : unsigned(26 downto 3) := (others => '0'); + signal background_write_next_address_matches_collect0 : std_logic := '0'; + signal background_write_next_address_matches_collect1 : std_logic := '0'; + signal background_chained_write : std_logic := '0'; + signal background_write_fetch : std_logic := '0'; + signal collect1_matches_collect0_plus_1 : std_logic := '0'; + signal collect0_matches_collect1_plus_1 : std_logic := '0'; + signal matches_cache_row_update_address : std_logic := '0'; + signal cache_row_update_address_changed : std_logic := '0'; + signal block_address_matches_cache_row_update_address : std_logic := '0'; + signal cache_row0_address_matches_cache_row_update_address : std_logic := '0'; + signal cache_row1_address_matches_cache_row_update_address : std_logic := '0'; + signal byte_phase_greater_than_address_low_bits : std_logic := '0'; + signal byte_phase_greater_than_address_end_of_row : std_logic := '0'; + signal block_address_matches_address : std_logic := '0'; + signal invalidate_read_cache : std_logic := '0'; + + signal write_continues : integer range 0 to 255 := 0; + signal write_continues_max : integer range 0 to 255 := 16; + + -- If we get too many writes in short succession, we may need to queue up to + -- two of the writes, while waiting for slow_devices to notice + signal queued_write : std_logic := '0'; + signal queued_wen_lo : std_logic := '0'; + signal queued_wen_hi : std_logic := '0'; + signal queued_wdata : unsigned(7 downto 0) := x"00"; + signal queued_wdata_hi : unsigned(7 downto 0) := x"00"; + signal queued_waddr : unsigned(26 downto 0) := to_unsigned(0,27); + signal queued2_write : std_logic := '0'; + signal queued2_wen_lo : std_logic := '0'; + signal queued2_wen_hi : std_logic := '0'; + signal queued2_wdata : unsigned(7 downto 0) := x"00"; + signal queued2_wdata_hi : unsigned(7 downto 0) := x"00"; + signal queued2_waddr : unsigned(26 downto 0) := to_unsigned(0,27); + + -- Delay sending of the initial configuration write command + -- to give the HyperRAM chip time to start up + -- Datasheet says 150usec is required, we do that, plus a bit. + signal start_delay_counter : integer + := 150*(1000/162)+20 + -- plus a correction factor to get initial config register write correctly + -- aligned with the clock + +2; + signal start_delay_expired : std_logic := '0'; + + -- phaseshift has to also start at 1 for the above to work. + signal hr_clk_phaseshift : std_logic := '1'; + signal hr_clk_phaseshift_current : std_logic := '1'; + signal last_hr_clk_phaseshift : std_logic := '1'; + + signal hr_clk_fast : std_logic := '1'; + signal hr_clk_fast_current : std_logic := '1'; + signal hr_clk : std_logic := '0'; + + signal hr_clock_phase165 : unsigned(1 downto 0) := "00"; + signal hr_clock_phase : unsigned(2 downto 0) := "000"; + signal hr_clock_phase_drive : unsigned(2 downto 0) := "111"; + + signal read_time_adjust : integer range 0 to 255 := 0; + signal seven_plus_read_time_adjust : unsigned(5 downto 0) := "000000"; + signal thirtyone_plus_read_time_adjust : unsigned(5 downto 0) := "000000"; + signal hyperram_access_address_read_time_adjusted : unsigned(5 downto 0) := "000000"; + + signal hyperram0_select : std_logic := '0'; + signal hyperram1_select : std_logic := '0'; + signal hyperram_access_address : unsigned(26 downto 0) := to_unsigned(0,27); + + signal read_request_held : std_logic := '0'; + signal write_request_held : std_logic := '0'; + signal mark_cache_for_prefetch : std_logic := '0'; + + signal viciv_last_request_toggle : std_logic := '0'; + signal viciv_bank : unsigned(7 downto 0) := x"00"; + signal viciv_data_buffer : cache_row_t := (others => x"00"); + signal viciv_buffer_toggle : std_logic := '0'; + signal last_viciv_buffer_toggle : std_logic := '0'; + signal viciv_next_byte : integer range 0 to 8 := 0; + signal viciv_request_count : unsigned(31 downto 0) := to_unsigned(0,32); + signal is_vic_fetch : boolean := false; + signal viciv_data_debug : std_logic := '0'; + signal viciv_debug_priority : std_logic := '0'; + + signal read_request_latch : std_logic := '0'; + signal read_request_delatch : std_logic := '0'; + signal read_request_prev : std_logic := '0'; + signal write_request_latch : std_logic := '0'; + signal write_request_prev : std_logic := '0'; + + signal prefetch_when_idle : boolean := false; + +begin + process (pixelclock,clock163,clock325,hr_clk,hr_clk_phaseshift) is + variable clock_status_vector : unsigned(4 downto 0); + variable tempaddr : unsigned(26 downto 0); + variable show_cache0 : boolean := false; + variable show_cache1 : boolean := false; + variable show_collect0 : boolean := false; + variable show_collect1 : boolean := false; + variable show_block : boolean := false; + variable show_always : boolean := true; + begin + if rising_edge(pixelclock) then + + invalidate_read_cache <= '0'; + cache_row_update_address_changed <= '0'; + + if read_request='1' then + read_request_latch <= '1'; + end if; + if write_request='1' then + write_request_latch <= '1'; + end if; + if read_request_delatch = '1' then + read_request_latch <= '0'; + end if; + + -- Present the data to the VIC-IV + if viciv_data_debug = '1' then + viciv_data_strobe <= '1'; + viciv_data_out <= viciv_request_count(7 downto 0); + else + viciv_data_strobe <= '0'; + end if; + if viciv_buffer_toggle /= last_viciv_buffer_toggle then + report "VIC: Starting to send data"; + last_viciv_buffer_toggle <= viciv_buffer_toggle; + viciv_data_out <= viciv_data_buffer(0); + report "VIC: Sending byte " & integer'image(0) + & " = $" & to_hstring(viciv_data_buffer(0)); + viciv_next_byte <= 1; + viciv_data_strobe <= '1'; + elsif viciv_next_byte < 8 then + report "VIC: Sending byte " & integer'image(viciv_next_byte) + & " = $" & to_hstring(viciv_data_buffer(viciv_next_byte)); + viciv_data_out <= viciv_data_buffer(viciv_next_byte); + viciv_next_byte <= viciv_next_byte + 1; + viciv_data_strobe <= '1'; + end if; + + if in_simulation = true then + write_latency2 <= to_unsigned(5,8); + extra_write_latency2 <= to_unsigned(3,8); + end if; + + report "read_request=" & std_logic'image(read_request) + & ", read_request_held=" & std_logic'image(read_request_held) + & ", write_request_held=" & std_logic'image(write_request_held) + & ", read_request_latch=" & std_logic'image(read_request_latch) + & ", write_request_latch=" & std_logic'image(write_request_latch) + & ", busy_internal=" & std_logic'image(busy_internal) + & ", write_request=" & std_logic'image(write_request) + & ", request_toggle(last) = " & std_logic'image(request_toggle) & "(" & std_logic'image(last_request_toggle) & ")." + & ", is_block_read=" & boolean'image(is_block_read) + & ", address=$" & to_hstring(address); + + -- Pseudo random bits so that we can do randomised cache row replacement + if random_bits /= to_unsigned(251,8) then + random_bits <= random_bits + 1; + else + random_bits <= x"00"; + end if; + + -- Update short-circuit cache line + -- (We don't change validity, since we don't know if it is + -- valid or not). + -- This has to happen IMMEDIATELY so that slow_devices doesn't + -- accidentally read old data, while we are still scheduling the write. + if address(26 downto 3) = current_cache_line_address(26 downto 3) then + report "Requesting update of current_cache_line due to write. Value = $" + & to_hstring(wdata) & ", byte offset = " & integer'image(to_integer(address(2 downto 0))); + if wen_lo = '1' then + current_cache_line_update(to_integer(address(2 downto 0))) <= wdata; + current_cache_line_update_flags(to_integer(address(2 downto 0))) <= + not current_cache_line_update_flags(to_integer(address(2 downto 0))); + current_cache_line_update_address <= current_cache_line_address; + end if; + if wen_hi = '1' then + current_cache_line_update(to_integer(address(2 downto 0))+1) <= wdata_hi; + current_cache_line_update_flags(to_integer(address(2 downto 0))+1) <= + not current_cache_line_update_flags(to_integer(address(2 downto 0))+1); + current_cache_line_update_address <= current_cache_line_address; + end if; + end if; + + if cache_enabled then + busy <= busy_internal or write_blocked or queued_write or queued2_write or (not start_delay_expired); + else + -- With no cache, we have to IMMEDIATELY assert busy when we see a + -- request to avoid a race-condition with slow_devices + busy <= busy_internal or write_blocked or queued_write or queued2_write + or read_request or write_request or read_request_latch or write_request_latch + or (not start_delay_expired); + end if; + + if write_blocked = '1' and first_transaction='0' then +-- report "DISPATCH: write_blocked asserted. Waiting for existing writes to flush..."; + null; + end if; + + -- Clear write block as soon as either write buffer clears + if (write_collect0_dispatchable='0' and write_collect0_toolate='0' and write_collect0_flushed='0') + or (write_collect1_dispatchable='0' and write_collect1_toolate='0' and write_collect1_flushed='0') + then + write_blocked <= queued_write or queued2_write; + else + write_blocked <= '1'; + busy <= '1'; + end if; + + -- Similarly as soon as we see a VIC-IV request come through we need to + -- assert busy + if viciv_request_toggle /= viciv_last_request_toggle then + busy <= '1'; + end if; + + fake_data_ready_strobe <= '0'; + + if read_request = '1' or write_request = '1' or read_request_latch='1' or write_request_latch='1' then + request_counter_int <= not request_counter_int; + request_counter <= request_counter_int; + end if; + + if cache_row0_address = cache_row1_address and cache_row0_address /= x"ffffff" then + report "ERROR: Cache row0 and row1 point to same address"; + show_cache0 := true; + show_cache1 := true; + end if; + + + + -- Clear write buffers once they have been flushed. + -- We have to wipe the address and valids, so that they don't get stuck being + -- used as stale sources for cache reading. + if write_collect0_dispatchable = '1' and write_collect0_toolate = '1' and write_collect0_flushed = '1' then + show_collect0 := true; + report "WRITE: Clearing collect0"; + write_collect0_address <= (others => '1'); + write_collect0_dispatchable <= '0'; + end if; + if write_collect1_dispatchable = '1' and write_collect1_toolate = '1' and write_collect1_flushed = '1' then + if write_collect1_dispatchable='1' then + show_collect1 := true; + end if; + report "WRITE: Clearing collect1"; + write_collect1_address <= (others => '1'); + write_collect1_dispatchable <= '0'; + end if; + + if write_collect0_dispatchable = '0' and write_collect0_toolate = '0' and write_collect0_flushed = '0' then + if queued_write='1' then + report "DISPATCH: Dequeuing queued write to $" & to_hstring(queued_waddr); + + -- Push it out as a normal batched write, that can collect others if they + -- come soon enough. + + write_collect0_valids <= (others => '0'); + if queued_wen_lo='1' then + write_collect0_valids(to_integer(queued_waddr(2 downto 0))) <= '1'; + write_collect0_data(to_integer(queued_waddr(2 downto 0))) <= queued_wdata; + end if; + if queued_wen_hi='1' then + write_collect0_valids(to_integer(queued_waddr(2 downto 0))+1) <= '1'; + write_collect0_data(to_integer(queued_waddr(2 downto 0))+1) <= queued_wdata_hi; + end if; + write_collect0_address <= queued_waddr(26 downto 3); + write_collect0_dispatchable <= '1'; + show_collect0 := true; + + queued_write <= '0'; + elsif queued2_write='1' then + report "DISPATCH: Dequeuing queued write to $" & to_hstring(queued2_waddr); + + -- Push it out as a normal batched write, that can collect others if they + -- come soon enough. + + write_collect0_valids <= (others => '0'); + if queued2_wen_lo='1' then + write_collect0_valids(to_integer(queued2_waddr(2 downto 0))) <= '1'; + write_collect0_data(to_integer(queued2_waddr(2 downto 0))) <= queued2_wdata; + end if; + if queued2_wen_hi='1' then + write_collect0_valids(to_integer(queued2_waddr(2 downto 0))+1) <= '1'; + write_collect0_data(to_integer(queued2_waddr(2 downto 0))+1) <= queued2_wdata_hi; + end if; + write_collect0_address <= queued2_waddr(26 downto 3); + write_collect0_dispatchable <= '1'; + show_collect0 := true; + + queued2_write <= '0'; + end if; + + end if; + if write_collect1_dispatchable = '0' and write_collect1_toolate = '0' and write_collect1_flushed = '0' then + if queued_write='1' then + report "DISPATCH: Dequeuing queued write to $" & to_hstring(queued_waddr); + + -- Push it out as a normal batched write, that can collect others if they + -- come soon enough. + + write_collect1_valids <= (others => '0'); + if queued_wen_lo='1' then + write_collect1_valids(to_integer(queued_waddr(2 downto 0))) <= '1'; + write_collect1_data(to_integer(queued_waddr(2 downto 0))) <= queued_wdata; + end if; + if queued_wen_hi='1' then + write_collect1_valids(to_integer(queued_waddr(2 downto 0))+1) <= '1'; + write_collect1_data(to_integer(queued_waddr(2 downto 0))+1) <= queued_wdata_hi; + end if; + write_collect1_address <= queued_waddr(26 downto 3); + write_collect1_dispatchable <= '1'; + show_collect1 := true; + + queued_write <= '0'; + end if; + end if; + + -- Ignore read requests to the current block read, as they get + -- short-circuited in the inner state machine to save time. + report "address = $" & to_hstring(address); + if (read_request or read_request_latch)='1' and busy_internal='0' + and ((is_block_read = false) or block_address_matches_address='0') + -- Don't but in on the VIC-IV (but once we have submitted a request, we + -- do have priority) + and (viciv_last_request_toggle = viciv_request_toggle) then + report "Making read request for $" & to_hstring(address); + -- Begin read request + + read_request_latch <= '0'; + + -- Check for cache read + -- We check the write buffers first, as any contents that they have + -- must take priority over everything else + if (block_valid='1') and (block_address_matches_address='1') then + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= block_data(to_integer(address(4 downto 3)))(to_integer(address(2 downto 0))); + if rdata_16en='1' then + fake_rdata_hi <= block_data(to_integer(address(4 downto 3)))(to_integer(address(2 downto 0))+1); + end if; + report "DISPATCH: Returning data $" + & to_hstring(block_data(to_integer(address(4 downto 3)))(to_integer(address(2 downto 0)))) + & " from read block."; + -- Now update current cache line to speed up subsequent reads + current_cache_line_update <= block_data(to_integer(address(4 downto 3))); + current_cache_line_new_address <= address(26 downto 3); + current_cache_line_update_all <= not current_cache_line_update_all; + + if (address(4 downto 3) = "11") and (flag_prefetch='1') + and (viciv_request_toggle = viciv_last_request_toggle) then + -- When attempting to read from the last 8 bytes of a block read, + -- we schedule a pre-fetch of the next 32 bytes, so that we can hide + -- the read latency as much as possible. + ram_reading <= '1'; + tempaddr(26 downto 5) := address(26 downto 5) + 1; + tempaddr(4 downto 0) := "00000"; + ram_address <= tempaddr; + request_toggle <= not request_toggle; + ram_prefetch <= true; + ram_normalfetch <= false; + + report "DISPATCH: Dispatching pre-fetch of $" & to_hstring(tempaddr); + -- Mark a cache line to receive the pre-fetched data, so that we don't + -- have to wait for it all to turn up, before being able to return + -- the first 8 bytes + mark_cache_for_prefetch <= '1'; + end if; + + elsif cache_enabled and rdata_16en='0' and (address(26 downto 3 ) = write_collect0_address and write_collect0_valids(to_integer(address(2 downto 0))) = '1') then + -- Write cache read-back + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= write_collect0_data(to_integer(address(2 downto 0))); + report "DISPATCH: Returning data $"& to_hstring(write_collect0_data(to_integer(address(2 downto 0))))&" from write collect0"; + elsif cache_enabled and rdata_16en='1' and (address(26 downto 3 ) = write_collect0_address + and write_collect0_valids(to_integer(address(2 downto 1)&"0")) = '1' + and write_collect0_valids(to_integer(address(2 downto 1)&"1")) = '1') then + -- Write cache read-back + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= write_collect0_data(to_integer(address(2 downto 1)&"0")); + fake_rdata_hi <= write_collect0_data(to_integer(address(2 downto 1)&"1")); + report "DISPATCH: Returning data $"& to_hstring(write_collect0_data(to_integer(address(2 downto 0))))&" from write collect0"; + elsif cache_enabled and rdata_16en='0' and (address(26 downto 3 ) = write_collect1_address and write_collect1_valids(to_integer(address(2 downto 0))) = '1') then + -- Write cache read-back + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= write_collect1_data(to_integer(address(2 downto 0))); + report "DISPATCH: Returning data $"& to_hstring(write_collect1_data(to_integer(address(2 downto 0))))&" from write collect1"; + elsif cache_enabled and rdata_16en='1' and (address(26 downto 3 ) = write_collect1_address + and write_collect1_valids(to_integer(address(2 downto 1)&"0")) = '1' + and write_collect1_valids(to_integer(address(2 downto 1)&"1")) = '1') then + -- Write cache read-back + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= write_collect1_data(to_integer(address(2 downto 1)&"0")); + fake_rdata_hi <= write_collect1_data(to_integer(address(2 downto 1)&"1")); + report "DISPATCH: Returning data $"& to_hstring(write_collect1_data(to_integer(address(2 downto 0))))&" from write collect1"; + elsif cache_enabled and rdata_16en='0' and (address(26 downto 3 ) = cache_row0_address and cache_row0_valids(to_integer(address(2 downto 0))) = '1') then + -- Cache reads + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= cache_row0_data(to_integer(address(2 downto 0))); + report "DISPATCH: Returning data $"& to_hstring(cache_row0_data(to_integer(address(2 downto 0))))&" from cache row0"; + elsif cache_enabled and rdata_16en='1' and (address(26 downto 3 ) = cache_row0_address + and cache_row0_valids(to_integer(address(2 downto 1)&"0")) = '1' + and cache_row0_valids(to_integer(address(2 downto 1)&"1")) = '1') then + -- Cache reads + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= cache_row0_data(to_integer(address(2 downto 1)&"0")); + fake_rdata_hi <= cache_row0_data(to_integer(address(2 downto 1)&"1")); + report "DISPATCH: Returning data $"& to_hstring(cache_row0_data(to_integer(address(2 downto 0))))&" from cache row0"; + elsif cache_enabled and rdata_16en='0' and (address(26 downto 3 ) = cache_row1_address and cache_row1_valids(to_integer(address(2 downto 0))) = '1') then + -- Cache read + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= cache_row1_data(to_integer(address(2 downto 0))); + report "DISPATCH: Returning data $"& to_hstring(cache_row1_data(to_integer(address(2 downto 0))))&" from cache row1"; + elsif cache_enabled and rdata_16en='1' and (address(26 downto 3 ) = cache_row1_address + and cache_row1_valids(to_integer(address(2 downto 1)&"0"))='1' + and cache_row1_valids(to_integer(address(2 downto 1)&"1"))='1') then + + -- Cache read + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + fake_rdata <= cache_row1_data(to_integer(address(2 downto 1)&"0")); + fake_rdata_hi <= cache_row1_data(to_integer(address(2 downto 1)&"1")); + report "DISPATCH: Returning data $"& to_hstring(cache_row1_data(to_integer(address(2 downto 0))))&" from cache row1"; + elsif address(23 downto 8) = x"00000" and address(25 downto 24) = "11" then + -- $B0000xx for now for debugging caches etc + case address(7 downto 0) is + when x"00" => fake_rdata(7) <= '1'; + fake_rdata(6 downto 3) <= (others => '0'); + fake_rdata(2 downto 0) <= cache_row0_address(23 downto 21); + when x"01" => fake_rdata <= cache_row0_address(20 downto 13); + when x"02" => fake_rdata <= cache_row0_address(12 downto 5); + when x"03" => fake_rdata(7 downto 3) <= cache_row0_address(4 downto 0); + fake_rdata(2 downto 0) <= "000"; + when x"04" => fake_rdata <= unsigned(cache_row0_valids); + when x"05" => fake_rdata <= x"AA"; + when x"06" => fake_rdata <= x"AA"; + when x"07" => fake_rdata <= x"AA"; + when x"08"|x"09"|x"0a"|x"0b"|x"0c"|x"0d"|x"0e"|x"0f" => + fake_rdata <= cache_row0_data(to_integer(address(2 downto 0))); + + when x"10" => fake_rdata(7) <= '1'; + fake_rdata(6 downto 3) <= (others => '0'); + fake_rdata(2 downto 0) <= cache_row1_address(23 downto 21); + when x"11" => fake_rdata <= cache_row1_address(20 downto 13); + when x"12" => fake_rdata <= cache_row1_address(12 downto 5); + when x"13" => fake_rdata(7 downto 3) <= cache_row1_address(4 downto 0); + fake_rdata(2 downto 0) <= "000"; + when x"14" => fake_rdata <= unsigned(cache_row1_valids); + when x"15" => fake_rdata <= x"AA"; + when x"16" => fake_rdata <= x"AA"; + when x"17" => fake_rdata <= x"AA"; + when x"18" + | x"19" + | x"1a" + | x"1b" + | x"1c" + | x"1d" + | x"1e" + | x"1f" => fake_rdata <= cache_row1_data(to_integer(address(2 downto 0))); + + when x"20" => fake_rdata <= write_collect0_address(23 downto 16); + when x"21" => fake_rdata <= write_collect0_address(15 downto 8); + when x"22" => fake_rdata(7 downto 3) <= write_collect0_address(7 downto 3); + fake_rdata(2 downto 0) <= "000"; + when x"23" => fake_rdata <= x"AA"; + when x"24" => fake_rdata <= unsigned(write_collect0_valids); + when x"25" => fake_rdata <= x"AA"; + when x"26" => fake_rdata <= x"00"; + fake_rdata(4) <= write_collect0_dispatchable; + fake_rdata(1) <= write_collect0_toolate; + fake_rdata(0) <= write_collect0_flushed; + when x"27" => fake_rdata <= x"AA"; + when x"28" + | x"29" + | x"2a" + | x"2b" + | x"2c" + | x"2d" + | x"2e" + | x"2f" => fake_rdata <= write_collect0_data(to_integer(address(2 downto 0))); + + when x"30" => fake_rdata <= write_collect1_address(23 downto 16); + when x"31" => fake_rdata <= write_collect1_address(15 downto 8); + when x"32" => fake_rdata(7 downto 3) <= write_collect1_address(7 downto 3); + fake_rdata(2 downto 0) <= "000"; + when x"33" => fake_rdata <= x"AA"; + when x"34" => fake_rdata <= unsigned(write_collect1_valids); + when x"35" => fake_rdata <= x"AA"; + when x"36" => fake_rdata <= x"00"; + fake_rdata(4) <= write_collect1_dispatchable; + fake_rdata(1) <= write_collect1_toolate; + fake_rdata(0) <= write_collect1_flushed; + when x"37" => fake_rdata <= x"AA"; + when x"38" + | x"39" + | x"3a" + | x"3b" + | x"3c" + | x"3d" + | x"3e" + | x"3f" => fake_rdata <= write_collect1_data(to_integer(address(2 downto 0))); + + when x"40" => fake_rdata <= block_address(23 downto 16); + when x"41" => fake_rdata <= block_address(15 downto 8); + when x"42" => fake_rdata(7 downto 5) <= block_address(7 downto 5); + fake_rdata(4 downto 0) <= "00000"; + when x"43" => fake_rdata <= x"AA"; + when x"44" => fake_rdata <= x"00"; + if (block_valid='1') then fake_rdata <= x"FF"; end if; + + when x"50" + | x"51" + | x"52" + | x"53" + | x"54" + | x"55" + | x"56" + | x"57" => fake_rdata <= block_data(0)(to_integer(address(2 downto 0))); + when x"58" + | x"59" + | x"5a" + | x"5b" + | x"5c" + | x"5d" + | x"5e" + | x"5f" => fake_rdata <= block_data(1)(to_integer(address(2 downto 0))); + + + when x"60" + | x"61" + | x"62" + | x"63" + | x"64" + | x"65" + | x"66" + | x"67" => fake_rdata <= block_data(2)(to_integer(address(2 downto 0))); + when x"68" + | x"69" + | x"6a" + | x"6b" + | x"6c" + | x"6d" + | x"6e" + | x"6f" => fake_rdata <= block_data(3)(to_integer(address(2 downto 0))); + + when x"80" => fake_rdata <= viciv_request_count(31 downto 24); + when x"81" => fake_rdata <= viciv_request_count(23 downto 16); + when x"82" => fake_rdata <= viciv_request_count(15 downto 8); + when x"83" => fake_rdata <= viciv_request_count( 7 downto 0); + + when x"90" => fake_rdata(2 downto 0) <= current_cache_line_address_drive(26 downto 24); + fake_rdata(7) <= '1'; + fake_rdata(6 downto 3) <= "0000"; + when x"91" => fake_rdata <= current_cache_line_address_drive(23 downto 16); + when x"92" => fake_rdata <= current_cache_line_address_drive(15 downto 8); + when x"93" => fake_rdata(7 downto 3) <= current_cache_line_address_drive( 7 downto 3); + fake_rdata(2 downto 0) <= "000"; + when x"94" => fake_rdata <= (others => current_cache_line_valid_drive); + + when x"98" + | x"99" + | x"9a" + | x"9b" + | x"9c" + | x"9d" + | x"9e" + | x"9f" => fake_rdata <= current_cache_line_drive(to_integer(address(2 downto 0))); + + + when others => fake_rdata <= x"BF"; + end case; + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + report "asserting data_ready_strobe for fake read"; + elsif address(23 downto 4) = x"FFFFF" and address(25 downto 24) = "11" then + -- Allow reading from dummy debug bitbash registers at $BFFFFFx + case address(3 downto 0) is + when x"0" => + fake_rdata <= to_unsigned(write_continues_max,8); + when x"1" => + fake_rdata <= viciv_bank; + when x"2" => + fake_rdata(0) <= fast_cmd_mode; + fake_rdata(1) <= fast_read_mode; + fake_rdata(2) <= fast_write_mode; + fake_rdata(3) <= read_phase_shift; + fake_rdata(4) <= block_read_enable; + fake_rdata(5) <= flag_prefetch; + fake_rdata(6) <= enable_current_cache_line; + if cache_enabled then + fake_rdata(7) <= '1'; + else + fake_rdata(7) <= '0'; + end if; + when x"3" => + fake_rdata <= write_latency; + when x"4" => + fake_rdata <= extra_write_latency; + when x"5" => + fake_rdata <= to_unsigned(read_time_adjust,8); + when x"6" => + fake_rdata <= rwr_delay; + when x"7" => + fake_rdata <= unsigned(cache_row0_valids); + when x"8" => + fake_rdata <= conf_buf0; + when x"9" => + fake_rdata <= conf_buf1; + + when x"a" => + fake_rdata <= cache_row0_address(7 downto 0); + when x"b" => + fake_rdata <= cache_row0_address(15 downto 8); + when x"c" => + fake_rdata <= cache_row0_address(23 downto 16); + + when x"d" => + fake_rdata <= write_latency2; + when x"e" => + fake_rdata <= extra_write_latency2; + when x"f" => + fake_rdata <= x"00"; + fake_rdata(0) <= viciv_data_debug; + fake_rdata(1) <= viciv_debug_priority; + when others => + -- This seems to be what gets returned all the time + fake_rdata <= x"42"; + end case; + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + report "asserting data_ready_strobe for fake read"; + elsif request_accepted = request_toggle then + -- Normal RAM read. + report "request_toggle flipped"; + ram_reading <= '1'; + ram_address <= address; + ram_normalfetch <= true; + -- We just need to check if there is a pre-fetch already + -- queued for this same address + if address(26 downto 3) = ram_address(26 downto 3) and ram_prefetch then + report "DISPATCH: Merging read with pre-fetch."; + else + report "DISPATCH: Cancelling pre-fetch to prioritise explicit read"; + ram_prefetch <= false; + end if; + request_toggle <= not request_toggle; + end if; + elsif queued_write='1' and write_collect0_dispatchable='0' and write_collect0_flushed='0' + and write_collect0_toolate='0' then + + report "DISPATCH: Executing queued write to $" & to_hstring(queued_waddr); + + -- Push it out as a normal batched write, that can collect others if they + -- come soon enough. + + write_collect0_valids <= (others => '0'); + if queued_wen_lo='1' then + write_collect0_valids(to_integer(queued_waddr(2 downto 0))) <= '1'; + write_collect0_data(to_integer(queued_waddr(2 downto 0))) <= queued_wdata; + end if; + if queued_wen_hi='1' then + write_collect0_valids(to_integer(queued_waddr(2 downto 0))+1) <= '1'; + write_collect0_data(to_integer(queued_waddr(2 downto 0))+1) <= queued_wdata_hi; + end if; + write_collect0_address <= queued_waddr(26 downto 3); + write_collect0_dispatchable <= '1'; + show_collect0 := true; + + queued_write <= '0'; + + elsif (write_request or write_request_latch)='1' and busy_internal='0' then + report "Making write request: addr $" & to_hstring(address) & " <= " & to_hstring(wdata); + -- Begin write request + -- Latch address and data + + write_request_latch <= '0'; + + if address(23 downto 4) = x"FFFFF" and address(25 downto 24) = "11" then + case address(3 downto 0) is + when x"0" => + write_continues_max <= to_integer(wdata); + when x"1" => + viciv_bank <= wdata; + when x"2" => + fast_cmd_mode <= wdata(0); + fast_read_mode <= wdata(1); + fast_write_mode <= wdata(2); + read_phase_shift <= wdata(3); + block_read_enable <= wdata(4); + flag_prefetch <= wdata(5); + enable_current_cache_line <= wdata(6); + if wdata(7)='1' then + cache_enabled <= true; + else + cache_enabled <= false; + end if; + when x"3" => + write_latency <= wdata; + when x"4" => + extra_write_latency <= wdata; + when x"5" => + read_time_adjust <= to_integer(wdata); + when x"6" => + rwr_delay <= wdata; + when x"8" => + conf_buf0_in <= wdata; + conf_buf0_set <= not conf_buf0_set; + when x"9" => + conf_buf1_in <= wdata; + conf_buf1_set <= not conf_buf1_set; + when x"d" => + write_latency2 <= wdata; + when x"e" => + extra_write_latency2 <= wdata; + when x"f" => + viciv_data_debug <= wdata(0); + viciv_debug_priority <= wdata(1); + when others => + null; + end case; + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + else + -- Always do cached writes, as apart from the latency before + -- they get written out, it seems to be pretty reliable + -- if cache_enabled = false then + if false then + -- Do normal write request + report "request_toggle flipped"; + report "DISPATCH: Accepted non-cached write"; + ram_prefetch <= false; + ram_normalfetch <= true; + request_toggle <= not request_toggle; + ram_reading <= '0'; + ram_address <= address; + ram_wdata <= wdata; + ram_wdata_hi <= wdata_hi; + ram_wdata_enlo <= wen_lo; + ram_wdata_enhi <= wen_hi; + else + -- Collect writes together for dispatch + + -- Can we add the write to an existing collected write? + if write_collect0_toolate = '0' and write_collect0_address = address(26 downto 3) + and write_collect0_dispatchable = '1' and write_collect0_toolate='0' + then + if wen_lo='1' then + write_collect0_valids(to_integer(address(2 downto 0))) <= '1'; + write_collect0_data(to_integer(address(2 downto 0))) <= wdata; + end if; + if wen_hi='1' then + write_collect0_valids(to_integer(address(2 downto 0))+1) <= '1'; + write_collect0_data(to_integer(address(2 downto 0))+1) <= wdata_hi; + end if; + show_collect0 := true; + elsif write_collect1_toolate = '0' and write_collect1_address = address(26 downto 3) + and write_collect1_dispatchable = '1' and write_collect1_toolate='0' then + if wen_lo='1' then + write_collect1_valids(to_integer(address(2 downto 0))) <= '1'; + write_collect1_data(to_integer(address(2 downto 0))) <= wdata; + end if; + if wen_hi='1' then + write_collect1_valids(to_integer(address(2 downto 0))+1) <= '1'; + write_collect1_data(to_integer(address(2 downto 0))+1) <= wdata_hi; + end if; + show_collect1 := true; + elsif write_collect0_dispatchable = '0' and write_collect0_toolate='0' then + write_collect0_valids <= (others => '0'); + if wen_lo='1' then + write_collect0_valids(to_integer(address(2 downto 0))) <= '1'; + write_collect0_data(to_integer(address(2 downto 0))) <= wdata; + end if; + if wen_hi='1' then + write_collect0_valids(to_integer(address(2 downto 0))+1) <= '1'; + write_collect0_data(to_integer(address(2 downto 0))+1) <= wdata_hi; + end if; + + write_collect0_address <= address(26 downto 3); + write_collect0_dispatchable <= '1'; + -- Block further writes if we already have one busy write buffer + write_blocked <= '1'; + show_collect0 := true; + elsif write_collect1_dispatchable = '0' and write_collect1_toolate='0' then + write_collect1_valids <= (others => '0'); + if wen_lo='1' then + write_collect1_valids(to_integer(address(2 downto 0))) <= '1'; + write_collect1_data(to_integer(address(2 downto 0))) <= wdata; + end if; + if wen_hi='1' then + write_collect1_valids(to_integer(address(2 downto 0))+1) <= '1'; + write_collect1_data(to_integer(address(2 downto 0))+1) <= wdata_hi; + end if; + write_collect1_address <= address(26 downto 3); + write_collect1_dispatchable <= '1'; + -- Block further writes if we already have one busy write buffer + write_blocked <= '1'; + show_collect1 := true; + else + -- No write collection point that we can use, so just block until + -- one becomes available + report "DISPATCH: Write blocked due to busy write buffers: " & + " addr $" & to_hstring(address) & " <= " & to_hstring(wdata); + if queued_write='1' then + -- Bother. We already had a queued write. + -- So remember that one, too + report "Stashing in queued2"; + queued2_waddr <= address; + queued2_wdata <= wdata; + queued2_wdata_hi <= wdata_hi; + queued2_wen_lo <= wen_lo; + queued2_wen_hi <= wen_hi; + queued2_write <= '1'; + else + report "Stashing in queued"; + queued_waddr <= address; + queued_wdata <= wdata; + queued_wdata_hi <= wdata_hi; + queued_wen_lo <= wen_lo; + queued_wen_hi <= wen_hi; + queued_write <= '1'; + end if; + + end if; + + -- Update read cache structures when writing + report "CACHE: Requesting update of cache due to write: $" & to_hstring(address) & " = $" & to_hstring(wdata); + cache_row_update_address <= address(26 downto 3); + cache_row_update_address_changed <= '1'; + cache_row_update_byte <= to_integer(address(2 downto 0)); + cache_row_update_value <= wdata; + cache_row_update_value_hi <= wdata_hi; + cache_row_update_lo <= wen_lo; + cache_row_update_hi <= wen_hi; + if cache_row_update_toggle = not last_cache_row_update_toggle then + -- At least one other cache update is pending. This means that + -- we will not be able to keep the cache consistent. The only + -- option is to invalidate the read cache rows, data block, + -- and current_cache_line. + invalidate_read_cache <= '1'; + else + cache_row_update_toggle <= not last_cache_row_update_toggle; + end if; + + end if; + end if; + else + -- Nothing new to do + if data_ready_toggle /= last_data_ready_toggle then + last_data_ready_toggle <= data_ready_toggle; + report "asserting fake_data_ready_strobe"; + fake_data_ready_strobe <= '1'; + end if; + end if; + + end if; + -- Optionally delay HR_CLK by 1/2 an 160MHz clock cycle + -- (actually just by optionally inverting it) + if rising_edge(clock325) then + + if show_cache0 or show_always then + report "cache_row0_address_matches_cache_row_update_address=" + & std_logic'image(cache_row0_address_matches_cache_row_update_address) + & ", cache_row_update_address=$" & to_hstring(cache_row_update_address&"000"); + report "CACHE cache0: address=$" & to_hstring(cache_row0_address&"000") & ", valids=" & to_string(cache_row0_valids) + & ", data = " + & to_hstring(cache_row0_data(0)) & " " + & to_hstring(cache_row0_data(1)) & " " + & to_hstring(cache_row0_data(2)) & " " + & to_hstring(cache_row0_data(3)) & " " + & to_hstring(cache_row0_data(4)) & " " + & to_hstring(cache_row0_data(5)) & " " + & to_hstring(cache_row0_data(6)) & " " + & to_hstring(cache_row0_data(7)) & " "; + show_cache0 := false; + end if; + + if show_cache1 or show_always then + report "CACHE cache1: address=$" & to_hstring(cache_row1_address&"000") & ", valids=" & to_string(cache_row1_valids) + & ", data = " + & to_hstring(cache_row1_data(0)) & " " + & to_hstring(cache_row1_data(1)) & " " + & to_hstring(cache_row1_data(2)) & " " + & to_hstring(cache_row1_data(3)) & " " + & to_hstring(cache_row1_data(4)) & " " + & to_hstring(cache_row1_data(5)) & " " + & to_hstring(cache_row1_data(6)) & " " + & to_hstring(cache_row1_data(7)) & " "; + show_cache1 := false; + end if; + if show_collect0 or show_always then + report "CACHE write0: $" & to_hstring(write_collect0_address&"000") & ", v=" & to_string(write_collect0_valids) + & ", d=" & std_logic'image(write_collect0_dispatchable) + & ", late=" & std_logic'image(write_collect0_toolate) + & ", fl=" & std_logic'image(write_collect0_flushed) + & ", data = " + & to_hstring(write_collect0_data(0)) & " " + & to_hstring(write_collect0_data(1)) & " " + & to_hstring(write_collect0_data(2)) & " " + & to_hstring(write_collect0_data(3)) & " " + & to_hstring(write_collect0_data(4)) & " " + & to_hstring(write_collect0_data(5)) & " " + & to_hstring(write_collect0_data(6)) & " " + & to_hstring(write_collect0_data(7)) & " "; + show_collect0 := false; + end if; + if show_collect1 or show_always then + report "CACHE write1: $" & to_hstring(write_collect1_address&"000") & ", v=" & to_string(write_collect1_valids) + & ", d=" & std_logic'image(write_collect1_dispatchable) + & ", late=" & std_logic'image(write_collect1_toolate) + & ", fl=" & std_logic'image(write_collect1_flushed) + & ", data = " + & to_hstring(write_collect1_data(0)) & " " + & to_hstring(write_collect1_data(1)) & " " + & to_hstring(write_collect1_data(2)) & " " + & to_hstring(write_collect1_data(3)) & " " + & to_hstring(write_collect1_data(4)) & " " + & to_hstring(write_collect1_data(5)) & " " + & to_hstring(write_collect1_data(6)) & " " + & to_hstring(write_collect1_data(7)) & " "; + show_collect1 := false; + end if; + if show_block or show_always then + report "CACHE block0: $" & to_hstring(block_address&"00000") & ", valid=" & std_logic'image(block_valid) + & ", byte_phase=" & integer'image(to_integer(byte_phase)); + for i in 0 to 3 loop + report "CACHE block0 segment " & integer'image(i) & ": " + & to_hstring(block_data(i)(0)) & " " + & to_hstring(block_data(i)(1)) & " " + & to_hstring(block_data(i)(2)) & " " + & to_hstring(block_data(i)(3)) & " " + & to_hstring(block_data(i)(4)) & " " + & to_hstring(block_data(i)(5)) & " " + & to_hstring(block_data(i)(6)) & " " + & to_hstring(block_data(i)(7)) & " "; + end loop; + show_block := false; + end if; + + + hr_clock_phase_drive <= hr_clock_phase; + hr_clock_phase <= hr_clock_phase + 1; + -- Changing at the end of a phase cycle prevents us having any + -- problematically short clock pulses when it matters. + if hr_clock_phase_drive="110" then + hr_clk_fast_current <= hr_clk_fast; + hr_clk_phaseshift_current <= hr_clk_phaseshift; + if hr_clk_fast /= hr_clk_fast_current or hr_clk_phaseshift_current /= hr_clk_phaseshift then + report "Updating hr_clock_fast to " & std_logic'image(hr_clk_fast) + & ", hr_clk_phaseshift to " & std_logic'image(hr_clk_phaseshift); + end if; + end if; + + -- Only change clock mode when safe to do so + clock_status_vector(4) := hr_clk_fast_current; + clock_status_vector(3) := hr_clk_phaseshift_current; + clock_status_vector(2 downto 0) := hr_clock_phase; + report "clock phase vector = " & to_string(std_logic_vector(clock_status_vector)); + case clock_status_vector is + -- Slow clock rate, no phase shift + when "00000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "00001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "00010" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "00011" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "00100" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "00101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "00110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "00111" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + + -- Slow clock rate, with phase shift = bring forward tick by 1/2 a cycle + when "01000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "01001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "01010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "01011" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "01100" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "01101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "01110" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "01111" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + + -- Fast clock rate, no phase shift + when "10000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "10001" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "10010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "10011" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "10100" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "10101" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "10110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "10111" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + + -- Fast clock rate, with phase shift + when "11000" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "11001" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "11010" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "11011" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "11100" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + when "11101" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "11110" => hr_clk <= '1'; hr_clk_p <= '1'; hr_clk_n <= '0'; + when "11111" => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + + when others => hr_clk <= '0'; hr_clk_p <= '0'; hr_clk_n <= '1'; + end case; + + end if; + + if rising_edge(clock163) then + hr_clock_phase165 <= hr_clock_phase165 + 1; + + cycle_count <= cycle_count + 1; + + if read_request_delatch='1' and read_request_latch='0' then + read_request_delatch <= '0'; + end if; + + mark_cache_for_prefetch <= '0'; + + hyperram_access_address_read_time_adjusted <= to_unsigned(to_integer(hyperram_access_address(2 downto 0))+read_time_adjust,6); + seven_plus_read_time_adjust <= to_unsigned(7 + read_time_adjust,6); + thirtyone_plus_read_time_adjust <= to_unsigned(31 + read_time_adjust,6); + + -- We run double the clock speed of the pixelclock area, so no request + -- can come in during the extra drive cycle we use to update these values + -- so as to improve the timing closure of the whole thing + ram_wdata_drive <= ram_wdata; + ram_wdata_hi_drive <= ram_wdata_hi; + ram_address_drive <= ram_address; + ram_reading_drive <= ram_reading; + ram_wdata_enlo_drive <= ram_wdata_enlo; + ram_wdata_enhi_drive <= ram_wdata_enhi; + if ram_address(26 downto 3) = current_cache_line_address(26 downto 3) then + ram_address_matches_current_cache_line_address <= '1'; + else + ram_address_matches_current_cache_line_address <= '0'; + end if; + if cache_row0_address = ram_address(26 downto 3) then + cache_row0_address_matches_ram_address <= '1'; + else + cache_row0_address_matches_ram_address <= '0'; + end if; + if cache_row1_address = ram_address(26 downto 3) then + cache_row1_address_matches_ram_address <= '1'; + else + cache_row1_address_matches_ram_address <= '0'; + end if; + if write_collect0_address = background_write_next_address then + background_write_next_address_matches_collect0 <= '1'; + else + background_write_next_address_matches_collect0 <= '0'; + end if; + if write_collect1_address = background_write_next_address then + background_write_next_address_matches_collect1 <= '1'; + else + background_write_next_address_matches_collect1 <= '0'; + end if; + if write_collect1_address = write_collect0_address + 1 then + collect1_matches_collect0_plus_1 <= '1'; + else + collect1_matches_collect0_plus_1 <= '0'; + end if; + if write_collect0_address = write_collect1_address + 1 then + collect0_matches_collect1_plus_1 <= '1'; + else + collect0_matches_collect1_plus_1 <= '0'; + end if; + + + if address(26 downto 5) = block_address then + block_address_matches_address <= '1'; + else + block_address_matches_address <= '0'; + end if; + + if address(26 downto 5) = hyperram_access_address(26 downto 5) then + address_matches_hyperram_access_address_block <= '1'; + else + address_matches_hyperram_access_address_block <= '0'; + end if; + if read_request='1' or read_request_held='1' then + read_request_prev <= '1'; + else + read_request_prev <= '0'; + end if; + if write_request='1' or write_request_held='1' then + write_request_prev <= '1'; + else + write_request_prev <= '0'; + end if; + + if write_collect0_address = (write_collect1_address + 1) then + write_collect0_address_matches_write_collect1_address_plus_1 <= '1'; + else + write_collect0_address_matches_write_collect1_address_plus_1 <= '0'; + end if; + + if to_integer(byte_phase) > to_integer(address(4 downto 0)) then + byte_phase_greater_than_address_low_bits <= '1'; + else + byte_phase_greater_than_address_low_bits <= '0'; + end if; + if to_integer(byte_phase) > to_integer(address(4 downto 3)&"111") then + byte_phase_greater_than_address_end_of_row <= '1'; + else + byte_phase_greater_than_address_end_of_row <= '0'; + end if; + + + -- Update short-circuit cache line + -- (We don't change validity, since we don't know if it is + -- valid or not). + if ram_address_matches_current_cache_line_address = '1' then + if ram_wdata_enlo_drive='1' then + current_cache_line_drive(to_integer(hyperram_access_address(2 downto 0))) <= ram_wdata_drive; + end if; + if ram_wdata_enhi_drive='1' then + current_cache_line_drive(to_integer(hyperram_access_address(2 downto 0))+1) <= ram_wdata_hi_drive; + end if; + end if; + + if current_cache_line_address(26 downto 5) = block_address(26 downto 5) + and (current_cache_line_address(4 downto 3) /= "11") and (block_valid='1') then + current_cache_line_matches_block <= '1'; + else + current_cache_line_matches_block <= '0'; + end if; + if (current_cache_line_address(26 downto 5) + 1) = block_address(26 downto 5) + and (current_cache_line_address(4 downto 3) = "11") and (block_valid='1') then + current_cache_line_plus_1_matches_block <= '1'; + else + current_cache_line_plus_1_matches_block <= '0'; + end if; + + if cache_row0_address = hyperram_access_address(26 downto 3) then + hyperram_access_address_matches_cache_row0 <= '1'; + else + hyperram_access_address_matches_cache_row0 <= '0'; + end if; + if cache_row1_address = hyperram_access_address(26 downto 3) then + hyperram_access_address_matches_cache_row1 <= '1'; + else + hyperram_access_address_matches_cache_row1 <= '0'; + end if; + if cache_row0_address = cache_row_update_address then + cache_row0_address_matches_cache_row_update_address <= '1'; + else + cache_row0_address_matches_cache_row_update_address <= '0'; + end if; + if cache_row1_address = cache_row_update_address then + cache_row1_address_matches_cache_row_update_address <= '1'; + else + cache_row1_address_matches_cache_row_update_address <= '0'; + end if; + if block_address = cache_row_update_address(26 downto 5) then + block_address_matches_cache_row_update_address <= '1'; + else + block_address_matches_cache_row_update_address <= '0'; + end if; + + + if enable_current_cache_line='1' then +-- if current_cache_line /= current_cache_line_drive then +-- report "CACHE: Updating current_cache_line from drive. Now " +-- & to_hstring(current_cache_line_drive(0)) & " ..."; +-- end if; + current_cache_line <= current_cache_line_drive; + current_cache_line_address <= current_cache_line_address_drive; + current_cache_line_valid <= current_cache_line_valid_drive; + end if; + + if mark_cache_for_prefetch='1' then + if random_bits(1)='0' then + report "Zeroing cache_row0_valids"; + cache_row0_valids <= (others => '0'); + cache_row0_address <= ram_address(26 downto 3); + cache_row0_address_matches_ram_address <= '1'; + show_cache0 := true; + else + report "Zeroing cache_row1_valids"; + cache_row1_valids <= (others => '0'); + cache_row1_address <= ram_address(26 downto 3); + cache_row1_address_matches_ram_address <= '1'; + show_cache1 := true; + end if; + end if; + + if data_ready_strobe_hold = '0' then + if fake_data_ready_strobe='1' then + report "asserting data_ready_strobe via fake_data_ready_strobe"; + end if; + data_ready_strobe <= fake_data_ready_strobe; + if fake_data_ready_strobe='1' then + report "DISPATCH: holding data_ready_strobe via fake data = $" & to_hstring(fake_rdata); + rdata <= fake_rdata; + rdata_hi <= fake_rdata_hi; + end if; + else + report "holding data_ready_strobe for an extra cycle"; + report "asserting data_ready_strobe"; + data_ready_strobe <= '1'; + end if; + data_ready_strobe_hold <= '0'; + + -- HyperRAM state machine + report "State = " & state_t'image(state) & " @ Cycle " & integer'image(cycle_count) + & ", config_reg_write=" & std_logic'image(config_reg_write); + + if conf_buf0_set /= last_conf_buf0_set then + last_conf_buf0_set <= conf_buf0_set; + conf_buf0 <= conf_buf0_in; + end if; + if conf_buf1_set /= last_conf_buf1_set then + last_conf_buf1_set <= conf_buf1_set; + conf_buf1 <= conf_buf1_in; + end if; + + + -- Invalidate cache if disabled + if cache_enabled = false then + report "Zeroing cache_row0_valids"; + cache_row0_valids <= (others => '0'); + cache_row1_valids <= (others => '0'); + current_cache_line_valid_drive <= '0'; + block_valid <= '0'; + end if; + + if current_cache_line_update_all = last_current_cache_line_update_all then + if current_cache_line_update_address = current_cache_line_address_drive then + for i in 0 to 7 loop + if current_cache_line_update_flags(i) /= last_current_cache_line_update_flags(i) then + report "CACHE: Driving update to current_cache_line byte " & integer'image(i) + & ", value $" & to_hstring(current_cache_line_update(i)); + last_current_cache_line_update_flags(i) <= current_cache_line_update_flags(i); + current_cache_line_drive(i) <= current_cache_line_update(i); + end if; + end loop; + else + report "CACHE: Rejecting stale current line updates for $" & to_hstring(current_cache_line_update_address&"000"); + end if; + else + report "DISPATCHER: Replacing current cache line with $" & to_hstring(current_cache_line_new_address&"000"); + last_current_cache_line_update_all <= current_cache_line_update_all; + current_cache_line_address_drive <= current_cache_line_new_address; + current_cache_line_drive <= current_cache_line_update; + current_cache_line_update_flags <= last_current_cache_line_update_flags; + end if; + + -- See if slow_devices is asking for the next 8 bytes. + -- If we have it, then pre-present it if we have it in our data block + -- (If it isn't in the data block, then we will have presumably already + -- started a pre-fetch when we serviced the access that created the current + -- data value in the current cache line entry. + -- This has to happen below the above single-byte update stuff, so that + -- we end retain cache coherency + if expansionram_current_cache_line_next_toggle /= last_current_cache_next_toggle then + last_current_cache_next_toggle <= expansionram_current_cache_line_next_toggle; + if current_cache_line_plus_1_matches_block = '1' + then + report "DISPATCHER: Presenting next 8 bytes to slow_devices. Was $" + & to_hstring(current_cache_line_address&"000") & ", new is $" + & to_hstring(current_cache_line_address(26 downto 5)&(current_cache_line_address(4 downto 3) + 1)&"000"); + current_cache_line_address_drive(26 downto 5) <= block_address; + current_cache_line_address_drive(4 downto 3) <= "00"; + current_cache_line_drive <= block_data(0); + current_cache_line_valid_drive <= '1'; + -- Cancel any other updates that might be scheduled for this + last_current_cache_line_update_all <= current_cache_line_update_all; + last_current_cache_line_update_flags <= current_cache_line_update_flags; + end if; + if current_cache_line_matches_block = '1' + then + report "DISPATCHER: Presenting next 8 bytes to slow_devices. Was $" + & to_hstring(current_cache_line_address&"000") & ", new is $" + & to_hstring(current_cache_line_address(26 downto 5)&(current_cache_line_address(4 downto 3) + 1)&"000") + & ", data is:" + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(0)) + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(1)) + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(2)) + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(3)) + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(4)) + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(5)) + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(6)) + & " " & to_hstring(block_data(to_integer(current_cache_line_address(4 downto 3)) + 1)(7)); + current_cache_line_address_drive(4 downto 3) <= current_cache_line_address(4 downto 3) + 1; + current_cache_line_drive <= block_data(to_integer(current_cache_line_address(4 downto 3)) + 1); + current_cache_line_valid_drive <= '1'; + -- Cancel any other updates that might be scheduled for this + last_current_cache_line_update_all <= current_cache_line_update_all; + last_current_cache_line_update_flags <= current_cache_line_update_flags; + + -- If it was the last row in the block that we have just presented, + -- it would be a really good idea to dispatch a pre-fetch right now. + -- The trick is that we can only safely do this, if we are idle. + if current_cache_line_address(4 downto 3) = "10" and flag_prefetch='1' then + report "DISPATCHER: Queuing chained pre-fetch"; + prefetch_when_idle <= true; + end if; + + end if; + end if; + + -- Keep read request when required + read_request_held <= read_request; + write_request_held <= write_request; + + if start_delay_expired='0' then + start_delay_counter <= start_delay_counter - 1; + if start_delay_counter = 0 then + start_delay_expired <= '1'; + state <= WriteSetup; + end if; + end if; + +-- report "CACHE: row update status: requested = " & boolean'image(cache_row_update_toggle /= last_cache_row_update_toggle) +-- & ", cache_row_update_address_changed = " & std_logic'image(cache_row_update_address_changed); + + if cache_row_update_toggle /= last_cache_row_update_toggle and cache_row_update_address_changed = '0' then + if cache_row0_address_matches_cache_row_update_address = '1' then + if cache_row_update_lo='1' then + report "DISPATCH: Updating cache0 via write: $" & to_hstring((cache_row_update_address&"000")+cache_row_update_byte) + & " gets $" & to_hstring(cache_row_update_value); + cache_row0_valids(cache_row_update_byte) <= '1'; + cache_row0_data(cache_row_update_byte) <= cache_row_update_value; + end if; + if cache_row_update_hi='1' then + report "DISPATCH: Updating cache0 via write: $" & to_hstring((cache_row_update_address&"001")+cache_row_update_byte) + & " gets $" & to_hstring(cache_row_update_value_hi); + cache_row0_valids(cache_row_update_byte+1) <= '1'; + cache_row0_data(cache_row_update_byte+1) <= cache_row_update_value_hi; + end if; + show_cache0 := true; + end if; + if cache_row1_address_matches_cache_row_update_address = '1' then + if cache_row_update_lo='1' then + report "DISPATCH: Updating cache1 via write: $" & to_hstring((cache_row_update_address&"000")+cache_row_update_byte) + & " gets $" & to_hstring(cache_row_update_value); + cache_row1_valids(cache_row_update_byte) <= '1'; + cache_row1_data(cache_row_update_byte) <= cache_row_update_value; + end if; + if cache_row_update_hi='1' then + report "DISPATCH: Updating cache1 via write: $" & to_hstring((cache_row_update_address&"001")+cache_row_update_byte) + & " gets $" & to_hstring(cache_row_update_value); + cache_row1_valids(cache_row_update_byte+1) <= '1'; + cache_row1_data(cache_row_update_byte+1) <= cache_row_update_value_hi; + end if; + show_cache1 := true; + end if; + if block_address_matches_cache_row_update_address = '1' then + if cache_row_update_lo='1' then + report "DISPATCH: Updating block data via write: $" & to_hstring((cache_row_update_address&"000")+cache_row_update_byte) + & " gets $" & to_hstring(cache_row_update_value); + block_data(to_integer(cache_row_update_address(4 downto 3)))(cache_row_update_byte) + <= cache_row_update_value; + end if; + if cache_row_update_hi='1' then + report "DISPATCH: Updating block data via write: $" & to_hstring((cache_row_update_address&"001")+cache_row_update_byte) + & " gets $" & to_hstring(cache_row_update_value_hi); + block_data(to_integer(cache_row_update_address(4 downto 3)))(cache_row_update_byte+1) + <= cache_row_update_value_hi; + end if; + show_block := true; + end if; + end if; + + if invalidate_read_cache='1' then + report "CACHE: Invalidating read cache due to write congestion."; + cache_row0_valids <= (others => '0'); + cache_row1_valids <= (others => '0'); + block_valid <= '0'; + current_cache_line_valid_drive <= '0'; + last_cache_row_update_toggle <= cache_row_update_toggle; + end if; + + case state is + when StartupDelay => + null; + when ReadAbort => + -- Make sure we don't abort a read so quickly, that we allow + -- glitching of clock line with clock phase shifting + hr_cs0 <= '1'; + state <= Idle; + when Idle => + report "Tristating hr_d"; + hr_d <= (others => 'Z'); + + read_request_held <= '0'; + write_request_held <= '0'; + + if not cache_enabled then + busy_internal <= '0'; + end if; + + first_transaction <= '0'; + is_block_read <= false; + is_prefetch <= ram_prefetch; + is_expected_to_respond <= ram_normalfetch; + is_vic_fetch <= false; + + -- All commands need the clock offset by 1/2 cycle + hr_clk_phaseshift <= write_phase_shift; + hr_clk_fast <= '1'; + + pause_phase <= '0'; + countdown_timeout <= '0'; + + -- Clear write buffer flags when they are empty + if write_collect0_dispatchable = '0' then + if write_collect0_toolate = '1' then + show_collect0 := true; + end if; + write_collect0_toolate <= '0'; + write_collect0_flushed <= '0'; + end if; + if write_collect1_dispatchable = '0' then + if write_collect1_toolate = '1' then + show_collect1 := true; + end if; + write_collect1_toolate <= '0'; + write_collect1_flushed <= '0'; + end if; + + -- Mark us ready for a new job, or pick up a new job + report + "r_t=" & std_logic'image(request_toggle) + & ", l_r_t=" & std_logic'image(last_request_toggle) + & ", hr_clk=" & std_logic'image(hr_clk) + & ", rwr_counter = " & integer'image(to_integer(rwr_counter)); + + if rwr_counter /= to_unsigned(0,8) then + rwr_counter <= rwr_counter - 1; + hr_d <= x"bb"; + end if; + if rwr_counter = to_unsigned(1,8) then + rwr_waiting <= '0'; + end if; + + -- Phase 101 guarantees that the clock base change will happen + -- within the comming clock cycle + if rwr_waiting='0' and hr_clock_phase165 = "10" then + if (viciv_request_toggle /= viciv_last_request_toggle) + -- Only start VIC-IV fetches if we don't have a transaction + -- already waiting to go. + and ((request_toggle = last_request_toggle) or viciv_debug_priority='1') + then + report "VIC: Received data request for $" & to_hstring(viciv_addr&"000") + & ", bank = $" & to_hstring(viciv_bank&"0000000000000000000"); + -- VIC-IV is asking for 8 bytes of data + viciv_last_request_toggle <= viciv_request_toggle; + + viciv_request_count <= viciv_request_count + 1; + + -- Prepare command vector + hr_command(47) <= '1'; -- READ + hr_command(46) <= '0'; -- Memory, not register space + hr_command(45) <= '1'; -- linear + hr_command(44 downto 32) <= (others => '0'); -- unused upper address bits + hr_command(15 downto 3) <= (others => '0'); -- reserved bits + hr_command(34 downto 31) <= viciv_bank(3 downto 0); + hr_command(30 downto 16) <= viciv_addr(18 downto 4); + hr_command(2) <= viciv_addr(3); + hr_command(1 downto 0) <= "00"; + + -- We want + hyperram0_select <= not viciv_bank(4); + hyperram1_select <= viciv_bank(4); + + hyperram_access_address(26 downto 19) <= viciv_bank; + hyperram_access_address(18 downto 3) <= viciv_addr(18 downto 3); + hyperram_access_address(2 downto 0) <= (others => '0'); + + busy_internal <= '1'; + ram_reading_held <= '1'; + is_expected_to_respond <= false; + is_vic_fetch <= true; + countdown <= 6; + countdown_is_zero <= '0'; + config_reg_write <= '0'; + hr_reset <= '1'; -- active low reset + pause_phase <= '0'; + + if fast_cmd_mode='1' then + state <= HyperRAMOutputCommand; + hr_clk_fast <= '1'; + hr_clk_phaseshift <= write_phase_shift; + else + state <= HyperRAMOutputCommandSlow; + hr_clk_fast <= '0'; + hr_clk_phaseshift <= write_phase_shift; + end if; + elsif prefetch_when_idle then + prefetch_when_idle <= false; + report "DISPATCHER: Dispatching chained pre-fetch"; + tempaddr(26 downto 5) := current_cache_line_address(26 downto 5) + 1; + tempaddr(4 downto 0) := "00000"; + hyperram_access_address <= tempaddr; + + -- We are reading on a 32 byte boundary, so command formation is + -- simpler. + hr_command(47) <= '1'; -- Read + hr_command(45) <= '1'; -- Linear read, not wrapped + hr_command(34 downto 17) <= tempaddr(22 downto 5); + hr_command(16 downto 0) <= (others => '0'); + + hyperram0_select <= not tempaddr(23); + hyperram1_select <= tempaddr(23); + hr_reset <= '1'; + pause_phase <= '0'; + is_prefetch <= true; + ram_reading_held <= '1'; + is_expected_to_respond <= false; + + if fast_cmd_mode='1' then + state <= HyperRAMOutputCommand; + hr_clk_fast <= '1'; + hr_clk_phaseshift <= write_phase_shift; + else + state <= HyperRAMOutputCommandSlow; + hr_clk_fast <= '0'; + hr_clk_phaseshift <= write_phase_shift; + end if; + + countdown <= 6; + config_reg_write <= '0'; + countdown_is_zero <= '0'; + + report "DISPATCH: Dispatching pre-fetch of $" & to_hstring(tempaddr) + & " in response to giving last row to current_cache_line"; + -- Mark a cache line to receive the pre-fetched data, so that we don't + -- have to wait for it all to turn up, before being able to return + -- the first 8 bytes + mark_cache_for_prefetch <= '1'; + + elsif (request_toggle /= last_request_toggle) + -- Only commence reads AFTER all pending writes have flushed, + -- to ensure cache coherence (there are corner-cases here with + -- chained writes, block reads and other bits and pieces). + and write_collect0_dispatchable='0' + and write_collect1_dispatchable='0' then + report "WAITING for job"; + ram_reading_held <= ram_reading; + + if ram_reading = '1' then + report "Waiting to start read"; + request_accepted <= request_toggle; + last_request_toggle <= request_toggle; + state <= ReadSetup; + report "Accepting job"; + busy_internal <= '1'; + else + report "Waiting to start write"; + report "Setting state to WriteSetup. random_bits=" & to_hstring(random_bits); + request_accepted <= request_toggle; + last_request_toggle <= request_toggle; + state <= WriteSetup; + report "Accepting job"; + busy_internal <= '1'; + + end if; + elsif (write_collect0_dispatchable = '1') + -- But only if the other collector doesn't have an address that + -- would chain to us. +-- and ((write_collect0_address /= (write_collect1_address + 1)) or write_collect1_dispatchable='0') + -- XXX The following slows access down noticeably through + -- inefficient scheduling. + and ((write_collect0_address_matches_write_collect1_address_plus_1='1') or write_collect1_dispatchable='0') + then + -- Do background write. + busy_internal <= '0'; + request_accepted <= request_toggle; + is_prefetch <= false; + is_expected_to_respond <= false; + + report "DISPATCH: Writing out collect0 @ $" & to_hstring(write_collect0_address&"000"); + + -- Mark the write buffer as being processed. + write_collect0_flushed <= '0'; + -- And that it is not (yet) too late to add extra bytes to the write. + write_collect0_toolate <= '0'; + + background_write_next_address <= write_collect0_address; + background_write_next_address_matches_collect0 <= '1'; + background_write <= '1'; + background_write_fetch <= '1'; + background_write_source <= '0'; -- collect 0 + report "background_write_source = 0"; + + config_reg_write <= write_collect0_address(25); + + -- Prepare command vector + hr_command(47) <= '0'; -- WRITE + hr_command(46) <= write_collect0_address(25); -- Memory, not register space + hr_command(45) <= '1'; -- linear + hr_command(44 downto 35) <= (others => '0'); -- unused upper address bits + hr_command(15 downto 3) <= (others => '0'); -- reserved bits + hr_command(34 downto 16) <= write_collect0_address(22 downto 4); + hr_command(2) <= write_collect0_address(3); + hr_command(1 downto 0) <= "00"; + hr_reset <= '1'; -- active low reset + + hyperram0_select <= not write_collect0_address(23); + hyperram1_select <= write_collect0_address(23); + + hyperram_access_address(26 downto 3) <= write_collect0_address; + hyperram_access_address(2 downto 0) <= (others => '0'); + + ram_reading_held <= '0'; + + -- This is the delay before we assert CS + + -- We have to use this intermediate stage to get the clock + -- phase right. + state <= StartBackgroundWrite; + + if write_collect0_address(25)='1' then + -- 48 bits of CA followed by 16 bit register value + -- (we shift the buffered config register values out automatically) + countdown <= 6 + 1; + else + countdown <= 6; + end if; + countdown_is_zero <= '0'; + + elsif write_collect1_dispatchable = '1' then + busy_internal <= '0'; + request_accepted <= request_toggle; + + is_prefetch <= false; + is_expected_to_respond <= false; + + report "DISPATCH: Writing out collect1 @ $" & to_hstring(write_collect1_address&"000"); + + -- Mark the write buffer as being processed. + write_collect1_flushed <= '0'; + -- And that it is not (yet) too late to add extra bytes to the write. + write_collect1_toolate <= '0'; + show_collect1 := true; + + config_reg_write <= write_collect1_address(25); + + background_write_next_address <= write_collect1_address; + background_write_next_address_matches_collect1 <= '1'; + background_write <= '1'; + background_write_fetch <= '1'; + background_write_source <= '1'; -- collect 1 + report "background_write_source = 1"; + + -- Prepare command vector + hr_command(47) <= '0'; -- WRITE + hr_command(46) <= write_collect1_address(25); -- Memory, not register space + hr_command(45) <= '1'; -- linear + hr_command(44 downto 35) <= (others => '0'); -- unused upper address bits + hr_command(15 downto 3) <= (others => '0'); -- reserved bits + hr_command(34 downto 16) <= write_collect1_address(22 downto 4); + hr_command(2) <= write_collect1_address(3); + hr_command(1 downto 0) <= "00"; + + ram_reading_held <= '0'; + + hyperram0_select <= not write_collect1_address(23); + hyperram1_select <= write_collect1_address(23); + + hyperram_access_address(26 downto 3) <= write_collect1_address; + hyperram_access_address(2 downto 0) <= (others => '0'); + + hr_reset <= '1'; -- active low reset + + state <= StartBackgroundWrite; + + if write_collect1_address(25)='1' then + -- 48 bits of CA followed by 16 bit register value + -- (we shift the buffered config register values out automatically) + countdown <= 6 + 1; + else + countdown <= 6; + end if; + countdown_is_zero <= '0'; + + report "clk_queue <= '00'"; + + else + report "Clearing busy_internal"; + busy_internal <= '0'; + request_accepted <= request_toggle; + end IF; + -- Release CS line between transactions + report "Releasing hyperram CS lines"; + hr_cs0 <= '1'; + end if; + + when StartBackgroundWrite => + report "in StartBackgroundWrite to synchronise with clock"; + pause_phase <= '0'; + if fast_cmd_mode='1' then + state <= HyperRAMOutputCommand; + hr_clk_phaseshift <= write_phase_shift; + hr_clk_fast <= '1'; + else + state <= HyperRAMOutputCommandSlow; + hr_clk_phaseshift <= write_phase_shift; + hr_clk_fast <= '0'; + end if; + + when ReadSetup => + report "Setting up to read $" & to_hstring(ram_address) & " ( address = $" & to_hstring(address) & ")"; + + -- Prepare command vector + hr_command(47) <= '1'; -- READ + -- Map actual RAM to bottom 32MB of 64MB space (repeated 4x) + -- and registers to upper 32MB +-- hr_command(46) <= '1'; -- Memory address space (1) / Register + hr_command(46) <= ram_address(25); -- Memory address space (1) / Register + -- address space select (0) ? + hr_command(45) <= '1'; -- Linear access (not wrapped) + hr_command(44 downto 37) <= (others => '0'); -- unused upper address bits + hr_command(34 downto 16) <= ram_address(22 downto 4); + hr_command(15 downto 3) <= (others => '0'); -- reserved bits + if ram_address(25) = '0' then + -- Always read on 8 byte boundaries, and read a full cache line + hr_command(2) <= ram_address(3); + hr_command(1 downto 0) <= "00"; + else + -- Except that register reads are weird: They read the same 2 bytes + -- over and over again, so we have to make it set bit 0 of the CA + -- for the "odd" registers" + hr_command(2 downto 1) <= "00"; + hr_command(0) <= ram_address(3); + end if; + + hyperram0_select <= not ram_address(23); + hyperram1_select <= ram_address(23); + + hyperram_access_address <= ram_address; + + hr_reset <= '1'; -- active low reset + pause_phase <= '0'; + + if fast_cmd_mode='1' then + state <= HyperRAMOutputCommand; + hr_clk_fast <= '1'; + hr_clk_phaseshift <= write_phase_shift; + else + state <= HyperRAMOutputCommandSlow; + hr_clk_fast <= '0'; + hr_clk_phaseshift <= write_phase_shift; + end if; + + countdown <= 6; + config_reg_write <= '0'; + countdown_is_zero <= '0'; + + when WriteSetup => + + report "Preparing hr_command etc for write to $" & to_hstring(ram_address); + + if not cache_enabled then + background_write_count <= 2; + background_write <= '0'; + end if; + + config_reg_write <= ram_address(25); + + -- Prepare command vector + -- As HyperRAM addresses on 16bit boundaries, we shift the address + -- down one bit. + hr_command(47) <= '0'; -- WRITE + hr_command(46) <= ram_address(25); -- Memory, not register space + hr_command(45) <= '1'; -- linear + + hr_command(44 downto 35) <= (others => '0'); -- unused upper address bits + hr_command(15 downto 3) <= (others => '0'); -- reserved bits + + hr_command(34 downto 16) <= ram_address(22 downto 4); + hr_command(2 downto 0) <= ram_address(3 downto 1); + + hr_reset <= '1'; -- active low reset + + hyperram0_select <= not ram_address(23); + hyperram1_select <= ram_address(23); + + hyperram_access_address <= ram_address; + + pause_phase <= '0'; + + if start_delay_expired = '1' then + if fast_cmd_mode='1' then + state <= HyperRAMOutputCommand; + hr_clk_fast <= '1'; + hr_clk_phaseshift <= write_phase_shift; + else + state <= HyperRAMOutputCommandSlow; + hr_clk_fast <= '0'; + hr_clk_phaseshift <= write_phase_shift; + end if; + end if; + if ram_address(25)='1' then + -- 48 bits of CA followed by 16 bit register value + -- (we shift the buffered config register values out automatically) + countdown <= 6 + 1; + else + countdown <= 6; + end if; + countdown_is_zero <= '0'; + + when HyperRAMOutputCommandSlow => + report "Writing command, hyperram_access_address=$" & to_hstring(hyperram_access_address); + report "hr_command = $" & to_hstring(hr_command); + -- Call HyperRAM to attention + hr_cs0 <= not hyperram0_select; + + hr_rwds <= 'Z'; + + -- Prepare for reading block data + is_block_read <= false; + if (hyperram_access_address(4 downto 3) = "00") and block_read_enable='1' and (ram_reading_held='1') + and (is_vic_fetch = false) then + block_valid <= '0'; + block_address <= hyperram_access_address(26 downto 5); + is_block_read <= true; + end if; + + pause_phase <= not pause_phase; + + if pause_phase='1' then + hr_clk_phaseshift <= write_phase_shift; + + if countdown_timeout='1' then + -- Finished shifting out + if ram_reading_held = '1' then + -- Reading: We can just wait until hr_rwds has gone low, and then + -- goes high again to indicate the first data byte + countdown <= 63; + countdown_is_zero <= '0'; + hr_rwds_high_seen <= '0'; + countdown_timeout <= '0'; + if fast_read_mode='1' then + hr_clk_fast <= '1'; + state <= HyperRAMReadWait; + else + pause_phase <= '1'; + hr_clk_fast <= '0'; + state <= HyperRAMReadWaitSlow; + end if; + elsif config_reg_write='1' and ram_reading_held='0' then + -- Config register write. + -- These are a bit weird, as they have no latency, and all 16 + -- bits have to get written at once. So we will have 2 buffer + -- registers that get setup, and then ANY write to the register + -- area will write those values, which we have done by shifting + -- those through and sending 48+16 bits instead of the usual + -- 48. + if background_write='1' then + if background_write_source = '0' then + write_collect0_flushed <= '1'; + show_collect0 := true; + else + write_collect1_flushed <= '1'; + show_collect1 := true; + end if; + end if; + + report "Finished writing config register"; + state <= HyperRAMFinishWriting; + else + -- Writing to memory, so count down the correct number of cycles; + -- Initial latency is reduced by 2 cycles for the last bytes + -- of the access command, and by 1 more to cover state + -- machine latency + if hyperram1_select='0' then + countdown <= to_integer(write_latency); + else + countdown <= to_integer(write_latency2); + end if; + -- XXX Doesn't work if write_latency(2) is $00 + countdown_is_zero <= '0'; + + + -- We are not just about ready to start writing, so mark the + -- write buffer as too late to be added to, because we will + -- snap-shot it in a moment. + if background_write = '1' then + report "WRITE: Asserting toolate signal for collect" & std_logic'image(background_write_source); + background_write_count <= 4 + 2; + -- We know we can do upto 128 bytes at least per write, + -- before a refresh is required. So allow 16x8 byte writes to + -- be chained. + write_continues <= write_continues_max; + if background_write_source = '0' then + write_collect0_toolate <= '1'; + write_collect0_flushed <= '0'; + show_collect0 := true; + else + write_collect1_toolate <= '1'; + write_collect1_flushed <= '0'; + show_collect1 := true; + end if; + end if; + countdown_timeout <= '0'; + if fast_write_mode='1' then + hr_clk_fast <= '1'; + state <= HyperRAMDoWrite; + else + hr_clk_fast <= '0'; + state <= HyperRAMDoWriteSlow; + end if; + end if; + end if; + + else + + -- Toggle data while clock steady + report "Presenting hr_command byte on hr_d = $" & to_hstring(hr_command(47 downto 40)) + & ", clock = " & std_logic'image(hr_clk) + & ", countdown = " & integer'image(countdown); + + hr_d <= hr_command(47 downto 40); + hr_command(47 downto 8) <= hr_command(39 downto 0); + + -- Also shift out config register values, if required + if config_reg_write='1' and ram_reading_held='0' then + report "shifting in conf value $" & to_hstring(conf_buf0); + hr_command(7 downto 0) <= conf_buf0; + conf_buf0 <= conf_buf1; + conf_buf1 <= conf_buf0; + else + hr_command(7 downto 0) <= x"00"; + end if; + + report "Writing command byte $" & to_hstring(hr_command(47 downto 40)); + + if countdown = 3 and config_reg_write='1' then + if background_write='1' then + if background_write_source = '0' then + write_collect0_toolate <= '1'; + else + write_collect1_toolate <= '1'; + end if; + end if; + end if; + + if countdown = 3 and (config_reg_write='0' or ram_reading_held='1') then + extra_latency <= hr_rwds; + if (hr_rwds='1' and hyperram0_select='1') then + report "Applying extra latency"; + end if; + end if; + if countdown = 1 then + countdown_is_zero <= '1'; + end if; + if countdown /= 0 then + countdown <= countdown - 1; + else + report "asserting countdown_timeout"; + countdown_timeout <= '1'; + end if; + end if; + byte_phase <= to_unsigned(0,6); + write_byte_phase <= '0'; + when HyperRAMOutputCommand => + report "Writing command"; + -- Call HyperRAM to attention + hr_cs0 <= not hyperram0_select; + + hr_rwds <= 'Z'; + + hr_clk_phaseshift <= write_byte_phase; + + -- Toggle data while clock steady +-- report "Presenting hr_command byte on hr_d = $" & to_hstring(hr_command(47 downto 40)) +-- & ", clock = " & std_logic'image(hr_clock) +-- & ", next_is_data = " & std_logic'image(next_is_data) +-- & ", countdown = " & integer'image(countdown) +-- & ", cs0= " & std_logic'image(hr_cs0); + + hr_d <= hr_command(47 downto 40); + hr_command(47 downto 8) <= hr_command(39 downto 0); + + -- Also shift out config register values, if required + if config_reg_write='1' and ram_reading_held='0' then + report "shifting in conf value $" & to_hstring(conf_buf0); + hr_command(7 downto 0) <= conf_buf0; + conf_buf0 <= conf_buf1; + conf_buf1 <= conf_buf0; + else + hr_command(7 downto 0) <= x"00"; + end if; + + report "Writing command byte $" & to_hstring(hr_command(47 downto 40)); + + if countdown = 3 and (config_reg_write='0' or ram_reading_held='1') then + if hyperram0_select='1' then + extra_latency <= hr_rwds; + end if; + if (hr_rwds='1' and hyperram0_select='1') then + report "Applying extra latency"; + end if; + end if; + if countdown = 1 then + countdown_is_zero <= '1'; + else + countdown_is_zero <= '0'; + end if; + if countdown_is_zero = '1' then + -- Finished shifting out + if ram_reading_held = '1' then + -- Reading: We can just wait until hr_rwds has gone low, and then + -- goes high again to indicate the first data byte + countdown <= 63; + countdown_is_zero <= '0'; + hr_rwds_high_seen <= '0'; + if fast_read_mode='1' then + hr_clk_fast <= '1'; + state <= HyperRAMReadWait; + else + pause_phase <= '0'; + hr_clk_fast <= '0'; + state <= HyperRAMReadWaitSlow; + end if; + elsif config_reg_write='1' and ram_reading_held='0' then + -- Config register write. + -- These are a bit weird, as they have no latency, and all 16 + -- bits have to get written at once. So we will have 2 buffer + -- registers that get setup, and then ANY write to the register + -- area will write those values, which we have done by shifting + -- those through and sending 48+16 bits instead of the usual + -- 48. + + if background_write='1' then + if background_write_source = '0' then + write_collect0_flushed <= '1'; + show_collect0 := true; + else + write_collect1_flushed <= '1'; + show_collect1 := true; + end if; + end if; + + report "Finished writing config register"; + state <= HyperRAMFinishWriting; + else + -- Writing to memory, so count down the correct number of cycles; + -- Initial latency is reduced by 2 cycles for the last bytes + -- of the access command, and by 1 more to cover state + -- machine latency + if hyperram0_select='1' then + countdown <= to_integer(write_latency); + else + countdown <= to_integer(write_latency2); + end if; + -- XXX Assumes write_latency > 0 + countdown_is_zero <= '0'; + + -- We are now just about ready to start writing, so mark the + -- write buffer as too late to be added to, because we will + -- snap-shot it in a moment. + if background_write = '1' then + report "WRITE: Asserting toolate signal"; + background_write_count <= 4 + 2; + -- We know we can do upto 128 bytes at least per write, + -- before a refresh is required. So allow 16x8 byte writes to + -- be chained. + write_continues <= write_continues_max; + if background_write_source = '0' then + write_collect0_toolate <= '1'; + write_collect0_flushed <= '0'; + show_collect0 := true; + else + write_collect1_toolate <= '1'; + write_collect1_flushed <= '0'; + show_collect1 := true; + end if; + end if; + + countdown_timeout <= '0'; + if fast_write_mode='1' then + state <= HyperRAMDoWrite; + else + state <= HyperRAMDoWriteSlow; + end if; + end if; + end if; + byte_phase <= to_unsigned(0,6); + write_byte_phase <= '0'; + + when HyperRAMDoWrite => + hr_clk_phaseshift <= write_phase_shift; + + report "WRITE: LatencyWait state, bg_wr=" & std_logic'image(background_write) + & ", count=" & integer'image(background_write_count); + + -- Now snap-shot the write buffer data, and mark the slot as flushed + if background_write = '1' then + if background_write_source = '0' and write_collect0_toolate='1' and write_collect0_flushed = '0' then + write_collect0_flushed <= '1'; + show_collect0 := true; + report "WRITE: background_write_data copied from write_collect0. Valids = " & to_string(write_collect0_valids); + background_write_fetch <= '1'; + background_write_data <= write_collect0_data; + background_write_valids <= write_collect0_valids; + + elsif background_write_source = '1' and write_collect1_toolate='1' and write_collect1_flushed = '0' then + write_collect1_flushed <= '1'; + show_collect1 := true; + report "WRITE: background_write_data copied from write_collect1"; + background_write_data <= write_collect1_data; + background_write_valids <= write_collect1_valids; + end if; + + -- Invalidate read cache when writing + if cache_enabled and hyperram_access_address_matches_cache_row0 = '1' then + report "Zeroing cache_row0_valids"; + cache_row0_valids <= (others => '0'); + elsif cache_enabled and hyperram_access_address_matches_cache_row1 = '1' then + report "Zeroing cache_row1_valids"; + cache_row1_valids <= (others => '0'); + end if; + end if; + + report "latency countdown = " & integer'image(countdown); + + -- Begin write mask pre-amble + if ram_reading_held = '0' and countdown = 2 then + hr_rwds <= '0'; + hr_d <= x"BE"; -- "before" data byte + end if; + + if countdown /= 0 then + countdown <= countdown - 1; + end if; + if countdown = 1 then + countdown_is_zero <= '1'; + end if; + if countdown_is_zero='1' then + if extra_latency='1' then + report "Waiting 6 more cycles for extra latency"; + -- If we were asked to wait for extra latency, + -- then wait another 6 cycles. + extra_latency <= '0'; + + if hyperram0_select='1' then + countdown <= to_integer(extra_write_latency); + else + countdown <= to_integer(extra_write_latency2); + end if; + -- Assumes extra latency is not zero + countdown_is_zero <= '0'; + else + -- Latency countdown for writing is over, we can now + -- begin writing bytes. + + -- HyperRAM works on 16-bit fundamental transfers. + -- This means we need to have two half-cycles, and pick which + -- one we want to write during. + -- If RWDS is asserted, then the write is masked, i.e., won't + -- occur. + -- In this first + + report "Presenting hr_d with ram_wdata or background data"; + if background_write='1' then + report "WRITE: Writing background byte $" & to_hstring(background_write_data(0)) + & ", valids= " & to_string(background_write_valids) + & ", background words left = " & integer'image(background_write_count); + hr_d <= background_write_data(0); + background_write_data(0) <= background_write_data(1); + background_write_data(1) <= background_write_data(2); + background_write_data(2) <= background_write_data(3); + background_write_data(3) <= background_write_data(4); + background_write_data(4) <= background_write_data(5); + background_write_data(5) <= background_write_data(6); + background_write_data(6) <= background_write_data(7); + background_write_data(7) <= x"00"; + + hr_rwds <= not background_write_valids(0); + background_write_valids(0 to 6) <= background_write_valids(1 to 7); + background_write_valids(7) <= '0'; + + if background_write_count = 0 and background_chained_write = '1' then + background_write_fetch <= '1'; + end if; + + else + -- XXX Doesn't handle 16-bit writes properly. But that's + -- okay, as they are only supported with the cache and + -- write-collecting, anyway. + hr_d <= ram_wdata; + hr_rwds <= hyperram_access_address(0) xor write_byte_phase; + end if; + + -- Write byte + write_byte_phase <= '1'; + if background_write='0' then + if write_byte_phase = '0' and hyperram_access_address(0)='1' then + report "Masking even byte"; + hr_d <= x"ee"; -- even "masked" data byte + elsif write_byte_phase = '1' and hyperram_access_address(0)='0' then + report "Masking odd byte"; + hr_d <= x"0d"; -- odd "masked" data byte + end if; + if background_write_count /= 0 then + background_write_count <= background_write_count - 1; + else + state <= HyperRAMFinishWriting; + end if; + elsif write_byte_phase='1' then + report "WRITE: Decrementing background_write_count from " & integer'image(background_write_count); + if background_write_count /= 0 then + background_write_count <= background_write_count - 1; + else + report "Advancing to HyperRAMFinishWriting"; + hr_clk_phaseshift <= write_phase_shift; + end if; + end if; + end if; + end if; + when HyperRAMDoWriteSlow => + pause_phase <= not pause_phase; + + -- Update cache + if cache_row0_address_matches_ram_address = '1' then + if ram_wdata_enlo_drive='1' then + cache_row0_valids(to_integer(ram_address_drive(2 downto 0))) <= '1'; + cache_row0_data(to_integer(ram_address_drive(2 downto 0))) <= ram_wdata_drive; + end if; + if ram_wdata_enhi_drive='1' then + cache_row0_valids(to_integer(ram_address_drive(2 downto 0))+1) <= '1'; + cache_row0_data(to_integer(ram_address_drive(2 downto 0))+1) <= ram_wdata_hi_drive; + end if; + show_cache0 := true; + elsif cache_row1_address_matches_ram_address='1' then + if ram_wdata_enlo_drive='1' then + cache_row1_valids(to_integer(ram_address_drive(2 downto 0))) <= '1'; + cache_row1_data(to_integer(ram_address_drive(2 downto 0))) <= ram_wdata_drive; + end if; + if ram_wdata_enhi_drive='1' then + cache_row1_valids(to_integer(ram_address_drive(2 downto 0))+1) <= '1'; + cache_row1_data(to_integer(ram_address_drive(2 downto 0))+1) <= ram_wdata_hi_drive; + end if; + show_cache1 := true; + else + if random_bits(1)='0' then + report "Zeroing cache_row0_valids"; + cache_row0_valids <= (others => '0'); + cache_row0_address <= ram_address_drive(26 downto 3); + cache_row0_address_matches_ram_address <= '1'; + if ram_wdata_enlo_drive='1' then + cache_row0_valids(to_integer(ram_address_drive(2 downto 0))) <= '1'; + cache_row0_data(to_integer(ram_address_drive(2 downto 0))) <= ram_wdata_drive; + end if; + if ram_wdata_enhi_drive='1' then + cache_row0_valids(to_integer(ram_address_drive(2 downto 0))+1) <= '1'; + cache_row0_data(to_integer(ram_address_drive(2 downto 0))+1) <= ram_wdata_hi_drive; + end if; + show_cache0 := true; + else + report "Zeroing cache_row1_valids"; + cache_row1_valids <= (others => '0'); + cache_row1_address <= ram_address_drive(26 downto 3); + cache_row1_address_matches_ram_address <= '1'; + if ram_wdata_enlo_drive='1' then + cache_row1_valids(to_integer(ram_address_drive(2 downto 0))) <= '1'; + cache_row1_data(to_integer(ram_address_drive(2 downto 0))) <= ram_wdata_drive; + end if; + if ram_wdata_enhi_drive='1' then + cache_row1_valids(to_integer(ram_address_drive(2 downto 0))+1) <= '1'; + cache_row1_data(to_integer(ram_address_drive(2 downto 0))+1) <= ram_wdata_hi_drive; + end if; + show_cache1 := true; + end if; + end if; + + -- Fetch takes 2 cycles, so schedule one cycle before last read + -- and shift, so that it happens after that last shift, but + -- before it is needed again. + if background_write_count = 0 and pause_phase = '0' then + -- See if we have another write collect that we can + -- continue with + -- XXX We suspect that chained writes might be problematic on the + -- external hyperram for some strange reason, so disable them. + if write_continues /= 0 and background_chained_write='1' then + if background_write_fetch = '0' then + report "WRITECONTINUE: Continuing write: Requesting fetch."; + background_write_fetch <= '1'; + end if; + else + report "WRITECONTINUE: No continuation. Terminating write."; + report "asserting countdown_timeout"; + countdown_timeout <= '1'; + end if; + end if; + + report "WRITE: LatencyWait state, bg_wr=" & std_logic'image(background_write) + & ", count=" & integer'image(background_write_count) + & ", background_write_fetch = " & std_logic'image(background_write_fetch) + & ", background_write_valids = " & to_string(background_write_valids) + & ", write_blocked=" & std_logic'image(write_blocked); + + -- Now snap-shot the write buffer data, and mark the slot as flushed + if background_write = '1' and + ( (background_write_next_address_matches_collect0 = '1') + or (background_write_next_address_matches_collect1 = '1') ) + then + if background_chained_write = '0' then + report "WRITE: background_chained_write <= 1"; + end if; + background_chained_write <= '1'; + else + if background_chained_write = '1' then + report "WRITE: background_chained_write <= 0"; + end if; + background_chained_write <= '0'; + + if hr_clock_phase165="11" and (background_write_valids = "00000000") + and (read_request='1' or write_request='1' or write_blocked='1') then + report "LatencyWait: Aborting tail of background write due to incoming job/write_blocked"; + state <= HyperRAMFinishWriting; + end if; + + + end if; + + if background_write_fetch = '1' then + report "WRITE: Doing fetch of background write data"; + background_write_fetch <= '0'; + background_write_next_address <= background_write_next_address + 1; + write_continues <= write_continues - 1; + background_write_count <= 7; + if background_write_next_address_matches_collect0 = '1' and background_write_source = '0' then + show_collect0 := true; + report "WRITE: background_write_data copied from write_collect0 (@ $" + & to_hstring(write_collect0_address&"000") + & "). Valids = " & to_string(write_collect0_valids) + & ", next addr was $" & to_hstring(background_write_next_address&"000"); + + background_write_next_address <= write_collect0_address + 1; + background_write_next_address_matches_collect0 <= '0'; + background_write_next_address_matches_collect1 <= collect1_matches_collect0_plus_1; + + background_write_data <= write_collect0_data; + background_write_valids <= write_collect0_valids; + write_collect0_flushed <= '1'; + + elsif background_write_next_address_matches_collect1 = '1' and background_write_source = '1' then + show_collect1 := true; + report "WRITE: background_write_data copied from write_collect1. Valids = " & to_string(write_collect1_valids) + & ", next addr was $" & to_hstring(background_write_next_address&"000"); + background_write_next_address <= write_collect1_address + 1; + background_write_next_address_matches_collect0 <= collect0_matches_collect1_plus_1; + background_write_next_address_matches_collect1 <= '0'; + + background_write_data <= write_collect1_data; + background_write_valids <= write_collect1_valids; + write_collect1_flushed <= '1'; + else + report "WRITE: Write is not chained."; + background_chained_write <= '0'; + end if; + end if; + + if pause_phase = '1' then + hr_clk_phaseshift <= write_phase_shift; + if countdown_timeout = '1' then + report "Advancing to HyperRAMFinishWriting"; + state <= HyperRAMFinishWriting; + end if; + else + + report "latency countdown = " & integer'image(countdown); + + -- Begin write mask pre-amble + if ram_reading_held = '0' and countdown = 2 then + hr_rwds <= '0'; + hr_d <= x"BE"; -- "before" data byte + end if; + + if countdown /= 0 then + countdown <= countdown - 1; + end if; + if countdown = 1 then + countdown_is_zero <= '1'; + end if; + if countdown_is_zero = '1' then + if extra_latency='1' then + report "Waiting 6 more cycles for extra latency"; + -- If we were asked to wait for extra latency, + -- then wait another 6 cycles. + extra_latency <= '0'; + if hyperram0_select='1' then + countdown <= to_integer(extra_write_latency); + else + countdown <= to_integer(extra_write_latency2); + end if; + -- XXX Assumes extra_write_latency is not zero + countdown_is_zero <= '0'; + else + -- Latency countdown for writing is over, we can now + -- begin writing bytes. + + -- HyperRAM works on 16-bit fundamental transfers. + -- This means we need to have two half-cycles, and pick which + -- one we want to write during. + -- If RWDS is asserted, then the write is masked, i.e., won't + -- occur. + -- In this first + + report "Presenting hr_d with ram_wdata or background data"; + if background_write='1' then + report "WRITE: Writing background byte $" & to_hstring(background_write_data(0)) + & ", valids= " & to_string(background_write_valids) + & ", background words left = " & integer'image(background_write_count); + hr_d <= background_write_data(0); + + background_write_data(0) <= background_write_data(1); + background_write_data(1) <= background_write_data(2); + background_write_data(2) <= background_write_data(3); + background_write_data(3) <= background_write_data(4); + background_write_data(4) <= background_write_data(5); + background_write_data(5) <= background_write_data(6); + background_write_data(6) <= background_write_data(7); + background_write_data(7) <= x"00"; + + hr_rwds <= not background_write_valids(0); + background_write_valids(0 to 6) <= background_write_valids(1 to 7); + background_write_valids(7) <= '0'; + else + -- XXX Doesn't handle 16-bit writes properly. But that's + -- okay, as they are only supported with the cache and + -- write-collecting, anyway. + hr_d <= ram_wdata; + hr_rwds <= hyperram_access_address(0) xor write_byte_phase; + end if; + + -- Finish resetting write collectors when chaining + if write_collect0_dispatchable='0' and write_collect0_flushed='1' and write_collect0_toolate='1' then + report "WRITECONTINUE: Resetting collect0"; + write_collect0_flushed <= '0'; + write_collect0_toolate <= '0'; + show_collect0 := true; + end if; + if write_collect1_dispatchable='0' and write_collect1_flushed='1' and write_collect1_toolate='1' then + report "WRITECONTINUE: Resetting collect1"; + write_collect1_flushed <= '0'; + write_collect1_toolate <= '0'; + show_collect1 := true; + end if; + + -- Write byte + write_byte_phase <= '1'; + if background_write='0' then + if write_byte_phase = '0' and hyperram_access_address(0)='1' then + hr_d <= x"ee"; -- even "masked" data byte + elsif write_byte_phase = '1' and hyperram_access_address(0)='0' then + hr_d <= x"0d"; -- odd "masked" data byte + end if; + if background_write_count /= 0 then + background_write_count <= background_write_count - 1; + else + state <= HyperRAMFinishWriting; + end if; + else + report "WRITE: Decrementing background_write_count from " & integer'image(background_write_count) + & ", write_continues = " & integer'image(write_continues); + if background_write_count /= 0 then + background_write_count <= background_write_count - 1; + if background_write_count = 3 and write_continues /= 0 then + report "WRITECONTINUE: Checking for chained writes (" & integer'image(write_continues) & " more continues allowed)"; + report "WRITECONTINUE: Am looking for $" & to_hstring(background_write_next_address&"000") & + ", options are 0:$" & to_hstring(write_collect0_address&"000") & + " and 1:$" & to_hstring(write_collect1_address&"000"); + show_collect0 := true; + show_collect1 := true; + -- Get ready to commit next write block, if one is there + if write_continues /= 0 and write_collect0_toolate='0' and write_collect0_flushed = '0' + and background_write_next_address_matches_collect0='1' then + report "WRITECONTINUE: Marking collect0 @ $" & to_hstring(write_collect0_address&"000") & " for chained write."; + write_collect0_toolate <= '1'; + background_write_source <= '0'; + report "background_write_source = 0"; + show_collect0 := true; + elsif write_continues /= 0 and write_collect1_toolate='0' and write_collect1_flushed = '0' + and background_write_next_address_matches_collect1='1' then + report "WRITECONTINUE: Marking collect1 @ $" & to_hstring(write_collect1_address&"000") & " for chained write."; + write_collect1_toolate <= '1'; + background_write_source <= '1'; + report "background_write_source = 1"; + show_collect1 := true; + end if; + end if; + end if; + + end if; + end if; + end if; + end if; + when HyperRAMFinishWriting => + -- Mask writing from here on. + hr_cs0 <= '1'; + hr_rwds <= 'Z'; + hr_d <= x"FA"; -- "after" data byte + hr_clk_phaseshift <= write_phase_shift; + report "clk_queue <= '00'"; + rwr_counter <= rwr_delay; + rwr_waiting <= '1'; + report "returning to idle"; + state <= Idle; + when HyperRAMReadWait => + hr_rwds <= 'Z'; + report "Presenting tri-state on hr_d"; + hr_d <= (others => 'Z'); + if countdown_is_zero = '0' then + countdown <= countdown - 1; + end if; + if countdown = 1 then + countdown_is_zero <= '1'; + end if; + if countdown_is_zero = '1' then + -- Timed out waiting for read -- so return anyway, rather + -- than locking the machine hard forever. + rdata_hi <= x"DD"; + rdata <= x"DD"; + rdata(0) <= data_ready_toggle; + rdata(1) <= busy_internal; + report "asserting data_ready_strobe"; + data_ready_strobe <= '1'; + data_ready_strobe_hold <= '1'; + rwr_counter <= rwr_delay; + rwr_waiting <= '1'; + hr_clk_phaseshift <= write_phase_shift; + report "returning to idle"; + state <= Idle; + end if; + + -- Abort memory pre-fetching if we are asked to do something + if is_block_read and (not is_vic_fetch) then + if (read_request_prev='1' or write_request_prev='1') then + -- Okay, here is the tricky case: If the request is for data + -- that is in this block read, we DONT want to abort the read, + -- because starting a new request will almost always be slower. + report "DISPATCH: new request is for $" & to_hstring(address) & ", and we are reading $" & to_hstring(hyperram_access_address) & ", read = " & std_logic'image(read_request); + report "DISPATCH:" + & " read_request=" & std_logic'image(read_request) + & " read_request_held=" & std_logic'image(read_request_held) + & " address_matches_hyperram_access_address_block=" & std_logic'image(address_matches_hyperram_access_address_block); + + if write_request_prev='1' and address_matches_hyperram_access_address_block='1' then + -- XXX We are writing to a block that we are pre-fetching. + -- The write will happen anyway. If we already have read the + -- byte, we can update it, else we have to abort the block, so + -- that the write can happen first. + if byte_phase_greater_than_address_low_bits = '0' then + report "DISPATCH: Aborting pre-fetch due to incoming conflicting write request"; + state <= ReadAbort; + end if; + + elsif read_request_prev='1' and address_matches_hyperram_access_address_block='1' then + -- New read request from later in this block. + -- We know that we will have the data soon. + -- The trick is coordinating our response. + -- If we have already read the byte, then it's relatively easy: + -- we can just return it, and pretend nothing happened... + -- except that the 80mhz state machine that talks to slow_devices + -- doesn't know that we can do this. + report "DISPATCH: Continuing with pre-fetch, because the read hits the block being read!"; + + -- Return the byte as soon as we have it available + -- We don't test request_toggle, as the outer 80MHz state + -- machine thinks we are still busy. + if address_matches_hyperram_access_address_block = '1' then + if byte_phase_greater_than_address_low_bits='1' then + report "DISPATCH: Supplying data from partially read data block. Value is $" + & to_hstring(block_data(to_integer(address(4 downto 3)))(to_integer(address(2 downto 0)))) + & " ( from (" & integer'image(to_integer(address(4 downto 3))) + & ")(" & integer'image(to_integer(address(2 downto 0))); + report "asserting data_ready_strobe"; + read_request_delatch <= '1'; + data_ready_strobe <= '1'; + data_ready_strobe_hold <= '1'; + rdata <= block_data(to_integer(address(4 downto 3)))(to_integer(address(2 downto 0))); + if rdata_16en='1' then + rdata_hi <= block_data(to_integer(address(4 downto 3)))(to_integer(address(2 downto 0))+1); + end if; + last_request_toggle <= request_toggle; + + -- Also push the whole cache line equivalent to + -- slow_devices to help it optimise linear reads + report "DISPATCH: byte_phase = " & integer'image(to_integer(byte_phase)) + & ", address=$" & to_hstring(address); + if byte_phase_greater_than_address_end_of_row = '1' then + report "DISPATCH: Pushing block line to current_cache_line"; + current_cache_line_drive <= block_data(to_integer(address(4 downto 3))); + current_cache_line_address_drive(26 downto 5) <= block_address(26 downto 5); + current_cache_line_address_drive(4 downto 3) <= address(4 downto 3); + current_cache_line_valid_drive <= '1'; + else + report "DISPATCH: " & integer'image(to_integer(byte_phase)) & " not > " & + integer'image(to_integer(address(4 downto 3)&"111")); + end if; + end if; + end if; + + elsif read_request_prev='1' and (not is_expected_to_respond) and (not is_vic_fetch) then + report "DISPATCH: Aborting pre-fetch due to incoming read request"; + state <= ReadAbort; + end if; + end if; + -- Because we can now abort at any time, we can pretend we are + -- not busy. We are just filling in time... + if busy_internal = '1' then + report "DISPATCH: Clearing busy during tail of pre-fetch"; + end if; + busy_internal <= '0'; + end if; + -- After we have read the first 8 bytes, we know that we are no longer + -- required to provide any further direct output, so clear the + -- flag, so that the above logic can terminate a pre-fetch when required. + if byte_phase = 8 and (not is_vic_fetch) then + report "DISPATCH: Clearing is_expected_to_respond"; + is_expected_to_respond <= false; + end if; + -- Clear busy flag as soon as we can, allowing for pipelining + -- through to and from slow_devices, so that we don't waste time, + -- but also that we avoid doing it too early and screwing things up. + if byte_phase = 4 then + if is_block_read and cache_enabled then + busy_internal <= '0'; + end if; + end if; + + hr_clk_phaseshift <= read_phase_shift xor hyperram1_select; + + if hyperram0_select='1' then + last_rwds <= hr_rwds; + end if; + -- HyperRAM drives RWDS basically to follow the clock. + -- But first valid data is when RWDS goes high, so we have to + -- wait until we see it go high. +-- report "DISPATCH watching for data: rwds=" & std_logic'image(hr_rwds) & ", clock=" & std_logic'image(hr_clock) +-- & ", rwds seen=" & std_logic'image(hr_rwds_high_seen); + + if ((hr_rwds='1') and (hyperram0_select='1')) then + hr_rwds_high_seen <= '1'; +-- if hr_rwds_high_seen = '0' then + -- report "DISPATCH saw hr_rwds go high at start of data stream"; +-- end if; + else + hr_rwds_high_seen <= '0'; + end if; + if ((hr_rwds='1') and (hyperram0_select='1')) or (hr_rwds_high_seen='1') then + -- Data has arrived: Latch either odd or even byte + -- as required. + report "DISPATCH Saw read data = $" & to_hstring(hr_d); + + -- Update cache + if (byte_phase < 32) and is_block_read and (not is_vic_fetch) then + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) + <= hr_d; + end if; + show_block := true; + end if; + if (byte_phase < 8) then + -- Store the bytes in the cache row + if is_vic_fetch then + if hyperram0_select='1' then + viciv_data_buffer(to_integer(byte_phase)) <= hr_d; + end if; + -- We load the data here 2x faster than it is sent to the VIC-IV + -- so we can start transmitting immediately, to minimise latency + if byte_phase = 0 then + report "VIC: Indicating buffer readiness"; + viciv_buffer_toggle <= not viciv_buffer_toggle; + end if; + elsif hyperram_access_address_matches_cache_row0 = '1' then + cache_row0_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row0_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache0 := true; + elsif hyperram_access_address_matches_cache_row1 = '1' then + cache_row1_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row1_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache1 := true; + elsif random_bits(1) = '0' then + report "Zeroing cache_row0_valids"; + cache_row0_valids <= (others => '0'); + cache_row0_address <= hyperram_access_address(26 downto 3); + hyperram_access_address_matches_cache_row0 <= '1'; + cache_row0_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row0_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache0 := true; + else + report "Zeroing cache_row1_valids"; + cache_row1_valids <= (others => '0'); + cache_row1_address <= hyperram_access_address(26 downto 3); + hyperram_access_address_matches_cache_row1 <= '1'; + cache_row1_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row1_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache1 := true; + end if; + elsif (byte_phase = 8) and is_expected_to_respond then + -- Export the appropriate cache line to slow_devices + if hyperram_access_address_matches_cache_row0 = '1' and cache_enabled and (not is_vic_fetch) then + if cache_row0_valids = x"FF" then + end if; + elsif hyperram_access_address_matches_cache_row1 = '1' and cache_enabled and (not is_vic_fetch) then + if cache_row1_valids = x"FF" then + current_cache_line_drive <= cache_row1_data; + current_cache_line_address_drive(26 downto 3) <= hyperram_access_address(26 downto 3); + current_cache_line_valid_drive <= '1'; + end if; + end if; + end if; + + -- Quickly return the correct byte + if to_integer(byte_phase) = (to_integer(hyperram_access_address(2 downto 0))+0) and is_expected_to_respond + and (not is_vic_fetch) then + if hyperram0_select='1' then + report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d) & ", hyperram0_select=" & std_logic'image(hyperram0_select) & ", hyperram1_select=" & std_logic'image(hyperram1_select); + if rdata_16en='1' and byte_phase(0)='1' then + rdata_hi <= hr_d; + else + rdata <= hr_d; + end if; + end if; + report "hr_return='1'"; + report "hr_return='0'"; + if rdata_16en='0' or byte_phase(0)='1' then + report "asserting data_ready_strobe"; + data_ready_strobe <= '1'; + data_ready_strobe_hold <= '1'; + end if; + end if; + report "byte_phase = " & integer'image(to_integer(byte_phase)); + if ((byte_phase = 7) and (is_block_read=false)) + or (byte_phase = 31) then + rwr_counter <= rwr_delay; + rwr_waiting <= '1'; + report "returning to idle"; + last_request_toggle <= request_toggle; + state <= Idle; + hr_cs0 <= '1'; + hr_clk_phaseshift <= write_phase_shift; + if is_block_read then + block_valid <= '1'; + end if; + is_prefetch <= false; + is_expected_to_respond <= false; + else + byte_phase <= byte_phase + 1; + end if; + end if; + when HyperRAMReadWaitSlow => + hr_rwds <= 'Z'; + report "Presenting tri-state on hr_d"; + hr_d <= (others => 'Z'); + + if hyperram0_select='1' then + hr_d_last <= hr_d; + end if; + + pause_phase <= not pause_phase; + + -- Abort memory pre-fetching if we are asked to do something + -- XXX unless it is for data that would be pre-fetched? + if is_block_read and (not is_expected_to_respond) and (not is_vic_fetch) then + if ( write_request='1') + -- If a new read is on the same cache line as the last, then + -- assume whatever read we are doing now will satisfy it +-- or (read_request='1' and address(26 downto 3) /= ram_address(26 downto 3)) + or (read_request='1') + then + report "DISPATCH: Aborting pre-fetch due to incoming request"; + state <= ReadAbort; + end if; + -- Because we can now abort at any time, we can pretend we are + -- not busy. We are just filling in time... + if busy_internal = '1' then + report "DISPATCH: Clearing busy during tail of pre-fetch"; + end if; + if cache_enabled then + busy_internal <= '0'; + end if; + end if; + -- After we have read the first 8 bytes, we know that we are no longer + -- required to provide any further direct output, so clear the + -- flag, so that the above logic can terminate a pre-fetch when required. + if byte_phase = 8 then + report "DISPATCH: Clearing is_expected_to_respond"; + is_expected_to_respond <= false; + end if; + + if pause_phase = '1' then + null; + else + hr_clk_phaseshift <= read_phase_shift xor hyperram1_select; + if countdown_is_zero = '0' then + countdown <= countdown - 1; + end if; + if countdown = 1 then + countdown_is_zero <= '1'; + end if; + if countdown_is_zero = '1' then + -- Timed out waiting for read -- so return anyway, rather + -- than locking the machine hard forever. + rdata_hi <= x"DD"; + rdata <= x"DD"; + rdata(0) <= data_ready_toggle; + rdata(1) <= busy_internal; + report "asserting data_ready_strobe"; + data_ready_strobe <= '1'; + data_ready_strobe_hold <= '1'; + rwr_counter <= rwr_delay; + rwr_waiting <= '1'; + report "returning to idle"; + state <= Idle; + hr_clk_phaseshift <= write_phase_shift; + end if; + + if hyperram0_select='1' then + last_rwds <= hr_rwds; + end if; + -- HyperRAM drives RWDS basically to follow the clock. + -- But first valid data is when RWDS goes high, so we have to + -- wait until we see it go high. +-- report "DISPATCH watching for data: rwds=" & std_logic'image(hr_rwds) & ", clock=" & std_logic'image(hr_clock) +-- & ", rwds seen=" & std_logic'image(hr_rwds_high_seen); + + if (hr_rwds='1') and (hyperram0_select='1') + then + hr_rwds_high_seen <= '1'; + else + hr_rwds_high_seen <= '0'; +-- if hr_rwds_high_seen = '0' then + -- report "DISPATCH saw hr_rwds go high at start of data stream"; +-- end if; + end if; + if ((hr_rwds='1') and (hyperram0_select='1')) + or (hr_rwds_high_seen='1') then + -- Data has arrived: Latch either odd or even byte + -- as required. +-- report "DISPATCH Saw read data = $" & to_hstring(hr_d); + + -- Update cache + if (byte_phase < 32) and is_block_read and (not is_vic_fetch) then + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + block_data(to_integer(byte_phase(4 downto 3)))(to_integer(byte_phase(2 downto 0))) + <= hr_d; + end if; + show_block := true; + end if; + if byte_phase < 8 then + -- Store the bytes in the cache row + if is_vic_fetch then + if hyperram0_select='1' then + viciv_data_buffer(to_integer(byte_phase)) <= hr_d; + end if; + -- We load the data here 2x faster than it is sent to the VIC-IV + -- so we can start transmitting immediately, to minimise latency + if byte_phase = 0 then + report "VIC: Indicating buffer readiness"; + viciv_buffer_toggle <= not viciv_buffer_toggle; + end if; + elsif hyperram_access_address_matches_cache_row0 = '1' then + cache_row0_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row0_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache0 := true; + elsif hyperram_access_address_matches_cache_row1 = '1' then + cache_row1_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row1_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache1 := true; + elsif random_bits(1) = '0' then + report "Zeroing cache_row0_valids"; + cache_row0_valids <= (others => '0'); + cache_row0_address <= hyperram_access_address(26 downto 3); + hyperram_access_address_matches_cache_row0 <= '1'; + cache_row0_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row0_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache0 := true; + else + report "Zeroing cache_row1_valids"; + cache_row1_valids <= (others => '0'); + cache_row1_address <= hyperram_access_address(26 downto 3); + hyperram_access_address_matches_cache_row1 <= '1'; + cache_row1_valids(to_integer(byte_phase)) <= '1'; + report "hr_sample='1'"; + report "hr_sample='0'"; + if hyperram0_select='1' then + cache_row1_data(to_integer(byte_phase)) <= hr_d; + end if; + show_cache1 := true; + end if; + else + -- Export the appropriate cache line to slow_devices + if hyperram_access_address_matches_cache_row0 = '1' and cache_enabled and (not is_vic_fetch) then + if cache_row0_valids = x"FF" then + current_cache_line_drive <= cache_row0_data; + current_cache_line_address_drive(26 downto 3) <= hyperram_access_address(26 downto 3); + current_cache_line_valid_drive <= '1'; + end if; + elsif hyperram_access_address_matches_cache_row1 = '1' and cache_enabled and (not is_vic_fetch) then + if cache_row1_valids = x"FF" then + current_cache_line_drive <= cache_row1_data; + current_cache_line_address_drive(26 downto 3) <= hyperram_access_address(26 downto 3); + current_cache_line_valid_drive <= '1'; + end if; + end if; + end if; + + -- Quickly return the correct byte + if byte_phase = hyperram_access_address_read_time_adjusted and (not is_vic_fetch) then + if hyperram0_select='1' then + report "DISPATCH: Returning freshly read data = $" & to_hstring(hr_d); + rdata <= hr_d; + end if; + report "hr_return='1'"; + report "hr_return='0'"; + if rdata_16en='0' then + report "asserting data_ready_strobe on low byte"; + data_ready_strobe <= '1'; + data_ready_strobe_hold <= '1'; + end if; + end if; + if byte_phase = (hyperram_access_address_read_time_adjusted+1) and (not is_vic_fetch) and (rdata_16en='1') then + if hyperram0_select='1' then + report "DISPATCH: Returning freshly read high-byte data = $" & to_hstring(hr_d); + rdata_hi <= hr_d; + end if; + report "hr_return='1'"; + report "hr_return='0'"; + + report "asserting data_ready_strobe on high byte"; + data_ready_strobe <= '1'; + data_ready_strobe_hold <= '1'; + + end if; + report "byte_phase = " & integer'image(to_integer(byte_phase)); + if (byte_phase = seven_plus_read_time_adjust and is_block_read=false) + or (byte_phase = thirtyone_plus_read_time_adjust and is_block_read=true) + then + rwr_counter <= rwr_delay; + rwr_waiting <= '1'; + report "returning to idle"; + state <= Idle; + hr_cs0 <= '1'; + hr_clk_phaseshift <= write_phase_shift; + else + byte_phase <= byte_phase + 1; + end if; + end if; + end if; + end case; + end if; + + end process; +end gothic; + + diff --git a/vhdl/hw/MEGA65/hyperram_ctl.vhd b/vhdl/hw/MEGA65/hyperram_ctl.vhd index 0e2f913f..c11b1c14 100644 --- a/vhdl/hw/MEGA65/hyperram_ctl.vhd +++ b/vhdl/hw/MEGA65/hyperram_ctl.vhd @@ -39,7 +39,12 @@ port( hr_rwds : inout std_logic; -- RW Data strobe hr_reset : out std_logic; -- Active low RESET line to HyperRAM hr_clk_p : out std_logic; - hr_cs0 : out std_logic + hr2_d : inout unsigned(7 downto 0); -- Data/Address + hr2_rwds : inout std_logic; -- RW Data strobe + hr2_reset : out std_logic; -- Active low RESET line to HyperRAM + hr2_clk_p : out std_logic; + hr_cs0 : out std_logic; + hr_cs1 : out std_logic ); end hyperram_ctl; @@ -74,7 +79,12 @@ component hyperram is hr_rwds : inout std_logic; hr_reset : out std_logic; hr_clk_p : out std_logic; - hr_cs0 : out std_logic + hr2_d : inout unsigned(7 downto 0); + hr2_rwds : inout std_logic; + hr2_reset : out std_logic; + hr2_clk_p : out std_logic; + hr_cs0 : out std_logic; + hr_cs1 : out std_logic ); end component; @@ -141,7 +151,12 @@ begin hr_rwds => hr_rwds, hr_reset => hr_reset, hr_clk_p => hr_clk_p, - hr_cs0 => hr_cs0 + hr2_d => hr2_d, + hr2_rwds => hr2_rwds, + hr2_reset => hr2_reset, + hr2_clk_p => hr2_clk_p, + hr_cs0 => hr_cs0, + hr_cs1 => hr_cs1 ); fsm_advance_state : process(clk, reset) diff --git a/vhdl/hw/MEGA65/hyperram_ctl_r6.vhd b/vhdl/hw/MEGA65/hyperram_ctl_r6.vhd new file mode 100644 index 00000000..0e2f913f --- /dev/null +++ b/vhdl/hw/MEGA65/hyperram_ctl_r6.vhd @@ -0,0 +1,346 @@ +-- QNICE-MEGA65 HyperRAM controller +-- done by sy2002 in April to August 2020 +-- +-- Wraps the MEGA65 HyperRAM controller so that it can be connected +-- to the QNICE CPU's data bus and controled via MMIO. +-- CPU wait states are automatically inserted by the HyperRAM controller. +-- data_out goes to zero, if not enabled +-- +-- Registers: +-- +-- Register $FFF0: Low word of address (15 downto 0) +-- Register $FFF1: High word of address (26 downto 16) +-- Register $FFF2: 8-bit data in/out (native mode: HyperRAM is 8-bit) +-- Register $FFF3: 16-bit data in/out (leads to address being multiplied by two) + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +entity hyperram_ctl is +port( + -- HyperRAM needs a base clock and then one with 2x speed and one with 4x speed + clk : in std_logic; -- currently 50 MHz QNICE system clock + clk2x : in std_logic; -- 100 Mhz + clk4x : in std_logic; -- 200 Mhz + + reset : in std_logic; + + -- connect to CPU's data bus (data high impedance when all reg_* are 0) + hram_en : in std_logic; + hram_we : in std_logic; + hram_reg : in std_logic_vector(3 downto 0); + hram_cpu_ws : out std_logic; -- insert CPU wait states (aka WAIT_FOR_DATA) + data_in : in std_logic_vector(15 downto 0); + data_out : out std_logic_vector(15 downto 0); + + -- hardware connections + hr_d : inout unsigned(7 downto 0); -- Data/Address + hr_rwds : inout std_logic; -- RW Data strobe + hr_reset : out std_logic; -- Active low RESET line to HyperRAM + hr_clk_p : out std_logic; + hr_cs0 : out std_logic +); +end hyperram_ctl; + +architecture beh of hyperram_ctl is + +component hyperram is + port ( pixelclock : in std_logic; + clock163 : in std_logic; + clock325 : in std_logic; + + -- Simple counter for number of requests received + request_counter : out std_logic; + + read_request : in std_logic; + write_request : in std_logic; + address : in unsigned(26 downto 0); + wdata : in unsigned(7 downto 0); + + rdata : out unsigned(7 downto 0); + data_ready_strobe : out std_logic; + busy : out std_logic; + + -- 16-bit enhancements + wen_hi : in std_logic; + wen_lo : in std_logic; + wdata_hi : in unsigned(7 downto 0); + rdata_hi : out unsigned(7 downto 0); + rdata_16en : in std_logic; + + -- HyperRAM hardware signals + hr_d : inout unsigned(7 downto 0); + hr_rwds : inout std_logic; + hr_reset : out std_logic; + hr_clk_p : out std_logic; + hr_cs0 : out std_logic + ); +end component; + +-- HyperRAM control and data signals +signal hram_read_request : std_logic; +signal hram_write_request : std_logic; +signal hram_address : unsigned(26 downto 0); +signal hram_wdata_ff : unsigned(15 downto 0) := (others => '0'); +signal hram_rdata : unsigned(15 downto 0); +signal hram_data_ready_strobe : std_logic; +signal hram_busy : std_logic; +signal hram_wen_hi : std_logic; +signal hram_wen_lo : std_logic; +signal hram_rdata_16en : std_logic; + +-- Controller logic +signal hram_addr_lo_ff : unsigned(15 downto 0) := (others => '0'); +signal hram_addr_hi_ff : unsigned(15 downto 0) := (others => '0'); +signal hram_rdata_ff : unsigned(15 downto 0) := (others => '0'); +signal hram_16bit_ff : std_logic := '0'; + + +type tHRAM_FSM_States is ( s_idle, + + s_read_start, + s_read_waitfordata, + s_read_waitforcpu, + + s_write1, + s_write2 + ); + +signal state_ff : tHRAM_FSM_States := s_idle; +signal state_next : tHRAM_FSM_States; + +signal fsm_state_next : tHRAM_FSM_States; +signal fsm_hram_rdata : unsigned(15 downto 0); +signal fsm_hram_16bit : std_logic; + + +signal dbg_chkadd_ff : unsigned(15 downto 0) := x"0000"; +signal fsm_chkadd : unsigned(15 downto 0); + +begin + + HRAM : hyperram + port map ( + pixelclock => clk, + clock163 => clk2x, + clock325 => clk4x, + read_request => hram_read_request, + write_request => hram_write_request, + address => hram_address, + wdata => hram_wdata_ff(7 downto 0), + wdata_hi => hram_wdata_ff(15 downto 8), + rdata => hram_rdata(7 downto 0), + rdata_hi => hram_rdata(15 downto 8), + wen_hi => hram_wen_hi, + wen_lo => hram_wen_lo, + rdata_16en => hram_rdata_16en, + data_ready_strobe => hram_data_ready_strobe, + busy => hram_busy, + hr_d => hr_d, + hr_rwds => hr_rwds, + hr_reset => hr_reset, + hr_clk_p => hr_clk_p, + hr_cs0 => hr_cs0 + ); + + fsm_advance_state : process(clk, reset) + begin + if reset = '1' then + state_ff <= s_idle; + hram_rdata_ff <= x"0000"; + hram_16bit_ff <= '0'; + + dbg_chkadd_ff <= (others => '0'); + else + if rising_edge(clk) then + state_ff <= fsm_state_next; + hram_rdata_ff <= fsm_hram_rdata; + hram_16bit_ff <= fsm_hram_16bit; + + dbg_chkadd_ff <= dbg_chkadd_ff + fsm_chkadd; + end if; + end if; + end process; + + fsm_next_state_decode : process (state_ff) + begin + case state_ff is + when s_idle => state_next <= s_idle; + + when s_read_start => state_next <= s_read_waitfordata; + when s_read_waitfordata => state_next <= s_read_waitforcpu; + when s_read_waitforcpu => state_next <= s_idle; + + when s_write1 => state_next <= s_write2; + when s_write2 => state_next <= s_idle; + end case; + end process; + + fsm_output_decode : process(state_ff, state_next, hram_rdata_ff, hram_rdata, hram_data_ready_strobe, hram_busy, + hram_16bit_ff, hram_reg, hram_en, hram_we) + begin + hram_cpu_ws <= '0'; + hram_read_request <= '0'; + hram_write_request <= '0'; + hram_wen_lo <= '1'; + hram_wen_hi <= '0'; + hram_rdata_16en <= '0'; + + fsm_state_next <= state_next; + fsm_chkadd <= x"0000"; + fsm_hram_rdata <= hram_rdata_ff; + fsm_hram_16bit <= hram_16bit_ff; + + case state_ff is + when s_idle => + + -- detect 16-bit mode + if hram_reg = x"3" then + fsm_hram_16bit <= '1'; + else + fsm_hram_16bit <= '0'; + end if; + + -- start read process + if hram_en = '1' and hram_we = '0' and (hram_reg = x"2" or hram_reg = x"3") then + hram_cpu_ws <= '1'; + if hram_busy = '0' then + fsm_state_next <= s_read_start; + end if; + + -- start write process + elsif hram_en = '1' and hram_we = '1' and (hram_reg = x"2" or hram_reg = x"3") then + hram_cpu_ws <= '1'; + if hram_busy = '0' then + fsm_state_next <= s_write1; + end if; + end if; + + -- READING + + when s_read_start => + hram_cpu_ws <= '1'; + hram_read_request <= '1'; + hram_rdata_16en <= hram_16bit_ff; + fsm_chkadd <= x"0100"; + if hram_busy = '0' and hram_data_ready_strobe = '0' then + fsm_state_next <= s_read_start; + else + hram_read_request <= '0'; + hram_rdata_16en <= '0'; -- is this correct? + if hram_data_ready_strobe = '1' then + fsm_hram_rdata <= hram_rdata; + fsm_state_next <= s_read_waitforcpu; + end if; + end if; + + when s_read_waitfordata => + hram_cpu_ws <= '1'; + fsm_chkadd <= x"0001"; + if hram_data_ready_strobe = '1' then + fsm_hram_rdata <= hram_rdata; + else + fsm_state_next <= s_read_waitfordata; + end if; + + when s_read_waitforcpu => + -- wait for CPU to deassert reading so that we can synchronously reset start_read_ff + if hram_en = '1' and hram_we = '0' and (hram_reg = x"2" or hram_reg = x"3") then + fsm_state_next <= s_read_waitforcpu; + end if; + + -- WRITING + + when s_write1 => + hram_write_request <= '1'; + hram_wen_hi <= hram_16bit_ff; + + -- TODO: Check, if necessary + when s_write2 => + null; + + end case; + end process; + + read_registers : process(hram_en, hram_we, hram_reg, hram_data_ready_strobe, hram_busy, + hram_address, hram_rdata_ff, dbg_chkadd_ff) + begin + data_out <= (others => '0'); + + if hram_en = '1' and hram_we = '0' then + case hram_reg is + + -- read low word of address + when x"0" => data_out <= std_logic_vector(hram_address(15 downto 0)); + + -- read (partial) high word of address + when x"1" => data_out <= std_logic_vector("00000" & hram_address(26 downto 16)); + + -- read 8-bit data + when x"2" => + data_out <= x"00" & std_logic_vector(hram_rdata_ff(7 downto 0)); + + -- read 16-bit data + when x"3" => + data_out <= std_logic_vector(hram_rdata_ff); + + -- debug + when x"6" => + data_out <= std_logic_vector(dbg_chkadd_ff); + + when others => + data_out <= (others => '0'); + end case; + end if; + end process; + + write_registers : process(clk, reset) + begin + if reset = '1' then + hram_addr_lo_ff <= (others => '0'); + hram_addr_hi_ff <= (others => '0'); + hram_wdata_ff <= (others => '0'); + else + if falling_edge(clk) then + if hram_en = '1' and hram_we = '1' then + case hram_reg is + + -- write low word of address + when x"0" => hram_addr_lo_ff <= unsigned(data_in); + + -- write high word of address + when x"1" => hram_addr_hi_ff <= unsigned(data_in); + + -- write 8-bit data register + when x"2" => + hram_wdata_ff <= x"00" & unsigned(data_in(7 downto 0)); + + -- write 16-bit data register + when x"3" => + hram_wdata_ff <= unsigned(data_in); + + when others => null; + end case; + end if; + end if; + end if; + end process; + + calc_hram_address : process(hram_addr_hi_ff, hram_addr_lo_ff, hram_16bit_ff, fsm_hram_16bit) + begin + -- 8-bit mode: address = plain concatenation of hi and low word + if hram_16bit_ff = '0' and fsm_hram_16bit = '0' then + hram_address <= hram_addr_hi_ff(10 downto 0) & hram_addr_lo_ff(15 downto 0); + + -- 16-bit mode: address is x2 + -- multiplication is done by a shift left which itself is done by wiring the + -- two source flip flops appropriately, so that everything happens combinatorically in "no time" + else + hram_address(26 downto 17) <= hram_addr_hi_ff(9 downto 0); + hram_address(16 downto 1) <= hram_addr_lo_ff(15 downto 0); + hram_address(0) <= '0'; + end if; + end process; + +end beh; diff --git a/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd b/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd index c69b6674..75f59807 100644 --- a/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd +++ b/vhdl/hw/MEGA65/sim/sim_hram_dbg.vhd @@ -171,7 +171,12 @@ begin hr_rwds => hr_rwds, hr_reset => hr_reset, hr_clk_p => hr_clk_p, - hr_cs0 => hr_cs0 + hr2_d => hr2_d, + hr2_rwds => hr2_rwds, + hr2_reset => hr2_reset, + hr2_clk_p => hr2_clk_p, + hr_cs0 => hr_cs0, + hr_cs1 => hr_cs1 ); -- memory mapped i/o controller diff --git a/vhdl/hw/MEGA65/sim/sim_hram_dbg_r6.vhd b/vhdl/hw/MEGA65/sim/sim_hram_dbg_r6.vhd new file mode 100644 index 00000000..c69b6674 --- /dev/null +++ b/vhdl/hw/MEGA65/sim/sim_hram_dbg_r6.vhd @@ -0,0 +1,247 @@ +---------------------------------------------------------------------------------- +-- MEGA65 Top Module for simulation: HRAM debugging +-- +-- done by sy2002 in June and August 2020 +---------------------------------------------------------------------------------- + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; + +library UNISIM; +use UNISIM.VCOMPONENTS.ALL; + +use work.env1_globals.all; + +entity MEGA65_HRAM_SIM is +end MEGA65_HRAM_SIM; + +architecture beh of MEGA65_HRAM_SIM is + +-- CPU control signals +signal cpu_addr : std_logic_vector(15 downto 0); +signal cpu_data_in : std_logic_vector(15 downto 0); +signal cpu_data_out : std_logic_vector(15 downto 0); +signal cpu_data_dir : std_logic; +signal cpu_data_valid : std_logic; +signal cpu_wait_for_data : std_logic; +signal cpu_halt : std_logic; + +-- MMIO control signals +signal switch_reg_enable : std_logic; +signal switch_data_out : std_logic_vector(15 downto 0); +signal rom_enable : std_logic; +signal rom_busy : std_logic; +signal rom_data_out : std_logic_vector(15 downto 0); +signal ram_enable : std_logic; +signal ram_busy : std_logic; +signal ram_data_out : std_logic_vector(15 downto 0); +signal hram_en : std_logic; +signal hram_we : std_logic; +signal hram_reg : std_logic_vector(3 downto 0); +signal hram_cpu_ws : std_logic; +signal hram_data_out : std_logic_vector(15 downto 0); + +-- Main clock: 50 MHz as long as we did not solve the timing issues of the register file +signal SLOW_CLOCK : std_logic; + +-- Pixelclock and fast clock for HRAM +signal CLK1x : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase +signal CLK2x : std_logic; -- 4x SLOW_CLOCK = 200 MHz + +-- emulate the switches on the Nexys4 dev board to toggle VGA and PS/2 +signal SWITCHES : std_logic_vector(15 downto 0); + +-- HRAM simulation signals +signal hr_d : unsigned(7 downto 0); -- Data/Address +signal hr_rwds : std_logic; -- RW Data strobe +signal hr_reset : std_logic; -- Active low RESET line to HyperRAM +signal hr_clk_p : std_logic; +signal hr2_d : unsigned(7 downto 0); -- Data/Address +signal hr2_rwds : std_logic; -- RW Data strobe +signal hr2_reset : std_logic; -- Active low RESET line to HyperRAM +signal hr2_clk_p : std_logic; +signal hr_cs0 : std_logic; +signal hr_cs1 : std_logic; + +signal gbl_reset : std_logic; +signal reset_counter : unsigned(15 downto 0) := x"0000"; + +begin + + cpu_data_in <= switch_data_out or rom_data_out or ram_data_out or hram_data_out; + + fakehyper0: entity work.s27kl0641 + generic map ( + id => "$8000000", + tdevice_vcs => 5 ns, + timingmodel => "S27KL0641DABHI000" + ) + port map ( + DQ7 => hr_d(7), + DQ6 => hr_d(6), + DQ5 => hr_d(5), + DQ4 => hr_d(4), + DQ3 => hr_d(3), + DQ2 => hr_d(2), + DQ1 => hr_d(1), + DQ0 => hr_d(0), + + CSNeg => hr_cs0, + CK => hr_clk_p, + RESETneg => hr_reset, + RWDS => hr_rwds + ); + + fakehyper1: entity work.s27kl0641 + generic map ( + id => "$8800000", + tdevice_vcs => 5 ns, + timingmodel => "S27KL0641DABHI000" + ) + port map ( + DQ7 => hr2_d(7), + DQ6 => hr2_d(6), + DQ5 => hr2_d(5), + DQ4 => hr2_d(4), + DQ3 => hr2_d(3), + DQ2 => hr2_d(2), + DQ1 => hr2_d(1), + DQ0 => hr2_d(0), + + CSNeg => hr_cs1, + CK => hr2_clk_p, + RESETneg => hr2_reset, + RWDS => hr2_rwds + ); + + -- QNICE CPU + cpu : entity work.QNICE_CPU + port map ( + CLK => SLOW_CLOCK, + RESET => gbl_reset, + WAIT_FOR_DATA => cpu_wait_for_data, + ADDR => cpu_addr, + DATA_IN => cpu_data_in, + DATA_OUT => cpu_data_out, + DATA_DIR => cpu_data_dir, + DATA_VALID => cpu_data_valid, + HALT => cpu_halt + ); + + -- ROM: up to 64kB consisting of up to 32.000 16 bit words + rom : entity work.BROM + generic map ( + FILE_NAME => ROM_FILE + ) + port map ( + clk => SLOW_CLOCK, + ce => rom_enable, + address => cpu_addr(14 downto 0), + data => rom_data_out, + busy => rom_busy + ); + + -- RAM: up to 64kB consisting of up to 32.000 16 bit words + ram : entity work.BRAM + port map ( + clk => SLOW_CLOCK, + ce => ram_enable, + address => cpu_addr(14 downto 0), + we => cpu_data_dir, + data_i => cpu_data_out, + data_o => ram_data_out, + busy => ram_busy + ); + + -- HyperRAM + HRAM : entity work.hyperram_ctl + port map ( + clk => SLOW_CLOCK, + clk2x => CLK1x, + clk4x => CLK2x, + reset => gbl_reset, + hram_en => hram_en, + hram_we => hram_we, + hram_reg => hram_reg, + hram_cpu_ws => hram_cpu_ws, + data_in => cpu_data_out, + data_out => hram_data_out, + hr_d => hr_d, + hr_rwds => hr_rwds, + hr_reset => hr_reset, + hr_clk_p => hr_clk_p, + hr_cs0 => hr_cs0 + ); + + -- memory mapped i/o controller + mmio_controller : entity work.mmio_mux + port map ( + HW_RESET => gbl_reset, + CLK => SLOW_CLOCK, + addr => cpu_addr, + data_dir => cpu_data_dir, + data_valid => cpu_data_valid, + cpu_wait_for_data => cpu_wait_for_data, + cpu_halt => cpu_halt, + rom_enable => rom_enable, + rom_busy => rom_busy, + ram_enable => ram_enable, + ram_busy => ram_busy, + switch_reg_enable => switch_reg_enable, + hram_en => hram_en, + hram_we => hram_we, + hram_reg => hram_reg, + hram_cpu_ws => hram_cpu_ws + ); + + generate_clocks: process + begin + SLOW_CLOCK <= '0'; + CLK1x <= '0'; + CLK2x <= '0'; + + wait for 2.5 ns; + CLK2x <= '1'; + + wait for 2.5 ns; + CLK2x <= '0'; + CLK1x <= '1'; + + wait for 2.5 ns; + CLK2x <= '1'; + + wait for 2.5 ns; + CLK2x <= '0'; + CLK1x <= '0'; + SLOW_CLOCK <= '1'; + + wait for 2.5 ns; + CLK2x <= '1'; + + wait for 2.5 ns; + CLK2x <= '0'; + CLK1x <= '1'; + + wait for 2.5 ns; + CLK2x <= '1'; + + wait for 2.5 ns; + end process; + + startup_reset_handler : process(CLK1x) + begin + if rising_edge(CLK1x) then + if reset_counter < x"3B1" then + reset_counter <= reset_counter + 1; + end if; + end if; + end process; + + -- HRAM needs *very* long to initialize ("busy=1" at the beginning) + gbl_reset <= '1' when reset_counter < x"3B1" else '0'; + + -- handle the toggle switches + switch_data_out <= x"0000"; + +end beh; From 87aeb51c727607e046bfc6ba38b2d3e35a2c37e9 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Wed, 4 Dec 2024 10:48:03 +0100 Subject: [PATCH 07/17] message restored --- pore/boot_message_mega65.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pore/boot_message_mega65.txt b/pore/boot_message_mega65.txt index 8fba060d..3ce2498c 100644 --- a/pore/boot_message_mega65.txt +++ b/pore/boot_message_mega65.txt @@ -1,5 +1,7 @@ PORE$NEWLINE .ASCII_W "\n\n" +; PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 [WIP] [only 16 regbnks] by sy2002 in July 2020 (GIT #" + ; PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 V1.6 [BETA/WIP] by sy2002 in July 2020 (GIT #" -PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 Version 1.6 by sy2002 - testing ... (GIT # \ No newline at end of file +PORE$RESETMSG .ASCII_W "QNICE-FPGA @ MEGA65 Version 1.6 by sy2002 in September 2020 (GIT # \ No newline at end of file From bc04f79b8ce4526848f201022423c2ce87e59f27 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Wed, 4 Dec 2024 11:18:45 +0100 Subject: [PATCH 08/17] unifying naming convention, adding rest of the ports to the top entity --- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 120 +++++++-------- vhdl/hw/MEGA65/MEGA65_R6.vhd | 211 +++++++++++++++++++------- 2 files changed, 216 insertions(+), 115 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc index 57bbd9a4..2d858bba 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -78,10 +78,10 @@ set_property -dict {PACKAGE_PIN B13 IOSTANDARD LVCMOS33} [get_ports {kb_jtagen_ # Micro SD Connector (external slot at back of the cover) set_property -dict {PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {sd_cd_i}]; # SD_CD -set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33} [get_ports {SD_CLK}]; # SD_CLK -set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {SD_MISO}]; # SD_D0 -set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {SD_MOSI}]; # SD_CMD -set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {SD_RESET}]; # SD_D3 +set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33} [get_ports {sd_clk_o}]; # SD_CLK +set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {sd_mosi_o}]; # SD_D0 +set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {sd_miso_i}]; # SD_CMD +set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {sd_reset_o}]; # SD_D3 set_property -dict {PACKAGE_PIN H3 IOSTANDARD LVCMOS33} [get_ports {sd_d1_i}]; # SD_D1 set_property -dict {PACKAGE_PIN J1 IOSTANDARD LVCMOS33} [get_ports {sd_d2_i}]; # SD_D2 @@ -235,38 +235,38 @@ set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {fb_left_n_ #set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports {dbg_11_io}]; # DBG11 # SMSC Ethernet PHY. U4 = KSZ8081RNDCA -#set_property -dict {PACKAGE_PIN L4 IOSTANDARD LVCMOS33} [get_ports {eth_clock_o}]; # ETH_CLK -#set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {eth_led2_o}]; # ETH_LED2 -#set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports {eth_mdc_o}]; # ETH_MDC -#set_property -dict {PACKAGE_PIN L5 IOSTANDARD LVCMOS33} [get_ports {eth_mdio_io}]; # ETH_MDIO -#set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVCMOS33} [get_ports {eth_reset_o}]; # ETH-RST -#set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[0]}]; # ETH_RX_D0 -#set_property -dict {PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[1]}]; # ETH_RX_D1 -#set_property -dict {PACKAGE_PIN K4 IOSTANDARD LVCMOS33} [get_ports {eth_rxdv_i}]; # ETH_CRS_DV -#set_property -dict {PACKAGE_PIN M6 IOSTANDARD LVCMOS33} [get_ports {eth_rxer_i}]; # ETH_RXER -#set_property -dict {PACKAGE_PIN L3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[0]}]; # ETH_TX_D0 -#set_property -dict {PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[1]}]; # ETH_TX_D1 -#set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {eth_txen_o}]; # ETH_TX_EN -#set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txd_o[*]}]; -#set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txen_o}]; -#set_property -dict {SLEW FAST} [get_ports {eth_clock_o}]; +set_property -dict {PACKAGE_PIN L4 IOSTANDARD LVCMOS33} [get_ports {eth_clock_o}]; # ETH_CLK +set_property -dict {PACKAGE_PIN R14 IOSTANDARD LVCMOS33} [get_ports {eth_led2_o}]; # ETH_LED2 +set_property -dict {PACKAGE_PIN J6 IOSTANDARD LVCMOS33} [get_ports {eth_mdc_o}]; # ETH_MDC +set_property -dict {PACKAGE_PIN L5 IOSTANDARD LVCMOS33} [get_ports {eth_mdio_io}]; # ETH_MDIO +set_property -dict {PACKAGE_PIN K6 IOSTANDARD LVCMOS33} [get_ports {eth_reset_o}]; # ETH-RST +set_property -dict {PACKAGE_PIN P4 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[0]}]; # ETH_RX_D0 +set_property -dict {PACKAGE_PIN L1 IOSTANDARD LVCMOS33} [get_ports {eth_rxd_i[1]}]; # ETH_RX_D1 +set_property -dict {PACKAGE_PIN K4 IOSTANDARD LVCMOS33} [get_ports {eth_rxdv_i}]; # ETH_CRS_DV +set_property -dict {PACKAGE_PIN M6 IOSTANDARD LVCMOS33} [get_ports {eth_rxer_i}]; # ETH_RXER +set_property -dict {PACKAGE_PIN L3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[0]}]; # ETH_TX_D0 +set_property -dict {PACKAGE_PIN K3 IOSTANDARD LVCMOS33} [get_ports {eth_txd_o[1]}]; # ETH_TX_D1 +set_property -dict {PACKAGE_PIN J4 IOSTANDARD LVCMOS33} [get_ports {eth_txen_o}]; # ETH_TX_EN +set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txd_o[*]}]; +set_property -dict {SLEW SLOW DRIVE 4} [get_ports {eth_txen_o}]; +set_property -dict {SLEW FAST} [get_ports {eth_clock_o}]; # FDC interface -#set_property -dict {PACKAGE_PIN P6 IOSTANDARD LVCMOS33} [get_ports {f_density_o}]; # F_REDWC -#set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {f_diskchanged_i}]; # F_DSCKCHG -#set_property -dict {PACKAGE_PIN M2 IOSTANDARD LVCMOS33} [get_ports {f_index_i}]; # F_INDEX -#set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports {f_motora_o}]; # F_MOTEA -#set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {f_motorb_o}]; # F_MOTEB -#set_property -dict {PACKAGE_PIN P1 IOSTANDARD LVCMOS33} [get_ports {f_rdata_i}]; # F_RDATA1 -#set_property -dict {PACKAGE_PIN N5 IOSTANDARD LVCMOS33} [get_ports {f_selecta_o}]; # F_DRVSA -#set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {f_selectb_o}]; # F_DRVSB -#set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {f_side1_o}]; # F_SIDE1 -#set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {f_stepdir_o}]; # F_DIR -#set_property -dict {PACKAGE_PIN M3 IOSTANDARD LVCMOS33} [get_ports {f_step_o}]; # F_STEP -#set_property -dict {PACKAGE_PIN N2 IOSTANDARD LVCMOS33} [get_ports {f_track0_i}]; # F_TRCK0 -#set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {f_wdata_o}]; # F_WDATE -#set_property -dict {PACKAGE_PIN N3 IOSTANDARD LVCMOS33} [get_ports {f_wgate_o}]; # F_WGATE -#set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {f_writeprotect_i}]; # F_WPT +set_property -dict {PACKAGE_PIN P6 IOSTANDARD LVCMOS33} [get_ports {f_density_o}]; # F_REDWC +set_property -dict {PACKAGE_PIN R1 IOSTANDARD LVCMOS33} [get_ports {f_diskchanged_i}]; # F_DSCKCHG +set_property -dict {PACKAGE_PIN M2 IOSTANDARD LVCMOS33} [get_ports {f_index_i}]; # F_INDEX +set_property -dict {PACKAGE_PIN M5 IOSTANDARD LVCMOS33} [get_ports {f_motora_o}]; # F_MOTEA +set_property -dict {PACKAGE_PIN H15 IOSTANDARD LVCMOS33} [get_ports {f_motorb_o}]; # F_MOTEB +set_property -dict {PACKAGE_PIN P1 IOSTANDARD LVCMOS33} [get_ports {f_rdata_i}]; # F_RDATA1 +set_property -dict {PACKAGE_PIN N5 IOSTANDARD LVCMOS33} [get_ports {f_selecta_o}]; # F_DRVSA +set_property -dict {PACKAGE_PIN G17 IOSTANDARD LVCMOS33} [get_ports {f_selectb_o}]; # F_DRVSB +set_property -dict {PACKAGE_PIN M1 IOSTANDARD LVCMOS33} [get_ports {f_side1_o}]; # F_SIDE1 +set_property -dict {PACKAGE_PIN P5 IOSTANDARD LVCMOS33} [get_ports {f_stepdir_o}]; # F_DIR +set_property -dict {PACKAGE_PIN M3 IOSTANDARD LVCMOS33} [get_ports {f_step_o}]; # F_STEP +set_property -dict {PACKAGE_PIN N2 IOSTANDARD LVCMOS33} [get_ports {f_track0_i}]; # F_TRCK0 +set_property -dict {PACKAGE_PIN N4 IOSTANDARD LVCMOS33} [get_ports {f_wdata_o}]; # F_WDATE +set_property -dict {PACKAGE_PIN N3 IOSTANDARD LVCMOS33} [get_ports {f_wgate_o}]; # F_WGATE +set_property -dict {PACKAGE_PIN P2 IOSTANDARD LVCMOS33} [get_ports {f_writeprotect_i}]; # F_WPT # I2C bus for on-board peripherals # U36. 24AA025E48T. Address 0x50. 2K Serial EEPROM. @@ -289,34 +289,34 @@ set_property -dict {PACKAGE_PIN U22 IOSTANDARD LVCMOS33} [get_ports {led_o}]; set_property -dict {PACKAGE_PIN V20 IOSTANDARD LVCMOS33} [get_ports {led_r_n_o}]; # LED_R # Pmod Header -#set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[0]}]; # B16_L17_P -#set_property -dict {PACKAGE_PIN E1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[1]}]; # B35_L3_P -#set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[2]}]; # B35_L2_P -#set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[3]}]; # B35_L1_P -#set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[0]}]; # B35_L5_N -#set_property -dict {PACKAGE_PIN D1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[1]}]; # B35_L3_N -#set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[2]}]; # B35_L2_N -#set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[3]}]; # B35_L1_N -#set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[0]}]; # B35_L4_P -#set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[1]}]; # B35_L4_N -#set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[2]}]; # B35_L12_N -#set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[3]}]; # B35_L10_P -#set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[0]}]; # B35_L6_P -#set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[1]}]; # B35_L6_N -#set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[2]}]; # B35_L12_P -#set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[3]}]; # B35_L10_N -#set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {pmod1_en_o}]; # PMOD1_EN -#set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {pmod1_flag_i}]; # PMOD1_FLG -#set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {pmod2_en_o}]; # PMOD2_EN -#set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports {pmod2_flag_i}]; # PMOD2_FLG +set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[0]}]; # B16_L17_P +set_property -dict {PACKAGE_PIN E1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[1]}]; # B35_L3_P +set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[2]}]; # B35_L2_P +set_property -dict {PACKAGE_PIN B1 IOSTANDARD LVCMOS33} [get_ports {p1hi_io[3]}]; # B35_L1_P +set_property -dict {PACKAGE_PIN F1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[0]}]; # B35_L5_N +set_property -dict {PACKAGE_PIN D1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[1]}]; # B35_L3_N +set_property -dict {PACKAGE_PIN B2 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[2]}]; # B35_L2_N +set_property -dict {PACKAGE_PIN A1 IOSTANDARD LVCMOS33} [get_ports {p1lo_io[3]}]; # B35_L1_N +set_property -dict {PACKAGE_PIN E2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[0]}]; # B35_L4_P +set_property -dict {PACKAGE_PIN D2 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[1]}]; # B35_L4_N +set_property -dict {PACKAGE_PIN G4 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[2]}]; # B35_L12_N +set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports {p2hi_io[3]}]; # B35_L10_P +set_property -dict {PACKAGE_PIN F3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[0]}]; # B35_L6_P +set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[1]}]; # B35_L6_N +set_property -dict {PACKAGE_PIN H4 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[2]}]; # B35_L12_P +set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports {p2lo_io[3]}]; # B35_L10_N +set_property -dict {PACKAGE_PIN J16 IOSTANDARD LVCMOS33} [get_ports {pmod1_en_o}]; # PMOD1_EN +set_property -dict {PACKAGE_PIN K16 IOSTANDARD LVCMOS33} [get_ports {pmod1_flag_i}]; # PMOD1_FLG +set_property -dict {PACKAGE_PIN M13 IOSTANDARD LVCMOS33} [get_ports {pmod2_en_o}]; # PMOD2_EN +set_property -dict {PACKAGE_PIN K17 IOSTANDARD LVCMOS33} [get_ports {pmod2_flag_i}]; # PMOD2_FLG # Quad SPI Flash. U5 = S25FL512SAGBHIS10 -#set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports {qspicsn_o}]; # SPI-CS -#set_property -dict {PACKAGE_PIN P22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[0]}]; # SPI-DQ0 -#set_property -dict {PACKAGE_PIN R22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[1]}]; # SPI-DQ1 -#set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[2]}]; # SPI-DQ2 -#set_property -dict {PACKAGE_PIN R21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[3]}]; # SPI-DQ3 -#set_property -dict {PULLUP TRUE} [get_ports {qspidb_io[*]}]; +set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports {qspicsn_o}]; # SPI-CS +set_property -dict {PACKAGE_PIN P22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[0]}]; # SPI-DQ0 +set_property -dict {PACKAGE_PIN R22 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[1]}]; # SPI-DQ1 +set_property -dict {PACKAGE_PIN P21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[2]}]; # SPI-DQ2 +set_property -dict {PACKAGE_PIN R21 IOSTANDARD LVCMOS33} [get_ports {qspidb_io[3]}]; # SPI-DQ3 +set_property -dict {PULLUP TRUE} [get_ports {qspidb_io[*]}]; # SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL set_property -dict {PACKAGE_PIN T4 IOSTANDARD LVCMOS33} [get_ports {sdram_a_o[0]}]; # SDRAM_A0 diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index 033b7b55..6a7d8326 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -62,13 +62,13 @@ entity MEGA65 is kb_jtagen_o : out std_logic; -- SD Card - SD_RESET : out std_logic; - SD_CLK : out std_logic; - SD_MOSI : out std_logic; - SD_MISO : in std_logic; - sd_cd_i : in std_logic; - sd_d1_i : in std_logic; - sd_d2_i : in std_logic; + sd_reset_o : out std_logic; + sd_clk_o : out std_logic; + sd_mosi_o : out std_logic; + sd_miso_i : in std_logic; + sd_cd_i : in std_logic; + sd_d1_i : in std_logic; + sd_d2_i : in std_logic; -- SD Connector (this is the slot at the bottom side of the case under the cover) sd2_reset_o : out std_logic; @@ -196,6 +196,23 @@ entity MEGA65 is led_r_n_o : out std_logic; led_o : out std_logic; + -- Pmod Header + p1lo_io : inout std_logic_vector(3 downto 0); + p1hi_io : inout std_logic_vector(3 downto 0); + p2lo_io : inout std_logic_vector(3 downto 0); + p2hi_io : inout std_logic_vector(3 downto 0); + pmod1_en_o : out std_logic; + pmod1_flag_i : in std_logic; + pmod2_en_o : out std_logic; + pmod2_flag_i : in std_logic; + + -- Quad SPI Flash. U5 = S25FL512SAGBHIS10 + qspidb_io : inout std_logic_vector(3 downto 0); + qspicsn_o : out std_logic; + + -- Debug. + dbg_11_io : inout std_logic; + -- SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL sdram_clk_o : out std_logic; sdram_cke_o : out std_logic; @@ -207,7 +224,37 @@ entity MEGA65 is sdram_a_o : out std_logic_vector(12 downto 0); sdram_dqml_o : out std_logic; sdram_dqmh_o : out std_logic; - sdram_dq_io : inout std_logic_vector(15 downto 0) + sdram_dq_io : inout std_logic_vector(15 downto 0); + + -- SMSC Ethernet PHY. U4 = KSZ8081RNDCA + eth_clock_o : out std_logic; + eth_led2_o : out std_logic; + eth_mdc_o : out std_logic; + eth_mdio_io : inout std_logic; + eth_reset_o : out std_logic; + eth_rxd_i : in std_logic_vector(1 downto 0); + eth_rxdv_i : in std_logic; + eth_rxer_i : in std_logic; + eth_txd_o : out std_logic_vector(1 downto 0); + eth_txen_o : out std_logic; + + -- FDC interface + f_density_o : out std_logic; + f_diskchanged_i : in std_logic; + f_index_i : in std_logic; + f_motora_o : out std_logic; + f_motorb_o : out std_logic; + f_rdata_i : in std_logic; + f_selecta_o : out std_logic; + f_selectb_o : out std_logic; + f_side1_o : out std_logic; + f_stepdir_o : out std_logic; + f_step_o : out std_logic; + f_track0_i : in std_logic; + f_wdata_o : out std_logic; + f_wgate_o : out std_logic; + f_writeprotect_i : in std_logic + ); end entity MEGA65; @@ -289,14 +336,14 @@ architecture beh of MEGA65 is signal vga_vsync : std_logic; -- 50 MHz as long as we did not solve the timing issues of the register file - signal SLOW_CLOCK : std_logic := '0'; + signal clk_50MHz : std_logic := '0'; -- Pixelclock and fast clock for HRAM - signal CLK1x : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase - signal CLK2x : std_logic; -- 4x SLOW_CLOCK = 200 MHz - signal clk25MHz : std_logic; -- 25.175 MHz pixelclock for 640x480 @ 60 Hz - signal pll_locked_main : std_logic; + signal clk_100MHz : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase + signal clk_200MHz : std_logic; -- 4x clk_50MHz = 200 MHz + signal clk_pixel : std_logic; -- 25.175 MHz pixelclock for 640x480 @ 60 Hz signal clk_fb_main : std_logic; + signal pll_locked_main : std_logic; -- combined pre- and post pore reset signal reset_ctl : std_logic; @@ -328,30 +375,84 @@ begin -- Due to a bug in the R5/R6 boards, the cartridge port needs to be enabled for joystick port 2 to work cart_en_o <= '1'; - - -- dummy HDMI differential output - hdmi_hiz_en_o <= 'L'; - hdmi_ls_oe_n_o <= 'H'; + -- Safe default values for not-used/unsupported ports + + vdac_psave_n_o <= '1'; + hdmi_hiz_en_o <= '0'; -- HDMI is 50 ohm terminated. + hdmi_ls_oe_n_o <= '1'; -- Disable HDMI output hdmi_scl_io <= 'Z'; hdmi_sda_io <= 'Z'; + dbg_11_io <= 'Z'; + + eth_clock_o <= '0'; + eth_led2_o <= '0'; + eth_mdc_o <= '0'; + eth_mdio_io <= 'Z'; + eth_reset_o <= '1'; + eth_txd_o <= (others => '0'); + eth_txen_o <= '0'; + + f_density_o <= '1'; + f_motora_o <= '1'; + f_motorb_o <= '1'; + f_selecta_o <= '1'; + f_selectb_o <= '1'; + f_side1_o <= '1'; + f_stepdir_o <= '1'; + f_step_o <= '1'; + f_wdata_o <= '1'; + f_wgate_o <= '1'; + + joystick_5v_disable_o <= '0'; -- Enable 5V power supply to joysticks + + led_g_n_o <= '1'; -- Off + led_r_n_o <= '1'; -- Off + led_o <= '0'; -- Off + + p1lo_io <= (others => 'Z'); + p1hi_io <= (others => 'Z'); + p2lo_io <= (others => 'Z'); + p2hi_io <= (others => 'Z'); + + pmod1_en_o <= '0'; + pmod2_en_o <= '0'; + + qspidb_io <= (others => 'Z'); + qspicsn_o <= '1'; + sdram_clk_o <= '0'; + sdram_cke_o <= '0'; + sdram_ras_n_o <= '1'; + sdram_cas_n_o <= '1'; + sdram_we_n_o <= '1'; + sdram_cs_n_o <= '1'; + sdram_ba_o <= (others => '0'); + sdram_a_o <= (others => '0'); + sdram_dqml_o <= '0'; + sdram_dqmh_o <= '0'; + sdram_dq_io <= (others => 'Z'); + + -- dummy HDMI differential output + tmds_data_obufds : for i in 0 to 2 generate begin tmds_data_obufds_bit : obufds - port map ( - i => 'L', - o => tmds_data_p_o(i), - ob => tmds_data_n_o(i) - ); + port map + ( + i => 'L', + o => tmds_data_p_o(i), + ob => tmds_data_n_o(i) + ); end generate tmds_data_obufds; tmds_clk_obufds : obufds - port map ( - i => 'L', - o => tmds_clk_p_o, - ob => tmds_clk_n_o - ); + port map + ( + i => 'L', + o => tmds_clk_p_o, + ob => tmds_clk_n_o + ); clk_main : mmcme2_base generic map @@ -371,10 +472,10 @@ begin clkin1 => clk_i, clkfbin => clk_fb_main, clkfbout => clk_fb_main, - clkout0 => clk25MHz, -- pixelclock - clkout1 => CLK1x, -- 100 MHz - clkout2 => SLOW_CLOCK, -- 50 MHz - clkout3 => CLK2x, -- 200 MHz + clkout0 => clk_pixel, -- pixelclock + clkout1 => clk_100MHz, -- 100 MHz + clkout2 => clk_50MHz, -- 50 MHz + clkout3 => clk_200MHz, -- 200 MHz locked => pll_locked_main ); @@ -382,7 +483,7 @@ begin cpu : entity work.QNICE_CPU port map ( - CLK => SLOW_CLOCK, + CLK => clk_50MHz, RESET => reset_ctl, WAIT_FOR_DATA => cpu_wait_for_data, ADDR => cpu_addr, @@ -403,7 +504,7 @@ begin ) port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, ce => rom_enable, address => cpu_addr(14 downto 0), data => rom_data_out, @@ -414,7 +515,7 @@ begin ram : entity work.BRAM port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, ce => ram_enable, address => cpu_addr(14 downto 0), we => cpu_data_dir, @@ -432,7 +533,7 @@ begin ) port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, ce => pore_rom_enable, address => cpu_addr(14 downto 0), data => pore_rom_data_out, @@ -444,8 +545,8 @@ begin port map ( reset => reset_ctl, - clk25MHz => clk25MHz, - clk50MHz => SLOW_CLOCK, + clk25MHz => clk_pixel, + clk50MHz => clk_50MHz, R => vga_r, G => vga_g, B => vga_b, @@ -466,7 +567,7 @@ begin ) port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, reset => reset_ctl, rx => uart_rxd_i, tx => uart_txd_o, @@ -487,7 +588,7 @@ begin ) port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, reset => reset_ctl, kb_io0 => kb_io0_o, kb_io1 => kb_io1_o, @@ -506,7 +607,7 @@ begin ) port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, reset => reset_ctl, int_n_out => cpu_int_n, grant_n_in => cpu_igrant_n, @@ -523,7 +624,7 @@ begin cyc : entity work.cycle_counter port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, impulse => '1', reset => reset_ctl, en => cyc_en, @@ -537,7 +638,7 @@ begin ins : entity work.cycle_counter port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, impulse => cpu_ins_cnt_strobe, reset => reset_ctl, en => ins_en, @@ -551,7 +652,7 @@ begin eae_inst : entity work.eae port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, reset => reset_ctl, en => eae_en, we => eae_we, @@ -564,26 +665,26 @@ begin sd_card : entity work.sdcard port map ( - clk => SLOW_CLOCK, + clk => clk_50MHz, reset => reset_ctl, en => sd_en, we => sd_we, reg => sd_reg, data_in => cpu_data_out, data_out => sd_data_out, - sd_reset => SD_RESET, - sd_clk => SD_CLK, - sd_mosi => SD_MOSI, - sd_miso => SD_MISO + sd_reset => sd_reset_o, + sd_clk => sd_clk_o, + sd_mosi => sd_mosi_o, + sd_miso => sd_miso_i ); -- HyperRAM HRAM : entity work.hyperram_ctl port map ( - clk => SLOW_CLOCK, - clk2x => CLK1x, - clk4x => CLK2x, + clk => clk_50MHz, + clk2x => clk_100MHz, + clk4x => clk_200MHz, reset => reset_ctl, hram_en => hram_en, hram_we => hram_we, @@ -608,7 +709,7 @@ begin port map ( HW_RESET => reset_button_i, - CLK => SLOW_CLOCK, -- @TODO change debouncer bitsize when going to 100 MHz + CLK => clk_50MHz, -- @TODO change debouncer bitsize when going to 100 MHz addr => cpu_addr, data_dir => cpu_data_dir, data_valid => cpu_data_valid, @@ -670,9 +771,9 @@ begin end if; end process; - video_signal_latches : process (clk25MHz) + video_signal_latches : process (clk_pixel) begin - if rising_edge(clk25MHz) then + if rising_edge(clk_pixel) then -- VGA: wire the simplified color system of the VGA component to the VGA outputs vga_red_o <= vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r; vga_green_o <= vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g; @@ -692,7 +793,7 @@ begin -- As of the time writing this (June 2020): it is absolutely unclear for me, why I need to -- invert the phase of the vdac_clk when use Vivado 2019.2. When using ISE 14.7, it works -- fine without the phase shift. - vdac_clk_o <= not clk25MHz; + vdac_clk_o <= not clk_pixel; -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) From 716983fff161ba761a680d693b6149d2e5682b75 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Wed, 4 Dec 2024 16:44:00 +0100 Subject: [PATCH 09/17] wiring of miso vs mosi for SD1 corrected, timming and place constraints added, SD1 and SD2 work --- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 36 ++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc index 2d858bba..f114c6b9 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -79,8 +79,8 @@ set_property -dict {PACKAGE_PIN B13 IOSTANDARD LVCMOS33} [get_ports {kb_jtagen_ # Micro SD Connector (external slot at back of the cover) set_property -dict {PACKAGE_PIN K1 IOSTANDARD LVCMOS33} [get_ports {sd_cd_i}]; # SD_CD set_property -dict {PACKAGE_PIN G2 IOSTANDARD LVCMOS33} [get_ports {sd_clk_o}]; # SD_CLK -set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {sd_mosi_o}]; # SD_D0 -set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {sd_miso_i}]; # SD_CMD +set_property -dict {PACKAGE_PIN H2 IOSTANDARD LVCMOS33} [get_ports {sd_miso_i}]; # SD_D0 +set_property -dict {PACKAGE_PIN J2 IOSTANDARD LVCMOS33} [get_ports {sd_mosi_o}]; # SD_CMD set_property -dict {PACKAGE_PIN K2 IOSTANDARD LVCMOS33} [get_ports {sd_reset_o}]; # SD_D3 set_property -dict {PACKAGE_PIN H3 IOSTANDARD LVCMOS33} [get_ports {sd_d1_i}]; # SD_D1 set_property -dict {PACKAGE_PIN J1 IOSTANDARD LVCMOS33} [get_ports {sd_d2_i}]; # SD_D2 @@ -232,7 +232,7 @@ set_property -dict {PACKAGE_PIN M18 IOSTANDARD LVCMOS33} [get_ports {fb_down_n_ set_property -dict {PACKAGE_PIN N19 IOSTANDARD LVCMOS33} [get_ports {fb_fire_n_o}]; # DBG7 = FB_FIRE_O set_property -dict {PACKAGE_PIN E18 IOSTANDARD LVCMOS33} [get_ports {fb_right_n_o}]; # DBG8 = FB_RIGHT_O set_property -dict {PACKAGE_PIN M17 IOSTANDARD LVCMOS33} [get_ports {fb_left_n_o}]; # DBG9 = FB_LEFT_O -#set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports {dbg_11_io}]; # DBG11 +set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports {dbg_11_io}]; # DBG11 # SMSC Ethernet PHY. U4 = KSZ8081RNDCA set_property -dict {PACKAGE_PIN L4 IOSTANDARD LVCMOS33} [get_ports {eth_clock_o}]; # ETH_CLK @@ -361,6 +361,30 @@ set_property -dict {PACKAGE_PIN G1 IOSTANDARD LVCMOS33} [get_ports {sdram_we_n set_property -dict {PULLUP FALSE SLEW FAST DRIVE 16} [get_ports {sdram_*}]; +################################ +## TIMING CONSTRAINTS +################################ + +## External clock signal (100 MHz) +create_clock -period 10.000 [get_ports clk_i] + +create_generated_clock -name Slow_Clock_25MHz -source [get_pins {clk_main/CLKOUT2}] -divide_by 2 [get_pins sd_card/Slow_Clock_25MHz_reg/Q] + +## Make the general clocks and the pixelclock unrelated to other to avoid erroneous timing +## violations, and hopefully make everything synthesise faster +set_clock_groups -asynchronous \ + -group { clk_i clk_100MHz clk_200MHz clkfbin clk_50MHz } \ + -group [get_clocks -of_objects [get_pins clk_main/CLKOUT0]] + +## EAE's combinatorial division networks take longer than +## the regular clock period, so we specify a multicycle path +## see also the comments in EAE.vhd and explanations in UG903/chapter 5/Multicycle Paths as well as ug911/page 25 +set_multicycle_path -from [get_cells -include_replicated {{eae_inst/op0_reg[*]} {eae_inst/op1_reg[*]}}] -to [get_cells -include_replicated {eae_inst/res_reg[*]}] -setup 3 +set_multicycle_path -from [get_cells -include_replicated {{eae_inst/op0_reg[*]} {eae_inst/op1_reg[*]}}] -to [get_cells -include_replicated {eae_inst/res_reg[*]}] -hold 2 + +## The following set_max delay works fine, too at 50 MHz main clock and is an alternative to the multicycle path +#set_max_delay -from [get_cells {{eae_inst/op0_reg[*]} {eae_inst/op1_reg[*]}}] -to [get_cells {eae_inst/res_reg[*]}] 34.000 + ################################ ## PLACEMENT CONSTRAINTS ################################ @@ -371,9 +395,9 @@ set_property -dict {PULLUP FALSE SLEW FAST DRIVE 16} [get_ports {sdram_*}]; #resize_pblock pblock_m65driver -add {SLICE_X0Y225:SLICE_X7Y243} # Place SD card controller in the middle between the left and right FPGA boundary because the output ports are at the opposide edges -#create_pblock pblock_sdcard -#add_cells_to_pblock pblock_sdcard [get_cells [list framework_inst/qnice_wrapper_inst/qnice_inst/sd_card]] -#resize_pblock pblock_sdcard -add {SLICE_X66Y178:SLICE_X99Y193} +create_pblock pblock_sdcard +add_cells_to_pblock pblock_sdcard [get_cells [list sd_card]] +resize_pblock pblock_sdcard -add {SLICE_X66Y178:SLICE_X99Y193} # Place phase-shifted VGA output registers near the actual output buffers #create_pblock pblock_vga From 1aad1c6ab008fa5359974871c671ab96b9bdbe70 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Thu, 5 Dec 2024 17:17:23 +0100 Subject: [PATCH 10/17] vdac_clk not inverted and set to 25.00MHz, auto-adjust works very well --- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 8 ++----- vhdl/hw/MEGA65/MEGA65_R6.vhd | 32 +++++++++++++-------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index ee240aee..c8d4963d 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -409,9 +409,7 @@ - - Vivado Synthesis Defaults - + @@ -421,9 +419,7 @@ - - Default settings for Implementation. - + diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index 6a7d8326..b0500857 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -335,13 +335,11 @@ architecture beh of MEGA65 is signal vga_hsync : std_logic; signal vga_vsync : std_logic; - -- 50 MHz as long as we did not solve the timing issues of the register file - signal clk_50MHz : std_logic := '0'; - -- Pixelclock and fast clock for HRAM + signal clk_25MHz : std_logic; -- 25 MHz pixelclock for 640x480 @ 60 Hz (within 1% tolerance) + signal clk_50MHz : std_logic := '0'; -- 50 MHz clock. aiming for 100 MHz signal clk_100MHz : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase signal clk_200MHz : std_logic; -- 4x clk_50MHz = 200 MHz - signal clk_pixel : std_logic; -- 25.175 MHz pixelclock for 640x480 @ 60 Hz signal clk_fb_main : std_logic; signal pll_locked_main : std_logic; @@ -457,13 +455,13 @@ begin clk_main : mmcme2_base generic map ( - clkin1_period => 10.0, -- 100 MHz (10 ns) - clkfbout_mult_f => 8.0, -- 800 MHz common multiply - divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range - clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but actual value is 25.197 MHz - clkout1_divide => 8, -- 100 MHz /8 - clkout2_divide => 16, -- 50 MHz /16 - clkout3_divide => 4 -- 200 MHz /4 + clkin1_period => 10.0, -- 100 MHz (10 ns) + clkfbout_mult_f => 8.0, -- 800 MHz common multiply + divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range + clkout0_divide_f => 32.0, -- Should be 25.175 MHz, but 25MHz is within 1% tolerance range + clkout1_divide => 8, -- 100 MHz /8 + clkout2_divide => 16, -- 50 MHz /16 + clkout3_divide => 4 -- 200 MHz /4 ) port map ( @@ -472,9 +470,9 @@ begin clkin1 => clk_i, clkfbin => clk_fb_main, clkfbout => clk_fb_main, - clkout0 => clk_pixel, -- pixelclock + clkout0 => clk_25MHz, -- pixelclock clkout1 => clk_100MHz, -- 100 MHz - clkout2 => clk_50MHz, -- 50 MHz + clkout2 => clk_50MHz, -- 50 MHz clkout3 => clk_200MHz, -- 200 MHz locked => pll_locked_main ); @@ -545,7 +543,7 @@ begin port map ( reset => reset_ctl, - clk25MHz => clk_pixel, + clk25MHz => clk_25MHz, clk50MHz => clk_50MHz, R => vga_r, G => vga_g, @@ -771,9 +769,9 @@ begin end if; end process; - video_signal_latches : process (clk_pixel) + video_signal_latches : process (clk_25MHz) begin - if rising_edge(clk_pixel) then + if rising_edge(clk_25MHz) then -- VGA: wire the simplified color system of the VGA component to the VGA outputs vga_red_o <= vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r; vga_green_o <= vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g; @@ -793,7 +791,7 @@ begin -- As of the time writing this (June 2020): it is absolutely unclear for me, why I need to -- invert the phase of the vdac_clk when use Vivado 2019.2. When using ISE 14.7, it works -- fine without the phase shift. - vdac_clk_o <= not clk_pixel; + vdac_clk_o <= clk_25MHz; -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) From 475de4b742c7427944dbcfcff2dbb3b6f1072231 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Fri, 6 Dec 2024 19:03:38 +0100 Subject: [PATCH 11/17] vga clock back to 25.197 MHz, vga_to_hdmi building blocks added to the project, bitstream generates but hdmi output still not working, wip --- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 2 +- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 147 ++- vhdl/hw/MEGA65/MEGA65_R6.vhd | 273 ++++-- vhdl/hw/MEGA65/cdc_stable.vhd | 71 ++ vhdl/hw/MEGA65/hdmi_tx_encoder.vhd | 177 ++++ vhdl/hw/MEGA65/serialiser_10to1_selectio.vhd | 142 +++ vhdl/hw/MEGA65/sync_reg.vhd | 87 ++ vhdl/hw/MEGA65/types_pkg.vhd | 32 + vhdl/hw/MEGA65/vga_to_hdmi.vhd | 944 +++++++++++++++++++ vhdl/hw/MEGA65/video_modes_pkg.vhd | 236 +++++ vhdl/hw/MEGA65/video_out_clock.vhd | 609 ++++++++++++ 11 files changed, 2589 insertions(+), 131 deletions(-) create mode 100644 vhdl/hw/MEGA65/cdc_stable.vhd create mode 100644 vhdl/hw/MEGA65/hdmi_tx_encoder.vhd create mode 100644 vhdl/hw/MEGA65/serialiser_10to1_selectio.vhd create mode 100644 vhdl/hw/MEGA65/sync_reg.vhd create mode 100644 vhdl/hw/MEGA65/types_pkg.vhd create mode 100644 vhdl/hw/MEGA65/vga_to_hdmi.vhd create mode 100644 vhdl/hw/MEGA65/video_modes_pkg.vhd create mode 100644 vhdl/hw/MEGA65/video_out_clock.vhd diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc index f114c6b9..bbb6e51e 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -366,7 +366,7 @@ set_property -dict {PULLUP FALSE SLEW FAST DRIVE 16} [get_ports {sdram_*}]; ################################ ## External clock signal (100 MHz) -create_clock -period 10.000 [get_ports clk_i] +#create_clock -period 10.000 [get_ports clk_i] create_generated_clock -name Slow_Clock_25MHz -source [get_pins {clk_main/CLKOUT2}] -divide_by 2 [get_pins sd_card/Slow_Clock_25MHz_reg/Q] diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index c8d4963d..6aef0cae 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -55,6 +55,8 @@ - + + - + + @@ -221,22 +236,24 @@ - + + - + - + + @@ -246,52 +263,56 @@ - + - + + - + - + + - + + - + + - + - + @@ -305,13 +326,61 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -343,30 +412,31 @@ - + + - + - + - + - + @@ -417,7 +487,7 @@ - + @@ -430,7 +500,6 @@ - diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index b0500857..2b0f868d 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -11,10 +11,16 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +library work; +use work.types_pkg.all; +use work.video_modes_pkg.all; +use work.env1_globals.all; + library unisim; use unisim.vcomponents.all; -use work.env1_globals.all; +library xpm; +use xpm.vcomponents.all; entity MEGA65 is port ( @@ -212,7 +218,7 @@ entity MEGA65 is -- Debug. dbg_11_io : inout std_logic; - + -- SDRAM - 32M x 16 bit, 3.3V VCC. U44 = IS42S16320F-6BL sdram_clk_o : out std_logic; sdram_cke_o : out std_logic; @@ -260,6 +266,8 @@ end entity MEGA65; architecture beh of MEGA65 is + constant HDMI_VIDEO_MODE : video_modes_t := C_HDMI_640x480p_60; + -- CPU control signals signal cpu_addr : std_logic_vector(15 downto 0); signal cpu_data_in : std_logic_vector(15 downto 0); @@ -327,6 +335,7 @@ architecture beh of MEGA65 is signal reset_pre_pore : std_logic; signal reset_post_pore : std_logic; + signal reset_ctl : std_logic; -- combined pre- and post pore reset -- VGA control signals signal vga_r : std_logic; @@ -335,17 +344,23 @@ architecture beh of MEGA65 is signal vga_hsync : std_logic; signal vga_vsync : std_logic; - -- Pixelclock and fast clock for HRAM - signal clk_25MHz : std_logic; -- 25 MHz pixelclock for 640x480 @ 60 Hz (within 1% tolerance) - signal clk_50MHz : std_logic := '0'; -- 50 MHz clock. aiming for 100 MHz + -- HDMI signals + signal tmds_clk : std_logic; -- HDMI pixel clock at 5x speed for TMDS @ 371.25 MHz + signal hdmi_clk : std_logic; -- HDMI pixel clock at normal speed @ 74.25 MHz + signal hdmi_rst : std_logic; + signal hdmi_tmds : slv_9_0_t(0 to 2); -- parallel TMDS symbol stream x 3 channels + signal hdmi_hs : std_logic; + signal hdmi_vs : std_logic; + signal hdmi_de : std_logic; + + -- Various clocks + signal clk_pixel : std_logic; -- 25 MHz pixelclock for 640x480 @ 60 Hz (within 1% tolerance) + signal clk_50MHz : std_logic; -- 50 MHz clock. aiming for 100 MHz signal clk_100MHz : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase signal clk_200MHz : std_logic; -- 4x clk_50MHz = 200 MHz signal clk_fb_main : std_logic; signal pll_locked_main : std_logic; - -- combined pre- and post pore reset - signal reset_ctl : std_logic; - -- enable displaying of address bus on system halt, if switch 2 is on signal i_til_reg0_enable : std_logic; signal i_til_data_in : std_logic_vector(15 downto 0); @@ -378,90 +393,70 @@ begin vdac_psave_n_o <= '1'; hdmi_hiz_en_o <= '0'; -- HDMI is 50 ohm terminated. - hdmi_ls_oe_n_o <= '1'; -- Disable HDMI output + hdmi_ls_oe_n_o <= '0'; -- Disable HDMI output hdmi_scl_io <= 'Z'; hdmi_sda_io <= 'Z'; - dbg_11_io <= 'Z'; - - eth_clock_o <= '0'; - eth_led2_o <= '0'; - eth_mdc_o <= '0'; - eth_mdio_io <= 'Z'; - eth_reset_o <= '1'; - eth_txd_o <= (others => '0'); - eth_txen_o <= '0'; - - f_density_o <= '1'; - f_motora_o <= '1'; - f_motorb_o <= '1'; - f_selecta_o <= '1'; - f_selectb_o <= '1'; - f_side1_o <= '1'; - f_stepdir_o <= '1'; - f_step_o <= '1'; - f_wdata_o <= '1'; - f_wgate_o <= '1'; - + + dbg_11_io <= 'Z'; + + eth_clock_o <= '0'; + eth_led2_o <= '0'; + eth_mdc_o <= '0'; + eth_mdio_io <= 'Z'; + eth_reset_o <= '1'; + eth_txd_o <= (others => '0'); + eth_txen_o <= '0'; + + f_density_o <= '1'; + f_motora_o <= '1'; + f_motorb_o <= '1'; + f_selecta_o <= '1'; + f_selectb_o <= '1'; + f_side1_o <= '1'; + f_stepdir_o <= '1'; + f_step_o <= '1'; + f_wdata_o <= '1'; + f_wgate_o <= '1'; + joystick_5v_disable_o <= '0'; -- Enable 5V power supply to joysticks - - led_g_n_o <= '1'; -- Off - led_r_n_o <= '1'; -- Off - led_o <= '0'; -- Off - - p1lo_io <= (others => 'Z'); - p1hi_io <= (others => 'Z'); - p2lo_io <= (others => 'Z'); - p2hi_io <= (others => 'Z'); - - pmod1_en_o <= '0'; - pmod2_en_o <= '0'; - - qspidb_io <= (others => 'Z'); - qspicsn_o <= '1'; - - sdram_clk_o <= '0'; - sdram_cke_o <= '0'; - sdram_ras_n_o <= '1'; - sdram_cas_n_o <= '1'; - sdram_we_n_o <= '1'; - sdram_cs_n_o <= '1'; - sdram_ba_o <= (others => '0'); - sdram_a_o <= (others => '0'); - sdram_dqml_o <= '0'; - sdram_dqmh_o <= '0'; - sdram_dq_io <= (others => 'Z'); - - -- dummy HDMI differential output - - tmds_data_obufds : for i in 0 to 2 generate - begin - tmds_data_obufds_bit : obufds - port map - ( - i => 'L', - o => tmds_data_p_o(i), - ob => tmds_data_n_o(i) - ); - end generate tmds_data_obufds; - tmds_clk_obufds : obufds - port map - ( - i => 'L', - o => tmds_clk_p_o, - ob => tmds_clk_n_o - ); + led_g_n_o <= '1'; -- Off + led_r_n_o <= '1'; -- Off + led_o <= '0'; -- Off + + p1lo_io <= (others => 'Z'); + p1hi_io <= (others => 'Z'); + p2lo_io <= (others => 'Z'); + p2hi_io <= (others => 'Z'); + + pmod1_en_o <= '0'; + pmod2_en_o <= '0'; + + qspidb_io <= (others => 'Z'); + qspicsn_o <= '1'; + + sdram_clk_o <= '0'; + sdram_cke_o <= '0'; + sdram_ras_n_o <= '1'; + sdram_cas_n_o <= '1'; + sdram_we_n_o <= '1'; + sdram_cs_n_o <= '1'; + sdram_ba_o <= (others => '0'); + sdram_a_o <= (others => '0'); + sdram_dqml_o <= '0'; + sdram_dqmh_o <= '0'; + sdram_dq_io <= (others => 'Z'); clk_main : mmcme2_base generic map ( clkin1_period => 10.0, -- 100 MHz (10 ns) - clkfbout_mult_f => 8.0, -- 800 MHz common multiply - divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range - clkout0_divide_f => 32.0, -- Should be 25.175 MHz, but 25MHz is within 1% tolerance range - clkout1_divide => 8, -- 100 MHz /8 - clkout2_divide => 16, -- 50 MHz /16 - clkout3_divide => 4 -- 200 MHz /4 + clkfbout_mult_f => 8.0, -- 800 MHz common multiply + divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range + clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but 25MHz is within 1% tolerance range + clkout1_divide => 8, -- 100 MHz /8 + clkout2_divide => 16, -- 50 MHz /16 + clkout3_divide => 4 -- 200 MHz /4 ) port map ( @@ -470,9 +465,9 @@ begin clkin1 => clk_i, clkfbin => clk_fb_main, clkfbout => clk_fb_main, - clkout0 => clk_25MHz, -- pixelclock + clkout0 => clk_pixel, -- pixelclock clkout1 => clk_100MHz, -- 100 MHz - clkout2 => clk_50MHz, -- 50 MHz + clkout2 => clk_50MHz, -- 50 MHz clkout3 => clk_200MHz, -- 200 MHz locked => pll_locked_main ); @@ -543,14 +538,14 @@ begin port map ( reset => reset_ctl, - clk25MHz => clk_25MHz, + clk25MHz => clk_pixel, clk50MHz => clk_50MHz, R => vga_r, G => vga_g, B => vga_b, hsync => vga_hsync, vsync => vga_vsync, - hdmi_de => open, + hdmi_de => hdmi_de, en => vga_en, we => vga_we, reg => vga_reg, @@ -769,9 +764,9 @@ begin end if; end process; - video_signal_latches : process (clk_25MHz) + video_signal_latches : process (clk_pixel) begin - if rising_edge(clk_25MHz) then + if rising_edge(clk_pixel) then -- VGA: wire the simplified color system of the VGA component to the VGA outputs vga_red_o <= vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r; vga_green_o <= vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g; @@ -791,7 +786,7 @@ begin -- As of the time writing this (June 2020): it is absolutely unclear for me, why I need to -- invert the phase of the vdac_clk when use Vivado 2019.2. When using ISE 14.7, it works -- fine without the phase shift. - vdac_clk_o <= clk_25MHz; + vdac_clk_o <= not clk_pixel; -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) @@ -802,4 +797,100 @@ begin reset_ctl <= '1' when (reset_pre_pore = '1' or reset_post_pore = '1' or pll_locked_main = '0') else '0'; -end architecture beh; + -- VGA to HDMI conversion -- + + -- reconfigurable MMCM: 25.2MHz, 27MHz, 74.25MHz or 148.5MHz + video_out_clock_inst : entity work.video_out_clock + generic map( + FREF => 100.0 -- Clock speed in MHz of the input clk_i + ) + port map + ( + rsti => not reset_ctl, + clki => clk_i, + sel => HDMI_VIDEO_MODE.CLK_SEL, + rsto => hdmi_rst, + clko => hdmi_clk, + clko_x5 => tmds_clk + ); -- video_out_clock_inst + + video2hdmi_inst : component xpm_cdc_array_single + generic map( + WIDTH => 27 + ) + port map + ( + src_clk => clk_pixel, + src_in(23 downto 0) => vga_red_o & vga_green_o & vga_blue_o, + src_in(24) => vga_hs_o, + src_in(25) => vga_vs_o, + src_in(26) => not vdac_blank_n_o, + dest_clk => hdmi_clk, + dest_out(23 downto 0) => open, + dest_out(24) => hdmi_hs, + dest_out(25) => hdmi_vs, + dest_out(26) => open + ); -- video2hdmi_inst + + -- (hdmi_red, hdmi_green, hdmi_blue) <= unsigned(hdmi_color); + + hdmi_data_gen : for i in 0 to 2 generate + begin + hdmi_data_inst : entity work.serialiser_10to1_selectio + port map + ( + rst => not reset_ctl, + clk => hdmi_clk, + clk_x5 => tmds_clk, + d => hdmi_tmds(i), + out_p => tmds_data_p_o(i), + out_n => tmds_data_n_o(i) + ); + end generate hdmi_data_gen; + + hdmi_clk_inst : entity work.serialiser_10to1_selectio + port map + ( + rst => not reset_ctl, + clk => hdmi_clk, + clk_x5 => tmds_clk, + d => "0000011111", + out_p => tmds_clk_p_o, + out_n => tmds_clk_n_o + ); -- hdmi_clk_inst + + vga_to_hdmi_inst : entity work.vga_to_hdmi + port map + ( + select_44100 => '0', + dvi => '1', + vic => std_logic_vector(to_unsigned(HDMI_VIDEO_MODE.CEA_CTA_VIC, 8)), + aspect => HDMI_VIDEO_MODE.ASPECT, + pix_rep => HDMI_VIDEO_MODE.PIXEL_REP, + vs_pol => HDMI_VIDEO_MODE.V_POL, + hs_pol => HDMI_VIDEO_MODE.H_POL, + + vga_rst => not reset_ctl, + vga_clk => vdac_clk_o, + vga_vs => vga_vs_o, + vga_hs => vga_hs_o, + vga_de => hdmi_de, + vga_r => vga_red_o, + vga_g => vga_green_o, + vga_b => vga_blue_o, + + -- PCM audio + pcm_clk => '1', + pcm_rst => '0', + pcm_clken => '0', + pcm_l => (others => '1'), + pcm_r => (others => '1'), + pcm_acr => '1', + pcm_n => (others => '1'), + pcm_cts => (others => '1'), + + -- TMDS output (parallel) + tmds => hdmi_tmds + ); -- vga_to_hdmi_inst + + end architecture beh; diff --git a/vhdl/hw/MEGA65/cdc_stable.vhd b/vhdl/hw/MEGA65/cdc_stable.vhd new file mode 100644 index 00000000..ae7c32d3 --- /dev/null +++ b/vhdl/hw/MEGA65/cdc_stable.vhd @@ -0,0 +1,71 @@ +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +-- Clock Domain Crossing specialized for slowly varying data: +-- Only propagate when all bits are stable. +-- +-- In the constraint file, add the following line: +-- set_max_delay 8 -datapath_only -from [get_clocks] -to [get_pins -hierarchical "*cdc_stable_gen.dst_*_d_reg[*]/D"] + +entity cdc_stable is + generic ( + G_DATA_SIZE : integer; + G_REGISTER_SRC : boolean := false -- Add register to input data + ); + port ( + src_clk_i : in std_logic := '0'; + src_data_i : in std_logic_vector(G_DATA_SIZE - 1 downto 0); + dst_clk_i : in std_logic; + dst_data_o : out std_logic_vector(G_DATA_SIZE - 1 downto 0) + ); +end entity cdc_stable; + +architecture synthesis of cdc_stable is + + signal src_data : std_logic_vector(G_DATA_SIZE - 1 downto 0); + signal dst_data_d : std_logic_vector(G_DATA_SIZE - 1 downto 0); + signal dst_data_dd : std_logic_vector(G_DATA_SIZE - 1 downto 0); + + attribute async_reg : string; + attribute async_reg of dst_data_d : signal is "true"; + attribute async_reg of dst_data_dd : signal is "true"; + +begin + + -- Optionally add a register to the input samples + + input_reg_gen : if G_REGISTER_SRC generate + + input_reg_proc : process (src_clk_i) + begin + if rising_edge(src_clk_i) then + src_data <= src_data_i; + end if; + end process input_reg_proc; + + else generate + src_data <= src_data_i; + end generate input_reg_gen; + + -- Use generate to create a nice unique name for constraining + + cdc_stable_gen : if true generate + + sample_proc : process (dst_clk_i) + begin + if rising_edge(dst_clk_i) then + dst_data_d <= src_data; -- CDC + dst_data_dd <= dst_data_d; + + -- Propagate, when sampling is stable + if dst_data_d = dst_data_dd then + dst_data_o <= dst_data_dd; + end if; + end if; + end process sample_proc; + + end generate cdc_stable_gen; + +end architecture synthesis; + diff --git a/vhdl/hw/MEGA65/hdmi_tx_encoder.vhd b/vhdl/hw/MEGA65/hdmi_tx_encoder.vhd new file mode 100644 index 00000000..6758c654 --- /dev/null +++ b/vhdl/hw/MEGA65/hdmi_tx_encoder.vhd @@ -0,0 +1,177 @@ +-------------------------------------------------------------------------------- +-- hdmi_tx_encoder.vhd -- +-- HDMI TMDS encoder channel. -- +-------------------------------------------------------------------------------- +-- (C) Copyright 2020 Adam Barnes -- +-- This file is part of The Tyto Project. The Tyto Project is free software: -- +-- you can redistribute it and/or modify it under the terms of the GNU Lesser -- +-- General Public License as published by the Free Software Foundation, -- +-- either version 3 of the License, or (at your option) any later version. -- +-- The Tyto Project is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- Lesser General Public License along with The Tyto Project. If not, see -- +-- https://www.gnu.org/licenses/. -- +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +package hdmi_tx_encoder_pkg is + + constant ENC_DVI : std_logic_vector(1 downto 0) := "00"; + constant ENC_GB_VIDEO : std_logic_vector(1 downto 0) := "01"; + constant ENC_DATA : std_logic_vector(1 downto 0) := "10"; + constant ENC_GB_DATA : std_logic_vector(1 downto 0) := "11"; + +end package hdmi_tx_encoder_pkg; + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.hdmi_tx_encoder_pkg.all; + +entity hdmi_tx_encoder is + generic ( + channel : integer range 0 to 2 -- affects encoding of guard bands + ); + port ( + rst : in std_logic; -- synchronous reset + clk : in std_logic; -- pixel clock + de : in std_logic; -- pixel data enable + p : in std_logic_vector(7 downto 0); -- pixel data + enc : in std_logic_vector(1 downto 0); -- encoding type (non-video) + c : in std_logic_vector(1 downto 0); -- control + d : in std_logic_vector(3 downto 0); -- aux data (for data islands) + q : out std_logic_vector(9 downto 0) -- TMDS encoded output + ); +end entity hdmi_tx_encoder; + +------------------------------------------------------------------------------- + +architecture synth of hdmi_tx_encoder is + + -- TMDS encoding related + signal n1p : unsigned(3 downto 0); -- 0 to 8 + signal q_m : std_logic_vector(8 downto 0); + signal n0q_m : unsigned(3 downto 0); -- 0 to 8 + signal n1q_m : unsigned(3 downto 0); -- 0 to 8 + signal diff01_5 : signed(4 downto 0); -- -8 to +8 (even) + signal diff10_5 : signed(4 downto 0); -- -8 to +8 (even) + alias diff01 : signed(3 downto 0) is diff01_5(4 downto 1); -- -4 to +4 + alias diff10 : signed(3 downto 0) is diff10_5(4 downto 1); -- -4 to +4 + signal cnt : signed(3 downto 0); -- -4 to +4 + + -- function to count bits + function Nv(x : std_logic_vector; v : std_logic) return integer is + variable n : integer; + begin + n := 0; + for i in 0 to x'length-1 loop + if x(i) = v then n := n+1; end if; + end loop; + return n; + end function Nv; + +begin + + n1p <= to_unsigned(Nv(p,'1'),4); + q_m(0) <= p(0); + q_m(8 downto 1) <= + '0' & (q_m(6 downto 0) xnor p(7 downto 1)) when n1p > x"4" or (n1p = x"4" and p(0) = '0') else + '1' & (q_m(6 downto 0) xor p(7 downto 1)); + n0q_m <= to_unsigned(Nv(q_m(7 downto 0),'0'),4); + n1q_m <= to_unsigned(Nv(q_m(7 downto 0),'1'),4); + diff01_5 <= signed(resize(n0q_m,5)) - signed(resize(n1q_m,5)); -- difference between number of 1s and number of 0s + diff10_5 <= signed(resize(n1q_m,5)) - signed(resize(n0q_m,5)); -- is always even so drop LSB from count + + process(clk) + begin + if rising_edge(clk) then + if rst = '1' then + q <= "1101010100"; + cnt <= x"0"; + else + if de = '1' then -- video + if (cnt = 0) or (n1q_m = n0q_m) then + q(9) <= not q_m(8); + q(8) <= q_m(8); + q(7 downto 0) <= q_m(7 downto 0) xor (7 downto 0 => not q_m(8)); + if q_m(8) = '0' then + cnt <= cnt + diff01; + else + cnt <= cnt + diff10; + end if; + elsif (cnt > x"0" and n1q_m > n0q_m) or (cnt < x"0" and n0q_m > n1q_m) then + q(9) <= '1'; + q(8) <= q_m(8); + q(7 downto 0) <= not q_m(7 downto 0); + cnt <= cnt + signed("000" & q_m(8 downto 8)) + diff01; + else + q(9) <= '0'; + q(8) <= q_m(8); + q(7 downto 0) <= q_m(7 downto 0); + cnt <= cnt - signed("000" & not q_m(8 downto 8)) + diff10; + end if; + else -- not video + cnt <= x"0"; + case enc is + when ENC_DVI => -- control + case c is + when "00" => q <= "1101010100"; + when "01" => q <= "0010101011"; + when "10" => q <= "0101010100"; + when "11" => q <= "1010101011"; + when others => q <= "XXXXXXXXXX"; + end case; + when ENC_GB_VIDEO => -- video guard band + case channel is + when 0 => q <= "1011001100"; + when 1 => q <= "0100110011"; + when 2 => q <= "1011001100"; + when others => q <= "XXXXXXXXXX"; + end case; + when ENC_DATA => -- data island contents + case d is + when "0000" => q <= "1010011100"; + when "0001" => q <= "1001100011"; + when "0010" => q <= "1011100100"; + when "0011" => q <= "1011100010"; + when "0100" => q <= "0101110001"; + when "0101" => q <= "0100011110"; + when "0110" => q <= "0110001110"; + when "0111" => q <= "0100111100"; + when "1000" => q <= "1011001100"; + when "1001" => q <= "0100111001"; + when "1010" => q <= "0110011100"; + when "1011" => q <= "1011000110"; + when "1100" => q <= "1010001110"; + when "1101" => q <= "1001110001"; + when "1110" => q <= "0101100011"; + when others => q <= "1011000011"; + end case; + when ENC_GB_DATA => -- data island guard band + case channel is + when 2 => q <= "0100110011"; + when 1 => q <= "0100110011"; + when 0 => -- special rules for channel 0... + case c is + when "00" => q <= "1010001110"; + when "01" => q <= "1001110001"; + when "10" => q <= "0101100011"; + when "11" => q <= "1011000011"; + when others => q <= "XXXXXXXXXX"; + end case; + end case; + when others => + q <= "XXXXXXXXXX"; + end case; + end if; + end if; + end if; + end process; + +end architecture synth; diff --git a/vhdl/hw/MEGA65/serialiser_10to1_selectio.vhd b/vhdl/hw/MEGA65/serialiser_10to1_selectio.vhd new file mode 100644 index 00000000..6da533a0 --- /dev/null +++ b/vhdl/hw/MEGA65/serialiser_10to1_selectio.vhd @@ -0,0 +1,142 @@ +-------------------------------------------------------------------------------- +-- serialiser_10to1_selectio.vhd -- +-- 10:1 serialiser driving SelectIO differential output pair. -- +-------------------------------------------------------------------------------- +-- (C) Copyright 2020 Adam Barnes -- +-- This file is part of The Tyto Project. The Tyto Project is free software: -- +-- you can redistribute it and/or modify it under the terms of the GNU Lesser -- +-- General Public License as published by the Free Software Foundation, -- +-- either version 3 of the License, or (at your option) any later version. -- +-- The Tyto Project is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- Lesser General Public License along with The Tyto Project. If not, see -- +-- https://www.gnu.org/licenses/. -- +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library unisim; +use unisim.vcomponents.all; + +entity serialiser_10to1_selectio is + port ( + rst : in std_logic; -- reset + clk : in std_logic; -- parallel data clcok + clk_x5 : in std_logic; -- serialiser DDR clock + d : in std_logic_vector(9 downto 0); -- input parallel data + out_p : out std_logic; -- output serial data + out_n : out std_logic -- " + ); +end entity serialiser_10to1_selectio; + +architecture synth of serialiser_10to1_selectio is + + signal s1 : std_logic; + signal s2 : std_logic; + signal q : std_logic; + +begin + + -- serialiser (master) + U_SER_M: oserdese2 + generic map ( + data_rate_oq => "DDR", -- DDR, SDR + data_rate_tq => "SDR", -- DDR, BUF, SDR + data_width => 10, -- Parallel data width (2-8,10,14) + init_oq => '0', -- Initial value of OQ output (1'b0,1'b1) + init_tq => '0', -- Initial value of TQ output (1'b0,1'b1) + serdes_mode => "MASTER", -- MASTER, SLAVE + srval_oq => '0', -- OQ output value when SR is used (1'b0,1'b1) + srval_tq => '0', -- TQ output value when SR is used (1'b0,1'b1) + tbyte_ctl => "FALSE", -- Enable tristate byte operation (FALSE, TRUE) + tbyte_src => "FALSE", -- Tristate byte source (FALSE, TRUE) + tristate_width => 1 -- 3-state converter width (1,4) + ) + port map ( + ofb => open, -- 1-bit output: Feedback path for data + oq => q, -- 1-bit output: Data path output + shiftout1 => open, -- SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each) + shiftout2 => open, + tbyteout => open, -- 1-bit output: Byte group tristate + tfb => open, -- 1-bit output: 3-state control + tq => open, -- 1-bit output: 3-state control + clk => clk_x5, -- 1-bit input: High speed clock + clkdiv => clk, -- 1-bit input: Divided clock + d1 => d(0), -- D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) + d2 => d(1), + d3 => d(2), + d4 => d(3), + d5 => d(4), + d6 => d(5), + d7 => d(6), + d8 => d(7), + oce => '1', -- 1-bit input: Output data clock enable + rst => rst, -- 1-bit input: Reset + shiftin1 => s1, -- SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each) + shiftin2 => s2, + t1 => '0', -- T1 - T4: 1-bit (each) input: Parallel 3-state inputs + t2 => '0', + t3 => '0', + t4 => '0', + tbytein => '0', -- 1-bit input: Byte group tristate + tce => '0' -- 1-bit input: 3-state clock enable + ); + + -- serialiser (slave) + U_SER_S: oserdese2 + generic map ( + data_rate_oq => "DDR", -- DDR, SDR + data_rate_tq => "SDR", -- DDR, BUF, SDR + data_width => 10, -- Parallel data width (2-8,10,14) + init_oq => '0', -- Initial value of OQ output (1'b0,1'b1) + init_tq => '0', -- Initial value of TQ output (1'b0,1'b1) + serdes_mode => "SLAVE", -- MASTER, SLAVE + srval_oq => '0', -- OQ output value when SR is used (1'b0,1'b1) + srval_tq => '0', -- TQ output value when SR is used (1'b0,1'b1) + tbyte_ctl => "FALSE", -- Enable tristate byte operation (FALSE, TRUE) + tbyte_src => "FALSE", -- Tristate byte source (FALSE, TRUE) + tristate_width => 1 -- 3-state converter width (1,4) + ) + port map ( + ofb => open, -- 1-bit output: Feedback path for data + oq => open, -- 1-bit output: Data path output + shiftout1 => s1, -- SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each) + shiftout2 => s2, + tbyteout => open, -- 1-bit output: Byte group tristate + tfb => open, -- 1-bit output: 3-state control + tq => open, -- 1-bit output: 3-state control + clk => clk_x5, -- 1-bit input: High speed clock + clkdiv => clk, -- 1-bit input: Divided clock + d1 => '0', -- D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each) + d2 => '0', + d3 => d(8), + d4 => d(9), + d5 => '0', + d6 => '0', + d7 => '0', + d8 => '0', + oce => '1', -- 1-bit input: Output data clock enable + rst => rst, -- 1-bit input: Reset + shiftin1 => '0', -- SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each) + shiftin2 => '0', + t1 => '0', -- T1 - T4: 1-bit (each) input: Parallel 3-state inputs + t2 => '0', + t3 => '0', + t4 => '0', + tbytein => '0', -- 1-bit input: Byte group tristate + tce => '0' -- 1-bit input: 3-state clock enable + ); + + -- differential output buffer + U_OBUF: obufds + port map ( + i => q, + o => out_p, + ob => out_n + ); + +end architecture synth; diff --git a/vhdl/hw/MEGA65/sync_reg.vhd b/vhdl/hw/MEGA65/sync_reg.vhd new file mode 100644 index 00000000..2c52f79e --- /dev/null +++ b/vhdl/hw/MEGA65/sync_reg.vhd @@ -0,0 +1,87 @@ +-------------------------------------------------------------------------------- +-- sync_reg.vhd -- +-- Synchronising register(s) for clock domain crossing. -- +-------------------------------------------------------------------------------- +-- (C) Copyright 2022 Adam Barnes -- +-- This file is part of The Tyto Project. The Tyto Project is free software: -- +-- you can redistribute it and/or modify it under the terms of the GNU Lesser -- +-- General Public License as published by the Free Software Foundation, -- +-- either version 3 of the License, or (at your option) any later version. -- +-- The Tyto Project is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- Lesser General Public License along with The Tyto Project. If not, see -- +-- https://www.gnu.org/licenses/. -- +-------------------------------------------------------------------------------- + +library ieee; + use ieee.std_logic_1164.all; + +package sync_reg_pkg is + + component sync_reg is + generic ( + width : integer := 1; + depth : integer := 2; + rst_state : std_logic := '0' + ); + port ( + rst : in std_logic := '0'; + clk : in std_logic; + d : in std_logic_vector(width-1 downto 0); + q : out std_logic_vector(width-1 downto 0) + ); + end component sync_reg; + +end package sync_reg_pkg; + +------------------------------------------------------------------------------- + +library ieee; + use ieee.std_logic_1164.all; + +entity sync_reg is + generic ( + width : integer := 1; + depth : integer := 2; + rst_state : std_logic := '0' + ); + port ( + rst : in std_logic := '0'; + clk : in std_logic; -- destination clock + d : in std_logic_vector(width-1 downto 0); -- input + q : out std_logic_vector(width-1 downto 0) -- output + ); +end entity sync_reg; + +architecture structural of sync_reg is + + subtype reg_level_t is std_logic_vector(width-1 downto 0); + type reg_t is array(0 to depth-1) of reg_level_t; + + signal reg : reg_t; + + attribute async_reg : string; + attribute async_reg of reg : signal is "TRUE"; + +begin + + MAIN: process (rst,clk) is + begin + if rst = '1' then + reg <= (others => (others => rst_state)); + elsif rising_edge(clk) then + for i in 0 to depth-1 loop + if i = 0 then + reg(i) <= d; + else + reg(i) <= reg(i-1); + end if; + end loop; + end if; + end process MAIN; + + q <= reg(depth-1); + +end architecture structural; diff --git a/vhdl/hw/MEGA65/types_pkg.vhd b/vhdl/hw/MEGA65/types_pkg.vhd new file mode 100644 index 00000000..5c6bcfc7 --- /dev/null +++ b/vhdl/hw/MEGA65/types_pkg.vhd @@ -0,0 +1,32 @@ +-------------------------------------------------------------------------------- +-- types_pkg.vhd -- +-- Common types package. -- +-------------------------------------------------------------------------------- +-- (C) Copyright 2020 Adam Barnes -- +-- This file is part of The Tyto Project. The Tyto Project is free software: -- +-- you can redistribute it and/or modify it under the terms of the GNU Lesser -- +-- General Public License as published by the Free Software Foundation, -- +-- either version 3 of the License, or (at your option) any later version. -- +-- The Tyto Project is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- Lesser General Public License along with The Tyto Project. If not, see -- +-- https://www.gnu.org/licenses/. -- +-------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +package types_pkg is + + type slv_31_0_t is array(natural range <>) of std_logic_vector(31 downto 0); + type slv_9_0_t is array(natural range <>) of std_logic_vector(9 downto 0); + type slv_7_0_t is array(natural range <>) of std_logic_vector(7 downto 0); + type slv_3_0_t is array(natural range <>) of std_logic_vector(3 downto 0); + type slv_1_0_t is array(natural range <>) of std_logic_vector(1 downto 0); + + type slv_7_0_2d_t is array(natural range <>,natural range <>) of std_logic_vector(7 downto 0); + type slv_3_0_2d_t is array(natural range <>,natural range <>) of std_logic_vector(3 downto 0); + +end package types_pkg; diff --git a/vhdl/hw/MEGA65/vga_to_hdmi.vhd b/vhdl/hw/MEGA65/vga_to_hdmi.vhd new file mode 100644 index 00000000..7d345f5e --- /dev/null +++ b/vhdl/hw/MEGA65/vga_to_hdmi.vhd @@ -0,0 +1,944 @@ +-------------------------------------------------------------------------------- +-- vga_to_hdmi.vhd -- +-- VGA to HDMI converter IP core; also injects PCM stereo audio. -- +-------------------------------------------------------------------------------- +-- (C) Copyright 2022 Adam Barnes -- +-- This file is part of The Tyto Project. The Tyto Project is free software: -- +-- you can redistribute it and/or modify it under the terms of the GNU Lesser -- +-- General Public License as published by the Free Software Foundation, -- +-- either version 3 of the License, or (at your option) any later version. -- +-- The Tyto Project is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- Lesser General Public License along with The Tyto Project. If not, see -- +-- https://www.gnu.org/licenses/. -- +-------------------------------------------------------------------------------- + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +library work; + use work.types_pkg.all; + use work.sync_reg_pkg.all; + use work.hdmi_tx_encoder_pkg.all; + +entity vga_to_hdmi is + port ( + + -- Select which of the two audio clocks above to use + select_44100 : in std_logic; + + dvi : in std_logic; -- DVI mode disables all HDMI enhancements e.g. audio + vic : in std_logic_vector(7 downto 0); -- CEA/CTA VIC + aspect : in std_logic_vector(1 downto 0); -- for aspect ratio signalling in AVI InfoFrames + pix_rep : in std_logic; -- signals pixel repetition (SD interlaced modes) + vs_pol : in std_logic; -- vertical sync output polarity } 1 = active high + hs_pol : in std_logic; -- horizontal sync output polarity } + + vga_rst : in std_logic; -- reset + vga_clk : in std_logic; -- pixel clock + vga_vs : in std_logic; -- vertical sync } active high + vga_hs : in std_logic; -- horizontal sync } + vga_de : in std_logic; -- data (pixel) enable + vga_r : in std_logic_vector(7 downto 0); -- pixel data, red channel } + vga_g : in std_logic_vector(7 downto 0); -- pixel data, green channel } 0..255 + vga_b : in std_logic_vector(7 downto 0); -- pixel data, blue channel } + + pcm_rst : in std_logic; -- audio reset + pcm_clk : in std_logic; -- audio clock } combined = fs + pcm_clken : in std_logic; -- audio clock enable } (audio sample rate) + pcm_l : in std_logic_vector(15 downto 0); -- left channel } audio + pcm_r : in std_logic_vector(15 downto 0); -- right channel } sample + pcm_acr : in std_logic; -- HDMI ACR packet strobe (frequency = 128fs/N e.g. 1kHz) + pcm_n : in std_logic_vector(19 downto 0); -- HDMI ACR N value + pcm_cts : in std_logic_vector(19 downto 0); -- HDMI ACR CTS value + + tmds : out slv_9_0_t(0 to 2) -- parallel TMDS symbol stream x 3 channels + + ); +end entity vga_to_hdmi; + +architecture synth of vga_to_hdmi is + + constant SUBPACKETS : integer := 4; -- per packet + constant PACKET_TYPES : integer := 4; -- types of data packet supported in this design + + constant CTL_NULL : std_logic_vector(3 downto 0) := "0000"; + constant CTL_PRE_VIDEO : std_logic_vector(3 downto 0) := "0001"; -- video period preamble + constant CTL_PRE_DATA : std_logic_vector(3 downto 0) := "0101"; -- data period preamble + + ---------------------------------------------------------------------- + -- audio/ACR related + + signal pcm_n_s : std_logic_vector(19 downto 0); -- pcm_n } synchronised + signal pcm_cts_s : std_logic_vector(19 downto 0); -- pcm_cts } + signal pcm_cs_v : std_logic_vector(0 to 39); -- IEC60958 channel status as a vector + signal pcm_count : integer range 0 to SUBPACKETS-1; -- used to assemble 4x samples into sample packet + + signal iec_req : std_logic; -- PCM to IEC sample request + signal iec_count : integer range 0 to 191; -- IEC60958 frame # + signal iec_sync : std_logic; -- IEC60958 b preamble (sync) + signal iec_l : std_logic_vector(23 downto 0); -- IEC60958 left channel sample + signal iec_lv : std_logic; -- IEC60958 left channel status + signal iec_lu : std_logic; -- IEC60958 left user data + signal iec_lc : std_logic; -- IEC60958 left channel status + signal iec_lp : std_logic; -- IEC60958 left channel status + signal iec_r : std_logic_vector(23 downto 0); -- IEC60958 right channel sample + signal iec_rv : std_logic; -- IEC60958 right channel status + signal iec_ru : std_logic; -- IEC60958 right user data + signal iec_rc : std_logic; -- IEC60958 right channel status + signal iec_rp : std_logic; -- IEC60958 right channel status + signal iec_ack : std_logic; -- } + + signal iec_req_s : std_logic_vector(0 to 4); -- } clock domain crossing logic + signal pcm_acr_s : std_logic_vector(0 to 2); -- } + + signal vga_iec_en : std_logic; -- enable for the following... + signal vga_iec_sync : std_logic; -- iec_sync } synchronised to vga_clk + signal vga_iec_l : std_logic_vector(23 downto 0); -- iec_l } + signal vga_iec_lv : std_logic; -- iec_lv } + signal vga_iec_lu : std_logic; -- iec_lu } + signal vga_iec_lc : std_logic; -- iec_lc } + signal vga_iec_lp : std_logic; -- iec_lp } + signal vga_iec_r : std_logic_vector(23 downto 0); -- iec_r } + signal vga_iec_rv : std_logic; -- iec_rv } + signal vga_iec_ru : std_logic; -- iec_ru } + signal vga_iec_rc : std_logic; -- iec_rc } + signal vga_iec_rp : std_logic; -- iec_rp } + signal vga_iec_data : std_logic_vector(56 downto 0); -- bus to carry above signals + signal vga_acr : std_logic; -- ACR enable pulse, synchronous to vga_clk + + ---------------------------------------------------------------------- + -- video input related + + signal dvi_s : std_logic; -- dvi } synchronised + signal vic_s : std_logic_vector(7 downto 0); -- vic } + signal aspect_s : std_logic_vector(1 downto 0); -- aspect } + signal pix_rep_s : std_logic; -- pix_rep } + signal vs_pol_s : std_logic; -- vs_pol } + signal hs_pol_s : std_logic; -- hs_pol } + + signal vga_vs_p : std_logic; -- vga_vs } polarity adjusted + signal vga_hs_p : std_logic; -- vga_hs } + + signal vga_vs_1 : std_logic; -- vga_vs, delayed by 1 clock + signal vga_hs_1 : std_logic; -- vga_hs, delayed by 1 clock + signal vga_de_1 : std_logic; -- vga_de, delayed by 1 clock + + constant buf_size : integer := 128; + type buf_t is array(0 to buf_size-1) of std_logic_vector(26 downto 0); + + signal buf : buf_t; -- video input buffer (circular) + signal buf_addr : integer range 0 to buf_size-1; -- video input buffer write/read address + signal buf_valid : boolean; -- indicates buffer has been filled once + signal buf_vs : std_logic; -- buffered VGA vertical sync + signal buf_hs : std_logic; -- buffered VGA horizontal sync + signal buf_de : std_logic; -- buffered VGA data (pixel) enable + signal buf_p : slv_7_0_t(0 to 2); -- buffered VGA pixel data, 3 channels + signal blank_count : integer range 0 to buf_size; -- video blank count + + ---------------------------------------------------------------------- + -- encoding related + + type u8 is array(natural range <>) of unsigned(7 downto 0); + type hb_array_t is array(0 to PACKET_TYPES-1) of u8(0 to 2); + type pb_array_t is array(0 to PACKET_TYPES-1) of u8(0 to 27); + type sb_array_t is array(0 to 3) of u8(0 to 6); + type period_t is ( + CONTROL, + VIDEO_PRE, + VIDEO_GB, + VIDEO, + DATA_PRE, + DATA_GB_LEADING, + DATA_ISLAND, + DATA_GB_TRAILING + ); + + signal data_req : std_logic_vector(0 to PACKET_TYPES-1); -- } data packet handshaking + signal data_ack : std_logic_vector(0 to PACKET_TYPES-1); -- } + + signal hb_a : u8(0 to 2); -- header bytes of audio sample packet in progress + signal pb_a : u8(0 to 27); -- packet bytes of audio sample packet in progress + signal hb : hb_array_t; -- header bytes for packet types 0..3 + signal pb : pb_array_t; -- packet bytes for packet types 0..3 + + -- HDMI encoding pipeline stage 1... + signal s1_period : period_t; -- period type + signal s1_pcount : unsigned(4 downto 0); -- counts time spent in period up to a max of 31 (also data island character #) + signal s1_dcount : unsigned(4 downto 0); -- counts consecutive data packets (max allowed is 18) + signal s1_hb : u8(0 to 2); -- current header + signal s1_sb : sb_array_t; -- current set of 4 subpackets + signal s1_vs : std_logic; -- vertical sync (pipelined from buffered input) + signal s1_hs : std_logic; -- horizontal sync (pipelined from buffered input) + signal s1_de : std_logic; -- data (pixel) enable (pipelined from buffered from input) + signal s1_p : slv_7_0_t(0 to 2); -- pixel data (3 channels) (pipelined from buffered input) + signal s1_enc : std_logic_vector(1 downto 0); -- encoding type required + signal s1_ctl : std_logic_vector(3 downto 0); -- CTL bits (indicate preamble type) + + -- HDMI encoding pipeline stage 2... + signal s2_data : std_logic; -- data period active + signal s2_pcount : unsigned(s1_pcount'range); -- data island character #= + signal s2_bch4 : std_logic; -- BCH block 4 bit + signal s2_bch_e : std_logic_vector(3 downto 0); -- BCH blocks 0-3 even bit + signal s2_bch_o : std_logic_vector(3 downto 0); -- BCH blocks 0-3 odd bit + signal s2_vs : std_logic; -- vertical sync (pipelined from previous stage) + signal s2_hs : std_logic; -- horizontal sync (pipelined from previous stage) + signal s2_de : std_logic; -- data (pixel) enable (pipelined from previous stage) + signal s2_p : slv_7_0_t(0 to 2); -- pixel data (3 channels) (pipelined from previous stage) + signal s2_enc : std_logic_vector(1 downto 0); -- encoding type (pipelined from previous stage) + signal s2_ctl : std_logic_vector(3 downto 0); -- CTL bits (pipelined from previous stage) + + -- HDMI encoding pipeline stage 3... + signal s3_data : std_logic; -- data period active + signal s3_pcount : unsigned(s1_pcount'range); -- data island character # + signal s3_bch4 : std_logic; -- BCH block 4 bit + signal s3_bch_e : std_logic_vector(s2_bch_e'range); -- BCH blocks 0-3 even bit + signal s3_bch_o : std_logic_vector(s2_bch_o'range); -- BCH blocks 0-3 odd bit + signal s3_bch_ecc : slv_7_0_t(0 to SUBPACKETS); -- ECC values for header (0) and 4 subpackets (1..4) + signal s3_vs : std_logic; -- vertical sync (pipelined from previous stage) + signal s3_hs : std_logic; -- horizontal sync (pipelined from previous stage) + signal s3_de : std_logic; -- data (pixel) enable (pipelined from previous stage) + signal s3_p : slv_7_0_t(0 to 2); -- pixel data (3 channels) (pipelined from previous stage) + signal s3_enc : std_logic_vector(1 downto 0); -- encoding type (pipelined from previous stage) + signal s3_ctl : std_logic_vector(3 downto 0); -- CTL bits (pipelined from previous stage) + + -- HDMI encoding pipeline stage 4... + signal s4_vs : std_logic; -- vertical sync (pipelined from previous stage) + signal s4_hs : std_logic; -- horizontal sync (pipelined from previous stage) + signal s4_de : std_logic; -- data (pixel) enable (pipelined from previous stage) + signal s4_p : slv_7_0_t(0 to 2); -- pixel data (3 channels) (pipelined from previous stage) + signal s4_enc : std_logic_vector(1 downto 0); -- encoding type (pipelined from previous stage) + signal s4_ctl : std_logic_vector(3 downto 0); -- CTL bits (pipelined from previous stage) + signal s4_c : slv_1_0_t(0 to 2); -- C input to TMDS encoder x 3 channels + signal s4_d : slv_3_0_t(0 to 2); -- aux data input to TMDS encoder x 3 channels + + ---------------------------------------------------------------------- + -- constant packet content + + -- packet type 0: audio clock sample packet + constant hb_0 : u8(0 to 2) := (x"02", x"0F", x"00"); + + -- packet type 1: audio clock regeneration packet + constant hb_1 : u8(0 to 2) := (x"01", x"00", x"00"); + + -- packet type 2: audio infoframe packet + constant hb_2 : u8(0 to 2) := (x"84", x"01", x"0A"); + constant pb_2 : u8(0 to 27) := + ( + 0 => x"70", -- checksum 84+01+0A+01+CKS = 00 + 1 => x"01", -- 00000001 CT(3:0),RSVD,CC(2:0) + 2 => x"00", -- 00000000 F(27:25),SF(2:0),SS(1:0) + 3 => x"00", -- 00000000 F(37:35),CXT(4:0) + 4 => x"00", -- 00000000 CA(7:0) + 5 => x"00", -- 00000001 DM_INH,LSV(3:0),F(52),LFEPBL(1:0) + 6 => x"00", -- 00000000 F(67:60) + 7 => x"00", -- 00000000 F(77:70) + 8 => x"00", -- 00000000 F(87:80) + 9 => x"00", -- 00000000 F(97:90) + 10 => x"00", -- 00000000 F(107:100) + others => x"00" -- zero + ); + + -- type 3: AVI infoframe packet + constant hb_3 : u8(0 to 2) := (x"82", x"02", x"0D"); + constant pb_3 : u8(0 to 27) := + ( + 0 => x"00", -- *NOT CONSTANT* checksum + 1 => x"02", -- RSVD,Y(1:0),A0,B(1:0),S(1:0) + 2 => x"00", -- *PART CONSTANT* C(1:0),M(1:0),R(3:0) + 3 => x"80", -- ITC,EC(2:0),Q(1:0),SC(1:0) + 4 => x"00", -- *NOT CONSTANT* VIC + 5 => x"30", -- *PART CONSTANT* YQ(1:0),CN(1:0),PR(3:0) + others => x"00" -- zero + ); + + function sum (data : u8) return unsigned is + variable r : unsigned(7 downto 0); + begin + r := x"00"; + for i in 0 to data'length-1 loop + r := r + data(i); + end loop; + return r; + end function sum; + + constant sum_3 : unsigned(7 downto 0) := sum(hb_3 & pb_3); + +---------------------------------------------------------------------- + +begin + + -- add IEC60958 channel status to PCM stream + + pcm_cs_v(0) <= '0'; -- consumer use + pcm_cs_v(1) <= '0'; -- PCM samples + pcm_cs_v(2) <= '1'; -- no copyright + pcm_cs_v(3 to 5) <= "000"; -- 2 channels without pre-emphasis + pcm_cs_v(6 to 7) <= "00"; -- channel status mode 0 + pcm_cs_v(8 to 15) <= "01000001"; -- category code + pcm_cs_v(16 to 19) <= "0000"; -- source - do not take into account + pcm_cs_v(20 to 23) <= "0000"; -- channel number - DYNAMIC (1/left or 2/right) + pcm_cs_v(28 to 29) <= "00"; -- clock accuracy level 2 + pcm_cs_v(30) <= '0'; -- reserved + pcm_cs_v(31) <= '0'; -- reserved + pcm_cs_v(32) <= '0'; -- max sample word length is 20 bits + pcm_cs_v(33 to 35) <= "100"; -- sample word length is 16 bits + pcm_cs_v(36 to 39) <= "0000"; -- original sample frequency not indicated + + PCM: process (pcm_rst, pcm_clk) is + variable cs, cs_l, cs_r : std_logic; + function xor_v (v : std_logic_vector) return std_logic is + variable i : integer; + variable r : std_logic; + begin + r := '0'; + for i in 0 to v'length-1 loop + r := r xor v(i); + end loop; + return r; + end function xor_v; + + begin + if pcm_rst = '1' then + -- iec_req <= '0'; + iec_count <= 0; + iec_sync <= '0'; + iec_l <= (others => '0'); + iec_lv <= '0'; + iec_lu <= '0'; + iec_lc <= '0'; + iec_lp <= '0'; + iec_r <= (others => '0'); + iec_rv <= '0'; + iec_ru <= '0'; + iec_rc <= '0'; + iec_rp <= '0'; + elsif rising_edge(pcm_clk) then + + -- Inform sink of the correct audio sample rate + if select_44100 = '0' then + pcm_cs_v(24 to 27) <= "0100"; -- 48KHz + else + pcm_cs_v(24 to 27) <= "0000"; -- 44.1KHz + end if; + + if pcm_clken = '1' then + if iec_count < 40 then + cs := pcm_cs_v(iec_count); + else + cs := '0'; + end if; + cs_l := cs; + cs_r := cs; + if iec_count = 20 then + cs_l := '1'; -- set channel number for left channel + elsif iec_count = 21 then + cs_r := '1'; -- set channel number for right channel + end if; + iec_sync <= '0'; + if iec_count = 0 then + iec_sync <= '1'; + end if; + iec_l <= pcm_l & x"00"; + iec_lv <= '0'; + iec_lu <= '0'; + iec_lc <= cs_l; + iec_lp <= xor_v(pcm_l & cs_l); + iec_r <= pcm_r & x"00"; + iec_rv <= '0'; + iec_ru <= '0'; + iec_rc <= cs_r; + iec_rp <= xor_v(pcm_r & cs_r); + if iec_count = 191 then + iec_count <= 0; + else + iec_count <= iec_count+1; + end if; + -- iec_req <= '1'; + -- elsif iec_ack = '1' then + -- iec_req <= '0'; + end if; + end if; + end process PCM; + + P_IEC_REQ: process (all) is + begin + if pcm_rst = '1' or iec_ack = '1' then + iec_req <= '0'; + elsif rising_edge(pcm_clk) and pcm_clken = '1' then + iec_req <= '1'; + end if; + end process P_IEC_REQ; + + -- clock domain crossing + + SYNC1: component sync_reg + generic map ( + WIDTH => 8, + DEPTH => 1 + ) + port map ( + clk => vga_clk, + rst => vga_rst, + d(0) => pcm_acr, + d(1) => pcm_acr_s(0), + d(2) => pcm_acr_s(1), + d(3) => iec_req, + d(4) => iec_req_s(0), + d(5) => iec_req_s(1), + d(6) => iec_req_s(2), + d(7) => iec_req_s(3), + q(0) => pcm_acr_s(0), + q(1) => pcm_acr_s(1), + q(2) => pcm_acr_s(2), + q(3) => iec_req_s(0), + q(4) => iec_req_s(1), + q(5) => iec_req_s(2), + q(6) => iec_req_s(3), + q(7) => iec_req_s(4) + ); + + vga_acr <= pcm_acr_s(1) and not pcm_acr_s(2); + vga_iec_en <= iec_req_s(3) and not iec_req_s(4); + iec_ack <= iec_req_s(4); + + -- SYNC2: component sync_reg + -- generic map ( + -- WIDTH => 1, + -- DEPTH => 2 + -- ) + -- port map ( + -- clk => pcm_clk, + -- d(0) => iec_req_s(2), + -- q(0) => iec_ack + -- ); + + SYNC3: component sync_reg + generic map ( + WIDTH => 57, + DEPTH => 2 + ) + port map ( + clk => vga_clk, + rst => vga_rst, + d(56) => iec_sync, + d(55) => iec_rp, + d(54) => iec_rc, + d(53) => iec_ru, + d(52) => iec_rv, + d(51 downto 28) => iec_r, + d(27) => iec_lp, + d(26) => iec_lc, + d(25) => iec_lu, + d(24) => iec_lv, + d(23 downto 0) => iec_l, + q(56) => vga_iec_sync, + q(55) => vga_iec_rp, + q(54) => vga_iec_rc, + q(53) => vga_iec_ru, + q(52) => vga_iec_rv, + q(51 downto 28) => vga_iec_r, + q(27) => vga_iec_lp, + q(26) => vga_iec_lc, + q(25) => vga_iec_lu, + q(24) => vga_iec_lv, + q(23 downto 0) => vga_iec_l + ); + + SYNC4 : component sync_reg + generic map ( + WIDTH => 54, + DEPTH => 2 + ) + port map ( + clk => vga_clk, + rst => vga_rst, + d(53 downto 34) => pcm_n, + d(33 downto 14) => pcm_cts, + d(13) => dvi, + d(12 downto 5) => vic, + d(4 downto 3) => aspect, + d(2) => pix_rep, + d(1) => vs_pol, + d(0) => hs_pol, + q(53 downto 34) => pcm_n_s, + q(33 downto 14) => pcm_cts_s, + q(13) => dvi_s, + q(12 downto 5) => vic_s, + q(4 downto 3) => aspect_s, + q(2) => pix_rep_s, + q(1) => vs_pol_s, + q(0) => hs_pol_s + ); + + -- inject preambles, guardbands and data packets + + vga_vs_p <= vga_vs xnor vs_pol_s; + vga_hs_p <= vga_hs xnor hs_pol_s; + + VGA: process (vga_rst, vga_clk) is + + variable buf_rdata : std_logic_vector(26 downto 0); + variable p : integer range 0 to PACKET_TYPES-1; + variable s1_hb_byte : integer range 0 to 3; + variable s1_hb_bit : integer range 0 to 7; + variable s1_sb_byte : integer range 0 to 7; + variable s1_sb_2bit : integer range 0 to 3; + + -- BCH ECC functions (see hdmi_bch_ecc.py) + function bch_ecc_1 ( -- 1 bit per clock + q : std_logic_vector(7 downto 0); + d : std_logic + ) return std_logic_vector is + variable r : std_logic_vector(7 downto 0); + begin + r(0) := d xor q(0) xor q(1); + r(1) := d xor q(0) xor q(2); + r(2) := q(3); + r(3) := q(4); + r(4) := q(5); + r(5) := q(6); + r(6) := q(7); + r(7) := d xor q(0); + return r; + end function bch_ecc_1; + + function bch_ecc_2 ( -- 2 bits per clock + q : std_logic_vector(7 downto 0); + d : std_logic_vector(1 downto 0) + ) return std_logic_vector is + variable r : std_logic_vector(7 downto 0); + begin + r(0) := d(1) xor q(1) xor q(2); + r(1) := d(0) xor d(1) xor q(0) xor q(1) xor q(3); + r(2) := q(4); + r(3) := q(5); + r(4) := q(6); + r(5) := q(7); + r(6) := d(0) xor q(0); + r(7) := d(0) xor d(1) xor q(0) xor q(1); + return r; + end function bch_ecc_2; + + begin + + if vga_rst = '1' then + + vga_vs_1 <= '0'; + vga_hs_1 <= '0'; + vga_de_1 <= '0'; + buf_valid <= false; + buf_addr <= 0; + buf_vs <= '0'; + buf_hs <= '0'; + buf_de <= '0'; + buf_p <= (others => (others => '0')); + blank_count <= 0; + data_req <= (others => '0'); + data_ack <= (others => '0'); + pcm_count <= 0; + hb_a <= (others => (others => '0')); + pb_a <= (others => (others => '0')); + hb <= (others => (others => (others => '0'))); + pb <= (others => (others => (others => '0'))); + s1_period <= CONTROL; + s1_pcount <= (others => '0'); + s1_dcount <= (others => '0'); + s1_hb <= (others => (others => '0')); + s1_sb <= (others => (others => (others => '0'))); + s1_vs <= '0'; + s1_hs <= '0'; + s1_de <= '0'; + s1_p <= (others => (others => '0')); + s1_enc <= ENC_DVI; + s1_ctl <= CTL_NULL; + s2_data <= '0'; + s2_pcount <= (others => '0'); + s2_bch4 <= '0'; + s2_bch_e <= (others => '0'); + s2_bch_o <= (others => '0'); + s2_vs <= '0'; + s2_hs <= '0'; + s2_de <= '0'; + s2_p <= (others => (others => '0')); + s2_enc <= ENC_DVI; + s2_ctl <= CTL_NULL; + s3_data <= '0'; + s3_pcount <= (others => '0'); + s3_bch4 <= '0'; + s3_bch_e <= (others => '0'); + s3_bch_o <= (others => '0'); + s3_bch_ecc <= (others => (others => '0')); + s3_vs <= '0'; + s3_hs <= '0'; + s3_de <= '0'; + s3_p <= (others => (others => '0')); + s3_enc <= ENC_DVI; + s3_ctl <= CTL_NULL; + s4_vs <= '0'; + s4_hs <= '0'; + s4_de <= '0'; + s4_p <= (others => (others => '0')); + s4_enc <= ENC_DVI; + s4_ctl <= CTL_NULL; + s4_d <= (others => (others => '0')); + + elsif rising_edge(vga_clk) then + + vga_vs_1 <= vga_vs_p; + vga_hs_1 <= vga_hs_p; + vga_de_1 <= vga_de; + + -- video input buffer for blank counting + + buf_rdata := buf(buf_addr); -- read before write + buf(buf_addr) <= vga_vs_p & vga_hs_p & vga_de & vga_b & vga_g & vga_r; + if buf_addr = buf_size-1 then + buf_addr <= 0; + buf_valid <= true; + else + buf_addr <= buf_addr+1; + end if; + if buf_valid = true then + buf_vs <= buf_rdata(26); + buf_hs <= buf_rdata(25); + buf_de <= buf_rdata(24); + buf_p(0) <= buf_rdata(23 downto 16); + buf_p(1) <= buf_rdata(15 downto 8); + buf_p(2) <= buf_rdata(7 downto 0); + else + buf_vs <= '0'; + buf_hs <= '0'; + buf_de <= '0'; + buf_p <= (others => (others => '0')); + end if; + if buf_valid = true then + if vga_de_1 = '0' and buf_de = '1' then + blank_count <= blank_count+1; + elsif vga_de_1 = '1' and buf_de = '0' then + blank_count <= blank_count-1; + end if; + else + if vga_de_1 = '0' then + blank_count <= blank_count+1; + end if; + end if; + + -- packet handshaking and contents + + hb_a(0 to 1) <= hb_0(0 to 1); + hb_a(2)(3 downto 0) <= hb_0(2)(3 downto 0); + if vga_iec_en = '1' then + hb_a(2)(pcm_count+4) <= vga_iec_sync; + pb_a((pcm_count*7)+0) <= unsigned(vga_iec_l(7 downto 0)); + pb_a((pcm_count*7)+1) <= unsigned(vga_iec_l(15 downto 8)); + pb_a((pcm_count*7)+2) <= unsigned(vga_iec_l(23 downto 16)); + pb_a((pcm_count*7)+3) <= unsigned(vga_iec_r(7 downto 0)); + pb_a((pcm_count*7)+4) <= unsigned(vga_iec_r(15 downto 8)); + pb_a((pcm_count*7)+5) <= unsigned(vga_iec_r(23 downto 16)); + pb_a((pcm_count*7)+6) <= + vga_iec_rp & vga_iec_rc & vga_iec_ru & vga_iec_rv & + vga_iec_lp & vga_iec_lc & vga_iec_lu & vga_iec_lv; + pcm_count <= (pcm_count + 1) mod 4; + if pcm_count = 0 then + data_req(0) <= '1'; + hb(0) <= hb_a; + pb(0) <= pb_a; + end if; + end if; + + if vga_acr = '1' then + data_req(1) <= '1'; + end if; + hb(1) <= hb_1; + pb(1) <= (others => x"00"); + for i in 0 to 3 loop + pb(1)((i*7)+1) <= x"0" & unsigned(pcm_cts_s(19 downto 16)); + pb(1)((i*7)+2) <= unsigned(pcm_cts_s(15 downto 8)); + pb(1)((i*7)+3) <= unsigned(pcm_cts_s(7 downto 0)); + pb(1)((i*7)+4) <= x"0" & unsigned(pcm_n_s(19 downto 16)); + pb(1)((i*7)+5) <= unsigned(pcm_n_s(15 downto 8)); + pb(1)((i*7)+6) <= unsigned(pcm_n_s(7 downto 0)); + end loop; + + if vga_vs_p = '1' and vga_vs_1 = '0' then -- once per field + data_req(2) <= '1'; + end if; + hb(2) <= hb_2; + pb(2) <= pb_2; + + if vga_vs_p = '1' and vga_vs_1 = '0' and vga_hs_p /= vga_hs_1 then -- once per frame + data_req(3) <= '1'; + end if; + hb(3) <= hb_3; + pb(3)(0 to 5) <= pb_3(0 to 5); + pb(3)(0) <= -- checksum + 1 + not ( + sum_3 + + pb(3)(2) + + pb(3)(4) + + pb(3)(5)(3 downto 0) + ); + pb(3)(2)(5 downto 4) <= unsigned(aspect_s); + -- pb(3)(2)(3) <= '1'; + -- pb(3)(2)(1 downto 0) <= unsigned(aspect_s); + pb(3)(4) <= unsigned(vic_s); + pb(3)(5)(0) <= pix_rep_s; + pb(3)(6 to 27) <= pb_3(6 to 27); + + for i in 0 to PACKET_TYPES-1 loop + if data_ack(i) = '1' then + data_req(i) <= '0'; + end if; + if data_req(i) = '0' then + data_ack(i) <= '0'; + end if; + end loop; + + -- HDMI encoding pipeline stage 1 + -- NOTE: we do not currently meet the requirement for + -- extended control periods by design... + + if s1_pcount /= "11111" then + s1_pcount <= s1_pcount+1; + end if; + + case s1_period is + + when CONTROL => + if buf_de = '0' then + if vga_de = '1' and blank_count = 10 then -- counting down to video + s1_period <= VIDEO_PRE; s1_enc <= ENC_DVI; s1_ctl <= CTL_PRE_VIDEO; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + elsif unsigned(s1_pcount) >= 11 and blank_count >= 66 then + -- we have satisfied 12 clock minimum for a control period; + -- to safely insert a data packet we need time for the following: + -- clocks period + -- 8 data preamble + -- 2 data guardband + -- 32 single data packet + -- 2 data guardband + -- 12 minimum control period + -- 8 video preamble (can be included in above?!) + -- 2 video guardband + -- total: 66 + if data_req /= "0000" then + s1_period <= DATA_PRE; s1_enc <= ENC_DVI; s1_ctl <= CTL_PRE_DATA; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + for i in 0 to PACKET_TYPES-1 loop -- prioritize + p := i; + exit when data_req(p) = '1'; + end loop; + data_ack(p) <= '1'; + s1_hb <= hb(p); + s1_sb(0) <= pb(p)(0 to 6); + s1_sb(1) <= pb(p)(7 to 13); + s1_sb(2) <= pb(p)(14 to 20); + s1_sb(3) <= pb(p)(21 to 27); + end if; + end if; + end if; + + when VIDEO_PRE => + if s1_pcount(2 downto 0) = "111" then + s1_period <= VIDEO_GB; s1_enc <= ENC_GB_VIDEO; s1_ctl <= CTL_NULL; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + end if; + + when VIDEO_GB => + if s1_pcount(0) = '1' then + s1_period <= VIDEO; s1_enc <= ENC_DVI; s1_ctl <= CTL_NULL; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + end if; + + when VIDEO => + if buf_de = '0' then + s1_period <= CONTROL; s1_enc <= ENC_DVI; s1_ctl <= CTL_NULL; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + end if; + + when DATA_PRE => + if s1_pcount(2 downto 0) = "111" then + s1_period <= DATA_GB_LEADING; s1_enc <= ENC_GB_DATA; s1_ctl <= CTL_NULL; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + end if; + + when DATA_GB_LEADING => + if s1_pcount(0) = '1' then + s1_period <= DATA_ISLAND; s1_enc <= ENC_DATA; s1_ctl <= CTL_NULL; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + end if; + + when DATA_ISLAND => + if (s1_pcount = "11111") then -- last clock of this packet + if (blank_count >= 56) -- there is enough blanking time for another packet + and (s1_dcount < 17) -- we haven't exceeded the limit of 18 consecutive packets + and (data_req /= "0000") -- another packet is requested + then -- do another data packet + s1_pcount <= (others => '0'); + s1_dcount <= s1_dcount+1; + for i in 0 to PACKET_TYPES-1 loop -- prioritize + p := i; + exit when data_req(p) = '1'; + end loop; + data_ack(p) <= '1'; + s1_hb <= hb(p); + s1_sb(0) <= pb(p)(0 to 6); + s1_sb(1) <= pb(p)(7 to 13); + s1_sb(2) <= pb(p)(14 to 20); + s1_sb(3) <= pb(p)(21 to 27); + else -- wrap up + s1_period <= DATA_GB_TRAILING; s1_enc <= ENC_GB_DATA; s1_ctl <= CTL_NULL; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + end if; + end if; + + when DATA_GB_TRAILING => + if s1_pcount(0) = '1' then + s1_period <= CONTROL; s1_enc <= ENC_DVI; s1_ctl <= CTL_NULL; + s1_pcount <= (others => '0'); s1_dcount <= (others => '0'); + end if; + + end case; + + s1_hb_byte := to_integer(unsigned(s1_pcount(4 downto 3))); + s1_hb_bit := to_integer(unsigned(s1_pcount(2 downto 0))); + s1_sb_byte := to_integer(unsigned(s1_pcount(4 downto 2))); + s1_sb_2bit := to_integer(unsigned(s1_pcount(1 downto 0))); + + s1_vs <= buf_vs; + s1_hs <= buf_hs; + s1_de <= buf_de; + s1_p <= buf_p; + + -- HDMI encoding pipeline stage 2 + + s2_data <= '0'; + if s1_period = DATA_ISLAND then + s2_data <= '1'; + end if; + s2_pcount <= s1_pcount; + s2_bch4 <= '0'; + if s1_hb_byte < s1_hb'length then + s2_bch4 <= s1_hb(s1_hb_byte)(s1_hb_bit); + end if; + for i in 0 to 3 loop + s2_bch_e(i) <= '0'; + s2_bch_o(i) <= '0'; + if s1_sb_byte < s1_sb(i)'length then + s2_bch_e(i) <= s1_sb(i)(s1_sb_byte)(0+(2*s1_sb_2bit)); + s2_bch_o(i) <= s1_sb(i)(s1_sb_byte)(1+(2*s1_sb_2bit)); + end if; + end loop; + + s2_vs <= s1_vs; + s2_hs <= s1_hs; + s2_de <= s1_de; + s2_p <= s1_p; + s2_enc <= s1_enc; + s2_ctl <= s1_ctl; + + -- HDMI encoding pipeline stage 3 + + s3_data <= s2_data; + s3_pcount <= s2_pcount; + s3_bch4 <= s2_bch4; + s3_bch_e <= s2_bch_e; + s3_bch_o <= s2_bch_o; + if unsigned(s2_pcount(4 downto 0)) = 0 then + s3_bch_ecc(4) <= bch_ecc_1(x"00", s2_bch4); + elsif unsigned(s2_pcount(4 downto 0)) < 24 then + s3_bch_ecc(4) <= bch_ecc_1(s3_bch_ecc(4), s2_bch4); + end if; + for i in 0 to 3 loop + if unsigned(s2_pcount(4 downto 0)) = 0 then + s3_bch_ecc(i) <= bch_ecc_2(x"00", s2_bch_o(i) & s2_bch_e(i)); + elsif unsigned(s2_pcount(4 downto 0)) < 28 then + s3_bch_ecc(i) <= bch_ecc_2(s3_bch_ecc(i), s2_bch_o(i) & s2_bch_e(i)); + end if; + end loop; + + s3_vs <= s2_vs; + s3_hs <= s2_hs; + s3_de <= s2_de; + s3_p <= s2_p; + s3_enc <= s2_enc; + s3_ctl <= s2_ctl; + + -- HDMI encoding pipeline stage 4 + + s4_d <= (others => (others => '0')); + if s3_data = '1' then + s4_d(0)(0) <= s3_hs; + s4_d(0)(1) <= s3_vs; + if unsigned(s3_pcount(4 downto 0)) < 24 then + s4_d(0)(2) <= s3_bch4; + else + s4_d(0)(2) <= s3_bch_ecc(4)(to_integer(unsigned(s3_pcount(2 downto 0)))); + end if; + if unsigned(s3_pcount) = 0 then + s4_d(0)(3) <= '0'; + else + s4_d(0)(3) <= '1'; + end if; + if unsigned(s3_pcount(4 downto 0)) < 28 then + s4_d(1) <= s3_bch_e; + s4_d(2) <= s3_bch_o; + else + for i in 0 to 3 loop + s4_d(1)(i) <= s3_bch_ecc(i)(0+(2*to_integer(unsigned(s3_pcount(1 downto 0))))); + s4_d(2)(i) <= s3_bch_ecc(i)(1+(2*to_integer(unsigned(s3_pcount(1 downto 0))))); + end loop; + end if; + end if; + + s4_vs <= s3_vs; + s4_hs <= s3_hs; + s4_de <= s3_de; + s4_p <= s3_p; + s4_enc <= s3_enc; + s4_ctl <= s3_ctl; + + -- DVI override + + if dvi_s = '1' then + s4_enc <= ENC_DVI; + s4_ctl <= (others => '0'); + s4_d <= (others => (others => '0')); + end if; + + end if; + + end process VGA; + + -- final encoder and serialiser stage + + s4_c(0)(0) <= s4_hs; + s4_c(0)(1) <= s4_vs; + s4_c(1) <= s4_ctl(1 downto 0); + s4_c(2) <= s4_ctl(3 downto 2); + + gen_tmds: for i in 0 to 2 generate + begin + + ENCODER: entity work.hdmi_tx_encoder + generic map ( + channel => i + ) + port map ( + rst => vga_rst, + clk => vga_clk, + de => s4_de, + p => s4_p(i), + c => s4_c(i), + d => s4_d(i), + enc => s4_enc, + q => tmds(i) + ); + + end generate gen_tmds; + +end architecture synth; diff --git a/vhdl/hw/MEGA65/video_modes_pkg.vhd b/vhdl/hw/MEGA65/video_modes_pkg.vhd new file mode 100644 index 00000000..2cd46015 --- /dev/null +++ b/vhdl/hw/MEGA65/video_modes_pkg.vhd @@ -0,0 +1,236 @@ +library ieee; +use ieee.std_logic_1164.all; + +package video_modes_pkg is + + type video_modes_t is record + CLK_KHZ : integer; -- Pixel clock frequency in kHz + CLK_SEL : std_logic_vector(2 downto 0); -- Pixel clock selection + -- 000 = 25.200 MHz + -- 001 = 27.000 MHz + -- 010 = 74.250 MHz + -- 011 = 148.500 MHz + -- 100 = 25.175 MHz + -- 101 = 27.027 MHz + -- 110 = 74.176 MHz + -- 111 = undefined + CEA_CTA_VIC : integer; -- CEA/CTA VIC + ASPECT : std_logic_vector(1 downto 0); -- aspect ratio: 01=4:3, 10=16:9 + PIXEL_REP : std_logic; -- 0=no pixel repetition; 1=pixel repetition + H_PIXELS : integer; -- horizontal display width in pixels + V_PIXELS : integer; -- vertical display width in rows + H_PULSE : integer; -- horizontal sync pulse width in pixels + H_BP : integer; -- horizontal back porch width in pixels + H_FP : integer; -- horizontal front porch width in pixels + V_PULSE : integer; -- vertical sync pulse width in rows + V_BP : integer; -- vertical back porch width in rows + V_FP : integer; -- vertical front porch width in rows + H_POL : std_logic; -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL : std_logic; -- vertical sync pulse polarity (1 = positive, 0 = negative) + end record video_modes_t; + + -- In the following, the supported video modes + -- are sorted according to the CEA-861-D document + + -------------------------------------------------------- + -- 50 Hz modes + -------------------------------------------------------- + + -- PAL 720x576 @ 50 Hz + -- Taken from section 4.9 in the document CEA-861-D + constant C_PAL_720_576_50 : video_modes_t := ( + CLK_KHZ => 27000, -- 27.000 MHz + CLK_SEL => "001", + CEA_CTA_VIC => 17, -- CEA/CTA VIC 17=PAL 720x576 @ 50 Hz + ASPECT => "01", -- aspect ratio: 01=4:3, 10=16:9: "01" for PAL + PIXEL_REP => '0', -- no pixel repetition + H_PIXELS => 720, -- horizontal display width in pixels + V_PIXELS => 576, -- vertical display width in rows + H_PULSE => 64, -- horizontal sync pulse width in pixels + H_BP => 63, -- horizontal back porch width in pixels + H_FP => 17, -- horizontal front porch width in pixels + V_PULSE => 5, -- vertical sync pulse width in rows + V_BP => 39, -- vertical back porch width in rows + V_FP => 5, -- vertical front porch width in rows + H_POL => '0', -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL => '0' -- vertical sync pulse polarity (1 = positive, 0 = negative) + ); + + -- HDMI 576p @ 50 Hz (720x576) + -- Taken from section 4.9 in the document CEA-861-D + constant C_HDMI_576p_50 : video_modes_t := ( + CLK_KHZ => 27000, -- 27.000 MHz + CLK_SEL => "001", + CEA_CTA_VIC => 17, -- CEA/CTA VIC: 720x576p, 50 Hz, 4:3 + ASPECT => "01", -- apsect ratio: 01=4:3, 10=16:9 + PIXEL_REP => '0', -- no pixel repetition + H_PIXELS => 720, -- horizontal display width in pixels + V_PIXELS => 576, -- vertical display width in rows + H_FP => 12, -- horizontal front porch width in pixels + H_PULSE => 64, -- horizontal sync pulse width in pixels + H_BP => 68, -- horizontal back porch width in pixels + V_FP => 5, -- vertical front porch width in rows + V_PULSE => 5, -- vertical sync pulse width in rows + V_BP => 39, -- vertical back porch width in rows + H_POL => '1', -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL => '1' -- vertical sync pulse polarity (1 = positive, 0 = negative) + ); + + -- HDMI 720p @ 50 Hz (1280x720) + -- Taken from section 4.7 in the document CEA-861-D + constant C_HDMI_720p_50 : video_modes_t := ( + CLK_KHZ => 74250, -- 74.250 MHz + CLK_SEL => "010", + CEA_CTA_VIC => 19, -- CEA/CTA VIC: 1280x720p, 50 Hz, 16:9 + ASPECT => "10", -- apsect ratio: 01=4:3, 10=16:9 + PIXEL_REP => '0', -- no pixel repetition + H_PIXELS => 1280, -- horizontal display width in pixels + V_PIXELS => 720, -- vertical display width in rows + H_FP => 440, -- horizontal front porch width in pixels + H_PULSE => 40, -- horizontal sync pulse width in pixels + H_BP => 220, -- horizontal back porch width in pixels + V_FP => 5, -- vertical front porch width in rows + V_PULSE => 5, -- vertical sync pulse width in rows + V_BP => 20, -- vertical back porch width in rows + H_POL => '1', -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL => '1' -- vertical sync pulse polarity (1 = positive, 0 = negative) + ); + + + -------------------------------------------------------- + -- 59.94 Hz modes + -------------------------------------------------------- + + -- HDMI 480p @ 59.94 Hz (720x480) + constant C_HDMI_720x480p_5994 : video_modes_t := ( + CLK_KHZ => 27000, -- 27.000 MHz + CLK_SEL => "001", + CEA_CTA_VIC => 2, + ASPECT => "01", -- apsect ratio: 01=4:3, 10=16:9 + PIXEL_REP => '0', -- no pixel repetition + H_PIXELS => 720, -- horizontal display width in pixels + V_PIXELS => 480, -- vertical display width in rows + H_FP => 16, -- horizontal front porch width in pixels + H_PULSE => 62, -- horizontal sync pulse width in pixels + H_BP => 60, -- horizontal back porch width in pixels + V_FP => 9, -- vertical front porch width in rows + V_PULSE => 6, -- vertical sync pulse width in rows + V_BP => 30, -- vertical back porch width in rows + H_POL => '0', -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL => '0' -- vertical sync pulse polarity (1 = positive, 0 = negative) + ); + + + -------------------------------------------------------- + -- 60.00 Hz modes + -------------------------------------------------------- + + -- HDMI 480p @ 60 Hz (640x480) + constant C_HDMI_640x480p_60 : video_modes_t := ( + CLK_KHZ => 25200, -- 25.200 MHz + CLK_SEL => "000", + CEA_CTA_VIC => 1, + ASPECT => "01", -- apsect ratio: 01=4:3, 10=16:9 + PIXEL_REP => '0', -- no pixel repetition + H_PIXELS => 640, -- horizontal display width in pixels + V_PIXELS => 480, -- vertical display width in rows + H_FP => 16, -- horizontal front porch width in pixels + H_PULSE => 96, -- horizontal sync pulse width in pixels + H_BP => 48, -- horizontal back porch width in pixels + V_FP => 10, -- vertical front porch width in rows + V_PULSE => 2, -- vertical sync pulse width in rows + V_BP => 33, -- vertical back porch width in rows + H_POL => '0', -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL => '0' -- vertical sync pulse polarity (1 = positive, 0 = negative) + ); + + -- HDMI 720p @ 60 Hz (1280x720) + -- Taken from section 4.3 in the document CEA-861-D + constant C_HDMI_720p_60 : video_modes_t := ( + CLK_KHZ => 74250, -- 74.250 MHz + CLK_SEL => "010", + CEA_CTA_VIC => 4, -- CEA/CTA VIC: 1280x720p, 60 Hz, 16:9 + ASPECT => "10", -- apsect ratio: 01=4:3, 10=16:9 + PIXEL_REP => '0', -- no pixel repetition + H_PIXELS => 1280, -- horizontal display width in pixels + V_PIXELS => 720, -- vertical display width in rows + H_FP => 110, -- horizontal front porch width in pixels + H_PULSE => 40, -- horizontal sync pulse width in pixels + H_BP => 220, -- horizontal back porch width in pixels + V_FP => 5, -- vertical front porch width in rows + V_PULSE => 5, -- vertical sync pulse width in rows + V_BP => 20, -- vertical back porch width in rows + H_POL => '0', -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL => '0' -- vertical sync pulse polarity (1 = positive, 0 = negative) + ); + + -- SVGA 800x600 @ 60 Hz + -- Taken from this link: http://tinyvga.com/vga-timing/800x600@60Hz + -- CAUTION: CTA/CTV VIC does not officially support SVGA 800x600; there are some monitors, where it works, though + constant C_SVGA_800_600_60 : video_modes_t := ( + CLK_KHZ => 40000, -- 40.000 MHz + CLK_SEL => "111", + CEA_CTA_VIC => 65, -- SVGA is not an official mode; "65" taken from here: https://www.raspberrypi.org/documentation/configuration/config-txt/video.md + ASPECT => "01", -- aspect ratio: 01=4:3, 10=16:9: "01" for SVGA + PIXEL_REP => '0', -- no pixel repetition + H_PIXELS => 800, -- horizontal display width in pixels + V_PIXELS => 600, -- vertical display width in rows + H_PULSE => 128, -- horizontal sync pulse width in pixels + H_BP => 88, -- horizontal back porch width in pixels + H_FP => 40, -- horizontal front porch width in pixels + V_PULSE => 4, -- vertical sync pulse width in rows + V_BP => 23, -- vertical back porch width in rows + V_FP => 1, -- vertical front porch width in rows + H_POL => '1', -- horizontal sync pulse polarity (1 = positive, 0 = negative) + V_POL => '1' -- vertical sync pulse polarity (1 = positive, 0 = negative) + ); + + type video_modes_vector is array(natural range<>) of video_modes_t; + + type video_mode_type is ( + C_VIDEO_HDMI_16_9_50 , -- HDMI 1280x720 @ 50 Hz + C_VIDEO_HDMI_16_9_60 , -- HDMI 1280x720 @ 60 Hz + C_VIDEO_HDMI_4_3_50 , -- PAL 576p in 4:3 @ 50 Hz + C_VIDEO_HDMI_5_4_50 , -- PAL 576p in 5:4 @ 50 Hz + C_VIDEO_HDMI_640_60 , -- HDMI 640x480 @ 60 Hz + C_VIDEO_HDMI_720_5994 , -- HDMI 720x480 @ 59.94 Hz + C_VIDEO_SVGA_800_60 -- SVGA 800x600 @ 60 Hz + ); + + pure function video_mode_to_slv(video_mode : video_mode_type) return std_logic_vector; + + pure function slv_to_video_mode(video_mode_slv : std_logic_vector) return video_mode_type; + +end package video_modes_pkg; + +package body video_modes_pkg is + + pure function video_mode_to_slv(video_mode : video_mode_type) return std_logic_vector is + begin + case video_mode is + when C_VIDEO_HDMI_16_9_50 => return "0000"; + when C_VIDEO_HDMI_16_9_60 => return "0001"; + when C_VIDEO_HDMI_4_3_50 => return "0010"; + when C_VIDEO_HDMI_5_4_50 => return "0011"; + when C_VIDEO_HDMI_640_60 => return "0100"; + when C_VIDEO_HDMI_720_5994 => return "0101"; + when C_VIDEO_SVGA_800_60 => return "0110"; + end case; + end function video_mode_to_slv; + + pure function slv_to_video_mode(video_mode_slv : std_logic_vector) return video_mode_type is + begin + case video_mode_slv is + when "0000" => return C_VIDEO_HDMI_16_9_50; + when "0001" => return C_VIDEO_HDMI_16_9_60; + when "0010" => return C_VIDEO_HDMI_4_3_50; + when "0011" => return C_VIDEO_HDMI_5_4_50; + when "0100" => return C_VIDEO_HDMI_640_60; + when "0101" => return C_VIDEO_HDMI_720_5994; + when "0110" => return C_VIDEO_SVGA_800_60; + when others => return C_VIDEO_HDMI_16_9_50; + end case; + end function slv_to_video_mode; + +end package body video_modes_pkg; + diff --git a/vhdl/hw/MEGA65/video_out_clock.vhd b/vhdl/hw/MEGA65/video_out_clock.vhd new file mode 100644 index 00000000..1a949e0e --- /dev/null +++ b/vhdl/hw/MEGA65/video_out_clock.vhd @@ -0,0 +1,609 @@ +-------------------------------------------------------------------------------- +-- video_out_clock.vhd -- +-- Pixel and serialiser clock synthesiser (dynamically configured MMCM). -- +-------------------------------------------------------------------------------- +-- (C) Copyright 2022 Adam Barnes -- +-- This file is part of The Tyto Project. The Tyto Project is free software: -- +-- you can redistribute it and/or modify it under the terms of the GNU Lesser -- +-- General Public License as published by the Free Software Foundation, -- +-- either version 3 of the License, or (at your option) any later version. -- +-- The Tyto Project is distributed in the hope that it will be useful, but -- +-- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- +-- License for more details. You should have received a copy of the GNU -- +-- Lesser General Public License along with The Tyto Project. If not, see -- +-- https://www.gnu.org/licenses/. -- +-------------------------------------------------------------------------------- + +-- Modified by MFJ in October 2023 +-- When programming the MMCM, the "locked" signal is de-asserted and the clock output is +-- invalid and contains glitches. Usually, the system is held in reset until "locked" +-- is asserted again. Instead, we here switch over to a "backup" clock of 50 MHz +-- until the MMCM is ready. This switch-over is done using a glitch-free clock +-- multiplexer, but since the latter is stateful, the switch-over has to be timed +-- carefully, so that the active clock is always valid. + +-- To generate the entries in these tables: +-- 1. Download the MMCM and PLL Dynamic Reconfiguration Application Note (XAPP888) +-- reference files. +-- 2. Use the Vivado Clock Wizard to generate the values of CLKFBOUT_MULT_F, +-- DIVCLK_DIVIDE, CLKOUT0_DIVIDE_F, and CLKOUT1_DIVIDE. Note them down on a piece of paper. +-- 3. Start Vivado, and run the xapp888 setup file: MMCME2_DRP/top_mmcme2.tcl +-- 4. Use the spreadsheet https://github.com/amb5l/tyto2/blob/main/src/common/video/xilinx_7series/video_out_clock.xls +-- type in the Clock Wizard values, and generate the tcl command. +-- 5. In Vivado, run the tcl command. This outputs the values for the table below. + +library ieee; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +library unisim; + use unisim.vcomponents.all; + +entity video_out_clock is + generic ( + fref : real -- reference clock frequency (MHz) (typically 100.0) + ); + port ( + + rsti : in std_logic; -- input (reference) clock synchronous reset + clki : in std_logic; -- input (reference) clock + sel : in std_logic_vector(2 downto 0); -- output clock select: + -- 000 = 25.200 MHz. E.g. 640x480 @ 60.00 Hz + -- 001 = 27.000 MHz. E.g. 720x480 @ 59.94 Hz + -- 010 = 74.250 MHz. E.g. 1280x720 @ 60.00 Hz + -- 011 = 148.500 MHz. + -- 100 = 25.175 MHz. E.g. 640x480 @ 59.94 Hz + -- 101 = 27.027 MHz. E.g. 720x480 @ 60.00 Hz + -- 110 = 74.176 MHz. E.g. 1280x720 @ 59.94 Hz + -- 111 = undefined + rsto : out std_logic; -- output clock synchronous reset + clko : out std_logic; -- pixel clock + clko_x5 : out std_logic -- serialiser clock (5x pixel clock) + + ); +end entity video_out_clock; + +architecture synth of video_out_clock is + + signal sel_s : std_logic_vector(2 downto 0); -- sel, synchronised to clki + + signal rsto_req : std_logic; -- rsto request, synchronous to clki + + signal mmcm_rst : std_logic; -- MMCM reset + signal locked : std_logic; -- MMCM locked output + signal locked_s : std_logic; -- above, synchronised to clki + + signal sel_prev : std_logic_vector(3 downto 0); -- to detect changes + signal clk_fb : std_logic; -- feedback clock + signal clku_fb : std_logic; -- unbuffered feedback clock + signal clko_u : std_logic; -- unbuffered pixel clock + signal clko_b : std_logic; -- buffered pixel clock + signal clko_u_x5 : std_logic; -- unbuffered serializer clock + + signal clki_div : std_logic; -- Input clock divided by 2 + + signal cfg_tbl_addr : std_logic_vector(7 downto 0); -- 8 x 32 entries + signal cfg_tbl_data : std_logic_vector(39 downto 0); -- 8 bit address + 16 bit write data + 16 bit read mask + + signal cfg_cnt : std_logic_vector(1 downto 0); -- Delay reset + signal cfg_rst : std_logic; -- DRP reset + signal cfg_daddr : std_logic_vector(6 downto 0); -- DRP register address + signal cfg_den : std_logic; -- DRP enable (pulse) + signal cfg_dwe : std_logic; -- DRP write enable + signal cfg_di : std_logic_vector(15 downto 0); -- DRP write data + signal cfg_do : std_logic_vector(15 downto 0); -- DRP read data + signal cfg_drdy : std_logic; -- DRP access complete + + type cfg_state_t is ( -- state machine states + idle, -- waiting for fsel change + reset_wait, -- put MMCM into reset + reset, -- put MMCM into reset + tbl, -- get first/next table value + rd, -- start read + rd_wait, -- wait for read to complete + wr, -- start write + wr_wait, -- wait for write to complete + lock_wait -- wait for reconfig to complete + ); + signal cfg_state : cfg_state_t; + signal clk_mux : std_logic; + + +begin + + MAIN: process (clki) is + + -- Contents of synchronous ROM table. + -- See MMCM and PLL Dynamic Reconfiguration Application Note (XAPP888) + -- for details of register map. + function cfg_tbl (addr : std_logic_vector) return std_logic_vector is + -- bits 39..32 = cfg_daddr (MSB = 1 for last entry) + -- bits 31..16 = cfg write data + -- bits 15..0 = cfg read mask + variable data : std_logic_vector(39 downto 0); + begin + data := x"0000000000"; + -- values below pasted in from video_out_clk.xls + if fref = 100.0 then + case addr is + -- Desired frequency = 25.200 MHz + -- CLKFBOUT_MULT_F = 31.500 + -- DIVCLK_DIVIDE = 5 + -- CLKOUT0_DIVIDE_F = 5.000 + -- CLKOUT1_DIVIDE = 25 + -- Actual frequency = 25.200 MHz + when x"00" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"01" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"02" => data := x"08" & x"1083" & x"1000"; -- CLKOUT0 Register 1 + when x"03" => data := x"09" & x"0080" & x"8000"; -- CLKOUT0 Register 2 + when x"04" => data := x"0A" & x"130d" & x"1000"; -- CLKOUT1 Register 1 + when x"05" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 + when x"06" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"07" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"08" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"09" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"0A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"0B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"0C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"0D" => data := x"13" & x"3000" & x"8000"; -- CLKOUT6 Register 2 + when x"0E" => data := x"14" & x"13CF" & x"1000"; -- CLKFBOUT Register 1 + when x"0F" => data := x"15" & x"4800" & x"8000"; -- CLKFBOUT Register 2 + when x"10" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register + when x"11" => data := x"18" & x"002C" & x"FC00"; -- Lock Register 1 + when x"12" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 + when x"13" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 + when x"14" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"15" => data := x"4E" & x"0900" & x"66FF"; -- Filter Register 1 + when x"16" => data := x"CF" & x"1000" & x"666F"; -- Filter Register 2 + + -- Desired frequency = 27.000 MHz + -- CLKFBOUT_MULT_F = 47.250 + -- DIVCLK_DIVIDE = 5 + -- CLKOUT0_DIVIDE_F = 7.000 + -- CLKOUT1_DIVIDE = 35 + -- Actual frequency = 74.250 MHz + when x"20" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"21" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"22" => data := x"08" & x"10C4" & x"1000"; -- CLKOUT0 Register 1 + when x"23" => data := x"09" & x"0080" & x"8000"; -- CLKOUT0 Register 2 + when x"24" => data := x"0A" & x"1452" & x"1000"; -- CLKOUT1 Register 1 + when x"25" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 + when x"26" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"27" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"28" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"29" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"2A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"2B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"2C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"2D" => data := x"13" & x"2800" & x"8000"; -- CLKOUT6 Register 2 + when x"2E" => data := x"14" & x"15D7" & x"1000"; -- CLKFBOUT Register 1 + when x"2F" => data := x"15" & x"2800" & x"8000"; -- CLKFBOUT Register 2 + when x"30" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register + when x"31" => data := x"18" & x"00FA" & x"FC00"; -- Lock Register 1 + when x"32" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 + when x"33" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 + when x"34" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"35" => data := x"4E" & x"1900" & x"66FF"; -- Filter Register 1 + when x"36" => data := x"CF" & x"0100" & x"666F"; -- Filter Register 2 + + -- Desired frequency = 74.250 MHz + -- CLKFBOUT_MULT_F = 37.125 + -- DIVCLK_DIVIDE = 5 + -- CLKOUT0_DIVIDE_F = 2.000 + -- CLKOUT1_DIVIDE = 10 + -- Actual frequency = 74.250 MHz + when x"40" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"41" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"42" => data := x"08" & x"1041" & x"1000"; -- CLKOUT0 Register 1 + when x"43" => data := x"09" & x"0000" & x"8000"; -- CLKOUT0 Register 2 + when x"44" => data := x"0A" & x"1145" & x"1000"; -- CLKOUT1 Register 1 + when x"45" => data := x"0B" & x"0000" & x"8000"; -- CLKOUT1 Register 2 + when x"46" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"47" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"48" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"49" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"4A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"4B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"4C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"4D" => data := x"13" & x"2400" & x"8000"; -- CLKOUT6 Register 2 + when x"4E" => data := x"14" & x"1491" & x"1000"; -- CLKFBOUT Register 1 + when x"4F" => data := x"15" & x"1800" & x"8000"; -- CLKFBOUT Register 2 + when x"50" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register + when x"51" => data := x"18" & x"00FA" & x"FC00"; -- Lock Register 1 + when x"52" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 + when x"53" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 + when x"54" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"55" => data := x"4E" & x"0900" & x"66FF"; -- Filter Register 1 + when x"56" => data := x"CF" & x"1000" & x"666F"; -- Filter Register 2 + + -- Desired frequency = 148.500 MHz + -- CLKFBOUT_MULT_F = 37.125 + -- DIVCLK_DIVIDE = 5 + -- CLKOUT0_DIVIDE_F = 1.000 + -- CLKOUT1_DIVIDE = 5 + -- Actual frequency = 148.500 MHz + when x"60" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"61" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"62" => data := x"08" & x"1041" & x"1000"; -- CLKOUT0 Register 1 + when x"63" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 + when x"64" => data := x"0A" & x"1083" & x"1000"; -- CLKOUT1 Register 1 + when x"65" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 + when x"66" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"67" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"68" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"69" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"6A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"6B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"6C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"6D" => data := x"13" & x"2400" & x"8000"; -- CLKOUT6 Register 2 + when x"6E" => data := x"14" & x"1491" & x"1000"; -- CLKFBOUT Register 1 + when x"6F" => data := x"15" & x"1800" & x"8000"; -- CLKFBOUT Register 2 + when x"70" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register + when x"71" => data := x"18" & x"00FA" & x"FC00"; -- Lock Register 1 + when x"72" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 + when x"73" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 + when x"74" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"75" => data := x"4E" & x"0900" & x"66FF"; -- Filter Register 1 + when x"76" => data := x"CF" & x"1000" & x"666F"; -- Filter Register 2 + + -- Desired frequency = 25.175 MHz + -- CLKFBOUT_MULT_F = 17.625 + -- DIVCLK_DIVIDE = 2 + -- CLKOUT0_DIVIDE_F = 7.000 + -- CLKOUT1_DIVIDE = 35 + -- Actual frequency = 25.179 MHz + when x"80" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"81" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"82" => data := x"08" & x"10C4" & x"1000"; -- CLKOUT0 Register 1 + when x"83" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 + when x"84" => data := x"0A" & x"1452" & x"1000"; -- CLKOUT1 Register 1 + when x"85" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 + when x"86" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"87" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"88" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"89" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"8A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"8B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"8C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"8D" => data := x"13" & x"3000" & x"8000"; -- CLKOUT6 Register 2 + when x"8E" => data := x"14" & x"1208" & x"1000"; -- CLKFBOUT Register 1 + when x"8F" => data := x"15" & x"5800" & x"8000"; -- CLKFBOUT Register 2 + when x"90" => data := x"16" & x"0041" & x"C000"; -- DIVCLK Register + when x"91" => data := x"18" & x"013F" & x"FC00"; -- Lock Register 1 + when x"92" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 + when x"93" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 + when x"94" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"95" => data := x"4E" & x"9900" & x"66FF"; -- Filter Register 1 + when x"96" => data := x"CF" & x"1100" & x"666F"; -- Filter Register 2 + + -- Desired frequency = 27.027 MHz + -- CLKFBOUT_MULT_F = 21.625 + -- DIVCLK_DIVIDE = 2 + -- CLKOUT0_DIVIDE_F = 8.000 + -- CLKOUT1_DIVIDE = 40 + -- Actual frequency = 27.031 MHz + when x"A0" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"A1" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"A2" => data := x"08" & x"1104" & x"1000"; -- CLKOUT0 Register 1 + when x"A3" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 + when x"A4" => data := x"0A" & x"1514" & x"1000"; -- CLKOUT1 Register 1 + when x"A5" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 + when x"A6" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"A7" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"A8" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"A9" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"AA" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"AB" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"AC" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"AD" => data := x"13" & x"3000" & x"8000"; -- CLKOUT6 Register 2 + when x"AE" => data := x"14" & x"128A" & x"1000"; -- CLKFBOUT Register 1 + when x"AF" => data := x"15" & x"5800" & x"8000"; -- CLKFBOUT Register 2 + when x"B0" => data := x"16" & x"0041" & x"C000"; -- DIVCLK Register + when x"B1" => data := x"18" & x"00DB" & x"FC00"; -- Lock Register 1 + when x"B2" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 + when x"B3" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 + when x"B4" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"B5" => data := x"4E" & x"9000" & x"66FF"; -- Filter Register 1 + when x"B6" => data := x"CF" & x"0100" & x"666F"; -- Filter Register 2 + + -- Desired frequency = 74.176 MHz + -- CLKFBOUT_MULT_F = 22.250 + -- DIVCLK_DIVIDE = 3 + -- CLKOUT0_DIVIDE_F = 2.000 + -- CLKOUT1_DIVIDE = 10 + -- Actual frequency = 74.167 MHz + when x"C0" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"C1" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"C2" => data := x"08" & x"1041" & x"1000"; -- CLKOUT0 Register 1 + when x"C3" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 + when x"C4" => data := x"0A" & x"1145" & x"1000"; -- CLKOUT1 Register 1 + when x"C5" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 + when x"C6" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"C7" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"C8" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"C9" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"CA" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"CB" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"CC" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"CD" => data := x"13" & x"0C00" & x"8000"; -- CLKOUT6 Register 2 + when x"CE" => data := x"14" & x"128A" & x"1000"; -- CLKFBOUT Register 1 + when x"CF" => data := x"15" & x"2C00" & x"8000"; -- CLKFBOUT Register 2 + when x"D0" => data := x"16" & x"0042" & x"C000"; -- DIVCLK Register + when x"D1" => data := x"18" & x"00C2" & x"FC00"; -- Lock Register 1 + when x"D2" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 + when x"D3" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 + when x"D4" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"D5" => data := x"4E" & x"1100" & x"66FF"; -- Filter Register 1 + when x"D6" => data := x"CF" & x"9000" & x"666F"; -- Filter Register 2 + + -- Desired frequency = 40.000 MHz + -- CLKFBOUT_MULT_F = 10 + -- DIVCLK_DIVIDE = 1 + -- CLKOUT0_DIVIDE_F = 5.000 + -- CLKOUT1_DIVIDE = 25 + -- Actual frequency = 40.000 MHz + when x"E0" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 + when x"E1" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 + when x"E2" => data := x"08" & x"1083" & x"1000"; -- CLKOUT0 Register 1 + when x"E3" => data := x"09" & x"0080" & x"8000"; -- CLKOUT0 Register 2 + when x"E4" => data := x"0A" & x"130D" & x"1000"; -- CLKOUT1 Register 1 + when x"E5" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 + when x"E6" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 + when x"E7" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 + when x"E8" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 + when x"E9" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 + when x"EA" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 + when x"EB" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 + when x"EC" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 + when x"ED" => data := x"13" & x"0000" & x"8000"; -- CLKOUT6 Register 2 + when x"EE" => data := x"14" & x"1145" & x"1000"; -- CLKFBOUT Register 1 + when x"EF" => data := x"15" & x"0000" & x"8000"; -- CLKFBOUT Register 2 + when x"F0" => data := x"16" & x"1041" & x"C000"; -- DIVCLK Register + when x"F1" => data := x"18" & x"01E8" & x"FC00"; -- Lock Register 1 + when x"F2" => data := x"19" & x"7001" & x"8000"; -- Lock Register 2 + when x"F3" => data := x"1A" & x"71E9" & x"8000"; -- Lock Register 3 + when x"F4" => data := x"28" & x"FFFF" & x"0000"; -- Power Register + when x"F5" => data := x"4E" & x"9900" & x"66FF"; -- Filter Register 1 + when x"F6" => data := x"CF" & x"1100" & x"666F"; -- Filter Register 2 + + when others => data := (others => '0'); + end case; + end if; + return data; + end function cfg_tbl; + + begin + if rising_edge(clki) then + + cfg_tbl_data <= cfg_tbl(cfg_tbl_addr); -- synchronous ROM + + -- defaults + cfg_den <= '0'; + cfg_dwe <= '0'; + + -- state machine + case cfg_state is + when IDLE => + if '0' & sel /= sel_prev -- frequency selection has changed (or initial startup) + or locked_s = '0' -- lock lost + then + clk_mux <= '0'; -- Switch to alternate clock + cfg_cnt <= "11"; + cfg_state <= RESET_WAIT; + end if; + when RESET_WAIT => -- Wait for clock switching to take effect + if cfg_cnt /= "00" then + cfg_cnt <= std_logic_vector(unsigned(cfg_cnt) - 1); + else + rsto_req <= '1'; + cfg_rst <= '1'; + cfg_state <= RESET; + end if; + when RESET => -- put MMCM into reset + sel_prev <= '0' & sel; + cfg_tbl_addr <= sel & "00000"; + cfg_state <= TBL; + when TBL => -- get table entry from sychronous ROM + cfg_state <= RD; + when RD => -- read specified register + cfg_daddr <= cfg_tbl_data(38 downto 32); + cfg_den <= '1'; + cfg_state <= RD_WAIT; + when RD_WAIT => -- wait for read to complete + if cfg_drdy = '1' then + cfg_di <= (cfg_do and cfg_tbl_data(15 downto 0)) or (cfg_tbl_data(31 downto 16) and not cfg_tbl_data(15 downto 0)); + cfg_den <= '1'; + cfg_dwe <= '1'; + cfg_state <= WR; + end if; + when WR => -- write modified contents back to same register + cfg_state <= WR_WAIT; + when WR_WAIT => -- wait for write to complete + if cfg_drdy = '1' then + if cfg_tbl_data(39) = '1' then -- last entry in table + cfg_tbl_addr <= (others => '0'); + cfg_state <= LOCK_WAIT; + else -- do next entry in table + cfg_tbl_addr(4 downto 0) <= std_logic_vector(unsigned(cfg_tbl_addr(4 downto 0)) + 1); + cfg_state <= TBL; + end if; + end if; + when LOCK_WAIT => -- wait for MMCM to lock + cfg_rst <= '0'; + if locked_s = '1' then -- all done + cfg_state <= IDLE; + rsto_req <= '0'; + clk_mux <= '1'; -- Switch to new clock + end if; + end case; + + if rsti = '1' then -- full reset + + sel_prev <= (others => '1'); -- force reconfig + cfg_rst <= '1'; + cfg_daddr <= (others => '0'); + cfg_den <= '0'; + cfg_dwe <= '0'; + cfg_di <= (others => '0'); + cfg_state <= RESET; + + rsto_req <= '1'; + + end if; + + end if; + end process MAIN; + + -- clock domain crossing + + SYNC1 : entity work.cdc_stable + generic map ( + G_DATA_SIZE => 4 + ) + port map ( + dst_clk_i => clki, + src_data_i(0) => locked, + src_data_i(1) => sel(0), + src_data_i(2) => sel(1), + src_data_i(3) => sel(2), + dst_data_o(0) => locked_s, + dst_data_o(1) => sel_s(0), + dst_data_o(2) => sel_s(1), + dst_data_o(3) => sel_s(2) + ); + + SYNC2 : entity work.cdc_stable + generic map ( + G_DATA_SIZE => 1 + ) + port map ( + dst_clk_i => clko_b, + src_data_i(0) => rsto_req or not locked or mmcm_rst, + dst_data_o(0) => rsto + ); + + mmcm_rst <= cfg_rst or rsti; + + -- For Static Timing Analysis it is necessary + -- that the default configuration corresponds to the fastest clock speed. + MMCM: component mmcme2_adv + generic map ( + bandwidth => "OPTIMIZED", + clkfbout_mult_f => 37.125, -- f_VCO = (100 MHz / 5) x 37.125 = 742.5 MHz + clkfbout_phase => 0.0, + clkfbout_use_fine_ps => false, + clkin1_period => 10.0, -- INPUT @ 100 MHz + clkin2_period => 0.0, + clkout0_divide_f => 2.0, -- TMDS @ 371.25 MHz + clkout0_duty_cycle => 0.5, + clkout0_phase => 0.0, + clkout0_use_fine_ps => false, + clkout1_divide => 10, -- HDMI @ 74.25 MHz + clkout1_duty_cycle => 0.5, + clkout1_phase => 0.0, + clkout1_use_fine_ps => false, + clkout2_divide => 1, + clkout2_duty_cycle => 0.5, + clkout2_phase => 0.0, + clkout2_use_fine_ps => false, + clkout3_divide => 1, + clkout3_duty_cycle => 0.5, + clkout3_phase => 0.0, + clkout3_use_fine_ps => false, + clkout4_cascade => false, + clkout4_divide => 1, + clkout4_duty_cycle => 0.5, + clkout4_phase => 0.0, + clkout4_use_fine_ps => false, + clkout5_divide => 1, + clkout5_duty_cycle => 0.5, + clkout5_phase => 0.0, + clkout5_use_fine_ps => false, + clkout6_divide => 1, + clkout6_duty_cycle => 0.5, + clkout6_phase => 0.0, + clkout6_use_fine_ps => false, + compensation => "ZHOLD", + divclk_divide => 5, + is_clkinsel_inverted => '0', + is_psen_inverted => '0', + is_psincdec_inverted => '0', + is_pwrdwn_inverted => '0', + is_rst_inverted => '0', + ref_jitter1 => 0.01, + ref_jitter2 => 0.01, + ss_en => "FALSE", + ss_mode => "CENTER_HIGH", + ss_mod_period => 10000, + startup_wait => false + ) + port map ( + pwrdwn => '0', + rst => mmcm_rst, + locked => locked, + clkin1 => clki, + clkin2 => '0', + clkinsel => '1', + clkinstopped => open, + clkfbin => clk_fb, + clkfbout => clku_fb, + clkfboutb => open, + clkfbstopped => open, + clkout0 => clko_u_x5, + clkout0b => open, + clkout1 => clko_u, + clkout1b => open, + clkout2 => open, + clkout2b => open, + clkout3 => open, + clkout3b => open, + clkout4 => open, + clkout5 => open, + clkout6 => open, + dclk => clki, + daddr => cfg_daddr, + den => cfg_den, + dwe => cfg_dwe, + di => cfg_di, + do => cfg_do, + drdy => cfg_drdy, + psclk => '0', + psdone => open, + psen => '0', + psincdec => '0' + ); + + U_BUFG_0: component bufg + port map ( + i => clko_u_x5, + o => clko_x5 + ); + + p_clki_div : process (clki) + begin + if rising_edge(clki) then + clki_div <= not clki_div; + end if; + end process p_clki_div; + + -- Force clock to '0' when MMCM is not locked. This avoids + -- any glitches during reconfiguration + U_BUFG_1: component bufgmux_ctrl + port map ( + s => clk_mux, + i0 => clki_div, + i1 => clko_u, + o => clko_b + ); + + U_BUFG_F: component bufg + port map ( + i => clku_fb, + o => clk_fb + ); + + clko <= clko_b; + +end architecture synth; + From 7f3127eb54441d1410a187baa742725047015639 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Fri, 6 Dec 2024 19:13:28 +0100 Subject: [PATCH 12/17] fixing typo --- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 3 ++- vhdl/hw/MEGA65/MEGA65_R6.vhd | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index 6aef0cae..a4f1798f 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -487,7 +487,7 @@ - + @@ -500,6 +500,7 @@ + diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index 2b0f868d..c679811d 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -453,7 +453,7 @@ begin clkin1_period => 10.0, -- 100 MHz (10 ns) clkfbout_mult_f => 8.0, -- 800 MHz common multiply divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range - clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but 25MHz is within 1% tolerance range + clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but 25.197 is close enough clkout1_divide => 8, -- 100 MHz /8 clkout2_divide => 16, -- 50 MHz /16 clkout3_divide => 4 -- 200 MHz /4 From 7c9af4ad923100c55651ecc45e37b73775e59cf3 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Fri, 6 Dec 2024 21:32:05 +0100 Subject: [PATCH 13/17] wip... --- hw/xilinx/MEGA65-R6/Vivado/mega65.xdc | 2 +- vhdl/hw/MEGA65/MEGA65_R6.vhd | 90 +++++++++++++-------------- 2 files changed, 43 insertions(+), 49 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc index bbb6e51e..f114c6b9 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xdc @@ -366,7 +366,7 @@ set_property -dict {PULLUP FALSE SLEW FAST DRIVE 16} [get_ports {sdram_*}]; ################################ ## External clock signal (100 MHz) -#create_clock -period 10.000 [get_ports clk_i] +create_clock -period 10.000 [get_ports clk_i] create_generated_clock -name Slow_Clock_25MHz -source [get_pins {clk_main/CLKOUT2}] -divide_by 2 [get_pins sd_card/Slow_Clock_25MHz_reg/Q] diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index c679811d..96a79585 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -341,8 +341,12 @@ architecture beh of MEGA65 is signal vga_r : std_logic; signal vga_g : std_logic; signal vga_b : std_logic; + signal vga_red : std_logic_vector(7 downto 0); + signal vga_green : std_logic_vector(7 downto 0); + signal vga_blue : std_logic_vector(7 downto 0); signal vga_hsync : std_logic; signal vga_vsync : std_logic; + signal vga_clk : std_logic; -- VGA pixel clock -- HDMI signals signal tmds_clk : std_logic; -- HDMI pixel clock at 5x speed for TMDS @ 371.25 MHz @@ -351,10 +355,8 @@ architecture beh of MEGA65 is signal hdmi_tmds : slv_9_0_t(0 to 2); -- parallel TMDS symbol stream x 3 channels signal hdmi_hs : std_logic; signal hdmi_vs : std_logic; - signal hdmi_de : std_logic; - -- Various clocks - signal clk_pixel : std_logic; -- 25 MHz pixelclock for 640x480 @ 60 Hz (within 1% tolerance) + -- Clocks and related signals signal clk_50MHz : std_logic; -- 50 MHz clock. aiming for 100 MHz signal clk_100MHz : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase signal clk_200MHz : std_logic; -- 4x clk_50MHz = 200 MHz @@ -465,7 +467,7 @@ begin clkin1 => clk_i, clkfbin => clk_fb_main, clkfbout => clk_fb_main, - clkout0 => clk_pixel, -- pixelclock + clkout0 => vga_clk, clkout1 => clk_100MHz, -- 100 MHz clkout2 => clk_50MHz, -- 50 MHz clkout3 => clk_200MHz, -- 200 MHz @@ -538,14 +540,14 @@ begin port map ( reset => reset_ctl, - clk25MHz => clk_pixel, + clk25MHz => vga_clk, clk50MHz => clk_50MHz, R => vga_r, G => vga_g, B => vga_b, hsync => vga_hsync, vsync => vga_vsync, - hdmi_de => hdmi_de, + hdmi_de => open, en => vga_en, we => vga_we, reg => vga_reg, @@ -553,6 +555,11 @@ begin data_out => vga_data_out ); + -- VGA: wire the simplified color system of the VGA component to the VGA outputs + vga_red <= (others => vga_r); + vga_green <= (others => vga_g); + vga_blue <= (others => vga_b); + -- special UART with FIFO that can be directly connected to the CPU bus uart : entity work.bus_uart generic map( @@ -764,29 +771,22 @@ begin end if; end process; - video_signal_latches : process (clk_pixel) + video_signal_latches : process (vga_clk) begin - if rising_edge(clk_pixel) then - -- VGA: wire the simplified color system of the VGA component to the VGA outputs - vga_red_o <= vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r & vga_r; - vga_green_o <= vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g & vga_g; - vga_blue_o <= vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b & vga_b; - - -- VGA horizontal and vertical sync - vga_hs_o <= vga_hsync; - vga_vs_o <= vga_vsync; + -- latching values at different edge than sampling by dac eliminates blurring + if falling_edge(vga_clk) then + vga_red_o <= vga_red; + vga_green_o <= vga_green; + vga_blue_o <= vga_blue; + vga_hs_o <= vga_hsync; + vga_vs_o <= vga_vsync; end if; end process; -- make the VDAC output the image vdac_sync_n_o <= '0'; vdac_blank_n_o <= '1'; - - -- Fix of the Vivado induced "blurry VGA screen": - -- As of the time writing this (June 2020): it is absolutely unclear for me, why I need to - -- invert the phase of the vdac_clk when use Vivado 2019.2. When using ISE 14.7, it works - -- fine without the phase shift. - vdac_clk_o <= not clk_pixel; + vdac_clk_o <= vga_clk; -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) @@ -806,7 +806,7 @@ begin ) port map ( - rsti => not reset_ctl, + rsti => reset_ctl, clki => clk_i, sel => HDMI_VIDEO_MODE.CLK_SEL, rsto => hdmi_rst, @@ -814,32 +814,26 @@ begin clko_x5 => tmds_clk ); -- video_out_clock_inst - video2hdmi_inst : component xpm_cdc_array_single + vga_to_hdmi_cdc : component xpm_cdc_array_single generic map( - WIDTH => 27 + WIDTH => 2 ) port map ( - src_clk => clk_pixel, - src_in(23 downto 0) => vga_red_o & vga_green_o & vga_blue_o, - src_in(24) => vga_hs_o, - src_in(25) => vga_vs_o, - src_in(26) => not vdac_blank_n_o, - dest_clk => hdmi_clk, - dest_out(23 downto 0) => open, - dest_out(24) => hdmi_hs, - dest_out(25) => hdmi_vs, - dest_out(26) => open - ); -- video2hdmi_inst - - -- (hdmi_red, hdmi_green, hdmi_blue) <= unsigned(hdmi_color); + src_clk => vga_clk, + src_in(0) => vga_hsync, + src_in(1) => vga_vsync, + dest_clk => hdmi_clk, + dest_out(0) => hdmi_hs, + dest_out(1) => hdmi_vs + ); hdmi_data_gen : for i in 0 to 2 generate begin hdmi_data_inst : entity work.serialiser_10to1_selectio port map ( - rst => not reset_ctl, + rst => reset_ctl, clk => hdmi_clk, clk_x5 => tmds_clk, d => hdmi_tmds(i), @@ -851,7 +845,7 @@ begin hdmi_clk_inst : entity work.serialiser_10to1_selectio port map ( - rst => not reset_ctl, + rst => reset_ctl, clk => hdmi_clk, clk_x5 => tmds_clk, d => "0000011111", @@ -870,14 +864,14 @@ begin vs_pol => HDMI_VIDEO_MODE.V_POL, hs_pol => HDMI_VIDEO_MODE.H_POL, - vga_rst => not reset_ctl, - vga_clk => vdac_clk_o, - vga_vs => vga_vs_o, - vga_hs => vga_hs_o, - vga_de => hdmi_de, - vga_r => vga_red_o, - vga_g => vga_green_o, - vga_b => vga_blue_o, + vga_rst => reset_ctl, + vga_clk => vga_clk, + vga_vs => vga_vsync, + vga_hs => vga_hsync, + vga_de => '1', + vga_r => vga_red, + vga_g => vga_green, + vga_b => vga_blue, -- PCM audio pcm_clk => '1', From 5a420fee392106d038567cc38078d7897c841651 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Sun, 8 Dec 2024 16:25:44 +0100 Subject: [PATCH 14/17] digital pipeline integrated yet hdmi signal not showing up --- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 117 +++++++++++++------------- vhdl/hw/MEGA65/MEGA65_R6.vhd | 71 +++++++++------- 2 files changed, 100 insertions(+), 88 deletions(-) diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index a4f1798f..6f86cf4b 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -45,7 +45,6 @@ - - - - - - - - - - - - @@ -371,6 +359,20 @@ + + + + + + + + + + + + + + diff --git a/vhdl/hw/MEGA65/MEGA65_R6.vhd b/vhdl/hw/MEGA65/MEGA65_R6.vhd index f68f7f87..a538f50d 100644 --- a/vhdl/hw/MEGA65/MEGA65_R6.vhd +++ b/vhdl/hw/MEGA65/MEGA65_R6.vhd @@ -347,24 +347,25 @@ architecture beh of MEGA65 is signal vga_hsync : std_logic; signal vga_vsync : std_logic; signal vga_de : std_logic; - signal vga_clk : std_logic; -- VGA pixel clock -- HDMI signals - signal tmds_clk : std_logic; -- HDMI pixel clock at 5x speed for TMDS @ 371.25 MHz - signal hdmi_clk : std_logic; -- HDMI pixel clock at normal speed @ 74.25 MHz - signal hdmi_rst : std_logic; - signal hdmi_tmds : slv_9_0_t(0 to 2); -- parallel TMDS symbol stream x 3 channels - signal hdmi_hs : std_logic; - signal hdmi_vs : std_logic; - signal hdmi_de : std_logic; + signal tmds_clk : std_logic; -- HDMI pixel clock at 5x speed for TMDS @ 371.25 MHz + signal hdmi_clk : std_logic; -- HDMI pixel clock at normal speed @ 74.25 MHz + signal hdmi_rst : std_logic; + signal hdmi_tmds : slv_9_0_t(0 to 2); -- parallel TMDS symbol stream x 3 channels + signal hdmi_hs : std_logic; + signal hdmi_vs : std_logic; + signal hdmi_de : std_logic; signal hdmi_red : std_logic_vector(7 downto 0); signal hdmi_green : std_logic_vector(7 downto 0); signal hdmi_blue : std_logic_vector(7 downto 0); -- Clocks and related signals + signal clk_25Mhz : std_logic; -- video pixel clock signal clk_50MHz : std_logic; -- 50 MHz clock. aiming for 100 MHz signal clk_100MHz : std_logic; -- 100 MHz clock created by mmcme2 for congruent phase - signal clk_200MHz : std_logic; -- 4x clk_50MHz = 200 MHz + signal clk_200MHz : std_logic; -- 200 MHz + signal clk_125MHz : std_logic; -- 125 MHz TMDS clock signal clk_fb_main : std_logic; signal pll_locked_main : std_logic; @@ -458,12 +459,13 @@ begin generic map ( clkin1_period => 10.0, -- 100 MHz (10 ns) - clkfbout_mult_f => 8.0, -- 800 MHz common multiply - divclk_divide => 1, -- 800 MHz /1 common divide to stay within 600MHz-1600MHz range - clkout0_divide_f => 31.75, -- Should be 25.175 MHz, but 25.197 is close enough - clkout1_divide => 8, -- 100 MHz /8 - clkout2_divide => 16, -- 50 MHz /16 - clkout3_divide => 4 -- 200 MHz /4 + clkfbout_mult_f => 10.0, -- 1000 MHz common multiply + divclk_divide => 1, -- 1000 MHz /1 common divide to stay within 600MHz-1600MHz range + clkout0_divide_f => 40.0, -- 25 MHz + clkout1_divide => 10, -- 100 MHz + clkout2_divide => 20, -- 50 MHz + clkout3_divide => 5, -- 200 MHz + clkout4_divide => 8 -- 125 MHz ) port map ( @@ -472,10 +474,11 @@ begin clkin1 => clk_i, clkfbin => clk_fb_main, clkfbout => clk_fb_main, - clkout0 => vga_clk, + clkout0 => clk_25MHz, -- 25 MHz video pixel clock clkout1 => clk_100MHz, -- 100 MHz clkout2 => clk_50MHz, -- 50 MHz clkout3 => clk_200MHz, -- 200 MHz + clkout4 => clk_125MHz, -- HDMI TMDS clock locked => pll_locked_main ); @@ -545,7 +548,7 @@ begin port map ( reset => reset_ctl, - clk25MHz => vga_clk, + clk25MHz => clk_25MHz, clk50MHz => clk_50MHz, R => vga_r, G => vga_g, @@ -776,10 +779,10 @@ begin end if; end process; - video_signal_latches : process (vga_clk) + video_signal_latches : process (clk_25MHz) begin -- latching values at different edge than sampling by dac eliminates blurring - if falling_edge(vga_clk) then + if falling_edge(clk_25MHz) then vga_red_o <= vga_red; vga_green_o <= vga_green; vga_blue_o <= vga_blue; @@ -791,7 +794,7 @@ begin -- make the VDAC output the image vdac_sync_n_o <= '0'; vdac_blank_n_o <= '1'; - vdac_clk_o <= vga_clk; + vdac_clk_o <= clk_25MHz; -- emulate the switches on the Nexys4 to toggle VGA and PS/2 keyboard -- bit #0: use UART as STDIN (0) / use MEGA65 keyboard as STDIN (1) @@ -802,102 +805,77 @@ begin reset_ctl <= '1' when (reset_pre_pore = '1' or reset_post_pore = '1' or pll_locked_main = '0') else '0'; - -- VGA to HDMI conversion -- + -- HDMI pixel clock and VGA pixel clock are the same, TMDS clock is directly derived + -- therefore CDC part can be ommitted (?) - -- reconfigurable MMCM: 25.2MHz, 27MHz, 74.25MHz or 148.5MHz - video_out_clock_inst : entity work.video_out_clock - generic map( - FREF => 100.0 -- Clock speed in MHz of the input clk_i - ) - port map - ( - rsti => reset_ctl, - clki => clk_i, - sel => VIDEO_MODE.CLK_SEL, - rsto => hdmi_rst, - clko => hdmi_clk, - clko_x5 => tmds_clk - ); -- video_out_clock_inst - - vga_to_hdmi_cdc : component xpm_cdc_array_single - generic map( - WIDTH => 27 - ) - port map - ( - src_clk => vga_clk, - src_in(0) => vga_hsync, - src_in(1) => vga_vsync, - src_in(2) => vga_de, - src_in(10 downto 3) => vga_red, - src_in(18 downto 11) => vga_green, - src_in(26 downto 19) => vga_blue, - dest_clk => hdmi_clk, - dest_out(0) => hdmi_hs, - dest_out(1) => hdmi_vs, - dest_out(2) => hdmi_de, - dest_out(10 downto 3) => hdmi_red, - dest_out(18 downto 11) => hdmi_green, - dest_out(26 downto 19) => hdmi_blue - ); + hdmi_clk <= clk_25MHz; + tmds_clk <= clk_125MHz; - hdmi_data_gen : for i in 0 to 2 generate - begin - hdmi_data_inst : entity work.serialiser_10to1_selectio - port map - ( - rst => hdmi_rst, - clk => hdmi_clk, - clk_x5 => tmds_clk, - d => hdmi_tmds(i), - out_p => tmds_data_p_o(i), - out_n => tmds_data_n_o(i) - ); - end generate hdmi_data_gen; - - hdmi_clk_inst : entity work.serialiser_10to1_selectio + hdmi_rst <= reset_ctl; + hdmi_hs <= vga_hsync; + hdmi_vs <= vga_vsync; + hdmi_de <= vga_de; + hdmi_red <= vga_red; + hdmi_green <= vga_green; + hdmi_blue <= vga_blue; + + hdmi_data_gen : for i in 0 to 2 generate + begin + hdmi_data_inst : entity work.serialiser_10to1_selectio port map ( rst => hdmi_rst, clk => hdmi_clk, clk_x5 => tmds_clk, - d => "0000011111", - out_p => tmds_clk_p_o, - out_n => tmds_clk_n_o - ); -- hdmi_clk_inst + d => hdmi_tmds(i), + out_p => tmds_data_p_o(i), + out_n => tmds_data_n_o(i) + ); + end generate hdmi_data_gen; - vga_to_hdmi_inst : entity work.vga_to_hdmi - port map - ( - select_44100 => '0', - dvi => '0', - vic => std_logic_vector(to_unsigned(VIDEO_MODE.CEA_CTA_VIC, 8)), - aspect => VIDEO_MODE.ASPECT, - pix_rep => VIDEO_MODE.PIXEL_REP, - vs_pol => VIDEO_MODE.V_POL, - hs_pol => VIDEO_MODE.H_POL, - - vga_rst => hdmi_rst, - vga_clk => hdmi_clk, - vga_vs => hdmi_vs, - vga_hs => hdmi_hs, - vga_de => hdmi_de, - vga_r => hdmi_red, - vga_g => hdmi_green, - vga_b => hdmi_blue, - - -- PCM audio - pcm_clk => '0', - pcm_rst => '0', - pcm_clken => '0', - pcm_l => (others => '0'), - pcm_r => (others => '0'), - pcm_acr => '0', - pcm_n => (others => '0'), - pcm_cts => (others => '0'), - - -- TMDS output (parallel) - tmds => hdmi_tmds - ); -- vga_to_hdmi_inst - - end architecture beh; + hdmi_clk_gen : entity work.serialiser_10to1_selectio + port map + ( + rst => hdmi_rst, + clk => hdmi_clk, + clk_x5 => tmds_clk, + d => "0000011111", + out_p => tmds_clk_p_o, + out_n => tmds_clk_n_o + ); -- hdmi_clk_inst + + vga_to_hdmi_inst : entity work.vga_to_hdmi + port map + ( + select_44100 => '0', + dvi => '0', + vic => std_logic_vector(to_unsigned(VIDEO_MODE.CEA_CTA_VIC, 8)), + aspect => VIDEO_MODE.ASPECT, + pix_rep => VIDEO_MODE.PIXEL_REP, + vs_pol => VIDEO_MODE.V_POL, + hs_pol => VIDEO_MODE.H_POL, + + vga_rst => hdmi_rst, + vga_clk => hdmi_clk, + vga_vs => hdmi_vs, + vga_hs => hdmi_hs, + vga_de => hdmi_de, + vga_r => hdmi_red, + vga_g => hdmi_green, + vga_b => hdmi_blue, + + -- PCM audio + pcm_clk => '0', + pcm_rst => '0', + pcm_clken => '0', + pcm_l => (others => '0'), + pcm_r => (others => '0'), + pcm_acr => '0', + pcm_n => (others => '0'), + pcm_cts => (others => '0'), + + -- TMDS output (parallel) + tmds => hdmi_tmds + ); -- vga_to_hdmi_inst + +end architecture beh; From ed86727997de2c4c7c104d0f007e5c5fda6045b4 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Tue, 10 Dec 2024 22:35:28 +0100 Subject: [PATCH 16/17] unused files removed --- hw/xilinx/MEGA65-R6/Vivado/mega65.xpr | 14 - vhdl/hw/MEGA65/cdc_stable.vhd | 71 --- vhdl/hw/MEGA65/video_out_clock.vhd | 609 -------------------------- 3 files changed, 694 deletions(-) delete mode 100644 vhdl/hw/MEGA65/cdc_stable.vhd delete mode 100644 vhdl/hw/MEGA65/video_out_clock.vhd diff --git a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr index fbbdc1c6..92f1301b 100644 --- a/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr +++ b/hw/xilinx/MEGA65-R6/Vivado/mega65.xpr @@ -359,20 +359,6 @@ - - - - - - - - - - - - - - diff --git a/vhdl/hw/MEGA65/cdc_stable.vhd b/vhdl/hw/MEGA65/cdc_stable.vhd deleted file mode 100644 index ae7c32d3..00000000 --- a/vhdl/hw/MEGA65/cdc_stable.vhd +++ /dev/null @@ -1,71 +0,0 @@ -library ieee; - use ieee.std_logic_1164.all; - use ieee.numeric_std.all; - --- Clock Domain Crossing specialized for slowly varying data: --- Only propagate when all bits are stable. --- --- In the constraint file, add the following line: --- set_max_delay 8 -datapath_only -from [get_clocks] -to [get_pins -hierarchical "*cdc_stable_gen.dst_*_d_reg[*]/D"] - -entity cdc_stable is - generic ( - G_DATA_SIZE : integer; - G_REGISTER_SRC : boolean := false -- Add register to input data - ); - port ( - src_clk_i : in std_logic := '0'; - src_data_i : in std_logic_vector(G_DATA_SIZE - 1 downto 0); - dst_clk_i : in std_logic; - dst_data_o : out std_logic_vector(G_DATA_SIZE - 1 downto 0) - ); -end entity cdc_stable; - -architecture synthesis of cdc_stable is - - signal src_data : std_logic_vector(G_DATA_SIZE - 1 downto 0); - signal dst_data_d : std_logic_vector(G_DATA_SIZE - 1 downto 0); - signal dst_data_dd : std_logic_vector(G_DATA_SIZE - 1 downto 0); - - attribute async_reg : string; - attribute async_reg of dst_data_d : signal is "true"; - attribute async_reg of dst_data_dd : signal is "true"; - -begin - - -- Optionally add a register to the input samples - - input_reg_gen : if G_REGISTER_SRC generate - - input_reg_proc : process (src_clk_i) - begin - if rising_edge(src_clk_i) then - src_data <= src_data_i; - end if; - end process input_reg_proc; - - else generate - src_data <= src_data_i; - end generate input_reg_gen; - - -- Use generate to create a nice unique name for constraining - - cdc_stable_gen : if true generate - - sample_proc : process (dst_clk_i) - begin - if rising_edge(dst_clk_i) then - dst_data_d <= src_data; -- CDC - dst_data_dd <= dst_data_d; - - -- Propagate, when sampling is stable - if dst_data_d = dst_data_dd then - dst_data_o <= dst_data_dd; - end if; - end if; - end process sample_proc; - - end generate cdc_stable_gen; - -end architecture synthesis; - diff --git a/vhdl/hw/MEGA65/video_out_clock.vhd b/vhdl/hw/MEGA65/video_out_clock.vhd deleted file mode 100644 index 1a949e0e..00000000 --- a/vhdl/hw/MEGA65/video_out_clock.vhd +++ /dev/null @@ -1,609 +0,0 @@ --------------------------------------------------------------------------------- --- video_out_clock.vhd -- --- Pixel and serialiser clock synthesiser (dynamically configured MMCM). -- --------------------------------------------------------------------------------- --- (C) Copyright 2022 Adam Barnes -- --- This file is part of The Tyto Project. The Tyto Project is free software: -- --- you can redistribute it and/or modify it under the terms of the GNU Lesser -- --- General Public License as published by the Free Software Foundation, -- --- either version 3 of the License, or (at your option) any later version. -- --- The Tyto Project is distributed in the hope that it will be useful, but -- --- WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- --- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -- --- License for more details. You should have received a copy of the GNU -- --- Lesser General Public License along with The Tyto Project. If not, see -- --- https://www.gnu.org/licenses/. -- --------------------------------------------------------------------------------- - --- Modified by MFJ in October 2023 --- When programming the MMCM, the "locked" signal is de-asserted and the clock output is --- invalid and contains glitches. Usually, the system is held in reset until "locked" --- is asserted again. Instead, we here switch over to a "backup" clock of 50 MHz --- until the MMCM is ready. This switch-over is done using a glitch-free clock --- multiplexer, but since the latter is stateful, the switch-over has to be timed --- carefully, so that the active clock is always valid. - --- To generate the entries in these tables: --- 1. Download the MMCM and PLL Dynamic Reconfiguration Application Note (XAPP888) --- reference files. --- 2. Use the Vivado Clock Wizard to generate the values of CLKFBOUT_MULT_F, --- DIVCLK_DIVIDE, CLKOUT0_DIVIDE_F, and CLKOUT1_DIVIDE. Note them down on a piece of paper. --- 3. Start Vivado, and run the xapp888 setup file: MMCME2_DRP/top_mmcme2.tcl --- 4. Use the spreadsheet https://github.com/amb5l/tyto2/blob/main/src/common/video/xilinx_7series/video_out_clock.xls --- type in the Clock Wizard values, and generate the tcl command. --- 5. In Vivado, run the tcl command. This outputs the values for the table below. - -library ieee; - use ieee.std_logic_1164.all; - use ieee.numeric_std.all; - -library unisim; - use unisim.vcomponents.all; - -entity video_out_clock is - generic ( - fref : real -- reference clock frequency (MHz) (typically 100.0) - ); - port ( - - rsti : in std_logic; -- input (reference) clock synchronous reset - clki : in std_logic; -- input (reference) clock - sel : in std_logic_vector(2 downto 0); -- output clock select: - -- 000 = 25.200 MHz. E.g. 640x480 @ 60.00 Hz - -- 001 = 27.000 MHz. E.g. 720x480 @ 59.94 Hz - -- 010 = 74.250 MHz. E.g. 1280x720 @ 60.00 Hz - -- 011 = 148.500 MHz. - -- 100 = 25.175 MHz. E.g. 640x480 @ 59.94 Hz - -- 101 = 27.027 MHz. E.g. 720x480 @ 60.00 Hz - -- 110 = 74.176 MHz. E.g. 1280x720 @ 59.94 Hz - -- 111 = undefined - rsto : out std_logic; -- output clock synchronous reset - clko : out std_logic; -- pixel clock - clko_x5 : out std_logic -- serialiser clock (5x pixel clock) - - ); -end entity video_out_clock; - -architecture synth of video_out_clock is - - signal sel_s : std_logic_vector(2 downto 0); -- sel, synchronised to clki - - signal rsto_req : std_logic; -- rsto request, synchronous to clki - - signal mmcm_rst : std_logic; -- MMCM reset - signal locked : std_logic; -- MMCM locked output - signal locked_s : std_logic; -- above, synchronised to clki - - signal sel_prev : std_logic_vector(3 downto 0); -- to detect changes - signal clk_fb : std_logic; -- feedback clock - signal clku_fb : std_logic; -- unbuffered feedback clock - signal clko_u : std_logic; -- unbuffered pixel clock - signal clko_b : std_logic; -- buffered pixel clock - signal clko_u_x5 : std_logic; -- unbuffered serializer clock - - signal clki_div : std_logic; -- Input clock divided by 2 - - signal cfg_tbl_addr : std_logic_vector(7 downto 0); -- 8 x 32 entries - signal cfg_tbl_data : std_logic_vector(39 downto 0); -- 8 bit address + 16 bit write data + 16 bit read mask - - signal cfg_cnt : std_logic_vector(1 downto 0); -- Delay reset - signal cfg_rst : std_logic; -- DRP reset - signal cfg_daddr : std_logic_vector(6 downto 0); -- DRP register address - signal cfg_den : std_logic; -- DRP enable (pulse) - signal cfg_dwe : std_logic; -- DRP write enable - signal cfg_di : std_logic_vector(15 downto 0); -- DRP write data - signal cfg_do : std_logic_vector(15 downto 0); -- DRP read data - signal cfg_drdy : std_logic; -- DRP access complete - - type cfg_state_t is ( -- state machine states - idle, -- waiting for fsel change - reset_wait, -- put MMCM into reset - reset, -- put MMCM into reset - tbl, -- get first/next table value - rd, -- start read - rd_wait, -- wait for read to complete - wr, -- start write - wr_wait, -- wait for write to complete - lock_wait -- wait for reconfig to complete - ); - signal cfg_state : cfg_state_t; - signal clk_mux : std_logic; - - -begin - - MAIN: process (clki) is - - -- Contents of synchronous ROM table. - -- See MMCM and PLL Dynamic Reconfiguration Application Note (XAPP888) - -- for details of register map. - function cfg_tbl (addr : std_logic_vector) return std_logic_vector is - -- bits 39..32 = cfg_daddr (MSB = 1 for last entry) - -- bits 31..16 = cfg write data - -- bits 15..0 = cfg read mask - variable data : std_logic_vector(39 downto 0); - begin - data := x"0000000000"; - -- values below pasted in from video_out_clk.xls - if fref = 100.0 then - case addr is - -- Desired frequency = 25.200 MHz - -- CLKFBOUT_MULT_F = 31.500 - -- DIVCLK_DIVIDE = 5 - -- CLKOUT0_DIVIDE_F = 5.000 - -- CLKOUT1_DIVIDE = 25 - -- Actual frequency = 25.200 MHz - when x"00" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"01" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"02" => data := x"08" & x"1083" & x"1000"; -- CLKOUT0 Register 1 - when x"03" => data := x"09" & x"0080" & x"8000"; -- CLKOUT0 Register 2 - when x"04" => data := x"0A" & x"130d" & x"1000"; -- CLKOUT1 Register 1 - when x"05" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 - when x"06" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"07" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"08" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"09" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"0A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"0B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"0C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"0D" => data := x"13" & x"3000" & x"8000"; -- CLKOUT6 Register 2 - when x"0E" => data := x"14" & x"13CF" & x"1000"; -- CLKFBOUT Register 1 - when x"0F" => data := x"15" & x"4800" & x"8000"; -- CLKFBOUT Register 2 - when x"10" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register - when x"11" => data := x"18" & x"002C" & x"FC00"; -- Lock Register 1 - when x"12" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 - when x"13" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 - when x"14" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"15" => data := x"4E" & x"0900" & x"66FF"; -- Filter Register 1 - when x"16" => data := x"CF" & x"1000" & x"666F"; -- Filter Register 2 - - -- Desired frequency = 27.000 MHz - -- CLKFBOUT_MULT_F = 47.250 - -- DIVCLK_DIVIDE = 5 - -- CLKOUT0_DIVIDE_F = 7.000 - -- CLKOUT1_DIVIDE = 35 - -- Actual frequency = 74.250 MHz - when x"20" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"21" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"22" => data := x"08" & x"10C4" & x"1000"; -- CLKOUT0 Register 1 - when x"23" => data := x"09" & x"0080" & x"8000"; -- CLKOUT0 Register 2 - when x"24" => data := x"0A" & x"1452" & x"1000"; -- CLKOUT1 Register 1 - when x"25" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 - when x"26" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"27" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"28" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"29" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"2A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"2B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"2C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"2D" => data := x"13" & x"2800" & x"8000"; -- CLKOUT6 Register 2 - when x"2E" => data := x"14" & x"15D7" & x"1000"; -- CLKFBOUT Register 1 - when x"2F" => data := x"15" & x"2800" & x"8000"; -- CLKFBOUT Register 2 - when x"30" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register - when x"31" => data := x"18" & x"00FA" & x"FC00"; -- Lock Register 1 - when x"32" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 - when x"33" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 - when x"34" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"35" => data := x"4E" & x"1900" & x"66FF"; -- Filter Register 1 - when x"36" => data := x"CF" & x"0100" & x"666F"; -- Filter Register 2 - - -- Desired frequency = 74.250 MHz - -- CLKFBOUT_MULT_F = 37.125 - -- DIVCLK_DIVIDE = 5 - -- CLKOUT0_DIVIDE_F = 2.000 - -- CLKOUT1_DIVIDE = 10 - -- Actual frequency = 74.250 MHz - when x"40" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"41" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"42" => data := x"08" & x"1041" & x"1000"; -- CLKOUT0 Register 1 - when x"43" => data := x"09" & x"0000" & x"8000"; -- CLKOUT0 Register 2 - when x"44" => data := x"0A" & x"1145" & x"1000"; -- CLKOUT1 Register 1 - when x"45" => data := x"0B" & x"0000" & x"8000"; -- CLKOUT1 Register 2 - when x"46" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"47" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"48" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"49" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"4A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"4B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"4C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"4D" => data := x"13" & x"2400" & x"8000"; -- CLKOUT6 Register 2 - when x"4E" => data := x"14" & x"1491" & x"1000"; -- CLKFBOUT Register 1 - when x"4F" => data := x"15" & x"1800" & x"8000"; -- CLKFBOUT Register 2 - when x"50" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register - when x"51" => data := x"18" & x"00FA" & x"FC00"; -- Lock Register 1 - when x"52" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 - when x"53" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 - when x"54" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"55" => data := x"4E" & x"0900" & x"66FF"; -- Filter Register 1 - when x"56" => data := x"CF" & x"1000" & x"666F"; -- Filter Register 2 - - -- Desired frequency = 148.500 MHz - -- CLKFBOUT_MULT_F = 37.125 - -- DIVCLK_DIVIDE = 5 - -- CLKOUT0_DIVIDE_F = 1.000 - -- CLKOUT1_DIVIDE = 5 - -- Actual frequency = 148.500 MHz - when x"60" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"61" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"62" => data := x"08" & x"1041" & x"1000"; -- CLKOUT0 Register 1 - when x"63" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 - when x"64" => data := x"0A" & x"1083" & x"1000"; -- CLKOUT1 Register 1 - when x"65" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 - when x"66" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"67" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"68" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"69" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"6A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"6B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"6C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"6D" => data := x"13" & x"2400" & x"8000"; -- CLKOUT6 Register 2 - when x"6E" => data := x"14" & x"1491" & x"1000"; -- CLKFBOUT Register 1 - when x"6F" => data := x"15" & x"1800" & x"8000"; -- CLKFBOUT Register 2 - when x"70" => data := x"16" & x"0083" & x"C000"; -- DIVCLK Register - when x"71" => data := x"18" & x"00FA" & x"FC00"; -- Lock Register 1 - when x"72" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 - when x"73" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 - when x"74" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"75" => data := x"4E" & x"0900" & x"66FF"; -- Filter Register 1 - when x"76" => data := x"CF" & x"1000" & x"666F"; -- Filter Register 2 - - -- Desired frequency = 25.175 MHz - -- CLKFBOUT_MULT_F = 17.625 - -- DIVCLK_DIVIDE = 2 - -- CLKOUT0_DIVIDE_F = 7.000 - -- CLKOUT1_DIVIDE = 35 - -- Actual frequency = 25.179 MHz - when x"80" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"81" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"82" => data := x"08" & x"10C4" & x"1000"; -- CLKOUT0 Register 1 - when x"83" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 - when x"84" => data := x"0A" & x"1452" & x"1000"; -- CLKOUT1 Register 1 - when x"85" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 - when x"86" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"87" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"88" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"89" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"8A" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"8B" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"8C" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"8D" => data := x"13" & x"3000" & x"8000"; -- CLKOUT6 Register 2 - when x"8E" => data := x"14" & x"1208" & x"1000"; -- CLKFBOUT Register 1 - when x"8F" => data := x"15" & x"5800" & x"8000"; -- CLKFBOUT Register 2 - when x"90" => data := x"16" & x"0041" & x"C000"; -- DIVCLK Register - when x"91" => data := x"18" & x"013F" & x"FC00"; -- Lock Register 1 - when x"92" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 - when x"93" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 - when x"94" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"95" => data := x"4E" & x"9900" & x"66FF"; -- Filter Register 1 - when x"96" => data := x"CF" & x"1100" & x"666F"; -- Filter Register 2 - - -- Desired frequency = 27.027 MHz - -- CLKFBOUT_MULT_F = 21.625 - -- DIVCLK_DIVIDE = 2 - -- CLKOUT0_DIVIDE_F = 8.000 - -- CLKOUT1_DIVIDE = 40 - -- Actual frequency = 27.031 MHz - when x"A0" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"A1" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"A2" => data := x"08" & x"1104" & x"1000"; -- CLKOUT0 Register 1 - when x"A3" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 - when x"A4" => data := x"0A" & x"1514" & x"1000"; -- CLKOUT1 Register 1 - when x"A5" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 - when x"A6" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"A7" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"A8" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"A9" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"AA" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"AB" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"AC" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"AD" => data := x"13" & x"3000" & x"8000"; -- CLKOUT6 Register 2 - when x"AE" => data := x"14" & x"128A" & x"1000"; -- CLKFBOUT Register 1 - when x"AF" => data := x"15" & x"5800" & x"8000"; -- CLKFBOUT Register 2 - when x"B0" => data := x"16" & x"0041" & x"C000"; -- DIVCLK Register - when x"B1" => data := x"18" & x"00DB" & x"FC00"; -- Lock Register 1 - when x"B2" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 - when x"B3" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 - when x"B4" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"B5" => data := x"4E" & x"9000" & x"66FF"; -- Filter Register 1 - when x"B6" => data := x"CF" & x"0100" & x"666F"; -- Filter Register 2 - - -- Desired frequency = 74.176 MHz - -- CLKFBOUT_MULT_F = 22.250 - -- DIVCLK_DIVIDE = 3 - -- CLKOUT0_DIVIDE_F = 2.000 - -- CLKOUT1_DIVIDE = 10 - -- Actual frequency = 74.167 MHz - when x"C0" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"C1" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"C2" => data := x"08" & x"1041" & x"1000"; -- CLKOUT0 Register 1 - when x"C3" => data := x"09" & x"00C0" & x"8000"; -- CLKOUT0 Register 2 - when x"C4" => data := x"0A" & x"1145" & x"1000"; -- CLKOUT1 Register 1 - when x"C5" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 - when x"C6" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"C7" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"C8" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"C9" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"CA" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"CB" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"CC" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"CD" => data := x"13" & x"0C00" & x"8000"; -- CLKOUT6 Register 2 - when x"CE" => data := x"14" & x"128A" & x"1000"; -- CLKFBOUT Register 1 - when x"CF" => data := x"15" & x"2C00" & x"8000"; -- CLKFBOUT Register 2 - when x"D0" => data := x"16" & x"0042" & x"C000"; -- DIVCLK Register - when x"D1" => data := x"18" & x"00C2" & x"FC00"; -- Lock Register 1 - when x"D2" => data := x"19" & x"7C01" & x"8000"; -- Lock Register 2 - when x"D3" => data := x"1A" & x"7DE9" & x"8000"; -- Lock Register 3 - when x"D4" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"D5" => data := x"4E" & x"1100" & x"66FF"; -- Filter Register 1 - when x"D6" => data := x"CF" & x"9000" & x"666F"; -- Filter Register 2 - - -- Desired frequency = 40.000 MHz - -- CLKFBOUT_MULT_F = 10 - -- DIVCLK_DIVIDE = 1 - -- CLKOUT0_DIVIDE_F = 5.000 - -- CLKOUT1_DIVIDE = 25 - -- Actual frequency = 40.000 MHz - when x"E0" => data := x"06" & x"1145" & x"1000"; -- CLKOUT5 Register 1 - when x"E1" => data := x"07" & x"0000" & x"8000"; -- CLKOUT5 Register 2 - when x"E2" => data := x"08" & x"1083" & x"1000"; -- CLKOUT0 Register 1 - when x"E3" => data := x"09" & x"0080" & x"8000"; -- CLKOUT0 Register 2 - when x"E4" => data := x"0A" & x"130D" & x"1000"; -- CLKOUT1 Register 1 - when x"E5" => data := x"0B" & x"0080" & x"8000"; -- CLKOUT1 Register 2 - when x"E6" => data := x"0C" & x"1145" & x"1000"; -- CLKOUT2 Register 1 - when x"E7" => data := x"0D" & x"0000" & x"8000"; -- CLKOUT2 Register 2 - when x"E8" => data := x"0E" & x"1145" & x"1000"; -- CLKOUT3 Register 1 - when x"E9" => data := x"0F" & x"0000" & x"8000"; -- CLKOUT3 Register 2 - when x"EA" => data := x"10" & x"1145" & x"1000"; -- CLKOUT4 Register 1 - when x"EB" => data := x"11" & x"0000" & x"8000"; -- CLKOUT4 Register 2 - when x"EC" => data := x"12" & x"1145" & x"1000"; -- CLKOUT6 Register 1 - when x"ED" => data := x"13" & x"0000" & x"8000"; -- CLKOUT6 Register 2 - when x"EE" => data := x"14" & x"1145" & x"1000"; -- CLKFBOUT Register 1 - when x"EF" => data := x"15" & x"0000" & x"8000"; -- CLKFBOUT Register 2 - when x"F0" => data := x"16" & x"1041" & x"C000"; -- DIVCLK Register - when x"F1" => data := x"18" & x"01E8" & x"FC00"; -- Lock Register 1 - when x"F2" => data := x"19" & x"7001" & x"8000"; -- Lock Register 2 - when x"F3" => data := x"1A" & x"71E9" & x"8000"; -- Lock Register 3 - when x"F4" => data := x"28" & x"FFFF" & x"0000"; -- Power Register - when x"F5" => data := x"4E" & x"9900" & x"66FF"; -- Filter Register 1 - when x"F6" => data := x"CF" & x"1100" & x"666F"; -- Filter Register 2 - - when others => data := (others => '0'); - end case; - end if; - return data; - end function cfg_tbl; - - begin - if rising_edge(clki) then - - cfg_tbl_data <= cfg_tbl(cfg_tbl_addr); -- synchronous ROM - - -- defaults - cfg_den <= '0'; - cfg_dwe <= '0'; - - -- state machine - case cfg_state is - when IDLE => - if '0' & sel /= sel_prev -- frequency selection has changed (or initial startup) - or locked_s = '0' -- lock lost - then - clk_mux <= '0'; -- Switch to alternate clock - cfg_cnt <= "11"; - cfg_state <= RESET_WAIT; - end if; - when RESET_WAIT => -- Wait for clock switching to take effect - if cfg_cnt /= "00" then - cfg_cnt <= std_logic_vector(unsigned(cfg_cnt) - 1); - else - rsto_req <= '1'; - cfg_rst <= '1'; - cfg_state <= RESET; - end if; - when RESET => -- put MMCM into reset - sel_prev <= '0' & sel; - cfg_tbl_addr <= sel & "00000"; - cfg_state <= TBL; - when TBL => -- get table entry from sychronous ROM - cfg_state <= RD; - when RD => -- read specified register - cfg_daddr <= cfg_tbl_data(38 downto 32); - cfg_den <= '1'; - cfg_state <= RD_WAIT; - when RD_WAIT => -- wait for read to complete - if cfg_drdy = '1' then - cfg_di <= (cfg_do and cfg_tbl_data(15 downto 0)) or (cfg_tbl_data(31 downto 16) and not cfg_tbl_data(15 downto 0)); - cfg_den <= '1'; - cfg_dwe <= '1'; - cfg_state <= WR; - end if; - when WR => -- write modified contents back to same register - cfg_state <= WR_WAIT; - when WR_WAIT => -- wait for write to complete - if cfg_drdy = '1' then - if cfg_tbl_data(39) = '1' then -- last entry in table - cfg_tbl_addr <= (others => '0'); - cfg_state <= LOCK_WAIT; - else -- do next entry in table - cfg_tbl_addr(4 downto 0) <= std_logic_vector(unsigned(cfg_tbl_addr(4 downto 0)) + 1); - cfg_state <= TBL; - end if; - end if; - when LOCK_WAIT => -- wait for MMCM to lock - cfg_rst <= '0'; - if locked_s = '1' then -- all done - cfg_state <= IDLE; - rsto_req <= '0'; - clk_mux <= '1'; -- Switch to new clock - end if; - end case; - - if rsti = '1' then -- full reset - - sel_prev <= (others => '1'); -- force reconfig - cfg_rst <= '1'; - cfg_daddr <= (others => '0'); - cfg_den <= '0'; - cfg_dwe <= '0'; - cfg_di <= (others => '0'); - cfg_state <= RESET; - - rsto_req <= '1'; - - end if; - - end if; - end process MAIN; - - -- clock domain crossing - - SYNC1 : entity work.cdc_stable - generic map ( - G_DATA_SIZE => 4 - ) - port map ( - dst_clk_i => clki, - src_data_i(0) => locked, - src_data_i(1) => sel(0), - src_data_i(2) => sel(1), - src_data_i(3) => sel(2), - dst_data_o(0) => locked_s, - dst_data_o(1) => sel_s(0), - dst_data_o(2) => sel_s(1), - dst_data_o(3) => sel_s(2) - ); - - SYNC2 : entity work.cdc_stable - generic map ( - G_DATA_SIZE => 1 - ) - port map ( - dst_clk_i => clko_b, - src_data_i(0) => rsto_req or not locked or mmcm_rst, - dst_data_o(0) => rsto - ); - - mmcm_rst <= cfg_rst or rsti; - - -- For Static Timing Analysis it is necessary - -- that the default configuration corresponds to the fastest clock speed. - MMCM: component mmcme2_adv - generic map ( - bandwidth => "OPTIMIZED", - clkfbout_mult_f => 37.125, -- f_VCO = (100 MHz / 5) x 37.125 = 742.5 MHz - clkfbout_phase => 0.0, - clkfbout_use_fine_ps => false, - clkin1_period => 10.0, -- INPUT @ 100 MHz - clkin2_period => 0.0, - clkout0_divide_f => 2.0, -- TMDS @ 371.25 MHz - clkout0_duty_cycle => 0.5, - clkout0_phase => 0.0, - clkout0_use_fine_ps => false, - clkout1_divide => 10, -- HDMI @ 74.25 MHz - clkout1_duty_cycle => 0.5, - clkout1_phase => 0.0, - clkout1_use_fine_ps => false, - clkout2_divide => 1, - clkout2_duty_cycle => 0.5, - clkout2_phase => 0.0, - clkout2_use_fine_ps => false, - clkout3_divide => 1, - clkout3_duty_cycle => 0.5, - clkout3_phase => 0.0, - clkout3_use_fine_ps => false, - clkout4_cascade => false, - clkout4_divide => 1, - clkout4_duty_cycle => 0.5, - clkout4_phase => 0.0, - clkout4_use_fine_ps => false, - clkout5_divide => 1, - clkout5_duty_cycle => 0.5, - clkout5_phase => 0.0, - clkout5_use_fine_ps => false, - clkout6_divide => 1, - clkout6_duty_cycle => 0.5, - clkout6_phase => 0.0, - clkout6_use_fine_ps => false, - compensation => "ZHOLD", - divclk_divide => 5, - is_clkinsel_inverted => '0', - is_psen_inverted => '0', - is_psincdec_inverted => '0', - is_pwrdwn_inverted => '0', - is_rst_inverted => '0', - ref_jitter1 => 0.01, - ref_jitter2 => 0.01, - ss_en => "FALSE", - ss_mode => "CENTER_HIGH", - ss_mod_period => 10000, - startup_wait => false - ) - port map ( - pwrdwn => '0', - rst => mmcm_rst, - locked => locked, - clkin1 => clki, - clkin2 => '0', - clkinsel => '1', - clkinstopped => open, - clkfbin => clk_fb, - clkfbout => clku_fb, - clkfboutb => open, - clkfbstopped => open, - clkout0 => clko_u_x5, - clkout0b => open, - clkout1 => clko_u, - clkout1b => open, - clkout2 => open, - clkout2b => open, - clkout3 => open, - clkout3b => open, - clkout4 => open, - clkout5 => open, - clkout6 => open, - dclk => clki, - daddr => cfg_daddr, - den => cfg_den, - dwe => cfg_dwe, - di => cfg_di, - do => cfg_do, - drdy => cfg_drdy, - psclk => '0', - psdone => open, - psen => '0', - psincdec => '0' - ); - - U_BUFG_0: component bufg - port map ( - i => clko_u_x5, - o => clko_x5 - ); - - p_clki_div : process (clki) - begin - if rising_edge(clki) then - clki_div <= not clki_div; - end if; - end process p_clki_div; - - -- Force clock to '0' when MMCM is not locked. This avoids - -- any glitches during reconfiguration - U_BUFG_1: component bufgmux_ctrl - port map ( - s => clk_mux, - i0 => clki_div, - i1 => clko_u, - o => clko_b - ); - - U_BUFG_F: component bufg - port map ( - i => clku_fb, - o => clk_fb - ); - - clko <= clko_b; - -end architecture synth; - From fa530d69181efdee5f1b76d3b8c36b65b2bae156 Mon Sep 17 00:00:00 2001 From: Robert Jaremczak Date: Mon, 10 Mar 2025 18:29:26 +0100 Subject: [PATCH 17/17] definition of uart_status removed from header --- emulator/uart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emulator/uart.h b/emulator/uart.h index f5b3e493..6fd5122d 100644 --- a/emulator/uart.h +++ b/emulator/uart.h @@ -55,7 +55,7 @@ typedef struct uart #define RESET_OUTPUT_PORT 15 //flag to ensure restoring a working terminal when closing the emulator by closing the SDL window -enum uart_status_t {uart_undef, uart_init, uart_rundown} uart_status; +enum uart_status_t {uart_undef, uart_init, uart_rundown}; unsigned int uart_read_register(uart *, unsigned int); void uart_write_register(uart *, unsigned int, unsigned int);