1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-02-26 16:43:21 +00:00

Add Gauntlet Code WIP

This commit is contained in:
Gehstock
2020-04-13 22:15:49 +02:00
parent 4a5b9cfa8e
commit f5e520c0ec
74 changed files with 19164 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2013 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus II 64-Bit
# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition
# Date created = 18:28:29 January 01, 2020
#
# -------------------------------------------------------------------------- #
QUARTUS_VERSION = "13.1"
DATE = "18:28:29 January 01, 2020"
# Revisions
PROJECT_REVISION = "Gauntlet_MiST"

View File

@@ -0,0 +1,259 @@
# -------------------------------------------------------------------------- #
#
# Copyright (C) 1991-2013 Altera Corporation
# Your use of Altera Corporation's design tools, logic functions
# and other software and tools, and its AMPP partner logic
# functions, and any output files from any of the foregoing
# (including device programming or simulation files), and any
# associated documentation or information are expressly subject
# to the terms and conditions of the Altera Program License
# Subscription Agreement, Altera MegaCore Function License
# Agreement, or other applicable license agreement, including,
# without limitation, that your use is for the sole purpose of
# programming logic devices manufactured by Altera and sold by
# Altera or its authorized distributors. Please refer to the
# applicable agreement for further details.
#
# -------------------------------------------------------------------------- #
#
# Quartus II 64-Bit
# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition
# Date created = 15:32:36 April 12, 2020
#
# -------------------------------------------------------------------------- #
#
# Notes:
#
# 1) The default values for assignments are stored in the file:
# Gauntlet_MiST_assignment_defaults.qdf
# If this file doesn't exist, see file:
# assignment_defaults.qdf
#
# 2) Altera recommends that you do not modify this file. This
# file is updated automatically by the Quartus II software
# and any changes you make may be lost or overwritten.
#
# -------------------------------------------------------------------------- #
# Project-Wide Assignments
# ========================
set_global_assignment -name PROJECT_CREATION_TIME_DATE "21:22:13 JUNE 04, 2019"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl"
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
set_global_assignment -name SMART_RECOMPILE ON
# Pin & Location Assignments
# ==========================
set_location_assignment PIN_7 -to LED
set_location_assignment PIN_54 -to CLOCK_27
set_location_assignment PIN_144 -to VGA_R[5]
set_location_assignment PIN_143 -to VGA_R[4]
set_location_assignment PIN_142 -to VGA_R[3]
set_location_assignment PIN_141 -to VGA_R[2]
set_location_assignment PIN_137 -to VGA_R[1]
set_location_assignment PIN_135 -to VGA_R[0]
set_location_assignment PIN_133 -to VGA_B[5]
set_location_assignment PIN_132 -to VGA_B[4]
set_location_assignment PIN_125 -to VGA_B[3]
set_location_assignment PIN_121 -to VGA_B[2]
set_location_assignment PIN_120 -to VGA_B[1]
set_location_assignment PIN_115 -to VGA_B[0]
set_location_assignment PIN_114 -to VGA_G[5]
set_location_assignment PIN_113 -to VGA_G[4]
set_location_assignment PIN_112 -to VGA_G[3]
set_location_assignment PIN_111 -to VGA_G[2]
set_location_assignment PIN_110 -to VGA_G[1]
set_location_assignment PIN_106 -to VGA_G[0]
set_location_assignment PIN_136 -to VGA_VS
set_location_assignment PIN_119 -to VGA_HS
set_location_assignment PIN_65 -to AUDIO_L
set_location_assignment PIN_80 -to AUDIO_R
set_location_assignment PIN_105 -to SPI_DO
set_location_assignment PIN_88 -to SPI_DI
set_location_assignment PIN_126 -to SPI_SCK
set_location_assignment PIN_127 -to SPI_SS2
set_location_assignment PIN_91 -to SPI_SS3
set_location_assignment PIN_13 -to CONF_DATA0
set_location_assignment PLL_1 -to "pll:pll|altpll:altpll_component"
set_location_assignment PIN_49 -to SDRAM_A[0]
set_location_assignment PIN_44 -to SDRAM_A[1]
set_location_assignment PIN_42 -to SDRAM_A[2]
set_location_assignment PIN_39 -to SDRAM_A[3]
set_location_assignment PIN_4 -to SDRAM_A[4]
set_location_assignment PIN_6 -to SDRAM_A[5]
set_location_assignment PIN_8 -to SDRAM_A[6]
set_location_assignment PIN_10 -to SDRAM_A[7]
set_location_assignment PIN_11 -to SDRAM_A[8]
set_location_assignment PIN_28 -to SDRAM_A[9]
set_location_assignment PIN_50 -to SDRAM_A[10]
set_location_assignment PIN_30 -to SDRAM_A[11]
set_location_assignment PIN_32 -to SDRAM_A[12]
set_location_assignment PIN_83 -to SDRAM_DQ[0]
set_location_assignment PIN_79 -to SDRAM_DQ[1]
set_location_assignment PIN_77 -to SDRAM_DQ[2]
set_location_assignment PIN_76 -to SDRAM_DQ[3]
set_location_assignment PIN_72 -to SDRAM_DQ[4]
set_location_assignment PIN_71 -to SDRAM_DQ[5]
set_location_assignment PIN_69 -to SDRAM_DQ[6]
set_location_assignment PIN_68 -to SDRAM_DQ[7]
set_location_assignment PIN_86 -to SDRAM_DQ[8]
set_location_assignment PIN_87 -to SDRAM_DQ[9]
set_location_assignment PIN_98 -to SDRAM_DQ[10]
set_location_assignment PIN_99 -to SDRAM_DQ[11]
set_location_assignment PIN_100 -to SDRAM_DQ[12]
set_location_assignment PIN_101 -to SDRAM_DQ[13]
set_location_assignment PIN_103 -to SDRAM_DQ[14]
set_location_assignment PIN_104 -to SDRAM_DQ[15]
set_location_assignment PIN_58 -to SDRAM_BA[0]
set_location_assignment PIN_51 -to SDRAM_BA[1]
set_location_assignment PIN_85 -to SDRAM_DQMH
set_location_assignment PIN_67 -to SDRAM_DQML
set_location_assignment PIN_60 -to SDRAM_nRAS
set_location_assignment PIN_64 -to SDRAM_nCAS
set_location_assignment PIN_66 -to SDRAM_nWE
set_location_assignment PIN_59 -to SDRAM_nCS
set_location_assignment PIN_33 -to SDRAM_CKE
set_location_assignment PIN_43 -to SDRAM_CLK
# Classic Timing Assignments
# ==========================
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON
set_global_assignment -name TIMEQUEST_DO_CCPP_REMOVAL ON
# Analysis & Synthesis Assignments
# ================================
set_global_assignment -name FAMILY "Cyclone III"
set_global_assignment -name TOP_LEVEL_ENTITY Gauntlet_MiST
set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144
set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8
set_global_assignment -name VHDL_INPUT_VERSION VHDL_2008
set_global_assignment -name VHDL_SHOW_LMF_MAPPING_MESSAGES OFF
# Fitter Assignments
# ==================
set_global_assignment -name DEVICE EP3C25E144C8
set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF
set_global_assignment -name ENABLE_NCE_PIN OFF
set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF
set_global_assignment -name CYCLONEIII_CONFIGURATION_SCHEME "PASSIVE SERIAL"
set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF
set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL"
set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO"
set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO"
# Assembler Assignments
# =====================
set_global_assignment -name USE_CONFIGURATION_DEVICE OFF
set_global_assignment -name GENERATE_RBF_FILE ON
# SignalTap II Assignments
# ========================
set_global_assignment -name ENABLE_SIGNALTAP OFF
set_global_assignment -name USE_SIGNALTAP_FILE output_files/trop.stp
# Power Estimation Assignments
# ============================
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
# Advanced I/O Timing Assignments
# ===============================
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise
set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise
set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall
# ---------------------------
# start ENTITY(Gauntlet_MiST)
# Pin & Location Assignments
# ==========================
# Fitter Assignments
# ==================
# start DESIGN_PARTITION(Top)
# ---------------------------
# Incremental Compilation Assignments
# ===================================
# end DESIGN_PARTITION(Top)
# -------------------------
# end ENTITY(Gauntlet_MiST)
# -------------------------
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[*]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[*]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[0]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[1]
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQMH
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQML
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCS
set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*]
set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_A[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQ[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_BA[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQML
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_DQMH
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nRAS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCAS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nWE
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_nCS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CKE
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_CLK
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_R[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_G[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_B[*]
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_HS
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_VS
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_L
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to AUDIO_R
set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SPI_DO
set_global_assignment -name SYSTEMVERILOG_FILE rtl/Gauntlet_MiST.sv
set_global_assignment -name VHDL_FILE rtl/GAUNTLET.vhd
set_global_assignment -name VHDL_FILE rtl/MAIN.vhd
set_global_assignment -name VHDL_FILE rtl/spram.vhd
set_global_assignment -name VHDL_FILE rtl/VIDEO.vhd
set_global_assignment -name VHDL_FILE rtl/AUDIO.vhd
set_global_assignment -name VHDL_FILE rtl/SLAPSTIC.vhd
set_global_assignment -name VHDL_FILE rtl/VRAMS.vhd
set_global_assignment -name VHDL_FILE rtl/SLAGS.vhd
set_global_assignment -name VHDL_FILE rtl/PFHS.vhd
set_global_assignment -name VHDL_FILE rtl/MOHLB.vhd
set_global_assignment -name VHDL_FILE rtl/SYNGEN.vhd
set_global_assignment -name VHDL_FILE rtl/GPC.vhd
set_global_assignment -name VHDL_FILE rtl/CRAMS.vhd
set_global_assignment -name VHDL_FILE rtl/POKEY.vhd
set_global_assignment -name VHDL_FILE rtl/TMS5220.vhd
set_global_assignment -name VHDL_FILE rtl/LS299.vhd
set_global_assignment -name VHDL_FILE rtl/LINEBUF.vhd
set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv
set_global_assignment -name VHDL_FILE rtl/pll_mist.vhd
set_global_assignment -name VHDL_FILE rtl/rom/ROM_6P.vhd
set_global_assignment -name VHDL_FILE rtl/rom/PROM_5L.vhd
set_global_assignment -name VHDL_FILE rtl/rom/PROM_5E.vhd
set_global_assignment -name VHDL_FILE rtl/rom/PROM_4R.vhd
set_global_assignment -name VHDL_FILE rtl/rom/EEP_14A.vhd
set_global_assignment -name QIP_FILE ../../../common/mist/mist.qip
set_global_assignment -name QIP_FILE ../../../common/CPU/68000/tg68last/TG68K.qip
set_global_assignment -name QIP_FILE ../../../common/CPU/T65/T65.qip
set_global_assignment -name QIP_FILE ../../../common/Sound/jt51/jt51.qip
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@@ -0,0 +1,15 @@
@echo off
del /s *.bak
del /s *.orig
del /s *.rej
rmdir /s /q db
rmdir /s /q incremental_db
rmdir /s /q output
rmdir /s /q simulation
rmdir /s /q greybox_tmp
del PLLJ_PLLSPE_INFO.txt
del *.qws
del *.ppf
del *.qip
del *.ddb
pause

Binary file not shown.

View File

@@ -0,0 +1,589 @@
# Atari Gauntlet FPGA Arcade
## Hardware
Initially all screen shots here were generated from test bench output of what the video signal would look like if it was displayed on a monitor. The testbench dumps the output video values for each frame in a .ppm (portable pixmap) text file which can then be directly viewed by a suitable viewer (eg FastStone Image Viewer). The .ppm file format consists of one line with the pixmap magic value P3, next line is the X and Y resolution and max number of colors, followed by hopefully at least X*Y lines of RGB color triplets like so:
<pre>
P3
336 240 15
15 15 15
0 0 0
15 15 15
12 11 15
10 9 15
...
</pre>
To start with, the Video section of the arcade game was implemented and debugged (sheets 8 though 16 in the schematic). Because there was no CPU to run the game, for simulation purposes the video RAMs are initialized with data dumped from MAME so as to produce the relevant game screens.
Progress has been made and the game has been successfully run on a Pipistrello FPGA board with a custom add-on board which has a 2Mx16 SRAM chip rated at 10ns access time. This is needed because there is no space inside the FPGA to store all the game ROMs.
## Platform Information
The following collection of information serves as notes used during debugging.
### Video Output
The game has a resolution of 336x240 pixels.
The video output is generated in `IRGB` format before being converted to `RGB` (sheet 16) so the total number of colors are 4 bits per color, plus a common 4 bit intensity for all colors for a total of 16 bits or 65536 colors.
The game uses the typical three layer video layout, `Text`, `Sprites` and `Background` with `Text` having the highest display priority (obscures sprites and playfield), `Sprites` having medium priority (only obscures background) and `Background` having the lowest priority. The schematic refers to the text layer as `AL` which seems to stand for Alphanumerics, the sprite layer is `MO` for Motion Objects and the background is `PF` for Play Field.
### Video Memory Layout
Table below borrowed from MAME source code. The video uses a total of 24KB RAM for the VRAM (video RAM) organized as three sections of 4Kb x 16 bits:
<pre>
Playfield
PF 900000-901FFF R/W xxxxxxxx xxxxxxxx Playfield RAM (64x64 tiles)
R/W x------- -------- (Horizontal flip)
R/W -xxx---- -------- (Palette select)
R/W ----xxxx xxxxxxxx (Tile index)
Motion Objects
MO 902000-9027FF R/W xxxxxxxx xxxxxxxx Motion object RAM TILE
R/W -xxxxxxx xxxxxxxx (Tile index)
MO 902800-902FFF R/W xxxxxxxx xxxxxxxx Motion object RAM XPOS
R/W xxxxxxxx x------- (X position)
R/W -------- ----xxxx (Palette select)
MO 903000-9037FF R/W xxxxxxxx xxxxxxxx Motion object RAM YPOS
R/W xxxxxxxx x------- (Y position)
R/W -------- -x------ (Horizontal flip)
R/W -------- --xxx--- (Number of X tiles - 1)
R/W -------- -----xxx (Number of Y tiles - 1)
MO 903800-903FFF R/W xxxxxxxx xxxxxxxx Motion object RAM LINK
R/W ------xx xxxxxxxx (Link to next object)
Spare Video
SP 904000-904FFF R/W xxxxxxxx xxxxxxxx Spare video RAM
Alphanumerics
AL 905000-905ED3 R/W xxxxxxxx xxxxxxxx Alphanumerics RAM (64x32 tiles)
R/W x------- -------- (Opaque/transparent)
R/W -xxxxx-- -------- (Palette select)
R/W ------xx xxxxxxxx (Tile index)
905F6E R/W xxxxxxxx x-----xx Playfield Y scroll/tile bank select
R/W xxxxxxxx x------- (Playfield Y scroll)
R/W -------- ------xx (Playfield tile bank select)
AL 905F80-905FBF R/W xxxxxxxx xxxxxxxx
AL 905FC0-905FFF R/W xxxxxxxx xxxxxxxx
</pre>
Additionally 2KB RAM are used for the CRAM (color palette RAM):
<pre>
AL 910000-9101FF R/W xxxxxxxx xxxxxxxx Alphanumerics palette RAM (256 entries)
MO 910200-9103FF R/W xxxxxxxx xxxxxxxx Motion object palette RAM (256 entries)
PL 910400-9105FF R/W xxxxxxxx xxxxxxxx Playfield palette RAM (256 entries)
EX 910600-9107FF R/W xxxxxxxx xxxxxxxx Extra palette RAM (256 entries)
R/W xxxx---- -------- (Intensity)
R/W ----xxxx -------- (Red)
R/W -------- xxxx---- (Green)
R/W -------- ----xxxx (Blue)
</pre>
There are 42 visible text lines across and 30 down, each text character requires a word
Top line starts at 905000 - 905053, remaining 22 words not visible on screen
Next line starts at 905080 - 9050D3, remaining 22 words not visible on screen
etc...
Bottom line starts at 905E80 - 905ED3, remaining 22 words not visible on screen
### Special Memory Locations
There are two special memory locations at 930000 and 905F6E that control overall MO and PF horizontal and vertical offset (scroll)
- 930000 = PF and MO horizontal scroll. Increasing values scrolls the playfield left. Any write to memory range 930XXX will work. The bottom 9 bits of the `WORD` written to 930000 will be latched by signal `/HSCRLD` into a 9 bit register formed by chips `9S` `6M` `7M` as well as latched into the internal register of custom chip `12K`, the `PFHS` (Play Field Horizontal Scroller). At game startup this is initialized to 0005.
- 905F6E = PF and MO vertical scroll. Increasing values scroll playfield up. This memory location is scanned each video frame and the top 9 bits are loaded into presettable counters `5J`,`5F`,`4F` when both `/VSYNC` and `/PFHST` are active (start of each video frame). The counters counts up from that value for each horizontal line. This effectively pushes an offset into VPOS via the adders `5D`, `5E`. Lowest 2 bits are also loaded into a counter at each start of frame and count up modulo 4 into a 2:4 decoder which selects graphic ROM chip selects `GCS0`..`GCS3`
### Sprite Format
Sprites are stored at memory range 902000-903FFF. A single sprite is defined by four words: a tile, xpos, ypos and link value stored at the same offset in four different memory regions (some additional attributes are also stored, see detailed memory map above).
The sprites form a linked list via the LINK memory region 903800-903FFF
The link to the next sprite is obtained by doubling the current LINK offset and adding it to LINK memory base 903800.
For example at game startup the initial screen has the sprite link list shown below based on initial sprite offset 0046. Doubling the offset, we get 8C and adding it to LINK base memory 903800 we get 90388C, then as per the table below each memory has a LINK offset pointing to the next sprite LINK address. Note that many tiles in the link list do not contain a visible sprite (value 0800) yet they are still part of the linked list, perhaps simply waiting for a valid sprite value to be stored at those addresses and the sprite then becomes visible.
<pre>
Memory 90388C 90389C 9038AA 9038B8 903978 90397A 90397C 90398C 903A1C 903A2C 903C38 903C3A 903C3C 903C7A 903D18 903D1A
Sprite 097E 0990 08FC 0AFC 1D42 1D48 1D52 1648 096C 0990 0800 0800 0800 09AB 0800 0800
Memory 903D1C 903D1E 903D20 903D58 903D5A 903D5C 903D5E 903D60 903D7A 903D98 903D9A 903D9C 903D9E 903DA0 903DD8 903DDA
Sprite 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800
Memory 903DDC 903DDE 903DE0 903E18 903E1A 903E1C 903E1E 903E20 903E58 903E5A 903E5C 903E5E 903E60 903E98 903E9A 903E9C
Sprite 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800
Memory 903E9E 903EA0 903ED8 903EDA 903EDC 903EDE 903EE0 903F18 903F1A 903F1C 903F1E 903F20 903F58 903F5A 903F5C 903F5E
Sprite 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800
Memory 903F60 903F98 903F9A 903F9C 903F9E 903FA0 903FD8 903FDA 903FDC 903FDE 903FE0 903FFA 903800
Sprite 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 0800 09E1 0000
</pre>
The sprite link list does not appear to be circular, so the LINK register must be somehow initialized with the offset of the first sprite in the link list at the start of each horizontal scanline. It appears that the first memory location (index=0) does not contain a LINK to a valid sprite during gameplay so once that memory location is reached, the LINK register remains zeroed until it is loaded again with a valid index.
Memory region 905F80-905FFF seems to control sprite visibility as follows
905F80 enables sprites on first 8 lines of screen 1..8
905F82 enables sprites on next 8 lines of screen 9..16
...
905FB8 enables sprites on next 8 lines of screen 321..328
905FBA enables sprites on last 8 lines of screen 329..336
To be determined
905FC0
..
905FFE
At each location, the word's top 6 bits seem to be unused and the word's bottom 10 bits (when doubled) is a pointer to a sprite offset (typically the first sprite in a linked list).
So for every word in the memory range 905F80-905FBA, if the word's bottom 10 bits point to a valid sprite, then if that sprite or any other sprites linked from it have y coordinates that fall within the screen range of 8 lines covered by that memory location, those portions of those sprites are visible on those lines on the screen.
From simulation, this memory range is scanned during each horizontal line, data from MO VRAM ends up on VRD then loaded on LINK register latch `8F`, `8J` on rising `RCLK` when `/LINK` signal is low.
## It's Alive!!!
After the initial translation of the schematic to RTL, the simulation produces the frame of video on the left but it's not the expected output as can be seen on the right from MAME:
[![Frame from Simulation](images/SIM00.png)](images/SIM00.png)
[![Frame from MAME](images/MAME02.png)](images/MAME02.png)
### Debugging the alphanumerics:
The top right corner under the Gauntlet logo, where the first text line should read "LEVEL 1", the L begins to be drawn but instead of drawing an L shape the display shows the 2 pixels of the top of the L replicated for all 8 lines after. All text characters exhibit this same behaviour.
Pixel data goes to GPC `APIX1`, `APIX0` from shifters `7P`, `7N` fed by `ROM 6P` driven by `VRD` bus through latches `4P`, `7R` on `4H` rising clock. `ROM 6P` address is `VRD9..0` registered, plus unregistered signals `4V`, `2V`, `1V`, `/4H`, address changes every 4 cycles.
Turns out `4V`, `2V`, `1V` were not being driven so `ROM 6P` was not being addressed properly and was not outputting enough new data to form proper characters. Connecting the additional signals properly produces a much more recognizable picture:
[![Alphanumerics fixed](images/SIM03.png)](images/SIM03.png)
Additionally GPC `I_D` bus connect order was wrong, so the colors were also reversed. Fixing that shows colors in the correct order:
[![Alphanumeric colors fixed](images/SIM04.png)](images/SIM04.png)
### Playfield debugging
The playfield shows pink stripes instead of the expected maze. Forcing the AL ROMs to return zero, makes the text on the right of the screen disappear. This reveals additional playfield that would normally be hidden under the text. Since AL was fixed earlier, the AL ROMs will be left disabled while troubleshooting the PF issue.
Adding debug code to the simulator to dump selected busses to a log file and debugging the GP bus address (ROM addresses), data out of ROMs and into SLAGS, reveals several mistakes such as unconnected signals, SLAGS selectors S0 S1 to the shifters were reversed, etc, so progressively the playfield becomes more and more visible.
[![Pink Stripes](images/SIM10.png)](images/SIM10.png)
[![More Stripes](images/SIM11.png)](images/SIM11.png)
[![Flipped blocks](images/SIM12.png)](images/SIM12.png)
The raw data from the correctly functioning SLAGS can be seen below. This is an example of what the `SLAGS` `MO` shifter output dumped into a .ppm file looks like before it is turned into an index into the color palette.
[![SLAGS MO output](images/SLAGS_MO.png)](images/SLAGS_MO.png)
And this is the corresponding `PF` shifters output. Since these values are intercepted straight from the SLAGS outputs before they hit the color palette, each value is written into the .ppm file three times (R=G=B) so as to form a grayscale image.
[![SLAGS PF output](images/SLAGS_PF.png)](images/SLAGS_PF.png)
### CRAM Debugging
PF is now looking much better but the colors are wrong. Suspecting CRAM, palette indexing.
[![Finally a maze](images/SIM13.png)](images/SIM13.png)
CRAM is addressed by the 10 bit bus CRA from GPC. The top two bits of address selects CPAL as follows:
- 0 = AL
- 1 = MO
- 2 = PF
- 3 = Extra
Top two bits have value of 2 so they correctly access PF CPAL, lower byte is an index into the PF CPAL.
From MAME it is apparent that for the initial screen, the game only uses CPAL indexes 280-29F for PF as below. This CPAL section shows what each index value is used for, X is don't care/unused, F is floor tile, the rest are different types of wall pieces.
<pre>
280: 0000 6631 9631 C631 F631 F643 F654 F876 -- X X X X X X F X
288: 8333 7223 A324 F334 C334 C445 E445 F445 -- wallshade F F F F F F F
290: F410 F010 F110 F322 B520 4531 F531 F731 -- X X X wallright X X walldown wallleft
298: FC63 F840 FD84 F335 F246 F158 F26A F37B -- walltop X X X X X X X
</pre>
Examination in the simulator shows the following discrepancies:
- wallshade color index expected 288 observed 257
- wallright color index expected 293 observed 24C
- walldown color index expected 296 observed 249
- wallleft color index expected 297 observed 248
- walltop color index expected 298 observed 247
It appears that the pattern is the original value lower byte + x20 xor 0xff. This incorrect data comes from the GPC (Graphic Priority Control) chip `12M` which in turn receives it from PFHS (Play Field Horizontal Scroll) chip `12K`. Since many of the custom chips in this schematic are based on earlier Atari arcade versions implemented with discrete components, checking schematic `SP-277` for the Atari System 1 where this `PFHS` implementation is based on, shows there is a small 64 bit `74F189` RAM chip inside the `PFHS`. A mistake made was in assuming that the data that goes into the RAM chip comes out exactly the same, but upon reading the RAM datasheet it turns out the data coming out of RAM is the **complement** of the data going in! After inverting the outputs from the `PFHS` RAM chip the PF now shows correct colors:
[![Correct Playfield](images/SIM14.png)](images/SIM14.png)
### Debugging Motion Objects
Sprites do not show on screen at all. When there are sprites on the screen, it seems `/VMATCH` asserts during sprite presence but, horizontal match doesn't so the `MATCH` signal is never asserted. It seems the VHDL implementation of `6S` F/F with both set and preset was incorrect, output `6S9` is never preset by `/VERTDL`, also `6S6` output is **inverted**, not just straight through. After inverting output `6S6` and fixing the async preset of F/F `6S` sprites now show (corrupted) on the top part of screen and they seem to repeat instead of just showing once. Further research shows that `MOHLB` (Motion Object Horizontal Line Buffer) had miscellaneous logic issues that needed correcting.
### More CRAM debugging
Just when the colors appeared to be OK, it became apparent that sprites like 0863 (ghost) show up with wrong colors. Investigating why an incorrect color palette is selected leads to discovering that CRA5, CRA7 outputs from 8U page 15 are stuck low because they were left unconnected and were not being driven. After connecting them to the appropriate drivers the colors now look correct. Below left is what it looked like before, right is what it looks like after the fix.
[![Color Trouble](images/SIM16.png)](images/SIM16.png)
### Debugging Motion Objects Overlap
Problem with sprite overlap, when sprites (like the ghosts) are overlapping, some minor corruption is visible, for example the shadow of the top ghost's arm is not obscuring the ghost underneath. Suspecting GPC (Graphic Priority Control) problem.
Left: how it looks, Right: how it should look.
[![Sprite Overlap](images/SIM17.png)](images/SIM17.png)
In other places there is visible corruption where extra pixels appear.
[![Sprite Corrupt](images/SIM20.png)](images/SIM20.png)
As opposed to how it looks in MAME
[![Sprite Correct](images/MAME01.png)](images/MAME01.png)
Sprite tuples for two ghosts to replicate issue
GH1 GH2
0890 0890
0202 0002
F392 F392
0001 0000
CRAM address comes from 12M GPC Graphic Priority Control output. This is not a `GPC` problem, need to check `MOHLB`
Exclude PF without recompiling simulation with following command:
isim force add {/tb\_fpga\_gauntlet/uut/gauntlet\_inst/video\_inst/p\_12M/i\_p} 80 -radix hex
<pre>
MPX to IRGB Sprite value mapping
D7 -> 8FFF Ghost arm light gray
D8 -> 6FFF Ghost arm medium gray
D9 -> 6FFF Ghost arm medium gray
DA -> 5EEF Ghost arm darker gray
DE -> 8C63 Ghost shadow brown
FF -> Seethrough
</pre>
`MOSR` bus input to `MOHLB` for ghost sprite, FF means transparent otherwise top 4 bits are D (1101) and select the palette, bottom 4 bits select the sprite color within the selected palette. Squinting, you can almost see the ghost pattern in the data below
<pre>
FF FF FF FF DE FF FF FF FF FF FF FF FF FF FF FF FF FF FF DE FF FF FF FF
FF FF FF DE DE FF FF FF FF FF FF FF FF FF FF FF FF FF FF DE DE FF FF FF
FF FF FF DE DE FF FF FF FF FF FF FF FF FF FF FF FF FF FF DE DE FF FF FF
FF D9 FF DE DE FF FF FF FF FF FF FF FF FF FF FF D9 FF FF DE DE FF FF FF
D8 D9 FF DE DE FF FF FF FF FF FF DE DE DE FF FF D8 D9 FF DE DE FF FF FF
D7 D9 D9 DE DE DE FF FF FF FF DE DE DE DE DE D8 D7 D9 FF DE DE FF FF FF
D7 D9 FF DE DE DE DE FF FF FF DE DE DE DE DE FF D7 DA DE DE DE FF FF FF
D7 D8 FF FF DE DE DE DE D8 D7 DA DE DE DE DE FF D8 DA DE DE FF FF FF FF
D7 D8 DA FF FF DE DE D8 D7 D7 D9 DA DE DE DE DE D8 DA DE FF FF FF FF FF
D8 D7 D9 DA FF FF DE D7 D7 D7 D8 DA DE DE DE D8 D9 DA FF FF FF FF FF FF
FF D8 D7 D8 D9 DA FF D7 D7 D7 D8 DA DE DE D9 D9 DA FF FF FF FF FF FF FF
FF FF D8 D7 D8 D9 D9 D7 D7 D7 D9 DA DA D9 DA DA FF FF FF FF FF FF FF FF
FF FF FF D8 D7 D7 D8 D7 D7 D7 DA DA DA DA DA DE FF FF FF FF FF FF FF FF
FF FF FF FF D8 D7 D7 D7 D7 D9 DA DA DA DA DE DE FF FF FF FF FF FF FF FF
FF FF FF FF FF D9 D7 D7 D7 D7 D9 D9 DA DE DE DE FF FF FF FF FF FF FF FF
FF FF FF FF FF FF D8 D7 D7 D7 D8 D9 DA DE DE DE FF FF FF FF FF FF FF FF
FF FF FF FF FF FF D8 D7 D7 D7 D8 D9 DA DE DE DE FF FF FF FF FF FF FF FF
FF FF FF FF FF FF D7 D7 D7 D7 D8 D9 DA DE DE FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF D7 D7 D7 D7 D8 D9 DA DE DE FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF D8 D7 D7 D7 D8 D9 DA FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF D8 D7 D8 D9 DA DE FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF D8 D7 D9 D9 DA FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF D7 D9 FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF D8 D9 FF FF FF FF FF FF FF FF FF FF FF FF FF FF
</pre>
Since `MPX` output of MO Horizontal Line Buffer is not as expected, problem may be with `MOHLB`.
Simplistic way of how `MOHLB` works:
There are two 512B RAMs that alternately buffer a **single video line** of sprites. Focusing on just one of those buffers, if two sprites overlap, the first sprite in the linked list is written to the buffer, then the next sprite in the linked list is written to the buffer, etc. If the sprites overlap and the current value of the sprite is visible (not FF) then it overwrites the memory location (covers the pixel of the sprite below) but if the current value of the sprite is transparent (FF), then it is not written to RAM so the pixel of the sprite below remains unchanged and shows through.
<pre>
Higher Sprite Data (new data to RAM) : D7 D9 FF DE DE DE DE FF FF FF DE DE DE DE DE FF D7 DA DE DE DE FF FF FF FF
Lower Sprite Data (existing data in RAM): FF FF FF FF D7 D9 FF DE DE DE DE FF FF FF DE DE DE DE DE FF D7 DA DE DE DE
Expected RAM Data : D7 D9 FF DE DE DE DE DE DE DE DE DE DE DE DE DE D7 DA DE DE DE DA DE DE DE
Observed RAM Data : D7 D9 FF DE D7 D9 DE DE DE DE DE DE DE DE DE DE D7 DA DE DE DE DA DE DE DE
</pre>
It seems the `MOHLB` works as designed, but the data presented to it is causing it to incorrectly overwrite earlier buffered data when it shouldn't. This feels like it's a side effect of forcing sprites to appear on screen by loading sprite offset 0 with sprite data. Possibly a side effect of the issue below so putting this on ice for now until problem below is resolved.
### Debugging Motion Objects LINK register
Sprites only show when sprite LINK value at offset 0 (memory 903800) points to a valid sprite, otherwise no sprites show at all.
Visible sprites at game start:
<pre>
Ypos 15..7
HFlip 6
Xpos 15..7 XTiles 5..3
Sprite bits 14..0 Palette 3..0 YTiles 2..0 Link 9..0 (offset x2 + 902000)
90208C=097E Food1 90288C=2E01 90308C=E812 90388C=004E
90209C=0999 Chest 90289C=6E01 90309C=E812 903978=00BE
90218C=1648 Hero 90298C=2E0F 90318C=C812 90397C=00C6
90221C=096C Food2 902A1C=6E01 90321C=B812
Must latch in Must latch in Must latch in Must latch in
3C3K on rising 4N 3N on rising 5C 5K on rising 8F 8J on rising
PICTDL HORZDL VERTDL /LINK
The latch signals come from MC1, MC0 decoded by 1:4 active low selector 8T. MC1, MC0 are generated by 1H, 2H, 4H, MATCH
3 /LINK
2 VERTDL
1 HORZDL
0 PICTDL
</pre>
The problem as observed from simulation is this:
If the word at 903800 contains 0400 (as per MAME simulation of game), the LINK register is loaded with the bottom 10 bits (all zero) from that memory location and therefore when it is used as a pointer into the MO VRAM, it points to offset 0 (memory 903800) so it is loaded again with zero and so on, so the LINK register is always zeroed and never finds any sprites to display.
If however as a test, the word at memory location 903800 is initialized with a value that points to an actual sprite's offset, then that value is loaded into the LINK register and the LINK register is used as an index into the MO VRAM LINK area to retrieve the next word which is used as an index to the next sprite and so on. ISE simulator confirms this, by loading the VRAM with an exact dump of the memory from MAME, then changing location 903800 from 0400 to 0046 (so it points to the first sprite offset) then the simulation indeed proceeds to display all sprites on the screen as expected. Note that this is a hack to force the display of sprites and not normal game behaviour.
To further examine the VRAM addressing, a dump of the VRD bus is sent to a log file together with the address accessed. Analysis of the log shows that at video frame 1, line 1 time offset 574515ns the screen vertical offset appears on the bus (905F6E=0080) and in the simulator it is verified that it is indeed loaded into counters `5J`, `5F`, `4F` as expected.
A little later at 576755ns memory location 905F80 is accessed. From experiments with MAME it is apparent that during game play the memory region 905F80 onwards stores sprite index values for sprites that should appear on the screen and this is where the LINK register should be loaded from initially. Further in the log, address 905F80 appears on the `VRD` bus and has value 0046 which is the value of the index to the first valid sprite but instead of being loaded into the `LINK` register `8F`, `8J` on the rising edge of the master clock when `/LINK` is low, the simulator shows that the enable signal `/LINK` goes low just as the master clock rises, and therefore misses loading the value on the VRD bus into the LINK register. By the time the master clock rises again, the `VRD` bus has changed value. There are two possibilities, either the VRD bus is early and should be delayed or the `/LINK` signal is late and should arrive about a half a master clock earlier.
The `/LINK` signal is generated by chip `8T` when both `MC1` `MC0` are high and gate signal is low. All those signals come from register `6U` which registers them on the rising master clock. Before reaching `6U` the signals come from the outputs of GAL `7U` which is not clocked.
Further experiments in ISIM indicate that forcibly initializing the `LINK` register to 046 at the start of each horizontal line, makes the sprites appear as expected. The LINK register must be initialized not earlier than H counter = 004 and possibly as late as H counter = 1A0. Initializing LINK earlier than 004 does not display all sprites (skips the first sprite in linked list) and initializing `LINK` as late as 1A0 makes the leftmost sprites on screen appear but leaves no time for the rightmost sprites to be displayed. Once `LINK` is initialized with 046 it follows through the sprite link list from index to index until it reaches index 0 and remains there (since the game does not place sprites at index 0 and its link index points to back to itself = 0 ).
During the game's initial startup screen, sprites should be visible during lines 42-62 (3187125 ns), 103-126 (7081365 ns) and 138-157 (9315765 ns)
Gut feel at this stage is that everything works as designed and the fault may be due to `SYNGEN`. The Sync Generator custom chip is based on the discrete chip implementation from schematic SP-277 for Atari System I. The GAL chips `136032.102.e5` and `136032.103.f7` may contain equations that while suitable for System I, may have been changed or tweaked in the `SYNGEN` for Gauntlet.
Further analysing the schematic and trying to understand how sprites function, of particular note is signal `/NXL` generated by `SYNGEN`. This signal comes from GAL `136032.103.f7` which monitors the H horizontal counters and resets them when a particular count is reached, therefore when `/NXL` pulses low, it resets the H counters to zero (start of new horizontal video line). It is not totally clear how the signals `/NXL` and `/NXL*` from schematic `SP-277` correspond with Gauntlet schema `SP-284` in regards to how many master clock cycles one is delayed with respect to the other.
Furthermore on sheet 9 of Gauntlet schema, the address selector chip `7S` has a direct override controlled by `/NXL` which causes the `VAS1` line to go low when `/NXL` is pulsed low once at the start of each horizontal line.
<pre>
VRAM addressing
VAS1* VAS0* VRAM_ADDR
0 0 PF 900000-901FFF
0 1 MO 902000-903FFF
1 0 AL 904000-905FFF
1 1 - No VRAM selected
VAS1 VAS0 VRAM_ADDR_BUS
0 0 from PF V and H counters
0 1 from MC1/MC0 and LINK register
1 0 from V and H counters
1 1 from CPU address bus
</pre>
Since `VAS1` and `VAS0` directly control which one of four buses is selected to make up the video RAM address lines, this seems like a very good candidate to force a particular address on the `VRAM` bus to cause `LINK` register initialization. Of note is that a delayed and inverted version of `/NXL` disables the address selector that controls the top 6 bits of of the `VRAM` address allowing the pullups to pull high forcing a particular range of addresses for one master clock cycle.
So when `/NXL` is low it forces `VAS1` to be low, limiting the `VRAM` address selection to only two out of the four available busses. `VAS0` is then used to select one of those two buses. `VAS0` comes directly from `VAS0*` delayed one master clock and `VAS0*` is created from `1H`, `2H`, `4H` and `/NXL` by GAL `7U`, but we see from the equations of `7U` GAL that one of the terms is "`/NXL` AND `1H`", but because `/NXL` is always low when `1H` is low (they are in sync) then `/NXL` has no chance of affecting the result of that logical AND. This doesn't seem correct and in fact points to the root cause of this entire sprite problem which has taken many hours of simulation and head scratching. The `/NXL` signal is delayed one master clock cycle inside `SYNGEN` before it comes out, then delayed again by the `5T` register. This turns out to be one delay too many and by eliminating the delay inside `SYNGEN` the portion of the `/NXL` low signal lines up with the part where `1H` is high, so essentially `/NXL` can now mask `1H` and influence the output `VAS0*` which directly affects the VRAM address selection.
ISIM testing now shows that removing the `/NXL` delay inside `SYNGEN` makes the sprites appear without having to force `LINK` register loading!!! So as suspected timing of the `/NXL` signal was at the root of the problem.
Below is the initial screen at game startup from simulation. The reason the playfield on the left hand side looks a little different from MAME is because I forgot to initialize the playfield horizontal scroll register to 005 as MAME does, so the playfield is scrolled right 5 pixels compared to the MAME reference picture.
[![Simulation screen 1](images/SIM21.png)](images/SIM21.png)
Same screen from MAME for reference.
[![Reference screen 1](images/MAME02.png)](images/MAME02.png)
Another simulation of a later game screen with lots of sprites visible. Again the playfield horizontal scroll register in the simulation has a slightly different value from MAME so the screen is shifted right by some number of pixels.
[![Simulation screen 2](images/SIM22.png)](images/SIM22.png)
Compared to the same MAME screen for reference.
[![Reference screen 2](images/MAME01.png)](images/MAME01.png)
## Debugging Commands
In MAME debug mode use ***w@930000=0005*** to write new horizontal scroll offsets, or ***w@905F6E=00CB*** for vertical scroll offsets
In ISIM to write to 930000 without recompiling simulation we can place a value on `VBD` then pulse `/HSCRLD` with the following commands. .
**restart;
isim force add {/tb\_fpga\_gauntlet/uut/gauntlet\_inst/video\_inst/bus\_VBD} CB -radix hex -time 3 us -cancel 5 us;
isim force add {/tb\_fpga\_gauntlet/uut/gauntlet\_inst/video\_inst/s\_HSCRLDn} 0 -radix bin -time 3 us -cancel 4 us;
run 18ms;**
MAME debug commands to follow the sprite link list from an initial index and dump the values. Set temp0 to initial index of interest then repeat the next two command as many times as necessary
**temp0=0046**
**temp1=w@(902000+temp0\*2); temp2=w@(902800+temp0\*2); temp3=w@(903000+temp0\*2); temp4=w@(903800+temp0\*2); temp0=w@(903800+temp0\*2)&3ff**
**printf "\n%04X TILE=%04X\n%04X XPOS=%d, PSEL=%d\n%04X YPOS=%d, HSIZ=%d, VSIZ=%d\n%04X LINK=%04X (%04X)",temp1,temp1&7fff,temp2,temp2>>7,temp2&15,temp3,temp3>>7,(temp3>>3)&7,temp3&7,temp4,temp4&3ff,903800+(temp4&3ff)\*2**
### Misc
Flow of data with no CPU active should be
<pre>
+-->[VRAMS]--vrd bus-->[VROM]--ab bus-->[SLAGS]--MOSR/PFSR bus-->[PFHS]--pfx bus-->[GPC]--cra bus-->[CRAMS]--RGBI out bus-->[Video Out]
|
|
+--vra--+-(3 --) [ma12..1 CPU address]
|-(2 AL) [HV counters]<------------------------------- [SYNGEN]<--------------[CLOCK]
|-(1 MO) [mc1,mc0,lnk9..0 from vrd on /link signal]
+-(0 PF) [pfv from counters, pfh from PFHS]
^
|
+---[VS1* VS0* selectors from 7U PROM]
</pre>
When no RAMs are selected the bus `VRD` floats
## Sound Section
<pre>
========================================================================
SOUND CPU
========================================================================
0000-0FFF R/W xxxxxxxx Program RAM
4000-FFFF R xxxxxxxx Program ROM
1000 W xxxxxxxx Sound response write
1010 R xxxxxxxx Sound command read
1020 R ----xxxx Coin inputs
R ----x--- (Coin 1)
R -----x-- (Coin 2)
R ------x- (Coin 3)
R -------x (Coin 4)
1020 W xxxxxxxx Mixer control
W xxx----- (TMS5220 volume)
W ---xx--- (POKEY volume)
W -----xxx (YM2151 volume)
1030 R xxxx---- Sound status read
R x------- (Sound command buffer full)
R -x------ (Sound response buffer full)
R --x----- (TMS5220 ready)
R ---x---- (Self test)
1030 W x------- YM2151 reset
1031 W x------- TMS5220 data strobe
1032 W x------- TMS5220 reset
1033 W x------- TMS5220 frequency
1800-180F R/W xxxxxxxx POKEY communications
1810-1811 R/W xxxxxxxx YM2151 communications
1820 W xxxxxxxx TMS5220 data latch
1830 R/W -------- IRQ acknowledge
========================================================================
Interrupts:
IRQ = timed interrupt
NMI = latch on sound command
========================================================================
</pre>
<pre>
List of sounds:
0 Reset all sounds
1 Silent (Volume off)
2 Noisy (Volume on)
3 Silences sounds
4 Music Chip Test (YM)
5 Effects Chip Test (Pokey)
6 Silences sounds
7 Silences sounds
8 Speech Chip Test (TMS)
YM sounds
09-65 Misc Effects
47/48 start/stop alarm sound
49/50 start/stop alarm sound
51/52 start/stop alarm sound
53/54 start/stop alarm sound
66/67 start/stop long music
68-71 long music different tempos
72 fade out music 68-71
73 melody
Pokey sounds
74-80 effects
TMS sounds
81-220 Speech Sounds
221 pokey vol off
222 pokey vol low
223 pokey vol med
224 pokey vol high
225
</pre>
Set DIP switch to service mode and advance to sound test, then from MAINCPU, write sound command as
w@803170=51
From MAINCPU, sound CPU reset should be
w@80312E=1
w@80312E=0
breakpoint 5787 reads 1010, x contains the sound to play
When AUDIOCPU is unused and it is reset then 1030=00 so from reset address 599e the condition doesn't match and CPU is stuck in infinite loop at 59A5
When AUDIOCPU is used it is reset then 1030=80 so from reset address 599e the condition matches and it jumps to 4002, where it initializes stack and continues running
IRQ FFFE 4187
RST FFFC 599E
NMI FFFA 5729
bp 4187,1,{printf "IRQ"; g}
bp 599E,1,{printf "RST"; g}
bp 5729,1,{printf "NMI"; g}
bp 578a,1,{printf "X=%x",X; g}
Skip RAM and ROM checks, jmp 40a3
audiocpu.md@402c=ea40a34c
breakpoint after NMI on read of snd command
bp 578a
watchpoint on YM access
wps 1810,2,rw,1,{printf "%X %X",wpaddr,wpdata; g}
NMI disable
audiocpu.mb@fffa=9c
SYNGEN 7M16 in , H1 = 3M58 H2=1M78
IRQ 17.15ms
## Main CPU Section
After an 8 month break from this project, spring, summer and autumn has come and gone, it is now cold and dark, time to get some work done :) Used the TG68K softcore from MiSTer as the base for the main CPU core. Initial problem was that the softcore doesn't match the pins of the real 68K CPU, for example `/AS` is completely missing and also the timing of the `R/W` and `/UDS`, `/LDS` signals coming out of the softcore is very wide so the whole timing doesn't match a real 68K bus access. After some research, the way others deal with that is to implement a wrapper around the softcore with a state machine to create or activate the signals in such a way that it more closely resembles a 68K in timing.
With a first draft wrapper, initial success was observed in simulation as the CPU comes out of reset, fetches `SP` from address 000000 and `PC` from address 000004 then continues execution. Additinally success is observed jumping into and returning from subroutines, meaning the correct data is pushed into and popped off the stack (RAM). Also interrupts work as expected which should not be surprising since the stack is functional.
### Memory.. unused
An interesting observation, even though the schematic sheet 3 shows RAMs attached to the CPU at address 800000, they do not appear to be used. Instead the stack is initialized with 904F00 which falls in the `SPARE` video memory area which seems to be used as the CPU RAM. Tracking down a picture of a Gauntlet board, it shows places 11A, 11B, 12A, 12B fitted with empty sockets.
### CPU simulation
Observations from MAME indicate that on game powerup it is not until frame 77 that a picture starts to appear. This is far too long to simulate as it takes about 90 seconds per frame to simulate. Poking around MAME debugger it seems a good starting point is address 040000, which produces a stable game with first video picture appearing at frame 35, a saving of 42 frames (1 hour of simulation).
This is an animation of the first 2 seconds (120 frames) produced by running the simulation in ISIM for about 3 hours.
[![Game startup simulation](images/gauntlet_anim1.gif)](images/gauntlet_anim1.gif)
### What memory test?
Poking around in the debugger I discovered a bug in the original game ROMs. At game power on, as well as performing ROM checksums to ensure that the ROMs are valid, the game also performs a RAM "test", or at least it tries to.
At address 0636 is the start of a number of calls to subroutine 0A2C which is called with registers A1 and A2 initialized to the following memory ranges:
<pre>
904000-904FFE Spare video RAM
910000-9107FE Palette RAM
900000-901FFE Playfield RAM
905000-905FFE Alphanumerics RAM
902000-903FFE Motion object RAM
</pre>
The idea is that the subroutine at 0A2C will go through every memory word in the range and fill the word first with 1's (8000, C000, E000, ..., FFFC, FFFE, FFFF) then with 0's (FFFF, 7FFF, 3FFF, ..., 0003, 0001, 0000) comparing that the data read from RAM is as expected.
The problem is that in the loop that compares the current address in A0 with the end address in A2, someone inserted a write to address 803100 (watchdog reset), so this messes up the carry flag and the branch back to 0B04 is never taken.
<pre>
000B1C: B1CA cmpa.l A2, A0
000B1E: 33C0 0080 3100 move.w D0, $803100.l
000B24: 65DE bcs $b04
</pre>
This means that only the first word in each memory region is tested before the loop falls through. If you were to swap around the instructions at 0B1C and 0B1E the bug would be fixed and the entire RAM range would be tested.
### Oh MAME, how could you...
I don't have access to a real Gauntlet arcade board, so I used MAME as my reference. Imagine my surprise after I got the game going and it appeared to function fine, when I went into the game "service mode" and I see this. Some of the sprite squares on the right hand side are cut off, while in MAME they appear whole.
[![Sprites 1](images/sprites1.png)](images/sprites1.png)
Immediate assumption was "MAME is correct" so there's a bug in my implementation whereupon I proceed to embarc on a very lengthy debug session in ISIM. The problem with simulations is that they're very very slow, so anything one can do to skip unnecessary game run time in simulation can shave literally hours of simulation time. Normally the game takes 12 seconds from bootup to come up and advance 9 test screens to get to the relevant sprite test screen. It takes 2-3 hours to simulate 2 seconds of game run time. Slight problem...
The most efficient way to deal with this is spend 10-20 minutes in MAME debug mode and find a suitable patch to the ROMs that causes the game to boot up and just jump to the relevant code that displays the sprites. Then the simulation time is cut to 5 minutes as it only needs to render the first 2 or 3 frames of video. This is exactly the process here, the game ROM was patched with the following code that executes straight from reset.
<pre>
0005E2: move #$2700, SR ; disable interrupts
0005E6: movea.w #$5A36, a3 ; set parameter
0005EA: movea.w #$5A32, a4 ; set parameter
0005EE: jmp $1BD6.w ; jump to relevant sprite code
</pre>
The real game ROMs are not in fact touched, instead a small script is run every time MAME debug mode is entered that apply this patch over the ROM memory.
<pre>
maincpu.md@5E6=367C5A36
maincpu.md@5EA=387C5A32
maincpu.md@5EE=4EF81BD6
</pre>
Armed with this ROM patch the investigation began and sure enough the simulator produced the relevant video frame in only a few minutes.
[![Sprites 2](images/sprites2.png)](images/sprites2.png)
Then it was a matter of following the signals backwards starting from the video output. After identifying the video line signal where the part of the sprites was missing, that data comes out of the color palette RAMs, which are driven by the Graphics Priority Chip `GPC` which apparently also outputs incomplete data. So the `GPC` is not at fault, tracing backwards, the `GPC` is driven by the two line buffers inside the Motion Object Horizonal Line Buffer chip `MOHLB`. Because the line buffers, buffer the video signal and output it one video line later, this introduces a delay, so in the simulation traces one must look to the time period of the previous video line to find the relevant data stored in the line buffers. Turns out this data is also incomplete, so the "fault" lies before the `MOHLB` which is driven by the outputs of the video ROMs.
So the next step is to check what is driving the address bus of the video ROMs. This is where things become complicated, see sheet 10 of the schematic. There is a fairly complex piece of circuitry that involves horizontal and vertical sprite address coordinate latches that also add offsets to those coordinates via adders and generate "match" signals when a sprite position matches the current H and V position of the video counters rendering the picture. Additionally there is also circuitry on page 14 which is also related in terms of timing and control signals. Long story short, after many hours in the simulator trying to understand how sprites are rendered to the video screen, it became apparent that the "problem" was in fact on page 14.
There is a PROM chip 4R and a countdown counter 5R. The PROM chip address is driven with bits 8 though 4 of the sprite horizontal position, as well as three bits representing one of the 8 possible sprite sizes. Based on the sprite horizontal position and size, the output of the PROM loads countdown counter 5R with a certain value when signal `/NEWMO` is aserted (New Motion Object aka sprite). The counter then counts down and generates signal `/END` which terminates the display of the sprite on screen.
It was now clear in the simulation that while the first few sprites on the screen were being drawn correctly, the last two sprites (large squares) were being terminated prematurely by the `/END` signal. Inspecting the contents of the 4R PROM, it has a repeating pattern of 1,3,5,7,9,B,D,F for most of its first half and zeroes for most of the last half. Each of those values represent one of the eight possible sprite sizes, except for the least significant bit, which when set indicates that a sprite is present and must be displayed. The other top three bits are loaded into the 5R countdown counter. Each set of 8 bytes in the PROM represent a 16 pixel horizontal line offset (because only bits 8 though 4 of sprites H position drive the PROM address, so bits 3 to 0 = 16 values are not evaluated). This means that as we move from address 0 in the PROM towards higher values, this represents lower H sprite coordinates (left of the screen) moving towards higher H coordinates (right of screen).
As we arrive to the middle of the PROM (almost all the way right of the screen), the repeating pattern of of 1,3,5,7,9,B,D,F, changes to to 1,3,5,7,7,7,7,7 and then 1,3,3,3,3,3,3,3 meaning that the counter value for larger sprites is artificially reduced causing them to be cut off before being fully displayed because the 5R countdown counter is loaded with a smaller value and asserts /END earlier. Then most of the last half of the PROM has zeroes meaning that no sprites will ever be displayed after a certain H coordinate (too far right / off screen).
So after wasting many hours analyzing this, it turns out there is nothing wrong, the FPGA implementation functions correctly and it is in fact MAME that is wrong, even though it seems to display "more correct" video output. As a test I filled the PROM entirely with the 1,3,5,7,9,B,D,F pattern and run a simulation since I knew now that would cause all sprites to be fully displayed regardless of H screen coordinate value. The simulation proved it:
[![Sprites 3](images/sprites3.png)](images/sprites3.png)
Finally thanks to Colin Davies, who was kind enough to hook up his real Gauntlet arcade PCB and run a test for me, the following picture shows that the real arcade game also displays cut off sprites on the right hand side, so yeah... MAME is wrong.
[![Sprites 4](images/sprites4.png)](images/sprites4.png)
Just for completeness though, it's worth pointing out that during gameplay, the rightmost 1/4 of the screen is always taken up by text display with player stats, so no sprites will even be visible in that region of the screen, therefore this will never be a problem.

View File

@@ -0,0 +1,18 @@
# Atari Gauntlet FPGA Arcade
## About
This is an FPGA implementation of Atari's arcade game "Gauntlet" from 1985, based on the SP-284 schematic circuit diagram.
[![Gauntlet Tile](doc/images/MAME00.png)](doc/images/MAME00.png)
[![Gauntlet Play](doc/images/MAME01.png)](doc/images/MAME01.png)
Here is a youtube video of the current status, click on picture below:
[![Gauntlet running on FPGA](https://img.youtube.com/vi/7A2k7wLUSUU/0.jpg)](https://www.youtube.com/watch?v=7A2k7wLUSUU)
The game is mostly functional right now, can coin up and start game, known problems are as follows:
* The TMS5220 speech synth is not implemented
* Audio mixing is not ideal, sound quality needs improvement.
* Game EPROM is implemented as RAM so game settings are lost on power off.
* Some game ROMs are stored external to FPGA, multiplexing may need improvement.
* Only player 1 controls are connected (minor).

View File

@@ -0,0 +1,510 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity AUDIO is
port(
I_MCKR : in std_logic; -- 7.14MHz
I_1H : in std_logic; -- 3.58MHz
I_2H : in std_logic; -- 1.79MHz
I_32V : in std_logic;
I_VBLANKn : in std_logic;
I_SNDNMIn : in std_logic;
I_SNDINTn : in std_logic;
I_SNDRESn : in std_logic;
I_SELFTESTn : in std_logic;
I_COIN : in std_logic_vector( 3 downto 0); -- 1L, 2, 3, 4R
I_SBD : in std_logic_vector( 7 downto 0);
O_SBD : out std_logic_vector( 7 downto 0) := (others=>'1');
O_WR68K : out std_logic;
O_RD68K : out std_logic;
O_CCTR1n : out std_logic;
O_CCTR2n : out std_logic;
O_AUDIO_L : out std_logic_vector( 7 downto 0) := (others=>'1');
O_AUDIO_R : out std_logic_vector( 7 downto 0) := (others=>'1');
-- ROMs are external
O_AP_EN : out std_logic;
O_AP_AD : out std_logic_vector(15 downto 0) := (others=>'1');
I_AP_DI : in std_logic_vector( 7 downto 0)
);
end AUDIO;
architecture RTL of AUDIO is
signal
sl_COINn,
sl_MIXn,
sl_MIXn_last,
sl_MUSICn,
sl_POKEYn,
sl_RD68kn,
sl_SBR_Wn,
sl_SBW_Rn,
sl_SIORDn,
sl_SIOWRn,
sl_SIRQACKn,
sl_SNDIRQn,
sl_SPHRDYn,
sl_SPHRESn,
sl_SPHWRRn,
sl_SPHWRn,
sl_SQUEAKn,
sl_SRDn,
sl_SWRn,
sl_VOICEn,
sl_VOICEn_last,
sl_WR68kn,
sl_YAMRESn,
sl_POKEY_cs
: std_logic := '0';
signal
sl_SYNC,
sl_MCKF,
sl_PHI2,
sl_CPU_ena,
sl_13L4,
sl_13L5,
sl_14L4,
sl_14P4,
sl_14P5,
sl_14P6,
sl_14P7,
sl_1H_last,
sl_32V_last,
sl_B02,
sl_YAMRES,
sl_ROM_CS,
sl_RAM_16M_cs,
sl_RAM_16N_cs,
sl_ROM_16R_cs,
sl_ROM_16S_cs
: std_logic := '1';
signal
sl_SWR
: std_logic_vector( 0 downto 0) := (others => '0');
signal
slv_YM_vol,
slv_PM_vol,
slv_SM_vol
: std_logic_vector( 2 downto 0) := (others => '0');
signal
sph_ctr
: std_logic_vector( 3 downto 0) := (others => '0');
signal
slv_12P,
slv_IO,
slv_16R_ROM_data,
slv_16S_ROM_data,
slv_16N_RAM_data,
slv_16M_RAM_data,
slv_SBDI,
slv_SBDO,
slv_TMS_data,
slv_YM_data,
slv_POKEY_data
: std_logic_vector( 7 downto 0) := (others => '0');
signal
s_TMS_out,
s_POK_out
: signed( 7 downto 0) := (others => '0');
signal
s_audio_TMS,
s_audio_POK,
s_audio_YML,
s_audio_YMR
: signed(11 downto 0) := (others => '0');
signal
s_chan_l,
s_chan_r
: signed(13 downto 0) := (others => '0');
signal
s_YML_out,
s_YMR_out
: std_logic_vector(15 downto 0) := (others => '0');
signal
slv_SBA
: std_logic_vector(23 downto 0) := (others => '0');
COMPONENT jt51
PORT
(
rst : IN STD_LOGIC;
clk : IN STD_LOGIC;
cen : IN STD_LOGIC;
cen_p1 : IN STD_LOGIC;
cs_n : IN STD_LOGIC;
wr_n : IN STD_LOGIC;
a0 : IN STD_LOGIC;
din : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
dout : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
ct1 : OUT STD_LOGIC;
ct2 : OUT STD_LOGIC;
irq_n : OUT STD_LOGIC;
sample : OUT STD_LOGIC;
left : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
right : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
xleft : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
xright : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
dacleft : OUT STD_LOGIC_VECTOR(15 DOWNTO 0);
dacright : OUT STD_LOGIC_VECTOR(15 DOWNTO 0)
);
END COMPONENT;
begin
O_RD68K <= sl_RD68Kn;
-- Delay CPU enable to create an artificial PHI2 clock enable, PHI1 is not used
p_cpuena : process
begin
wait until falling_edge(I_MCKR);
-- use 1H and 2H to create a short clock enable for the 7MHz master clock
sl_CPU_ena <= I_1H and (not I_2H);
sl_PHI2 <= sl_CPU_ena;
end process;
sl_MCKF <= not I_MCKR;
O_WR68K <= sl_WR68kn;
-------------
-- sheet 5 --
-------------
u_15_16L : entity work.T65
port map (
MODE => "00", -- "00" => 6502, "01" => 65C02, "10" => 65C816
Enable => sl_CPU_ena, -- clock enable to run at 1.7MHz
Abort_n => '1',
CLK => I_MCKR, -- in, system clock 7MHz
IRQ_n => sl_SNDIRQn, -- in, active low irq
NMI_n => I_SNDNMIn, -- in, active low nmi
RES_n => I_SNDRESn, -- in, active low reset
RDY => '1', -- in, ready
SO_n => '1', -- in, set overflow
DI => slv_SBDI, -- in, data
A => slv_SBA, -- out, address
DO => slv_SBDO, -- out, data
R_W_n => sl_SBR_Wn, -- out, read /write
SYNC => sl_SYNC -- out, sync
);
O_SBD <= slv_SBDO;
O_AP_EN <= (sl_CPU_ena or sl_PHI2) and sl_ROM_CS and sl_SBR_Wn; -- when reading from ROM range
O_AP_AD <= slv_SBA(15 downto 0);
-- 15P, 16K, 16L are just buffers
p_cpubus : process
begin
wait until rising_edge(I_MCKR);
if sl_PHI2 = '1' then
-- CPU input data bus mux
if sl_SBR_Wn = '1' and sl_ROM_CS = '1' then slv_SBDI <= I_AP_DI; -- @4000-FFFF
elsif sl_SRDn = '0' and sl_RAM_16M_CS = '1' then slv_SBDI <= slv_16M_RAM_data; -- @0000-07FF
elsif sl_SRDn = '0' and sl_RAM_16N_CS = '1' then slv_SBDI <= slv_16N_RAM_data; -- @0800-0FFF
elsif sl_SBR_Wn = '1' and sl_POKEYn = '0' then slv_SBDI <= slv_POKEY_data; -- @1800
elsif sl_SBR_Wn = '1' and sl_MUSICn = '0' then slv_SBDI <= slv_YM_data; -- @1810
elsif sl_SBR_Wn = '1' and sl_RD68Kn = '0' then slv_SBDI <= I_SBD; -- @1010
elsif sl_SBR_Wn = '1' and (sl_COINn = '0' or sl_SIORDn = '0') then slv_SBDI <= slv_12P; -- @1020, @1030
else slv_SBDI <= (others=>'Z'); -- FIXME
end if;
end if;
end process;
p_16N : entity work.spram
generic map (
widthad_a => 11,
width_a => 8)
port map (
address => slv_SBA(10 downto 0),
clock => sl_MCKF,-- and sl_RAM_16N_CS,
data => slv_SBDO,
wren => sl_SWR(0),
q => slv_16N_RAM_data
);
p_16M : entity work.spram
generic map (
widthad_a => 11,
width_a => 8)
port map (
address => slv_SBA(10 downto 0),
clock => sl_MCKF,-- and sl_RAM_16M_CS,
data => slv_SBDO,
wren => sl_SWR(0),
q => slv_16M_RAM_data
);
-- Xilinx Block RAMs are active high, so inverted from schematic
sl_ROM_16S_CS <= not sl_14L4; -- @8000-FFFF
sl_ROM_16R_CS <= not sl_13L5; -- @4000-7FFF
sl_RAM_16N_CS <= not sl_14P5; -- @0800-0FFF
sl_RAM_16M_CS <= not sl_14P4; -- @0000-07FF
sl_ROM_CS <= sl_ROM_16S_CS or sl_ROM_16R_CS;
-- Address Decoding
-- 14L
sl_14L4 <= ( not slv_SBA(15)); -- @8000-FFFF
-- 13L
sl_13L5 <= ( slv_SBA(15)) or ( not slv_SBA(14)); -- Y1 @4000-7FFF
sl_13L4 <= ( slv_SBA(15)) or ( slv_SBA(14)); -- Y0 @0000-3FFF
-- 14P
sl_14P7 <= sl_13L4 or ( not slv_SBA(12)) or ( not slv_SBA(11)); -- Y3 @1800-1FFF
sl_14P6 <= sl_13L4 or ( not slv_SBA(12)) or ( slv_SBA(11)); -- Y2 @1000-17FF
sl_14P5 <= sl_13L4 or ( slv_SBA(12)) or ( not slv_SBA(11)); -- Y1 @0800-0FFF
sl_14P4 <= sl_13L4 or ( slv_SBA(12)) or ( slv_SBA(11)); -- Y0 @0000-07FF
sl_SIRQACKn <= sl_14P7 or ( not slv_SBA(5)) or ( not slv_SBA(4)); -- Y3 @1830
sl_VOICEn <= sl_14P7 or ( not slv_SBA(5)) or ( slv_SBA(4)); -- Y2 @1820
sl_MUSICn <= sl_14P7 or ( slv_SBA(5)) or ( not slv_SBA(4)); -- Y1 @1810
sl_POKEYn <= sl_14P7 or ( slv_SBA(5)) or ( slv_SBA(4)); -- Y0 @1800
sl_POKEY_cs <= not sl_POKEYn;
-- 12R
sl_SIORDn <= (not sl_B02) or sl_14P6 or ( not slv_SBA(5)) or ( not slv_SBA(4) or ( not sl_SBR_Wn )); -- Y7 @1030 RD
sl_SIOWRn <= (not sl_B02) or sl_14P6 or ( not slv_SBA(5)) or ( not slv_SBA(4) or ( sl_SBR_Wn )); -- Y6 @1030 WR
sl_COINn <= (not sl_B02) or sl_14P6 or ( not slv_SBA(5)) or ( slv_SBA(4) or ( not sl_SBR_Wn )); -- Y5 @1020 RD
sl_MIXn <= (not sl_B02) or sl_14P6 or ( not slv_SBA(5)) or ( slv_SBA(4) or ( sl_SBR_Wn )); -- Y4 @1020 WR
sl_RD68Kn <= (not sl_B02) or sl_14P6 or ( slv_SBA(5)) or ( not slv_SBA(4) or ( not sl_SBR_Wn )); -- Y3 @1010 RD
-- sl_12R13 <= (not sl_B02) or sl_14P6 or ( slv_SBA(5)) or ( not slv_SBA(4) or ( sl_SBR_Wn )); -- Y2
-- sl_12R14 <= (not sl_B02) or sl_14P6 or ( slv_SBA(5)) or ( slv_SBA(4) or ( not sl_SBR_Wn )); -- Y1
sl_WR68Kn <= (not sl_B02) or sl_14P6 or ( slv_SBA(5)) or ( slv_SBA(4) or ( sl_SBR_Wn )); -- Y0 @1000 WR
-- 14M F/F
p_14M : process
begin
wait until rising_edge(I_MCKR);
sl_32V_last <= I_32V;
if sl_SIRQACKn = '0' then
sl_SNDIRQn <= '1';
elsif sl_32V_last = '0' and I_32V = '1' then
sl_SNDIRQn <= not I_VBLANKn;
end if;
end process;
-- 16T/U simplified addressable latch
p_16T_U : process
begin
wait until rising_edge(sl_MCKF);
if I_SNDRESn = '0' then
sl_YAMRESn <= '0';
sl_SPHWRRn <= '0';
sl_SPHRESn <= '0';
sl_SQUEAKn <= '0';
O_CCTR1n <= '0';
O_CCTR2n <= '0';
else
if sl_SIOWRn = '0' then
case slv_SBA(2 downto 0) is
when "000" => sl_YAMRESn <= slv_SBDO(7); -- @1030
when "001" => sl_SPHWRRn <= slv_SBDO(7); -- @1031
when "010" => sl_SPHRESn <= slv_SBDO(7); -- @1032
when "011" => sl_SQUEAKn <= slv_SBDO(7); -- @1033
when "100" => O_CCTR1n <= not slv_SBDO(7); -- @1034 (inverted by Q17)
when "101" => O_CCTR2n <= not slv_SBDO(7); -- @1035 (inverted by Q18)
when others => null;
end case;
end if;
end if;
end process;
-- gate 14N
sl_SPHWRn <= sl_SPHWRRn and sl_SPHRESn;
-- gates 12S
sl_SWRn <= not (sl_B02 and sl_SBW_Rn);
sl_SRDn <= not (sl_B02 and sl_SBR_Wn);
sl_SWR(0) <= not sl_SWRn; -- inverted for Xilinx Block RAM
sl_SBW_Rn <= not sl_SBR_Wn;
sl_B02 <= sl_PHI2;
-------------
-- sheet 6 --
-------------
-- 14S counter is clocked by 1H = 3.5795MHz and provides TMS5220 clock
-- when SQUEAK is 0 counter is preset with 5, else 7 then counts up to F before being preset again
-- divide by 11 gives 325.4KHz, divide by 9 gives 397.7KHz
p_14S : process
begin
wait until rising_edge(I_MCKR);
if I_1H = '0' then
if sph_ctr = "1111" then
sph_ctr <= "01" & sl_SQUEAKn & '1';
else
sph_ctr <= sph_ctr + 1;
end if;
end if;
end process;
-- 13P
p_13P : process
begin
wait until rising_edge(I_MCKR);
sl_VOICEn_last <= sl_VOICEn;
if sl_VOICEn_last = '0' and sl_VOICEn = '1' then
slv_TMS_data <= slv_SBDO;
end if;
end process;
-- 15S latch - 3 bit volume control
p_15S : process(I_SNDRESn, I_MCKR)
begin
if I_SNDRESn = '0' then
slv_SM_vol <= "000";
slv_PM_vol <= "000";
slv_YM_vol <= "000";
elsif rising_edge(I_MCKR) then
sl_MIXn_last <= sl_MIXn;
if sl_MIXn_last = '0' and sl_MIXn = '1' then
slv_SM_vol <= slv_SBDO(7 downto 5);
slv_PM_vol <= slv_SBDO(4 downto 3) & slv_SBDO(3); -- PM0 and PM1 are connected together by R132
slv_YM_vol <= slv_SBDO(2 downto 0);
end if;
end if;
end process;
sl_YAMRES <= not sl_YAMRESn;
-- YM2151 sound
u_15R : JT51
port map(
-- inputs
rst => sl_YAMRES, -- active high reset
clk => I_1H, -- FIXME
cen => '1',
cen_p1 => I_2H,
a0 => slv_SBA(0),
wr_n => sl_SWRn,
cs_n => sl_MUSICn,
din => slv_SBDO,
-- outputs
dout => slv_YM_data,
irq_n => open,
ct1 => open,
ct2 => open,
-- Low resolution outputs (same as real chip)
sample => open, -- marks new output sample
left => open, -- std_logic_vector(15 downto 0)
right => open, -- std_logic_vector(15 downto 0)
-- Full resolution outputs
xleft => s_YML_out, -- std_logic_vector(15 downto 0)
xright => s_YMR_out, -- std_logic_vector(15 downto 0)
dacleft => open,
dacright => open
);
-- -- YM3012 DAC - not used becase YM2151 core outputs parallel sound data
-- u_15T : entity work.YM3012
-- generic map (signed_data => false)
-- port map (
-- PHI0 => clk,
-- ICL => reset,
-- SDATA => ym_sd,
-- SAM1 => ym_sam1,
-- SAM2 => ym_sam2,
-- CH1 => open,
-- Ch2 => open
-- );
-- POKEY sound (Atari custom chip 137430-001)
u_15L : entity work.POKEY
port map (
ADDR => slv_SBA(3 downto 0),
DIN => slv_SBDO,
DOUT => slv_POKEY_data,
DOUT_OE_L => open,
RW_L => sl_SBR_Wn,
CS => sl_POKEY_cs,
CS_L => '0',
AUDIO_OUT => s_POK_out,
PIN => x"00",
ENA => sl_CPU_ena,
CLK => I_MCKR
);
-- TMS5220 Voice Synthesis
u_13R : entity work.TMS5220
port map (
I_OSC => sph_ctr(2),
I_WSn => sl_SPHWRn,
I_RSn => sl_SPHRESn,
I_DATA => '1',
I_TEST => '1',
I_DBUS => slv_TMS_data,
O_DBUS => open,
O_RDYn => sl_SPHRDYn,
O_INTn => open,
O_M0 => open,
O_M1 => open,
O_ADD8 => open,
O_ADD4 => open,
O_ADD2 => open,
O_ADD1 => open,
O_ROMCLK => open,
O_T11 => open,
O_IO => open,
O_PRMOUT => open,
O_SPKR => s_TMS_out
);
-- FIXME this mixing isn't ideal, sound volume ends up too low
-- Pokey sounds OK, but YM seems a bit distorted, try and do better
p_volmux : process
begin
wait until rising_edge(I_MCKR);
-- volume control applied to signed outputs
s_audio_TMS <= signed('0' & slv_SM_vol) * signed(s_TMS_out);
s_audio_POK <= signed('0' & slv_PM_vol) * signed(s_POK_out);
s_audio_YML <= signed('0' & slv_YM_vol) * signed(s_YML_out(15 downto 8));
s_audio_YMR <= signed('0' & slv_YM_vol) * signed(s_YMR_out(15 downto 8));
-- sign extend to 14 bits and add all outputs together as signed integers
s_chan_l <= signed(s_audio_YML(11) & s_audio_YML(11) & s_audio_YML)
+ ( signed(s_audio_POK(11) & s_audio_POK(11) & s_audio_POK)
+ signed(s_audio_TMS(11) & s_audio_TMS(11) & s_audio_TMS) );
s_chan_r <= signed(s_audio_YMR(11) & s_audio_YMR(11) & s_audio_YMR)
+ ( signed(s_audio_POK(11) & s_audio_POK(11) & s_audio_POK)
+ signed(s_audio_TMS(11) & s_audio_TMS(11) & s_audio_TMS) );
-- convert output back to unsigned for DAC usage
O_AUDIO_L <= std_logic_vector(not s_chan_l(13) & s_chan_l(12 downto 6));
O_AUDIO_R <= std_logic_vector(not s_chan_r(13) & s_chan_r(12 downto 6));
end process;
-------------
-- sheet 7 --
-------------
-- 12P buffer
slv_12P <= (not I_SNDNMIn) & (not I_SNDINTn) & sl_SPHRDYn & I_SELFTESTn & I_COIN;
end RTL;

View File

@@ -0,0 +1,81 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity CRAMS is
port(
I_MCKR : in std_logic;
I_UDSn : in std_logic;
I_LDSn : in std_logic;
I_CRAMn : in std_logic;
I_BR_Wn : in std_logic;
I_CRA : in std_logic_vector( 9 downto 0);
I_DB : in std_logic_vector(15 downto 0);
O_DB : out std_logic_vector(15 downto 0)
);
end CRAMS;
architecture RTL of CRAMS is
signal
sl_CRAM_CS,
sl_CRAMWRn
: std_logic := '1';
signal
slv_CRAM_WE
: std_logic_vector(1 downto 0) := (others=>'0');
begin
------------------------
-- sheet 15 Color RAM --
------------------------
-- 9L, 9M, 10L, 10M RAM
p_9L_10L : entity work.spram--Lo
generic map (
widthad_a => 10,
width_a => 8)
port map (
address => I_CRA(9 downto 0),
clock => I_MCKR,-- and sl_CRAM_CS,
data => I_DB(7 downto 0),
wren => slv_CRAM_WE(0),
q => O_DB(7 downto 0)
);
p_9M_10M : entity work.spram--Hi
generic map (
widthad_a => 10,
width_a => 8)
port map (
address => I_CRA(9 downto 0),
clock => I_MCKR,-- and sl_CRAM_CS,
data => I_DB(15 downto 8),
wren => slv_CRAM_WE(1),
q => O_DB(15 downto 8)
);
slv_CRAM_WE <= not (
(((not I_CRAMn) and I_UDSn) or sl_CRAMWRn) &
(((not I_CRAMn) and I_LDSn) or sl_CRAMWRn)
);
-- gates 7W, 11P
sl_CRAM_CS <= not (I_UDSn and I_LDSn and (not I_CRAMn));
-- gate 7X
sl_CRAMWRn <= I_CRAMn or I_BR_Wn;
end RTL;

View File

@@ -0,0 +1,229 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
-- From: https://en.wikipedia.org/wiki/Gauntlet_(1985_video_game)
-- Developer: Atari Games
-- Publishers: Atari Games, U.S. Gold
-- Designer: Ed Logg
-- Platform: Arcade
-- Release: October 1985
-- Genres: Hack and slash, dungeon crawl
-- Mode: Single-player, 4-player multiplayer
-- Cabinet: Custom upright
-- Arcade system: Atari Gauntlet
-- CPU: Motorola 68010 @ 7.15909 MHz, MOS Technology 6502 @ 1.789772 MHz
-- Sound: Yamaha YM2151 @ 3.579545, Atari POKEY @ 1.789772 MHz, Texas Instruments TMS5220@ 650.826 kHz
-- Display: Raster, 336x240 resolution
library ieee;
use ieee.std_logic_1164.all;
--pragma translate_off
use ieee.std_logic_textio.all;
use std.textio.all;
--pragma translate_on
entity GAUNTLET is
port(
-- System Clock
I_CLK_14M : in std_logic;
I_CLK_7M : in std_logic;
-- Active high reset
I_RESET : in std_logic;
-- Player controls, active low
I_P1 : in std_logic_vector(7 downto 0);
I_P2 : in std_logic_vector(7 downto 0);
I_P3 : in std_logic_vector(7 downto 0);
I_P4 : in std_logic_vector(7 downto 0);
-- System inputs
I_SYS : in std_logic_vector(4 downto 0);
O_LEDS : out std_logic_vector(4 downto 1);
-- Audio out
O_AUDIO_L : out std_logic_vector( 7 downto 0) := (others=>'0');
O_AUDIO_R : out std_logic_vector( 7 downto 0) := (others=>'0');
-- Monitor output
O_VIDEO_I : out std_logic_vector(3 downto 0);
O_VIDEO_R : out std_logic_vector(3 downto 0);
O_VIDEO_G : out std_logic_vector(3 downto 0);
O_VIDEO_B : out std_logic_vector(3 downto 0);
O_HSYNC : out std_logic;
O_VSYNC : out std_logic;
O_CSYNC : out std_logic;
-- GFX ROMs
O_GP_EN : out std_logic := '0';
O_GP_ADDR : out std_logic_vector(15 downto 0) := (others=>'0');
I_GP_DATA : in std_logic_vector(31 downto 0) := (others=>'0');
-- Main Program ROMs
O_MP_EN : out std_logic := '0';
O_MP_ADDR : out std_logic_vector(18 downto 0) := (others=>'0');
I_MP_DATA : in std_logic_vector(15 downto 0) := (others=>'0');
-- Audio Program ROMs
O_AP_EN : out std_logic := '0';
O_AP_ADDR : out std_logic_vector(15 downto 0) := (others=>'0');
I_AP_DATA : in std_logic_vector( 7 downto 0) := (others=>'0')
);
end GAUNTLET;
architecture RTL of GAUNTLET is
signal
sl_1H,
sl_2H,
sl_32V,
sl_R_Wn,
sl_LDSn,
sl_UDSn,
sl_VCPU,
sl_SNDNMIn,
sl_SNDINTn,
sl_SNDRESn,
sl_CRAMn,
sl_VBUSn,
sl_VRAMn,
sl_MBUSn,
sl_VRDTACK,
sl_VBLANKn,
sl_VBKACKn,
sl_VBKINTn,
sl_HSCRLDn
: std_logic := '1';
signal sl_WR68K : std_logic := '0';
signal sl_RD68K : std_logic := '0';
signal
slv_SBDI,
slv_SBDO
: std_logic_vector( 7 downto 0) := (others=>'0');
signal
slv_addr
: std_logic_vector(14 downto 1) := (others=>'0');
signal
slv_vdata,
slv_data
: std_logic_vector(15 downto 0) := (others=>'0');
begin
u_main : entity work.MAIN
port map (
I_MCKR => I_CLK_7M,
I_XCKR => I_CLK_14M,
I_RESET => I_RESET,
I_VBLANKn => sl_VBLANKn,
I_VBKINTn => sl_VBKINTn,
I_VCPU => sl_VCPU,
I_WR68K => sl_WR68K,
I_RD68K => sl_RD68K,
I_SBD => slv_SBDO,
I_DATA => slv_vdata,
I_SELFTESTn => I_SYS(4),
I_P1 => I_P1,
I_P2 => I_P2,
I_P3 => I_P3,
I_P4 => I_P4,
O_HSCRLDn => sl_HSCRLDn,
O_SNDNMIn => sl_SNDNMIn,
O_SNDINTn => sl_SNDINTn,
O_SNDRESn => sl_SNDRESn,
O_CRAMn => sl_CRAMn,
O_VRAMn => sl_VRAMn,
O_VBUSn => sl_VBUSn,
O_VRDTACK => sl_VRDTACK,
O_VBKACKn => sl_VBKACKn,
O_R_Wn => sl_R_Wn,
O_LDSn => sl_LDSn,
O_UDSn => sl_UDSn,
O_LEDS => O_LEDS,
O_SBD => slv_SBDI,
O_ADDR => slv_addr,
O_DATA => slv_data,
-- external CPU ROMs
O_MP_EN => O_MP_EN,
O_MP_ADDR => O_MP_ADDR,
I_MP_DATA => I_MP_DATA
);
u_video : entity work.VIDEO
port map (
I_MCKR => I_CLK_7M,
I_ADDR => slv_addr,
I_DATA => slv_data,
I_HSCRLDn => sl_HSCRLDn,
I_CRAMn => sl_CRAMn,
I_VRAMn => sl_VRAMn,
I_VBUSn => sl_VBUSn,
I_VRDTACK => sl_VRDTACK,
I_VBKACKn => sl_VBKACKn,
I_R_Wn => sl_R_Wn,
I_LDSn => sl_LDSn,
I_UDSn => sl_UDSn,
O_VCPU => sl_VCPU,
O_1H => sl_1H,
O_2H => sl_2H,
O_32V => sl_32V,
O_VBKINTn => sl_VBKINTn,
O_VBLANKn => sl_VBLANKn,
O_DATA => slv_vdata,
O_I => O_VIDEO_I,
O_R => O_VIDEO_R,
O_G => O_VIDEO_G,
O_B => O_VIDEO_B,
O_HSYNC => O_HSYNC,
O_VSYNC => O_VSYNC,
O_CSYNC => O_CSYNC,
-- external GFX ROMs
O_GP_EN => O_GP_EN,
O_GP_ADDR => O_GP_ADDR,
I_GP_DATA => I_GP_DATA
);
u_audio : entity work.AUDIO
port map (
I_MCKR => I_CLK_7M,
I_1H => sl_1H,
I_2H => sl_2H,
I_32V => sl_32V,
I_VBLANKn => sl_VBLANKn,
I_SNDNMIn => sl_SNDNMIn,
I_SNDINTn => sl_SNDINTn,
I_SNDRESn => sl_SNDRESn,
I_SELFTESTn => I_SYS(4),
I_COIN => I_SYS(3 downto 0), -- 1L, 2, 3, 4R
I_SBD => slv_SBDI,
O_SBD => slv_SBDO,
O_WR68K => sl_WR68K,
O_RD68K => sl_RD68K,
O_CCTR1n => open, -- coin counter open collector active low
O_CCTR2n => open, -- coin counter open collector active low
O_AUDIO_L => O_AUDIO_L,
O_AUDIO_R => O_AUDIO_R,
-- external audio ROMs
O_AP_EN => O_AP_EN,
O_AP_AD => O_AP_ADDR,
I_AP_DI => I_AP_DATA
);
end RTL;

View File

@@ -0,0 +1,141 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- Graphic Priority Control (Atari custom chip 137419-101)
-- This GPC was derived from System I SP-277 schematic
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity GPC is
port(
I_CK : in std_logic; -- MCKR
I_PFM : in std_logic; -- PFSC/MO
I_4H : in std_logic; -- 4H
I_SEL : in std_logic; -- /CRAM
I_AL : in std_logic_vector(1 downto 0); -- APIX
I_MA : in std_logic_vector(1 downto 0); -- MA9, MA10
I_D : in std_logic_vector(3 downto 0); -- VRD
I_P : in std_logic_vector(7 downto 0); -- PFX
I_M : in std_logic_vector(7 downto 0); -- MPX
O_CA : out std_logic_vector(9 downto 0) -- CRA
);
end GPC;
architecture RTL of GPC is
signal
sl_gate,
sl_3C6,
sl_3F2,
sl_1C12,
sl_4HD,
sl_3H
: std_logic := '1';
signal
PROM_3E_data,
slv_CRAS,
slv_hcnt
: std_logic_vector(1 downto 0) := (others=>'1');
signal
slv_ALC
: std_logic_vector(2 downto 0) := (others=>'1');
signal
slv_3H
: std_logic_vector(3 downto 0) := (others=>'1');
signal
slv_9D
: std_logic_vector(7 downto 0) := (others=>'1');
begin
-- 8D tristate buffers
O_CA <= I_MA & "ZZZZZZZZ" when I_SEL = '0' else slv_CRAS & slv_9D;
-- gate 3C output 6 (PFX7..3)
sl_3C6 <= (not (I_P(7) or I_P(6) or I_P(5) or I_P(4) or I_P(3)));
-- gate 1C output 12 (MPX3..1)
sl_1C12 <= (not (I_M(3) and I_M(2) and I_M(1)));
-- when any of these are high, PROM output is all low
sl_gate <= not (sl_3F2 or I_AL(1) or I_AL(0));
-- These equations describe the PROM 3E contents,
-- top 2 data bits are the same as bottom 2 data bits as can be seen in PROM dump
PROM_3E_data(1) <= sl_gate and ((sl_3C6 and I_PFM) or (not I_M(7)) or (I_M(0) and (not sl_1C12)) );
PROM_3E_data(0) <= sl_gate and not ((sl_3C6 and I_PFM) or (((not I_M(7)) or (I_M(0))) and (not sl_1C12)) );
-- Graphic Priority Control selection
-- 3C9 3C7 4C7 4C9 7C7 7C9 6C7 6C9 case
-- GND GND GND ALC2 ALC1 ALC0 APIX1 APIX0 0
-- GND /MPX6 /MPX5 /MPX4 /MPX3 /MPX2 /MPX1 /MPX0 1
-- PFX7 PFX6 PFX5 PFX4 PFX3 PFX2 PFX1 PFX0 2
-- PFX3 PFX2 PFX1 PFX0 /MPX3 /MPX2 /MPX1 /MPX0 3
-- 9D latch
p_9D : process
begin
wait until falling_edge(I_CK);
if I_SEL = '1' then
-- 3C, 4C, 7C, 6C dual 4:1 muxes
case PROM_3E_data is
when "00" => slv_9D <= "000" & slv_ALC & I_AL;
when "01" => slv_9D <= '0' & not I_M(6 downto 0);
when "10" => slv_9D <= I_P;
when "11" => slv_9D <= I_P(3 downto 0) & not I_M(3 downto 0);
when others => slv_9D <= "11111111";
end case;
end if;
end process;
-- 3H latch
p_3H : process
begin
wait until rising_edge(I_CK);
if (sl_3H='1') and (I_4H='0') then
slv_3H <= I_D;
end if;
end process;
-- recreate part of the horizontal counter to generate the 3H signal
p_hcnt : process
begin
wait until rising_edge(I_CK);
sl_4HD <= I_4H;
if (sl_4HD='0' and I_4H='1') then
slv_hcnt<="01";
else
slv_hcnt <= slv_hcnt + 1;
end if;
end process;
sl_3H <= slv_hcnt(1) and slv_hcnt(0);
-- The old circuit built with discrete chips is gated by "/H03 = 1H nand 2H;" but LSI chip does not
-- have 1H, 2H or /H03 coming in so here we bring H03 from outside the chip
-- 3F latch
p_3F : process
begin
wait until falling_edge(I_CK);
if sl_3H='1' then
sl_3F2 <= slv_3H(3);
slv_ALC <= slv_3H(2 downto 0);
end if;
end process;
-- 1B, 5B latch
p_1B_5B : process
begin
wait until falling_edge(I_CK);
slv_CRAS <= PROM_3E_data;
end process;
end RTL;

View File

@@ -0,0 +1,309 @@
module Gauntlet_MiST(
output LED,
output [5:0] VGA_R,
output [5:0] VGA_G,
output [5:0] VGA_B,
output VGA_HS,
output VGA_VS,
output AUDIO_L,
output AUDIO_R,
input SPI_SCK,
inout SPI_DO,
input SPI_DI,
input SPI_SS2,
input SPI_SS3,
input SPI_SS4,
input CONF_DATA0,
input CLOCK_27,
output [12:0] SDRAM_A,
inout [15:0] SDRAM_DQ,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nWE,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nCS,
output [1:0] SDRAM_BA,
output SDRAM_CLK,
output SDRAM_CKE
);
`include "rtl/build_id.v"
localparam CONF_STR = {
"GAUNTLET;ROM;",
"O2,Rotate Controls,Off,On;",
"O34,Scanlines,Off,25%,50%,75%;",
"O5,Blending,Off,On;",
"O7,Service,Off,On;",
"T0,Reset;",
"V,v1.0.",`BUILD_DATE
};
wire rotate = status[2];
wire [1:0] scanlines = status[4:3];
wire blend = status[5];
wire joyswap = status[6];
wire service = status[7];
reg oneplayer;
assign LED = ~ioctl_downl;
assign SDRAM_CLK = clk_sd;
assign SDRAM_CKE = 1;
wire clk_sys, clk_14, clk_7, clk_sd;
wire pll_locked;
pll_mist pll(
.inclk0(CLOCK_27),
.areset(0),
.c0(clk_sd),//64
.c1(clk_sys),//28
.c2(clk_14),//14
.c3(clk_7),//7
.locked(pll_locked)
);
wire [31:0] status;
wire [1:0] buttons;
wire [1:0] switches;
wire [7:0] joystick_0;
wire [7:0] joystick_1;
wire scandoublerD;
wire ypbpr;
wire no_csync;
wire key_pressed;
wire [7:0] key_code;
wire key_strobe;
user_io #(
.STRLEN(($size(CONF_STR)>>3)),
.ROM_DIRECT_UPLOAD(1'b1))
user_io(
.clk_sys (clk_sys ),
.conf_str (CONF_STR ),
.SPI_CLK (SPI_SCK ),
.SPI_SS_IO (CONF_DATA0 ),
.SPI_MISO (SPI_DO ),
.SPI_MOSI (SPI_DI ),
.buttons (buttons ),
.switches (switches ),
.scandoubler_disable (scandoublerD ),
.ypbpr (ypbpr ),
.no_csync (no_csync ),
.key_strobe (key_strobe ),
.key_pressed (key_pressed ),
.key_code (key_code ),
.joystick_0 (joystick_0 ),
.joystick_1 (joystick_1 ),
.status (status )
);
wire [18:0] rom_addr;
wire [15:0] rom_do;
wire [15:0] snd_addr;
wire [15:0] snd_do;
wire [15:0] sp_addr;
wire [31:0] sp_do;
wire [24:0] sp_ioctl_addr = ioctl_addr - 20'h34000;
wire [24:0] snd_ioctl_addr = ioctl_addr - 18'h28000;
/* ROM structure
00000-27FFF CPU1 160k Program
28000-33FFF CPU2 48k Sound
34000-73FFF GFX2 256k
for now
*/
wire ioctl_downl;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [7:0] ioctl_dout;
data_io #(.ROM_DIRECT_UPLOAD(1'b1)) data_io(
.clk_sys ( clk_sys ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS2 ( SPI_SS2 ),
.SPI_SS4 ( SPI_SS4 ),
.SPI_DI ( SPI_DI ),
.SPI_DO ( SPI_DO ),
.ioctl_download( ioctl_downl ),
.ioctl_index ( ioctl_index ),
.ioctl_wr ( ioctl_wr ),
.ioctl_addr ( ioctl_addr ),
.ioctl_dout ( ioctl_dout )
);
reg port1_req, port2_req;
sdram sdram(
.*,
.init_n ( pll_locked ),
.clk ( clk_sd ),
// port1 used for main + sound CPU
.port1_req ( port1_req ),
.port1_ack ( ),
.port1_a ( ioctl_addr[23:1] ),
.port1_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ),
.port1_we ( ioctl_downl ),
.port1_d ( {ioctl_dout, ioctl_dout} ),
.port1_q ( ),
.cpu1_addr ( ioctl_downl ? 18'h3ffff : {rom_addr[18:0]} ),
.cpu1_q ( rom_do ),
.cpu2_addr ( ioctl_downl ? 18'h3ffff : snd_ioctl_addr ),
.cpu2_q ( snd_do ),
// port2 for sprite graphics
.port2_req ( port2_req ),
.port2_ack ( ),
.port2_a ( {sp_ioctl_addr[23:16], sp_ioctl_addr[13:0], sp_ioctl_addr[15]} ), // merge sprite roms to 32-bit wide words
.port2_ds ( {sp_ioctl_addr[14], ~sp_ioctl_addr[14]} ),
.port2_we ( ioctl_downl ),
.port2_d ( {ioctl_dout, ioctl_dout} ),
.port2_q ( ),
.sp_addr ( ioctl_downl ? 15'h7fff : sp_addr ),
.sp_q ( sp_do )
);
// ROM download controller
always @(posedge clk_sys) begin
reg ioctl_wr_last = 0;
ioctl_wr_last <= ioctl_wr;
if (ioctl_downl) begin
if (~ioctl_wr_last && ioctl_wr) begin
port1_req <= ~port1_req;
port2_req <= ~port2_req;
end
end
// async clock domain crossing here (clk_snd -> clk_sys)
end
// reset signal generation
reg reset = 1;
reg rom_loaded = 0;
always @(posedge clk_sys) begin
reg ioctl_downlD;
reg [15:0] reset_count;
ioctl_downlD <= ioctl_downl;
if (status[0] | buttons[1]/* ~rom_loaded*/)reset_count <= 16'hffff;
else if (reset_count != 0) reset_count <= reset_count - 1'd1;
if (ioctl_downlD & ~ioctl_downl) rom_loaded <= 1;
reset <= reset_count != 16'h0000;
end
wire [7:0] audiol, audior;
wire hs, vs, cs;
wire blankn;
wire [3:0] g,b,r;
GAUNTLET GAUNTLET(
.I_CLK_14M(clk_14),
.I_CLK_7M(clk_7),
.I_RESET(reset),
.I_P1({m_up,m_down,m_left,m_right,1'b1,1'b1,m_fireA,m_one_player}),
.I_P2(8'hFF),
.I_P3(8'hFF),
.I_P4(8'hFF),
.I_SYS({~service,m_coin1,m_coin2,1'b1,1'b1}),
.O_LEDS(),
.O_AUDIO_L(audiol),
.O_AUDIO_R(audior),
.O_VIDEO_I(),
.O_VIDEO_R(r),
.O_VIDEO_G(g),
.O_VIDEO_B(b),
.O_HSYNC(hs),
.O_VSYNC(vs),
.O_CSYNC(blankn),
// GFX ROMs
.O_GP_EN(),
.O_GP_ADDR(sp_addr),
.I_GP_DATA(sp_do),
// Main Program ROMs
.O_MP_EN(),
.O_MP_ADDR(rom_addr),
.I_MP_DATA(rom_do),
// Audio Program ROMs
.O_AP_EN(),
.O_AP_ADDR(snd_addr),
.I_AP_DATA(snd_addr[0] ? snd_do[15:8] : snd_do[7:0])
);
mist_video #(.COLOR_DEPTH(4), .SD_HCNT_WIDTH(11)) mist_video(
.clk_sys ( clk_sys ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS3 ( SPI_SS3 ),
.SPI_DI ( SPI_DI ),
.R ( blankn ? r : 0 ),
.G ( blankn ? g : 0 ),
.B ( blankn ? b : 0 ),
.HSync ( hs ),
.VSync ( vs ),
.VGA_R ( VGA_R ),
.VGA_G ( VGA_G ),
.VGA_B ( VGA_B ),
.VGA_VS ( VGA_VS ),
.VGA_HS ( VGA_HS ),
.rotate ( { 2'b10, rotate } ),
.ce_divider ( 1'b1 ),
.scandoubler_disable( scandoublerD ),
.scanlines ( scanlines ),
.blend ( blend ),
.ypbpr ( ypbpr ),
.no_csync ( no_csync )
);
dac #(
.C_bits(8))
dacl(
.clk_i(clk_sys),
.res_n_i(1),
.dac_i(audiol),
.dac_o(AUDIO_L)
);
dac #(
.C_bits(8))
dacr(
.clk_i(clk_sys),
.res_n_i(1),
.dac_i(audior),
.dac_o(AUDIO_R)
);
wire m_up, m_down, m_left, m_right, m_fireA, m_fireB, m_fireC, m_fireD, m_fireE, m_fireF;
wire m_up2, m_down2, m_left2, m_right2, m_fire2A, m_fire2B, m_fire2C, m_fire2D, m_fire2E, m_fire2F;
wire m_tilt, m_coin1, m_coin2, m_coin3, m_coin4, m_one_player, m_two_players, m_three_players, m_four_players;
arcade_inputs inputs (
.clk ( clk_sys ),
.key_strobe ( key_strobe ),
.key_pressed ( key_pressed ),
.key_code ( key_code ),
.joystick_0 ( joystick_0 ),
.joystick_1 ( joystick_1 ),
.rotate ( rotate ),
.orientation ( 2'b10 ),
.joyswap ( joyswap ),
.oneplayer ( oneplayer ),
.controls ( {m_tilt, m_coin4, m_coin3, m_coin2, m_coin1, m_four_players, m_three_players, m_two_players, m_one_player} ),
.player1 ( {m_fireF, m_fireE, m_fireD, m_fireC, m_fireB, m_fireA, m_up, m_down, m_left, m_right} ),
.player2 ( {m_fire2F, m_fire2E, m_fire2D, m_fire2C, m_fire2B, m_fire2A, m_up2, m_down2, m_left2, m_right2} )
);
endmodule

View File

@@ -0,0 +1,99 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- Line Buffer used in Motion Object Horizontal Line Buffer module
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity LINEBUF is
port(
I_MCKR : in std_logic;
I_BUFCLRn : in std_logic;
I_LDn : in std_logic;
I_FLBn : in std_logic;
I_CSn : in std_logic;
I_HPOS : in std_logic_vector(8 downto 0);
I_MOSR : in std_logic_vector(7 downto 0);
O_MPX : out std_logic_vector(7 downto 0)
);
end LINEBUF;
architecture RTL of LINEBUF is
-- type RAM_ARRAY is array (0 to 511) of std_logic_vector(7 downto 0);
-- signal RAM : RAM_ARRAY := ((others=>(others=>'1')));
-- attribute ram_style : string;
-- attribute ram_style of RAM : signal is "block";
signal
sl_CLRn,
sl_LDn,
sl_CSn
: std_logic := '1';
signal
slv_LBD
: std_logic_vector( 7 downto 0) := (others=>'1');
signal
slv_LB
: std_logic_vector( 8 downto 0) := (others=>'1');
begin
sl_CLRn <= I_FLBn or I_BUFCLRn;
sl_LDn <= I_FLBn or I_LDn;
sl_CSn <= (not I_FLBn) and I_CSn;
-- 3T, 3R, 3W, 3U, 3S, 3X counters
p_ctrs : process
begin
wait until rising_edge(I_MCKR);
if sl_CLRn = '0' then
slv_LB <= (others=>'0');
elsif sl_LDn = '0' then
slv_LB <= I_HPOS;
else
slv_LB <= slv_LB + 1;
end if;
end process;
-- 1X, 1W, 2X, 2W RAM
-- p_rams : process
-- begin
-- -- MCKR connected to /WE so RAM is written when MCKR is low
-- wait until falling_edge(I_MCKR);
-- if sl_CSn = '0' then
-- RAM(to_integer(unsigned(slv_LB))) <= slv_LBD;
-- -- 4W, 5W latches
-- O_MPX <= RAM(to_integer(unsigned(slv_LB)));
-- else
-- O_MPX <= (others=>'1');
-- end if;
-- end process;
buff : entity work.spram
generic map (
widthad_a => 9,
width_a => 8)
port map (
address => slv_LB,
clock => I_MCKR,
data => slv_LBD,
wren => not sl_CSn,--?
q => O_MPX
);
-- LBD bus mux, 4X, 5X or pullups RN1, RN2
slv_LBD <= I_MOSR when I_FLBn = '0' else (others=>'1');
end RTL;

View File

@@ -0,0 +1,50 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
library ieee;
use ieee.std_logic_1164.all;
-- simplified 74LS299 shifter as used in SLAGS
entity LS299 is
port(
I_CK : in std_logic; -- Clock
I_DATA : in std_logic_vector(7 downto 0); -- parallel input
I_SEL : in std_logic_vector(1 downto 0); -- S1 S0
I_SL : in std_logic; -- SL shift left input
I_SR : in std_logic; -- SR shift right input
O_SL : out std_logic; -- QA shift left output
O_SR : out std_logic -- QH shift right output
);
end LS299;
architecture RTL of LS299 is
signal slv_shifter : std_logic_vector(7 downto 0) := (others=>'0');
begin
O_SR <= slv_shifter(7);
O_SL <= slv_shifter(0);
-- LS299 shifter
-- datasheet labels shifter inputs ABCDEFGH corresponding to D7..D0 as connected to circuit
-- so because the bit order is reversed, then shift left/right directions are also reversed
p_shift : process
begin
wait until rising_edge(I_CK);
case I_SEL is
when "11" => slv_shifter <= I_DATA; -- load
when "10" => slv_shifter <= I_SL & slv_shifter(7 downto 1); -- left >HGFEDCB
when "01" => slv_shifter <= slv_shifter(6 downto 0) & I_SR ; -- right GFEDCBA<
when "00" => -- hold
when others => null;
end case;
end process;
end RTL;

View File

@@ -0,0 +1,625 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity MAIN is
port(
I_MCKR : in std_logic; -- 7MHz
I_XCKR : in std_logic;
I_RESET : in std_logic; -- active high
I_VBLANKn : in std_logic;
I_VBKINTn : in std_logic;
I_VCPU : in std_logic;
I_WR68K : in std_logic;
I_RD68K : in std_logic;
I_SBD : in std_logic_vector( 7 downto 0);
I_DATA : in std_logic_vector(15 downto 0);
-- active low player inputs
I_SELFTESTn : in std_logic;
I_P1 : in std_logic_vector( 7 downto 0); -- U, D, L, R, -, -, F, S
I_P2 : in std_logic_vector( 7 downto 0); -- U, D, L, R, -, -, F, S
I_P3 : in std_logic_vector( 7 downto 0); -- U, D, L, R, -, -, F, S
I_P4 : in std_logic_vector( 7 downto 0); -- U, D, L, R, -, -, F, S
O_HSCRLDn : out std_logic;
O_SNDNMIn : out std_logic;
O_SNDINTn : out std_logic;
O_SNDRESn : out std_logic;
O_CRAMn : out std_logic;
O_VRAMn : out std_logic;
O_VBUSn : out std_logic;
O_VRDTACK : out std_logic;
O_VBKACKn : out std_logic;
O_R_Wn : out std_logic;
O_LDSn : out std_logic;
O_UDSn : out std_logic;
O_LEDS : out std_logic_vector( 4 downto 1) := (others=>'0');
O_SBD : out std_logic_vector( 7 downto 0) := (others=>'0');
O_ADDR : out std_logic_vector(14 downto 1) := (others=>'0');
O_DATA : out std_logic_vector(15 downto 0) := (others=>'0');
-- external program ROMs
O_MP_EN : out std_logic;
O_MP_ADDR : out std_logic_vector(18 downto 0) := (others=>'0');
I_MP_DATA : in std_logic_vector(15 downto 0) := (others=>'0')
);
end MAIN;
architecture RTL of MAIN is
signal
sl_13L_Y0,
-- sl_13L_Y1,
sl_13L_Y2,
sl_13L_Y3,
sl_8T_Y0,
sl_8T_Y1,
-- sl_8T_Y2,
sl_8T_Y3,
sl_13M_Y0,
sl_13M_Y1,
sl_13M_Y2,
sl_13M_Y3,
sl_14K_Y0,
-- sl_14K_Y1,
sl_14K_Y2,
-- sl_14K_Y3,
sl_14K_Y4,
sl_14K_Y5,
-- sl_14K_Y6,
sl_14K_Y7,
sl_14D_Y0,
sl_14D_Y1,
sl_14D_Y2,
sl_14D_Y3,
sl_14D_Y4,
-- sl_14D_Y5,
-- sl_14D_Y6,
sl_14D_Y7,
sl_10D_Y0,
-- sl_10D_Y1,
-- sl_10D_Y2,
sl_10D_Y3,
sl_10D_Y4,
-- sl_10D_Y5,
-- sl_10D_Y6,
-- sl_10D_Y7,
sl_13N9,
sl_BAS,
sl_VCPU,
sl_SNDRDn,
sl_SNDWRn,
sl_SNDWRn_last,
sl_VBLANKn_last,
sl_VCPU_last,
sl_WR68K_last,
sl_WLn_last,
sl_SNDINTn,
sl_SNDBUF,
sl_SNDRESn,
sl_13Na_clr,
sl_UNLOCKn,
sl_LATCHn,
sl_WDOGn,
sl_INPUTn,
sl_VPA,
sl_RCO,
sl_PL4n,
sl_PL3n,
sl_PL2n,
sl_PL1n,
sl_EEP_OEn,
sl_EEP_CEn,
sl_SLAPSTK,
sl_BS0,
sl_BS1,
sl_ASn,
sl_ROM,
sl_SYSRESn,
-- sl_CPU_HALT,
sl_CPU_RESET,
sl_ROM_H_Ln,
sl_R_Wn,
-- sl_BR_Wn,
sl_BW_Rn,
sl_DTACKn,
sl_drive,
sl_LDSn,
sl_UDSn,
sl_CRAMn,
sl_VBUSn,
sl_VRAMn,
sl_VRAMn_last,
sl_MBUSn,
sl_VBKACKn,
sl_HSCRLDn
: std_logic := '1';
signal
sl_68KBUF,
sl_VRDTACK
: std_logic := '0';
signal
sl_WH,
sl_WL,
sl_WHn,
sl_WLn
: std_logic := '0';
signal
slv_BS,
slv_RAMn,
slv_RAM
: std_logic_vector( 1 downto 0) := (others=>'1');
signal
slv_FC,
slv_ROMEN,
slv_IPL
: std_logic_vector( 2 downto 0) := (others=>'1');
signal
ctr_11N,
ctr_11R
: std_logic_vector( 3 downto 0) := (others=>'0');
signal
slv_SBDI,
slv_14F,
slv_EEP_14A,
slv_11A_data,
slv_11B_data,
slv_12A_data,
slv_12B_data
: std_logic_vector( 7 downto 0) := (others=>'1');
signal
slv_cpu_di,
slv_cpu_do,
slv_VRAM_PF,
slv_VRAM_MO,
slv_VRAM_AL,
slv_CRAM,
VID_D
: std_logic_vector(15 downto 0) := (others=>'0');
signal
VID_A : std_logic_vector(18 downto 0) := (others=>'0');
signal
slv_cpu_ad
: std_logic_vector(23 downto 0) := (others=>'0');
begin
O_ADDR <= slv_cpu_ad(14 downto 1);
O_DATA <= slv_cpu_do;
O_HSCRLDn <= sl_HSCRLDn;
O_SNDNMIn <= not sl_68KBUF;
O_SNDINTn <= not sl_SNDBUF;
O_CRAMn <= sl_CRAMn;
O_VRAMn <= sl_VRAMn;
O_VBUSn <= sl_VBUSn;
O_VRDTACK <= sl_VRDTACK;
O_VBKACKn <= sl_VBKACKn;
O_R_Wn <= sl_R_Wn;
O_LDSn <= sl_LDSn;
O_UDSn <= sl_UDSn;
sl_VCPU <= I_VCPU;
----------------------------
-- sheet 2
----------------------------
-- reset circuit
-- counter counts VBLANK intervals from 8 up to 15
-- the system resets if it reaches 0 without being preset by watchdog back to 8
p_11R : process(I_RESET, I_MCKR)
begin
if I_RESET = '1' then
ctr_11R <= "0000";
elsif rising_edge(I_MCKR) then
sl_VBLANKn_last<=I_VBLANKn;
if sl_WDOGn = '0' then
ctr_11R <= "1000";
elsif sl_VBLANKn_last='1' and I_VBLANKn='0' then
ctr_11R <= ctr_11R + 1;
end if;
end if;
end process;
sl_SYSRESn <= ctr_11R(3);
-- sl_CPU_HALT <= ctr_11R(3); -- softcore CPU doesn't have HALT
sl_CPU_RESET <= sl_SYSRESn;
-- Xilinx BRAMs have positive logic
sl_WH <= not sl_WHn;
sl_WL <= not sl_WLn;
-- gates 12N, 14L
sl_WHn <= sl_UDSn or sl_R_Wn;
sl_WLn <= sl_LDSn or sl_R_Wn;
-- sl_BR_Wn <= sl_R_Wn;
sl_BW_Rn <= not sl_R_Wn;
sl_BAS <= not sl_ASn;
-- VRDTACK signal generation
p_12Ja : process
begin
wait until rising_edge(I_XCKR);
sl_VCPU_last <= sl_VCPU;
sl_VRAMn_last <= sl_VRAMn;
if sl_BAS = '0' then
sl_VRDTACK <= '0';
elsif sl_VCPU_last = '0' and sl_VCPU = '1' then
sl_VRDTACK <= not sl_VRAMn_last;
end if;
end process;
-- 11J gate
sl_VPA <= not (sl_BAS and slv_FC(2) and slv_FC(1) and slv_FC(0) );
-- 11S gate
sl_DTACKn <= not (sl_VRDTACK or sl_RCO);
-- interrupt priority
slv_IPL(2) <= I_VBKINTn and sl_SNDINTn; -- the open collectors make an AND gate
slv_IPL(1) <= sl_SNDINTn;
slv_IPL(0) <= '1';
sl_RCO <= ctr_11N(3) and ctr_11N(2) and ctr_11N(1) and ctr_11N(0) and sl_VPA;
-- busk ACK delay
p_11N : process
begin
wait until rising_edge(I_MCKR);
-- clear
if sl_BAS = '0' or sl_VRAMn = '0' then
ctr_11N <= (others=>'0');
-- load
elsif ctr_11N(3) = '0' then
ctr_11N <= '1' & '1' & sl_EEP_CEn & '1';
-- count
elsif sl_VPA = '1' and sl_DTACKn = '1' then
ctr_11N <= ctr_11N + 1;
end if;
end process;
-- 13L 2:4 decoder
sl_13L_Y3 <= sl_ASn or ( not slv_cpu_ad(23) ) or ( not slv_cpu_ad(20) );
sl_13L_Y2 <= sl_ASn or ( not slv_cpu_ad(23) ) or ( slv_cpu_ad(20) );
-- sl_13L_Y1 <= sl_ASn or ( slv_cpu_ad(23) ) or ( not slv_cpu_ad(20) ); -- unused
sl_13L_Y0 <= sl_ASn or ( slv_cpu_ad(23) ) or ( slv_cpu_ad(20) );
sl_VBUSn <= sl_13L_Y3;
sl_MBUSn <= sl_13L_Y2;
sl_ROM <= sl_13L_Y0 or sl_BW_Rn;
-- 8T 2:4 decoder, gate 7X
sl_8T_Y3 <= sl_VBUSn or ( not slv_cpu_ad(17) ) or ( not slv_cpu_ad(16) );
-- sl_8T_Y2 <= sl_VBUSn or ( not slv_cpu_ad(17) ) or ( slv_cpu_ad(16) ); -- unused
sl_8T_Y1 <= sl_VBUSn or ( slv_cpu_ad(17) ) or ( not slv_cpu_ad(16) );
sl_8T_Y0 <= sl_VBUSn or ( slv_cpu_ad(17) ) or ( slv_cpu_ad(16) );
sl_HSCRLDn <= sl_8T_Y3 or sl_WLn;
sl_CRAMn <= sl_8T_Y1;
sl_VRAMn <= sl_8T_Y0;
-- 13M 2:4 decoder
sl_13M_Y3 <= sl_MBUSn or ( not slv_cpu_ad(13) ) or ( not slv_cpu_ad(12) );
sl_13M_Y2 <= sl_MBUSn or ( not slv_cpu_ad(13) ) or ( slv_cpu_ad(12) );
sl_13M_Y1 <= sl_MBUSn or ( slv_cpu_ad(13) ) or ( not slv_cpu_ad(12) );
sl_13M_Y0 <= sl_MBUSn or ( slv_cpu_ad(13) ) or ( slv_cpu_ad(12) );
sl_EEP_CEn <= sl_13M_Y2;
slv_RAMn(1) <= sl_13M_Y1;
slv_RAMn(0) <= sl_13M_Y0;
-- Xilinx BRAMS positive logic
slv_RAM(1) <= not slv_RAMn(1);
slv_RAM(0) <= not slv_RAMn(0);
-- 14K 3:8 decoder
sl_14K_Y7 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( not slv_cpu_ad( 6) ) or ( not slv_cpu_ad( 5) ) or ( not slv_cpu_ad( 4) );
-- sl_14K_Y6 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( not slv_cpu_ad( 6) ) or ( not slv_cpu_ad( 5) ) or ( slv_cpu_ad( 4) ); -- unused
sl_14K_Y5 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( not slv_cpu_ad( 6) ) or ( slv_cpu_ad( 5) ) or ( not slv_cpu_ad( 4) );
sl_14K_Y4 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( not slv_cpu_ad( 6) ) or ( slv_cpu_ad( 5) ) or ( slv_cpu_ad( 4) );
-- sl_14K_Y3 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( slv_cpu_ad( 6) ) or ( not slv_cpu_ad( 5) ) or ( not slv_cpu_ad( 4) ); -- unused
sl_14K_Y2 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( slv_cpu_ad( 6) ) or ( not slv_cpu_ad( 5) ) or ( slv_cpu_ad( 4) );
-- sl_14K_Y1 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( slv_cpu_ad( 6) ) or ( slv_cpu_ad( 5) ) or ( not slv_cpu_ad( 4) ); -- unused
sl_14K_Y0 <= sl_13M_Y3 or sl_WLn or (not slv_cpu_ad(8)) or ( slv_cpu_ad( 6) ) or ( slv_cpu_ad( 5) ) or ( slv_cpu_ad( 4) );
sl_SNDWRn <= sl_14K_Y7;
sl_UNLOCKn <= sl_14K_Y5;
sl_VBKACKn <= sl_14K_Y4;
sl_LATCHn <= sl_14K_Y2;
sl_WDOGn <= sl_14K_Y0;
-- 14D 3:8 decoder
sl_14D_Y7 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( not slv_cpu_ad( 3) ) or ( not slv_cpu_ad( 2) ) or ( not slv_cpu_ad( 1) );
-- sl_14D_Y6 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( not slv_cpu_ad( 3) ) or ( not slv_cpu_ad( 2) ) or ( slv_cpu_ad( 1) ); -- unused
-- sl_14D_Y5 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( not slv_cpu_ad( 3) ) or ( slv_cpu_ad( 2) ) or ( not slv_cpu_ad( 1) ); -- unused
sl_14D_Y4 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( not slv_cpu_ad( 3) ) or ( slv_cpu_ad( 2) ) or ( slv_cpu_ad( 1) );
sl_14D_Y3 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( slv_cpu_ad( 3) ) or ( not slv_cpu_ad( 2) ) or ( not slv_cpu_ad( 1) );
sl_14D_Y2 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( slv_cpu_ad( 3) ) or ( not slv_cpu_ad( 2) ) or ( slv_cpu_ad( 1) );
sl_14D_Y1 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( slv_cpu_ad( 3) ) or ( slv_cpu_ad( 2) ) or ( not slv_cpu_ad( 1) );
sl_14D_Y0 <= sl_13M_Y3 or (not sl_R_Wn) or slv_cpu_ad(8) or ( slv_cpu_ad( 3) ) or ( slv_cpu_ad( 2) ) or ( slv_cpu_ad( 1) );
sl_SNDRDn <= sl_14D_Y7;
sl_INPUTn <= sl_14D_Y4;
sl_PL4n <= sl_14D_Y3;
sl_PL3n <= sl_14D_Y2;
sl_PL2n <= sl_14D_Y1;
sl_PL1n <= sl_14D_Y0;
-- 10D 3:8 decoder
-- sl_10D_Y7 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( not slv_cpu_ad(18) ) or ( not slv_cpu_ad(17) ) or ( not slv_cpu_ad(16) );
-- sl_10D_Y6 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( not slv_cpu_ad(18) ) or ( not slv_cpu_ad(17) ) or ( slv_cpu_ad(16) );
-- sl_10D_Y5 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( not slv_cpu_ad(18) ) or ( slv_cpu_ad(17) ) or ( not slv_cpu_ad(16) ); -- unused
sl_10D_Y4 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( not slv_cpu_ad(18) ) or ( slv_cpu_ad(17) ) or ( slv_cpu_ad(16) );
sl_10D_Y3 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( slv_cpu_ad(18) ) or ( not slv_cpu_ad(17) ) or ( not slv_cpu_ad(16) );
-- sl_10D_Y2 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( slv_cpu_ad(18) ) or ( not slv_cpu_ad(17) ) or ( slv_cpu_ad(16) ); -- unused
-- sl_10D_Y1 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( slv_cpu_ad(18) ) or ( slv_cpu_ad(17) ) or ( not slv_cpu_ad(16) ); -- unused
sl_10D_Y0 <= slv_cpu_ad(23) or slv_cpu_ad(22) or ( slv_cpu_ad(18) ) or ( slv_cpu_ad(17) ) or ( slv_cpu_ad(16) );
-- slv_ROMEN(4)<= sl_10D_Y7;
-- slv_ROMEN(3)<= sl_10D_Y6;
-- slv_ROMEN(2)<= sl_10D_Y5;
slv_ROMEN(1)<= sl_10D_Y4;
sl_SLAPSTK <= sl_10D_Y3;
slv_ROMEN(0)<= sl_10D_Y0;
-- Wrapper around 68010 soft core
u_12E : entity work.TG68K
port map (
-- ins
CLK => I_MCKR, -- CLK 7.1591MHz
RST => sl_CPU_RESET, -- RESET active low
-- HALT in sync with reset
-- BR tied high
-- BGACK tied high
-- BERR tied high
clkena_ext => '1',
IPL => slv_IPL, -- IPL
DTACK => sl_DTACKn, -- DTACK active low
VPA => sl_VPA, -- VPA active low
DI => slv_cpu_di, -- DATA in
-- outs
AS => sl_ASn, -- AS
UDS => sl_UDSn, -- UDS
LDS => sl_LDSn, -- LDS
WR => sl_R_Wn, -- R/W
-- E not connected
-- VMA not connected
-- BG not connected
FC => slv_FC, -- FC2..0
ADDR => slv_cpu_ad, -- ADDR
DO => slv_cpu_do, -- DATA out
--
cpusel => "01", -- CPU type selector 00->68000 01->68010 11->68020
nRSTout => open -- reset out (not used);
);
u_11A : entity work.spram
generic map (
widthad_a => 11,
width_a => 8)
port map (
address => slv_cpu_ad(11 downto 1),
clock => I_XCKR and not slv_RAM(0),
data => slv_cpu_do(15 downto 8),
wren => sl_WH,
q => slv_11A_data
);
u_11B : entity work.spram
generic map (
widthad_a => 11,
width_a => 8)
port map (
address => slv_cpu_ad(11 downto 1),
clock => I_XCKR and not slv_RAM(0),
data => slv_cpu_do( 7 downto 0),
wren => sl_WL,
q => slv_11B_data
);
u_12A : entity work.spram
generic map (
widthad_a => 11,
width_a => 8)
port map (
address => slv_cpu_ad(11 downto 1),
clock => I_XCKR and not slv_RAM(1),
data => slv_cpu_do(15 downto 8),
wren => sl_WH,
q => slv_12A_data
);
u_12B : entity work.spram
generic map (
widthad_a => 11,
width_a => 8)
port map (
address => slv_cpu_ad(11 downto 1),
clock => I_XCKR and not slv_RAM(1),
data => slv_cpu_do( 7 downto 0),
wren => sl_WL,
q => slv_12B_data
);
-- gate 14L, buffer 13C
sl_ROM_H_Ln <= not slv_cpu_ad(15);
p_12Jb : process
begin
wait until rising_edge(I_XCKR);
if I_RD68K = '0' then
sl_68KBUF <= '0';
elsif sl_SNDWRn_last = '0' and sl_SNDWRn = '1' then
sl_68KBUF <= '1';
end if;
end process;
p_13Na : process(I_MCKR, sl_UNLOCKn)
begin
if sl_UNLOCKn = '0' then
sl_13N9 <= '1';
elsif rising_edge(I_MCKR) then
sl_WLn_last <= sl_WLn;
if sl_SYSRESn = '0' then
sl_13N9 <= '0';
elsif sl_WLn_last = '0' and sl_WLn = '1' then
sl_13N9 <= '0';
end if;
end if;
end process;
-- Sound Board data latch out
p_13J : process
begin
wait until rising_edge(I_XCKR);
sl_SNDWRn_last <= sl_SNDWRn;
if sl_SNDWRn_last = '0' and sl_SNDWRn = '1' then
O_SBD <= slv_cpu_do(7 downto 0);
end if;
end process;
-- Sound Board data latch in
p_14J : process
begin
wait until rising_edge(I_XCKR);
sl_WR68K_last <= I_WR68K;
if sl_WR68K_last = '0' and I_WR68K = '1' then
slv_SBDI <= I_SBD;
end if;
end process;
p_13Nb : process
begin
wait until rising_edge(I_XCKR);
if sl_13Na_clr = '0' then
sl_SNDBUF <= '0';
elsif sl_WR68K_last = '0' and I_WR68K = '1' then
sl_SNDBUF <= '1';
end if;
end process;
sl_13Na_clr <= sl_SNDRDn and sl_SNDRESn;
sl_SNDINTn <= not sl_SNDBUF;
sl_EEP_OEn <= sl_13N9 and sl_SYSRESn;
O_SNDRESn <= sl_SNDRESn;
-- 14A simplified addressable latch
p_14A : process
begin
wait until rising_edge(I_MCKR);
if sl_SYSRESn = '0' then
sl_SNDRESn <= '0';
O_LEDS <= (others=>'0');
else
if sl_LATCHn = '0' then
case slv_cpu_ad(3 downto 1) is
when "000" => O_LEDS(1) <= slv_cpu_do(0);
when "001" => O_LEDS(2) <= slv_cpu_do(0);
when "010" => O_LEDS(3) <= slv_cpu_do(0);
when "011" => O_LEDS(4) <= slv_cpu_do(0);
when "111" => sl_SNDRESn <= slv_cpu_do(0);
when others => null;
end case;
end if;
end if;
end process;
-- 12C and 12D bidirectional buffers not required because we have separate in/out busses to CPU
----------------------------
-- sheet 4
----------------------------
p_10C : entity work.SLAPSTIC
port map (
I_CK => I_MCKR,
I_ASn => sl_ASn,
I_CSn => sl_SLAPSTK,
I_A => slv_cpu_ad(14 downto 1),
O_BS => slv_BS
);
p_EEP_14A : entity work.EEP_14A
port map (
CLK => I_XCKR,
WEn => sl_WLn,
CEn => sl_EEP_CEn,
OEn => sl_EEP_OEn,
AD => slv_cpu_ad( 9 downto 1),
DI => slv_cpu_do( 7 downto 0),
DO => slv_EEP_14A
);
-- address bus and enable for externally located program ROMs 7A, 7B, 9A, 9B, 10A, 10B
-- top 4 address bits map each ROM into external memory space
O_MP_EN <=
not (sl_ASn or sl_ROM);
O_MP_ADDR <=
x"4" & sl_ROM_H_Ln & slv_cpu_ad(14 downto 1) when sl_ROM='0' and slv_ROMEN(1)='0' else -- /ROM1 7A/B
x"5" & sl_ROM_H_Ln & slv_cpu_ad(14 downto 1) when sl_ROM='0' and slv_ROMEN(0)='0' else -- /ROM0 9A/B
x"6" & '0' & slv_BS( 1 downto 0) & slv_cpu_ad(12 downto 1) when sl_ROM='0' and sl_SLAPSTK ='0' else -- SLAP 10A/B
(others=>'0');
----------------------------
-- sheet 7
----------------------------
-- buffer 14F
slv_14F <= '0' & I_VBLANKn & sl_68KBUF & sl_SNDBUF & I_SELFTESTn & "000";
-- CPU data bus input
-- ROM=0 SLAPSTK=0 x16 data from 10A, 10B ROMs
-- ROM=0 /ROM0=0 x16 data from 9A, 9B ROMs
-- ROM=0 /ROM1=0 x16 data from 7A, 7B ROMs
-- ROM=0 /ROM2=0 x16 data from 6A, 6B ROMs
-- ROM=0 /ROM3=0 x16 data from 5A, 5B ROMs
-- ROM=0 /ROM4=0 x16 data from 3A, 3B ROMs
-- MBUS=0 R/W=1 RAM0=0 x16 data from 11A, 11B RAMs
-- MBUS=0 R/W=1 RAM1=0 x16 data from 12A, 12B RAMs
-- VBUS=0 R/W=1 x16 data from 9E, 10E VBD bus
-- MBUS=0 EEPROM=0 /WL=1 x8 data from 13/14A EEPROM
-- MBUS=0 /SNDRD=0 x8 data from 14J sound latch
-- MBUS=0 R/W=1 /PL1=0 x8 data from 14AB
-- MBUS=0 R/W=1 /PL2=0 x8 data from 14B
-- MBUS=0 R/W=1 /PL3=0 x8 data from 14C
-- MBUS=0 R/W=1 /PL4=0 x8 data from 14E
-- MBUS=0 R/W=1 /INPUT=0 x8 data from 14F
-- CPU input data bus mux
slv_cpu_di <=
I_MP_DATA when sl_ROM='0' else -- ROMs 10A/B, 9A/B, 7A/B
slv_11A_data & slv_11B_data when sl_R_Wn='1' and slv_RAM(0)='1' else -- RAMs 11A/B
slv_12A_data & slv_12B_data when sl_R_Wn='1' and slv_RAM(1)='1' else -- RAMs 12A/B
I_DATA when sl_R_Wn='1' and sl_VBUSn ='0' else -- 9E, 10E VID BUS
x"00" & slv_EEP_14A when sl_R_Wn='1' and sl_EEP_CEn='0' and sl_EEP_OEn='0' else -- EEPROM
x"00" & slv_SBDI when sl_SNDRDn ='0' else -- 14J sound latch
x"00" & I_P1 when sl_PL1n ='0' else -- 14AB
x"00" & I_P2 when sl_PL2n ='0' else -- 14B
x"00" & I_P3 when sl_PL3n ='0' else -- 14C
x"00" & I_P4 when sl_PL4n ='0' else -- 14E
x"00" & slv_14F when sl_INPUTn ='0' else -- 14F
(others=>'0');
end RTL;

View File

@@ -0,0 +1,87 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- Motion Object Horizontal Line Buffer
library ieee;
use ieee.std_logic_1164.all;
entity MOHLB is
port(
I_MCKR : in std_logic;
I_LMPDn : in std_logic;
I_LDABn : in std_logic;
I_BUFCLRn : in std_logic;
I_HPOS : in std_logic_vector(8 downto 0);
I_MOSR : in std_logic_vector(7 downto 0);
O_MPX : out std_logic_vector(7 downto 0)
);
end MOHLB;
architecture RTL of MOHLB is
signal
sl_FLBAn,
sl_FLBBn,
sl_2_3X8
: std_logic := '1';
signal
slv_MPXA,
slv_MPXB
: std_logic_vector( 7 downto 0) := (others=>'1');
begin
----------------------------------------
-- sheet 13 Motion Object Line Buffer --
----------------------------------------
-- 5S latch
p_5S : process
begin
wait until rising_edge(I_MCKR);
sl_FLBBn <= (not sl_FLBBn) xor I_BUFCLRn;
end process;
sl_FLBAn <= not sl_FLBBn;
-- gates 2/3X
sl_2_3X8 <= ( not I_LMPDn ) or ( I_MOSR(3) and I_MOSR(2) and I_MOSR(1) and I_MOSR(0) );
-- Line Buffer A
u_LBA : entity work.LINEBUF
port map (
I_MCKR => I_MCKR,
I_BUFCLRn => I_BUFCLRn,
I_LDn => I_LDABn,
I_FLBn => sl_FLBAn,
I_CSn => sl_2_3X8,
I_HPOS => I_HPOS,
I_MOSR => I_MOSR,
O_MPX => slv_MPXA
);
-- Line Buffer B
u_LBB : entity work.LINEBUF
port map (
I_MCKR => I_MCKR,
I_BUFCLRn => I_BUFCLRn,
I_LDn => I_LDABn,
I_FLBn => sl_FLBBn,
I_CSn => sl_2_3X8,
I_HPOS => I_HPOS,
I_MOSR => I_MOSR,
O_MPX => slv_MPXB
);
-- MPX bus mux
O_MPX <= slv_MPXA when sl_FLBBn = '0' else slv_MPXB;
end RTL;

View File

@@ -0,0 +1,123 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- Play Field Horizontal Scroll (Atari custom chip 137419-104)
-- This PFHS was derived from System I SP-277 schematic
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity PFHS is
port(
I_CK : in std_logic; -- MCKR
I_ST : in std_logic; -- PFHST
I_4H : in std_logic; -- 4H
I_H03 : in std_logic; -- H03
I_HS : in std_logic; -- HSCRLD
I_SPC : in std_logic; -- PFSPC
I_D : in std_logic_vector(8 downto 0); -- VBD
I_PS : in std_logic_vector(7 downto 0); -- PFSR
O_PFM : out std_logic; -- PFSC/MO
O_PFH : out std_logic_vector(5 downto 0); -- PF8H..PH256H
O_XP : out std_logic_vector(7 downto 0) -- PFX
);
end PFHS;
architecture RTL of PFHS is
type RAM_ARRAY is array (0 to 7) of std_logic_vector(7 downto 0);
signal
sl_4H_last,
sl_HS_last,
sl_SPC_last
: std_logic := '1';
signal
RAM_4M_5M_addr
: std_logic_vector(2 downto 0) := (others=>'1');
signal
slv_8E_9B
: std_logic_vector(5 downto 0) := (others=>'1');
signal
slv_4D
: std_logic_vector(7 downto 0) := (others=>'1');
signal
slv_10F,
slv_11E
: std_logic_vector(8 downto 0) := (others=>'1');
begin
O_PFH <= slv_8E_9B;
O_XP <= slv_4D;
-- 10F and 1B latches
p_10F_1B : process
begin
-- until rising edge I_HS in schema
wait until rising_edge(I_CK);
if (I_HS = '0') then
slv_10F <= I_D;
end if;
end process;
-- 11E latch
p_11E : process
begin
-- until rising edge I_SPC in schema
wait until rising_edge(I_CK);
if (I_SPC = '0') then
slv_11E <= I_D;
end if;
end process;
-- 12E 8:1 mux
O_PFM <= slv_11E(to_integer(unsigned(slv_4D(2 downto 0))));
-- two 74LS189 16x4 bit RAMs, arranged as one 16x8 RAM
-- but only 3 address lines used, so really one 8x8 RAM
-- IMPORTANT: data out is the COMPLEMENT of data in!!!
p_4M_5M : process
variable RAM : RAM_ARRAY;
attribute ram_style : string;
attribute ram_style of RAM : variable is "distributed";
begin
wait until falling_edge(I_CK);
slv_4D <= RAM(to_integer(unsigned(RAM_4M_5M_addr))); -- 4D latch
RAM(to_integer(unsigned(RAM_4M_5M_addr))) := not I_PS;
end process;
-- 6D counter
p_6D : process
begin
wait until rising_edge(I_CK);
if I_ST = '0' or RAM_4M_5M_addr = "111" then
RAM_4M_5M_addr <= slv_10F(2 downto 0);
else
RAM_4M_5M_addr <= RAM_4M_5M_addr + 1;
end if;
end process;
-- 8E, 9B counters
p_8E_9B : process
begin
-- until rising edge I_4H in schema, we use H03 to detect rising edge
wait until rising_edge(I_CK);
if I_H03 = '1' and I_4H = '0' then
if I_ST = '0' then
slv_8E_9B <= slv_10F(8 downto 3);
else
slv_8E_9B <= slv_8E_9B + 1;
end if;
end if;
end process;
end RTL;

View File

@@ -0,0 +1,560 @@
--
-- Copyright (c) MikeJ - May 2004
--
-- All rights reserved
--
-- Redistribution and use in source and synthezised forms, with or without
-- modification, are permitted provided that the following conditions are met:
--
-- Redistributions of source code must retain the above copyright notice,
-- this list of conditions and the following disclaimer.
--
-- Redistributions in synthesized form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
--
-- Neither the name of the author nor the names of other contributors may
-- be used to endorse or promote products derived from this software without
-- specific prior written permission.
--
-- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-- POSSIBILITY OF SUCH DAMAGE.
--
-- You are responsible for any legal issues arising from your use of this code.
--
-- The latest version of this file can be found at: www.fpgaarcade.com
--
-- Email support@fpgaarcade.com
--
-- Revision list
--
-- version 002 return 00 on allpot when fast scan completed to fix self test
-- version 001 initial release (this version should be considered Beta
-- it seems to make all the right sort of sounds however ... )
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity POKEY is
port (
ADDR : in std_logic_vector(3 downto 0);
DIN : in std_logic_vector(7 downto 0);
DOUT : out std_logic_vector(7 downto 0);
DOUT_OE_L : out std_logic;
RW_L : in std_logic;
CS : in std_logic; -- used as enable
CS_L : in std_logic;
--
AUDIO_OUT : out signed(7 downto 0);
--
PIN : in std_logic_vector(7 downto 0);
ENA : in std_logic;
CLK : in std_logic -- note 6 Mhz
);
end;
architecture RTL of POKEY is
type array_8x8 is array (0 to 7) of std_logic_vector(7 downto 0);
type array_4x8 is array (1 to 4) of std_logic_vector(7 downto 0);
type array_4x4 is array (1 to 4) of std_logic_vector(3 downto 0);
type array_4x9 is array (1 to 4) of std_logic_vector(8 downto 0);
type array_2x17 is array (1 to 2) of std_logic_vector(16 downto 0);
type bool_4 is array (1 to 4) of boolean;
signal we : std_logic :='0';
signal oe : std_logic :='0';
--
signal ena_64k_15k : std_logic :='0';
signal cnt_64k : std_logic_vector(4 downto 0) := (others => '0');
signal ena_64k : std_logic :='0';
signal cnt_15k : std_logic_vector(6 downto 0) := (others => '0');
signal ena_15k : std_logic :='0';
--
signal poly4 : std_logic_vector(3 downto 0) := (others => '0');
signal poly5 : std_logic_vector(4 downto 0) := (others => '0');
signal poly9 : std_logic_vector(8 downto 0) := (others => '0');
signal poly17 : std_logic_vector(16 downto 0) := (others => '0');
signal poly_17_9 : std_logic :='0';
-- registers
signal audf : array_4x8 := (others => (others => '0'));
signal audc : array_4x8 := (others => (others => '0'));
signal audctl : std_logic_vector(7 downto 0) := (others => '0');
signal stimer : std_logic_vector(7 downto 0) := (others => '0');
signal skres : std_logic_vector(7 downto 0) := (others => '0');
signal potgo : std_logic :='0';
signal serout : std_logic_vector(7 downto 0) := (others => '0');
signal irqen : std_logic_vector(7 downto 0) := (others => '0');
signal skctls : std_logic_vector(7 downto 0) := (others => '0');
signal reset : std_logic :='0';
--
signal kbcode : std_logic_vector(7 downto 0) := (others => '0');
signal random : std_logic_vector(7 downto 0) := (others => '0');
signal serin : std_logic_vector(7 downto 0) := (others => '0');
signal irqst : std_logic_vector(7 downto 0) := (others => '0');
signal skstat : std_logic_vector(7 downto 0) := (others => '0');
--
signal pot_fin : std_logic :='0';
signal pot_cnt : std_logic_vector(7 downto 0) := (others => '0');
signal pot_val : array_8x8 := (others => (others => '0'));
signal pin_reg : std_logic_vector(7 downto 0) := (others => '0');
signal pin_reg_gated : std_logic_vector(7 downto 0) := (others => '0');
--
signal chan_ena : std_logic_vector(4 downto 1) := (others => '0');
signal tone_gen_div : std_logic_vector(4 downto 1) := (others => '0');
signal tone_gen_cnt : array_4x8 := (others => (others => '0'));
signal tone_gen_div_mux : std_logic_vector(4 downto 1) := (others => '0');
signal tone_gen_zero : std_logic_vector(4 downto 1) := (others => '0');
signal tone_gen_zero_t : array_4x8 := (others => (others => '0'));
signal chan_done_load : std_logic_vector(4 downto 1) := (others => '0');
--
signal poly_sel : std_logic_vector(4 downto 1) := (others => '0');
signal poly_sel_hp : std_logic_vector(4 downto 1) := (others => '0');
signal poly_sel_hp_t1 : std_logic_vector(4 downto 1) := (others => '0');
signal poly_sel_hp_reg : std_logic_vector(4 downto 1) := (others => '0');
signal tone_gen_final : std_logic_vector(4 downto 1) := (others => '0');
begin
p_we : process(RW_L, CS_L, CS, ENA)
begin
we <= (not CS_L) and CS and (not RW_L) and ENA;
end process;
p_oe : process(RW_L, CS_L, CS)
begin
oe <= (not CS_L) and CS and RW_L;
end process;
DOUT_OE_L <= not oe;
p_ipreg : process
begin
wait until rising_edge(CLK);
pin_reg <= PIN;
end process;
p_dividers : process
begin
wait until rising_edge(CLK);
if (ENA = '1') then
ena_64k <= '0';
if cnt_64k = "00000" then
cnt_64k <= "11011"; -- 28 - 1
ena_64k <= '1';
else
cnt_64k <= cnt_64k - "1";
end if;
ena_15k <= '0';
if cnt_15k = "0000000" then
cnt_15k <= "1110001"; -- 114 - 1
ena_15k <= '1';
else
cnt_15k <= cnt_15k - "1";
end if;
end if;
end process;
p_ena_64k_15k : process(ena_64k, ena_15k, audctl)
begin
if (audctl(0) = '1') then
ena_64k_15k <= ena_15k;
else
ena_64k_15k <= ena_64k;
end if;
end process;
p_poly : process
variable poly9_zero : std_logic;
variable poly17_zero : std_logic;
begin
wait until rising_edge(CLK);
if (ENA = '1') then
poly4 <= poly4(2 downto 0) & not (poly4(3) xor poly4(2));
poly5 <= poly5(3 downto 0) & not (poly5(4) xor poly4(2)); -- used inverted
-- not correct
poly9_zero := '0';
if (poly9 = "000000000") then poly9_zero := '1'; end if;
poly9 <= poly9(7 downto 0) & (poly9(8) xor poly9(3) xor poly9_zero);
poly17_zero := '0';
if (poly17 = "00000000000000000") then poly17_zero := '1'; end if;
poly17 <= poly17(15 downto 0) & (poly17(16) xor poly17(2) xor poly17_zero);
end if;
end process;
p_random_mux : process(audctl, poly9, poly17)
begin
-- bit unnecessary this ....
for i in 0 to 7 loop
if (audctl(7) = '1') then -- 9 bit poly
random(i) <= poly9(8-i);
else
random(i) <= poly17(16-i);
end if;
end loop;
if (audctl(7) = '1') then
poly_17_9 <= poly9(8);
else
poly_17_9 <= poly17(16);
end if;
end process;
p_wdata : process
begin
wait until rising_edge(CLK);
potgo <= '0';
--if (reset = '1') then
-- no idea what the reset state is
--audf <= (others => (others => '0'));
--audc <= (others => (others => '0'));
--audctl <= x"00";
--else
if (we = '1') then
case ADDR is
when x"0" => audf(1) <= DIN;
when x"1" => audc(1) <= DIN;
when x"2" => audf(2) <= DIN;
when x"3" => audc(2) <= DIN;
when x"4" => audf(3) <= DIN;
when x"5" => audc(3) <= DIN;
when x"6" => audf(4) <= DIN;
when x"7" => audc(4) <= DIN;
when x"8" => audctl <= DIN;
when x"9" => stimer <= DIN;
when x"A" => skres <= DIN;
when x"B" => potgo <= '1';
--when x"C" =>
when x"D" => serout <= DIN;
when x"E" => irqen <= DIN;
when x"F" => skctls <= DIN;
when others => null;
end case;
end if;
--end if;
end process;
p_reset : process(skctls)
begin
-- chip in reset if bits 1..0 of skctls are both zero
reset <= '0';
if (skctls(1 downto 0) = "00") then
reset <= '1';
end if;
end process;
p_rdata : process(oe, ADDR, pot_val, pin_reg_gated, kbcode, random, serin, irqst, skstat)
begin
DOUT <= x"00";
if (oe = '1') then -- keep things quiet
case ADDR IS
when x"0" => DOUT <= pot_val(0); -- pot 0
when x"1" => DOUT <= pot_val(1); -- pot 1
when x"2" => DOUT <= pot_val(2); -- pot 2
when x"3" => DOUT <= pot_val(3); -- pot 3
when x"4" => DOUT <= pot_val(4); -- pot 4
when x"5" => DOUT <= pot_val(5); -- pot 5
when x"6" => DOUT <= pot_val(6); -- pot 6
when x"7" => DOUT <= pot_val(7); -- pot 7
when x"8" => DOUT <= pin_reg_gated;-- allpot
when x"9" => DOUT <= kbcode;
when x"A" => DOUT <= random;
when x"B" => DOUT <= x"FF";
when x"C" => DOUT <= x"FF";
when x"D" => DOUT <= serin;
when x"E" => DOUT <= irqst;
when x"F" => DOUT <= skstat;
when others => null;
end case;
end if;
end process;
-- POT ANALOGUE IN UNTESTED !!
p_pot_cnt : process
begin
wait until rising_edge(CLK);
if (potgo = '1') then
pot_cnt <= x"00";
elsif ((ena_15k = '1') or (skctls(2) = '1')) and (ENA = '1') then -- fast scan mode
pot_cnt <= pot_cnt + "1";
end if;
end process;
p_pot_comp : process
begin
wait until rising_edge(CLK);
if (reset = '1') then
pot_fin <= '1';
else
if (potgo = '1') then
pot_fin <= '0';
elsif (pot_cnt = x"E4") then -- 228
pot_fin <= '1';
end if;
end if;
end process;
p_pot_val : process
begin
wait until rising_edge(CLK);
for i in 0 to 7 loop
if (pot_fin = '0') and (pin_reg(i) = '0') then
-- continue latching counter value until input reaches ViH threshold
pot_val(i) <= pot_cnt;
end if;
end loop;
end process;
-- dump transistors
--PIN <= x"00" when (pot_fin = '1') else (others => 'Z');
p_in_gate : process(pin_reg, reset) -- dump transistor fakeup
begin
pin_reg_gated <= pin_reg;
-- I think the datasheet lies about dump transistors being disabled
-- in fast scan mode, as the self test fails ....
if (reset = '1') or (pot_fin = '1') then --and (skctls(2) = '0'))
pin_reg_gated <= x"00";
end if;
end process;
p_tone_cnt_ena : process(audctl, ena_64k_15k, tone_gen_div)
variable chan_ena1, chan_ena3 : std_ulogic;
begin
if (audctl(6) = '1') then
chan_ena1 := '1'; -- 1.5 MHz,
else
chan_ena1 := ena_64k_15k;
end if;
chan_ena(1) <= chan_ena1;
if (audctl(4) = '1') then -- chan 1/2 joined
chan_ena(2) <= chan_ena1;
else
chan_ena(2) <= ena_64k_15k;
end if;
if (audctl(5) = '1') then
chan_ena3 := '1'; -- 1.5 MHz,
else
chan_ena3 := ena_64k_15k; -- 64 KHz
end if;
chan_ena(3) <= chan_ena3;
if (audctl(3) = '1') then -- chan 3/4 joined
chan_ena(4) <= chan_ena3;
else
chan_ena(4) <= ena_64k_15k; -- 64 KHz
end if;
end process;
p_tone_generator_zero : process(tone_gen_cnt, chan_ena)
begin
for i in 1 to 4 loop
if (tone_gen_cnt(i) = "00000000") and (chan_ena(i) = '1') then
tone_gen_zero(i) <= '1';
else
tone_gen_zero(i) <= '0';
end if;
end loop;
end process;
p_tone_generators : process
variable chan_load : std_logic_vector(4 downto 1);
variable chan_dec : std_logic_vector(4 downto 1);
begin
-- quite tricky this .. but I think it does the correct stuff
-- bet this is not how is was done originally !
--
-- nasty frig to easily get exact chip behaviour in high speed mode
-- fout = fin / 2(audf + n) when n=4 or 7 in 16 bit mode
wait until rising_edge(CLK);
if (ENA = '1') then
tone_gen_div <= "0000";
if (audctl(4) = '1') then -- chan 1/2 joined
chan_load(1) := '0';
chan_load(2) := '0';
if (tone_gen_zero_t(1)(5) = '1') and (tone_gen_zero_t(2)(5) = '1') and (chan_done_load(1) = '0') then
chan_load(1) := '1';
chan_load(2) := '1';
end if;
chan_dec(1) := '1';
chan_dec(2) := tone_gen_zero(1);
else
chan_load(1) := tone_gen_zero_t(1)(2) and not chan_done_load(1);
chan_load(2) := tone_gen_zero_t(2)(2) and not chan_done_load(2);
chan_dec(1) := '1';
chan_dec(2) := '1';
end if;
if (audctl(3) = '1') then -- chan 1/2 joined
chan_load(3) := '0';
chan_load(4) := '0';
if (tone_gen_zero_t(3)(5) = '1') and (tone_gen_zero_t(4)(5) = '1') and (chan_done_load(3) = '0') then
chan_load(3) := '1';
chan_load(4) := '1';
end if;
chan_dec(3) := '1';
chan_dec(4) := tone_gen_zero(3);
else
chan_load(3) := tone_gen_zero_t(3)(2) and not chan_done_load(3);
chan_load(4) := tone_gen_zero_t(4)(2) and not chan_done_load(4);
chan_dec(3) := '1';
chan_dec(4) := '1';
end if;
for i in 1 to 4 loop
if (chan_load(i) = '1') then
chan_done_load(i) <= '1';
tone_gen_div(i) <= '1';
tone_gen_cnt(i) <= audf(i);
elsif (chan_dec(i) = '1') and (chan_ena(i) = '1') then
chan_done_load(i) <= '0';
tone_gen_cnt(i) <= tone_gen_cnt(i) - "1";
end if;
tone_gen_div(i) <= chan_load(i);
tone_gen_zero_t(i)(7 downto 0) <= tone_gen_zero_t(i)(6 downto 0) & tone_gen_zero(i);
end loop;
end if;
end process;
p_tone_generator_mux : process(audctl, tone_gen_div)
begin
if (audctl(4) = '1') then -- chan 1/2 joined
tone_gen_div_mux(1) <= tone_gen_div(1); -- do they both waggle
tone_gen_div_mux(2) <= tone_gen_div(2); -- or do I mute chan 1?
else
tone_gen_div_mux(1) <= tone_gen_div(1);
tone_gen_div_mux(2) <= tone_gen_div(2);
end if;
if (audctl(3) = '1') then -- chan 3/4 joined
tone_gen_div_mux(3) <= tone_gen_div(3); -- ditto
tone_gen_div_mux(4) <= tone_gen_div(4);
else
tone_gen_div_mux(3) <= tone_gen_div(3);
tone_gen_div_mux(4) <= tone_gen_div(4);
end if;
end process;
p_poly_gating : process(audc, poly4, poly5, poly_17_9, tone_gen_div_mux)
variable filter_a : std_logic_vector(4 downto 1);
variable filter_b : std_logic_vector(4 downto 1);
begin
for i in 1 to 4 loop
if (audc(i)(7) = '0') then
filter_a(i) := poly5(4) and tone_gen_div_mux(i);-- 5 bit poly
else
filter_a(i) := tone_gen_div_mux(i);
end if;
if (audc(i)(6) = '0') then
filter_b(i) := poly_17_9 and filter_a(i);-- 17 bit poly
else
filter_b(i) := poly4(3) and filter_a(i);-- 4 bit poly
end if;
if (audc(i)(5) = '0') then
poly_sel(i) <= filter_b(i);
else
poly_sel(i) <= filter_a(i);
end if;
end loop;
end process;
p_high_pass_filters : process(audctl, poly_sel, poly_sel_hp_reg)
begin
poly_sel_hp <= poly_sel;
if (audctl(2) = '1') then
poly_sel_hp(1) <= poly_sel(1) xor poly_sel_hp_reg(1);
end if;
if (audctl(1) = '1') then
poly_sel_hp(2) <= poly_sel(2) xor poly_sel_hp_reg(2);
end if;
end process;
p_audio_out : process
begin
wait until rising_edge(CLK);
if (ENA = '1') then
for i in 1 to 4 loop
-- filter reg
if (tone_gen_div(3) = '1') then -- tone gen 1 clocked by gen 3
poly_sel_hp_reg(1) <= poly_sel(1);
end if;
if (tone_gen_div(4) = '1') then -- tone gen 2 clocked by gen 4
poly_sel_hp_reg(2) <= poly_sel(2);
end if;
poly_sel_hp_t1 <= poly_sel_hp;
if (poly_sel_hp(i) = '1') and (poly_sel_hp_t1(i) = '0') then -- rising edge
tone_gen_final(i) <= not tone_gen_final(i);
end if;
end loop;
end if;
end process;
p_op_mixer : process
variable vol : array_4x4;
variable sum12 : std_logic_vector(4 downto 0);
variable sum34 : std_logic_vector(4 downto 0);
variable sum : std_logic_vector(5 downto 0);
begin
wait until rising_edge(CLK);
if (ENA = '1') then
for i in 1 to 4 loop
if (audc(i)(4) = '1') then -- vol only
vol(i) := audc(i)(3 downto 0);
else
if (tone_gen_final(i) = '1') then
vol(i) := audc(i)(3 downto 0);
else
vol(i) := "0000";
end if;
end if;
end loop;
sum12 := ('0' & vol(1)) + ('0' & vol(2));
sum34 := ('0' & vol(3)) + ('0' & vol(4));
sum := ('0' & sum12) + ('0' & sum34);
if (reset = '1') then
AUDIO_OUT <= (others=>'0');
else
if (sum(5) = '1') then
-- clip to max
AUDIO_OUT <= x"7F";
else
-- signed output
AUDIO_OUT <= signed((sum(4 downto 0) & "000") - x"80");
end if;
end if;
end if;
end process;
-- keyboard / serial etc to do
end architecture RTL;

View File

@@ -0,0 +1,135 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- Storage/Logic Array Graphics Shifter (Atari custom chip 137415-101)
-- This SLAGS was derived from Marble Madness SP-276 schematic
library ieee;
use ieee.std_logic_1164.all;
entity SLAGS is
port(
I_PHIN : in std_logic; -- RCLOCK
I_A : in std_logic_vector(7 downto 0);
I_B : in std_logic_vector(7 downto 0);
I_HLDAn : in std_logic; -- /HOLDA
I_HLDBn : in std_logic; -- /HOLDB
I_FLP : in std_logic; -- MGHF
I_MO_PFn : in std_logic; -- MO/ /PF
I_LDn : in std_logic; -- /GLD
O_PFDA : out std_logic; -- PFSR Play Field Shift Register
O_PFDB : out std_logic; -- PFSR Play Field Shift Register
O_MODA : out std_logic; -- MOSR Motion Object Shift Register
O_MODB : out std_logic -- MOSR Motion Object Shift Register
);
end SLAGS;
architecture RTL of SLAGS is
signal
sl_MOFDA,
sl_MOSDA,
sl_MOFDB,
sl_MOSDB,
sl_PFFDA,
sl_PFSDA,
sl_PFFDB,
sl_PFSDB,
sl_LDMOn,
sl_LDPFn,
sl_MOFLP,
sl_MO_HLDAn,
sl_MO_HLDBn,
sl_PFFLP,
sl_PF_HLDAn,
sl_PF_HLDBn
: std_logic := '1';
signal
slv_1B_4B,
slv_1A_5B,
sel_MOSA,
sel_MOSB,
sel_PFSA,
sel_PFSB,
slv_2A,
slv_2B,
slv_3A,
slv_3B
: std_logic_vector(1 downto 0) := (others=>'1');
begin
-- gates 6B, 12A - shifter controls MO /PF
sl_LDPFn <= I_LDn or ( I_MO_PFn);
sl_LDMOn <= I_LDn or (not I_MO_PFn);
-- latch 8B
p_8B : process
begin
wait until rising_edge(I_PHIN);
if sl_LDPFn = '0' then
sl_PFFLP <= I_FLP;
sl_PF_HLDAn <= I_HLDAn;
sl_PF_HLDBn <= I_HLDBn;
end if;
end process;
-- latch 11A
p_11A : process
begin
wait until rising_edge(I_PHIN);
if sl_LDMOn = '0' then
sl_MOFLP <= I_FLP;
sl_MO_HLDAn <= I_HLDAn;
sl_MO_HLDBn <= I_HLDBn;
end if;
end process;
-- shift register select signals
sel_MOSB(0) <= not (sl_LDMOn and not (sl_MO_HLDBn and (not sl_MOFLP)));
sel_MOSB(1) <= not (sl_LDMOn and not (sl_MO_HLDBn and ( sl_MOFLP)));
sel_MOSA(0) <= not (sl_LDMOn and not (sl_MO_HLDAn and (not sl_MOFLP)));
sel_MOSA(1) <= not (sl_LDMOn and not (sl_MO_HLDAn and ( sl_MOFLP)));
sel_PFSB(0) <= not (sl_LDPFn and not (sl_PF_HLDBn and (not sl_PFFLP)));
sel_PFSB(1) <= not (sl_LDPFn and not (sl_PF_HLDBn and ( sl_PFFLP)));
sel_PFSA(0) <= not (sl_LDPFn and not (sl_PF_HLDAn and (not sl_PFFLP)));
sel_PFSA(1) <= not (sl_LDPFn and not (sl_PF_HLDAn and ( sl_PFFLP)));
-- LS299 shifters
u_MOSB : entity work.LS299 port map ( I_CK=>I_PHIN, I_DATA=>I_B, I_SL=>'0', I_SR=>'0', I_SEL=>sel_MOSB, O_SL=>sl_MOFDB, O_SR=>sl_MOSDB );
u_MOSA : entity work.LS299 port map ( I_CK=>I_PHIN, I_DATA=>I_A, I_SL=>'0', I_SR=>'0', I_SEL=>sel_MOSA, O_SL=>sl_MOFDA, O_SR=>sl_MOSDA );
u_PFSB : entity work.LS299 port map ( I_CK=>I_PHIN, I_DATA=>I_B, I_SL=>'0', I_SR=>'0', I_SEL=>sel_PFSB, O_SL=>sl_PFFDB, O_SR=>sl_PFSDB );
u_PFSA : entity work.LS299 port map ( I_CK=>I_PHIN, I_DATA=>I_A, I_SL=>'0', I_SR=>'0', I_SEL=>sel_PFSA, O_SL=>sl_PFFDA, O_SR=>sl_PFSDA );
-- selectors 1A, 1B, 4B, 5B 0=A 1=B
-- selects left or right shifter outputs based on FLP
slv_1B_4B <= sl_PFFDB & sl_PFFDA when sl_PFFLP = '1' else sl_PFSDB & sl_PFSDA;
slv_1A_5B <= sl_MOFDB & sl_MOFDA when sl_MOFLP = '1' else sl_MOSDB & sl_MOSDA;
-- latches 2A, 2B, 3A, 3B
-- 2 clock cycle delay line
p_2A_2B_3A_3B : process
begin
wait until rising_edge(I_PHIN);
slv_3B <= slv_1B_4B;
slv_3A <= slv_3B;
slv_2B <= slv_1A_5B;
slv_2A <= slv_2B;
end process;
-- outputs
O_MODB <= slv_2A(1);
O_MODA <= slv_2A(0);
O_PFDB <= slv_3A(1);
O_PFDA <= slv_3A(0);
end RTL;

View File

@@ -0,0 +1,780 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- SLAPSTIC 137412-104 GAUNTLET
-- This SLAPSTIC was translated from MAME "slapstic.cpp" source code pretty much verbatim :)
-- The original MAME C++ code is left in as comments
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity SLAPSTIC is
generic (
chip_type : integer range 100 to 118 := 104 -- see generate statements below to select correct type
);
port(
I_CK : in std_logic;
I_ASn : in std_logic;
I_CSn : in std_logic;
I_A : in std_logic_vector(13 downto 0);
O_BS : out std_logic_vector( 1 downto 0)
);
end SLAPSTIC;
architecture RTL of SLAPSTIC is
signal slv_BS : std_logic_vector( 1 downto 0) := (others=>'0');
type slap_sm is (DIS, ENA, ALT1, ALT2, ALT3, BIT1, BIT2, BIT3, ADD1, ADD2, ADD3);
signal state : slap_sm;
signal sl_ASn_last : std_logic:='0';
signal additive : std_logic:='0';
signal bitwise : std_logic:='0';
signal addr : std_logic_vector(15 downto 0) := (others=>'0');
signal ini_bank : std_logic_vector( 1 downto 0) := (others=>'0');
signal cur_bank : std_logic_vector( 1 downto 0) := (others=>'1');
signal alt_bank : std_logic_vector( 1 downto 0) := (others=>'0');
signal bit_bank : std_logic_vector( 1 downto 0) := (others=>'0');
signal bit_xor : std_logic_vector( 1 downto 0) := (others=>'0');
signal add_bank : std_logic_vector( 1 downto 0) := (others=>'0');
signal val_bank0 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bank1 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bank2 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bank3 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_alt1 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_alt2 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_alt3 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_alt4 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_alt1 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_alt2 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_alt3 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_alt4 : std_logic_vector(15 downto 0) := (others=>'0');
signal altshift : natural range 0 to 3 := 0;
signal mask_bit1 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_bit2c0 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_bit2s0 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_bit2c1 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_bit2s1 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_bit3 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bit1 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bit2c0 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bit2s0 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bit2c1 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bit2s1 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_bit3 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_add1 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_add2 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_add3 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_addp1 : std_logic_vector(15 downto 0) := (others=>'0');
signal mask_addp2 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_add1 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_add2 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_add3 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_addp1 : std_logic_vector(15 downto 0) := (others=>'0');
signal val_addp2 : std_logic_vector(15 downto 0) := (others=>'0');
begin
--/* slapstic 137412-101: Empire Strikes Back/Tetris (NOT confirmed) */
--static const struct slapstic_data slapstic101 =
--{
gen_101 : if chip_type = 101 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0080"; -- { 0x0080,0x0090,0x00a0,0x00b0 },/* bank select values */
val_bank1 <= x"0090";
val_bank2 <= x"00A0";
val_bank3 <= x"00B0";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"FFFF"; -- { 0x007f,UNKNOWN }, /* 1st mask/value in sequence */
mask_alt2 <= x"1FFF"; val_alt2 <= x"1DFF"; -- { 0x1fff,0x1dff }, /* 2nd mask/value in sequence */
mask_alt3 <= x"1FFC"; val_alt3 <= x"1B5C"; -- { 0x1ffc,0x1b5c }, /* 3rd mask/value in sequence */
mask_alt4 <= x"1FCF"; val_alt4 <= x"0080"; -- { 0x1fcf,0x0080 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"1FF0"; val_bit1 <= x"1540"; -- { 0x1ff0,0x1540 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"1FF3"; val_bit2c0 <= x"1540"; -- { 0x1ff3,0x1540 }, /* clear bit 0 value */
mask_bit2s0 <= x"1FF3"; val_bit2s0 <= x"1541"; -- { 0x1ff3,0x1541 }, /* set bit 0 value */
mask_bit2c1 <= x"1FF3"; val_bit2c1 <= x"1542"; -- { 0x1ff3,0x1542 }, /* clear bit 1 value */
mask_bit2s1 <= x"1FF3"; val_bit2s1 <= x"1543"; -- { 0x1ff3,0x1543 }, /* set bit 1 value */
mask_bit3 <= x"1FF8"; val_bit3 <= x"1550"; -- { 0x1ff8,0x1550 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-103: Marble Madness (confirmed) */
--static const struct slapstic_data slapstic103 =
--{
gen_103 : if chip_type = 103 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0040"; -- { 0x0040,0x0050,0x0060,0x0070 },/* bank select values */
val_bank1 <= x"0050";
val_bank2 <= x"0060";
val_bank3 <= x"0070";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"002D"; -- { 0x007f,0x002d }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"3D14"; -- { 0x3fff,0x3d14 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"3D24"; -- { 0x3ffc,0x3d24 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FCF"; val_alt4 <= x"0040"; -- { 0x3fcf,0x0040 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"34C0"; -- { 0x3ff0,0x34c0 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"34C0"; -- { 0x3ff3,0x34c0 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"34C1"; -- { 0x3ff3,0x34c1 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"34C2"; -- { 0x3ff3,0x34c2 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"34C3"; -- { 0x3ff3,0x34c3 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"34D0"; -- { 0x3ff8,0x34d0 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-104: Gauntlet (confirmed) */
--static const struct slapstic_data slapstic104 =
--{
gen_104 : if chip_type = 104 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0020"; -- { 0x0020,0x0028,0x0030,0x0038 },/* bank select values */
val_bank1 <= x"0028";
val_bank2 <= x"0030";
val_bank3 <= x"0038";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"0069"; -- { 0x007f,0x0069 }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"3735"; -- { 0x3fff,0x3735 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"3764"; -- { 0x3ffc,0x3764 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FE7"; val_alt4 <= x"0020"; -- { 0x3fe7,0x0020 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"3D90"; -- { 0x3ff0,0x3d90 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"3D90"; -- { 0x3ff3,0x3d90 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"3D91"; -- { 0x3ff3,0x3d91 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"3D92"; -- { 0x3ff3,0x3d92 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"3D93"; -- { 0x3ff3,0x3d93 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"3DA0"; -- { 0x3ff8,0x3da0 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-105: Indiana Jones/Paperboy (confirmed) */
--static const struct slapstic_data slapstic105 =
--{
gen_105 : if chip_type = 105 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0010"; -- { 0x0010,0x0014,0x0018,0x001c },/* bank select values */
val_bank1 <= x"0014";
val_bank2 <= x"0018";
val_bank3 <= x"001C";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"003D"; -- { 0x007f,0x003d }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"0092"; -- { 0x3fff,0x0092 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"00A4"; -- { 0x3ffc,0x00a4 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FF3"; val_alt4 <= x"0010"; -- { 0x3ff3,0x0010 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"35B0"; -- { 0x3ff0,0x35b0 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"35B0"; -- { 0x3ff3,0x35b0 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"35B1"; -- { 0x3ff3,0x35b1 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"35B2"; -- { 0x3ff3,0x35b2 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"35B3"; -- { 0x3ff3,0x35b3 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"35C0"; -- { 0x3ff8,0x35c0 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-106: Gauntlet II (confirmed) */
--static const struct slapstic_data slapstic106 =
--{
gen_106 : if chip_type = 106 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0008"; -- { 0x0008,0x000a,0x000c,0x000e },/* bank select values */
val_bank1 <= x"000A";
val_bank2 <= x"000C";
val_bank3 <= x"000E";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"002B"; -- { 0x007f,0x002b }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"0052"; -- { 0x3fff,0x0052 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"0064"; -- { 0x3ffc,0x0064 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FF9"; val_alt4 <= x"0008"; -- { 0x3ff9,0x0008 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"3DA0"; -- { 0x3ff0,0x3da0 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"3DA0"; -- { 0x3ff3,0x3da0 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"3DA1"; -- { 0x3ff3,0x3da1 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"3DA2"; -- { 0x3ff3,0x3da2 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"3DA3"; -- { 0x3ff3,0x3da3 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"3DB0"; -- { 0x3ff8,0x3db0 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-107: Peter Packrat/Xybots/2p Gauntlet/720 (confirmed) */
--static const struct slapstic_data slapstic107 =
--{
gen_107 : if chip_type = 107 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0018"; -- { 0x0018,0x001a,0x001c,0x001e },/* bank select values */
val_bank1 <= x"001A";
val_bank2 <= x"001C";
val_bank3 <= x"001E";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"006B"; -- { 0x007f,0x006b }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"3D52"; -- { 0x3fff,0x3d52 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"3D64"; -- { 0x3ffc,0x3d64 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FF9"; val_alt4 <= x"0018"; -- { 0x3ff9,0x0018 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"00A0"; -- { 0x3ff0,0x00a0 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"00A0"; -- { 0x3ff3,0x00a0 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"00A1"; -- { 0x3ff3,0x00a1 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"00A2"; -- { 0x3ff3,0x00a2 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"00A3"; -- { 0x3ff3,0x00a3 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"00B0"; -- { 0x3ff8,0x00b0 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-108: Road Runner/Super Sprint (confirmed) */
--static const struct slapstic_data slapstic108 =
--{
gen_108 : if chip_type = 108 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0028"; -- { 0x0028,0x002a,0x002c,0x002e },/* bank select values */
val_bank1 <= x"002A";
val_bank2 <= x"002C";
val_bank3 <= x"002E";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"001F"; -- { 0x007f,0x001f }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"3772"; -- { 0x3fff,0x3772 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"3764"; -- { 0x3ffc,0x3764 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FF9"; val_alt4 <= x"0028"; -- { 0x3ff9,0x0028 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"0060"; -- { 0x3ff0,0x0060 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"0060"; -- { 0x3ff3,0x0060 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"0061"; -- { 0x3ff3,0x0061 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"0062"; -- { 0x3ff3,0x0062 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"0063"; -- { 0x3ff3,0x0063 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"0070"; -- { 0x3ff8,0x0070 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-109: Championship Sprint/Road Blasters (confirmed) */
--static const struct slapstic_data slapstic109 =
--{
gen_109 : if chip_type = 109 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0008"; -- { 0x0008,0x000a,0x000c,0x000e },/* bank select values */
val_bank1 <= x"000A";
val_bank2 <= x"000C";
val_bank3 <= x"000E";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"002B"; -- { 0x007f,0x002b }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"0052"; -- { 0x3fff,0x0052 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"0064"; -- { 0x3ffc,0x0064 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FF9"; val_alt4 <= x"0008"; -- { 0x3ff9,0x0008 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"3DA0"; -- { 0x3ff0,0x3da0 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"3DA0"; -- { 0x3ff3,0x3da0 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"3DA1"; -- { 0x3ff3,0x3da1 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"3DA2"; -- { 0x3ff3,0x3da2 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"3DA3"; -- { 0x3ff3,0x3da3 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"3DB0"; -- { 0x3ff8,0x3db0 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/* slapstic 137412-110: Road Blasters/APB (confirmed) */
--static const struct slapstic_data slapstic110 =
--{
gen_110 : if chip_type = 110 generate -- /* basic banking */
ini_bank <= "11"; -- 3, /* starting bank */
val_bank0 <= x"0040"; -- { 0x0040,0x0050,0x0060,0x0070 },/* bank select values */
val_bank1 <= x"0050";
val_bank2 <= x"0060";
val_bank3 <= x"0070";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"002D"; -- { 0x007f,0x002d }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"3D14"; -- { 0x3fff,0x3d14 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3FFC"; val_alt3 <= x"3D24"; -- { 0x3ffc,0x3d24 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FCF"; val_alt4 <= x"0040"; -- { 0x3fcf,0x0040 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
bitwise <= '1'; -- /* bitwise banking */
mask_bit1 <= x"3FF0"; val_bit1 <= x"34C0"; -- { 0x3ff0,0x34c0 }, /* 1st mask/value in sequence */
mask_bit2c0 <= x"3FF3"; val_bit2c0 <= x"34C0"; -- { 0x3ff3,0x34c0 }, /* clear bit 0 value */
mask_bit2s0 <= x"3FF3"; val_bit2s0 <= x"34C1"; -- { 0x3ff3,0x34c1 }, /* set bit 0 value */
mask_bit2c1 <= x"3FF3"; val_bit2c1 <= x"34C2"; -- { 0x3ff3,0x34c2 }, /* clear bit 1 value */
mask_bit2s1 <= x"3FF3"; val_bit2s1 <= x"34C3"; -- { 0x3ff3,0x34c3 }, /* set bit 1 value */
mask_bit3 <= x"3FF8"; val_bit3 <= x"34D0"; -- { 0x3ff8,0x34d0 }, /* final mask/value in sequence */
-- /* additive banking */
additive <= '0'; -- NO_ADDITIVE
end generate; --};
--/*************************************
-- *
-- * Slapstic-2 definitions
-- *
-- *************************************/
--/* slapstic 137412-111: Pit Fighter (confirmed) */
--static const struct slapstic_data slapstic111 =
--{
gen_111 : if chip_type = 111 generate -- /* basic banking */
ini_bank <= "00"; -- 0, /* starting bank */
val_bank0 <= x"0042"; -- { 0x0042,0x0052,0x0062,0x0072 },/* bank select values */
val_bank1 <= x"0052";
val_bank2 <= x"0062";
val_bank3 <= x"0072";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"000A"; -- { 0x007f,0x000a }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"28A4"; -- { 0x3fff,0x28a4 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"0784"; val_alt3 <= x"0080"; -- { 0x0784,0x0080 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FCF"; val_alt4 <= x"0042"; -- { 0x3fcf,0x0042 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"00A1"; -- { 0x3fff,0x00a1 }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"00A2"; -- { 0x3fff,0x00a2 }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3C4F"; val_addp1 <= x"284D"; -- { 0x3c4f,0x284d }, /* +1 mask/value */
mask_addp2 <= x"3A5F"; val_addp2 <= x"285D"; -- { 0x3a5f,0x285d }, /* +2 mask/value */
mask_add3 <= x"3FF8"; val_add3 <= x"2800"; -- { 0x3ff8,0x2800 } /* final mask/value in sequence */
end generate; --};
--/* slapstic 137412-112: Pit Fighter (Japan) (confirmed) */
--static const struct slapstic_data slapstic112 =
--{
gen_112 : if chip_type = 112 generate -- /* basic banking */
ini_bank <= "11"; -- 0, /* starting bank */
val_bank0 <= x"002C"; -- { 0x002c,0x003c,0x006c,0x007c },/* bank select values */
val_bank1 <= x"003C";
val_bank2 <= x"006C";
val_bank3 <= x"007C";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"0014"; -- { 0x007f,0x0014 }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"29A0"; -- { 0x3fff,0x29a0 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"0073"; val_alt3 <= x"0010"; -- { 0x0073,0x0010 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FAF"; val_alt4 <= x"002C"; -- { 0x3faf,0x002c }, /* 4th mask/value in sequence */
altshift <= 2; -- 2, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"2DCE"; -- { 0x3fff,0x2dce }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"2DCF"; -- { 0x3fff,0x2dcf }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3DEF"; val_addp1 <= x"15E2"; -- { 0x3def,0x15e2 }, /* +1 mask/value */
mask_addp2 <= x"3FBF"; val_addp2 <= x"15A2"; -- { 0x3fbf,0x15a2 }, /* +2 mask/value */
mask_add3 <= x"3FFC"; val_add3 <= x"1450"; -- { 0x3ffc,0x1450 } /* final mask/value in sequence */
end generate; --};
--/* slapstic 137412-113: Unknown (Europe) (confirmed) */
--static const struct slapstic_data slapstic113 =
--{
gen_113 : if chip_type = 113 generate -- /* basic banking */
ini_bank <= "00"; -- 0, /* starting bank */
val_bank0 <= x"0008"; -- { 0x0008,0x0018,0x0028,0x0038 },/* bank select values */
val_bank1 <= x"0018";
val_bank2 <= x"0028";
val_bank3 <= x"0038";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"0059"; -- { 0x007f,0x0059 }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"11A5"; -- { 0x3fff,0x11a5 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"0860"; val_alt3 <= x"0800"; -- { 0x0860,0x0800 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FCF"; val_alt4 <= x"0008"; -- { 0x3fcf,0x0008 }, /* 4th mask/value in sequence */
altshift <= 3; -- 3, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"049B"; -- { 0x3fff,0x049b }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"049C"; -- { 0x3fff,0x049c }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3FCF"; val_addp1 <= x"3EC7"; -- { 0x3fcf,0x3ec7 }, /* +1 mask/value */
mask_addp2 <= x"3EDF"; val_addp2 <= x"3ED7"; -- { 0x3edf,0x3ed7 }, /* +2 mask/value */
mask_add3 <= x"3FFF"; val_add3 <= x"3FB2"; -- { 0x3fff,0x3fb2 } /* final mask/value in sequence */
end generate; --};
--/* slapstic 137412-114: Pit Fighter (rev 9) (confirmed) */
--static const struct slapstic_data slapstic114 =
--{
gen_114 : if chip_type = 114 generate -- /* basic banking */
ini_bank <= "00"; -- 0, /* starting bank */
val_bank0 <= x"0040"; -- { 0x0040,0x0048,0x0050,0x0058 },/* bank select values */
val_bank1 <= x"0048";
val_bank2 <= x"0050";
val_bank3 <= x"0058";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"0016"; -- { 0x007f,0x0016 }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"24DE"; -- { 0x3fff,0x24de }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3871"; val_alt3 <= x"0000"; -- { 0x3871,0x0000 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FE7"; val_alt4 <= x"0040"; -- { 0x3fe7,0x0040 }, /* 4th mask/value in sequence */
altshift <= 1; -- 1, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"0AB7"; -- { 0x3fff,0x0ab7 }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"0AB8"; -- { 0x3fff,0x0ab8 }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3F63"; val_addp1 <= x"0D40"; -- { 0x3f63,0x0d40 }, /* +1 mask/value */
mask_addp2 <= x"3FD9"; val_addp2 <= x"0DC8"; -- { 0x3fd9,0x0dc8 }, /* +2 mask/value */
mask_add3 <= x"3FFF"; val_add3 <= x"0AB0"; -- { 0x3fff,0x0ab0 } /* final mask/value in sequence */
end generate; --};
--/* slapstic 137412-115: Race Drivin' DSK board (confirmed) */
--static const struct slapstic_data slapstic115 =
--{
gen_115 : if chip_type = 115 generate -- /* basic banking */
ini_bank <= "00"; -- 0, /* starting bank */
val_bank0 <= x"0020"; -- { 0x0020,0x0022,0x0024,0x0026 },/* bank select values */
val_bank1 <= x"0022";
val_bank2 <= x"0024";
val_bank3 <= x"0026";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"0054"; -- { 0x007f,0x0054 }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"3E01"; -- { 0x3fff,0x3e01 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"3879"; val_alt3 <= x"0029"; -- { 0x3879,0x0029 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FF9"; val_alt4 <= x"0020"; -- { 0x3ff9,0x0020 }, /* 4th mask/value in sequence */
altshift <= 1; -- 1, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"2591"; -- { 0x3fff,0x2591 }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"2592"; -- { 0x3fff,0x2592 }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3FE6"; val_addp1 <= x"3402"; -- { 0x3fe6,0x3402 }, /* +1 mask/value */
mask_addp2 <= x"3FB4"; val_addp2 <= x"3410"; -- { 0x3fb4,0x3410 }, /* +2 mask/value */
mask_add3 <= x"3FFF"; val_add3 <= x"34A2"; -- { 0x3fff,0x34a2 } /* final mask/value in sequence */
end generate; --};
--/* slapstic 137412-116: Hydra (confirmed) */
--static const struct slapstic_data slapstic116 =
--{
gen_116 : if chip_type = 116 generate -- /* basic banking */
ini_bank <= "00"; -- 0, /* starting bank */
val_bank0 <= x"0044"; -- { 0x0044,0x004c,0x0054,0x005c },/* bank select values */
val_bank1 <= x"004C";
val_bank2 <= x"0054";
val_bank3 <= x"005C";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"0069"; -- { 0x007f,0x0069 }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"2BAB"; -- { 0x3fff,0x2bab }, /* 2nd mask/value in sequence */
mask_alt3 <= x"387C"; val_alt3 <= x"0808"; -- { 0x387c,0x0808 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FE7"; val_alt4 <= x"0044"; -- { 0x3fe7,0x0044 }, /* 4th mask/value in sequence */
altshift <= 0; -- 0, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"3F7C"; -- { 0x3fff,0x3f7c }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"3F7D"; -- { 0x3fff,0x3f7d }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3DB2"; val_addp1 <= x"3C12"; -- { 0x3db2,0x3c12 }, /* +1 mask/value */
mask_addp2 <= x"3FE3"; val_addp2 <= x"3E43"; -- { 0x3fe3,0x3e43 }, /* +2 mask/value */
mask_add3 <= x"3FFF"; val_add3 <= x"2BA8"; -- { 0x3fff,0x2ba8 } /* final mask/value in sequence */
end generate; --};
--/* slapstic 137412-117: Race Drivin' main board (confirmed) */
--static const struct slapstic_data slapstic117 =
--{
gen_117 : if chip_type = 117 generate -- /* basic banking */
ini_bank <= "00"; -- 0, /* starting bank */
val_bank0 <= x"0008"; -- { 0x0008,0x001a,0x002c,0x003e },/* bank select values */
val_bank1 <= x"001A";
val_bank2 <= x"002C";
val_bank3 <= x"003E";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"007D"; -- { 0x007f,0x007d }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"3580"; -- { 0x3fff,0x3580 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"0079"; val_alt3 <= x"0020"; -- { 0x0079,0x0020 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3FC9"; val_alt4 <= x"0008"; -- { 0x3fc9,0x0008 }, /* 4th mask/value in sequence */
altshift <= 1; -- 1, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"0676"; -- { 0x3fff,0x0676 }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"0677"; -- { 0x3fff,0x0677 }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3E62"; val_addp1 <= x"1A42"; -- { 0x3e62,0x1a42 }, /* +1 mask/value */
mask_addp2 <= x"3E35"; val_addp2 <= x"1A11"; -- { 0x3e35,0x1a11 }, /* +2 mask/value */
mask_add3 <= x"3FFF"; val_add3 <= x"1A42"; -- { 0x3fff,0x1a42 } /* final mask/value in sequence */
end generate; --};
--/* slapstic 137412-118: Rampart/Vindicators II (confirmed) */
--static const struct slapstic_data slapstic118 =
--{
gen_118 : if chip_type = 118 generate -- /* basic banking */
ini_bank <= "00"; -- 0, /* starting bank */
val_bank0 <= x"0014"; -- { 0x0014,0x0034,0x0054,0x0074 },/* bank select values */
val_bank1 <= x"0034";
val_bank2 <= x"0054";
val_bank3 <= x"0074";
-- /* alternate banking */
mask_alt1 <= x"007F"; val_alt1 <= x"0002"; -- { 0x007f,0x0002 }, /* 1st mask/value in sequence */
mask_alt2 <= x"3FFF"; val_alt2 <= x"1950"; -- { 0x3fff,0x1950 }, /* 2nd mask/value in sequence */
mask_alt3 <= x"0067"; val_alt3 <= x"0020"; -- { 0x0067,0x0020 }, /* 3rd mask/value in sequence */
mask_alt4 <= x"3F9F"; val_alt4 <= x"0014"; -- { 0x3f9f,0x0014 }, /* 4th mask/value in sequence */
altshift <= 3; -- 3, /* shift to get bank from 3rd */
-- /* bitwise banking */
bitwise <= '0'; -- NO_BITWISE,
additive <= '1'; -- /* additive banking */
mask_add1 <= x"3FFF"; val_add1 <= x"1958"; -- { 0x3fff,0x1958 }, /* 1st mask/value in sequence */
mask_add2 <= x"3FFF"; val_add2 <= x"1959"; -- { 0x3fff,0x1959 }, /* 2nd mask/value in sequence */
mask_addp1 <= x"3F73"; val_addp1 <= x"3052"; -- { 0x3f73,0x3052 }, /* +1 mask/value */
mask_addp2 <= x"3F67"; val_addp2 <= x"3042"; -- { 0x3f67,0x3042 }, /* +2 mask/value */
mask_add3 <= x"3FF8"; val_add3 <= x"30E0"; -- { 0x3ff8,0x30e0 } /* final mask/value in sequence */
end generate; --};
slv_BS <= cur_bank;
O_BS <= slv_BS;
-- expand address to 16 bits for easier representation in hex
addr <= "00" & I_A;
p_slap : process
begin
wait until rising_edge(I_CK);
sl_ASn_last <= I_ASn; -- detect /AS transition
if I_CSn = '0' then
if sl_ASn_last = '0' and I_ASn = '1' then
-- /* reset is universal */
if addr = x"0000" then -- if (offset == 0x0000)
-- {
state <= ENA; -- state = ENABLED;
-- }
-- /* otherwise, use the state machine */
else -- else
-- {
case state is -- switch (state)
-- {
-- /* DISABLED state: everything is ignored except a reset */
when DIS => -- case DISABLED:
-- break;
-- /* ENABLED state: the chip has been activated and is ready for a bankswitch */
when ENA => -- case ENABLED:
-- /* check for request to enter bitwise state */
if bitwise = '1' and (addr and mask_bit1) = val_bit1 then -- if (MATCHES_MASK_VALUE(offset, slapstic.bit1))
-- {
state <= BIT1; -- state = BITWISE1;
-- }
-- /* check for request to enter additive state */
elsif additive = '1' and (addr and mask_add1) = val_add1 then -- else if (MATCHES_MASK_VALUE(offset, slapstic.add1))
-- {
state <= ADD1; -- state = ADDITIVE1;
-- }
-- /* check for request to enter alternate state */
elsif (addr and mask_alt1) = val_alt1 then -- else if (MATCHES_MASK_VALUE(offset, slapstic.alt1))
-- {
state <= ALT1; -- state = ALTERNATE1;
-- }
-- /* special kludge for catching the second alternate address if */
-- /* the first one was missed (since it's usually an opcode fetch) */
elsif (addr and mask_alt2) = val_alt2 then -- else if (MATCHES_MASK_VALUE(offset, slapstic.alt2))
-- {
state <= ALT2; -- state = alt2_kludge(space, offset);
-- }
-- /* check for standard bankswitches */
elsif addr = val_bank0 then -- else if (offset == slapstic.bank[0])
-- {
state <= DIS; -- state = DISABLED;
cur_bank <= "00"; -- current_bank = 0;
-- }
elsif addr = val_bank1 then -- else if (offset == slapstic.bank[1])
-- {
state <= DIS; -- state = DISABLED;
cur_bank <= "01"; -- current_bank = 1;
-- }
elsif addr = val_bank2 then -- else if (offset == slapstic.bank[2])
-- {
state <= DIS; -- state = DISABLED;
cur_bank <= "10"; -- current_bank = 2;
-- }
elsif addr = val_bank3 then -- else if (offset == slapstic.bank[3])
-- {
state <= DIS; -- state = DISABLED;
cur_bank <= "11"; -- current_bank = 3;
end if; -- }
-- break;
-- /* ALTERNATE1 state: look for alternate2 offset, or else fall back to ENABLED */
when ALT1 => -- case ALTERNATE1:
if (addr and mask_alt2) = val_alt2 then -- if (MATCHES_MASK_VALUE(offset, slapstic.alt2))
-- {
state <= ALT2; -- state = ALTERNATE2;
-- }
else -- else
-- {
state <= ENA; -- state = ENABLED;
end if; -- }
-- break;
-- /* ALTERNATE2 state: look for altbank offset, or else fall back to ENABLED */
when ALT2 => -- case ALTERNATE2:
if (addr and mask_alt3) = val_alt3 then -- if (MATCHES_MASK_VALUE(offset, slapstic.alt3))
-- {
state <= ALT3; -- state = ALTERNATE3;
alt_bank <= addr(altshift+1) & addr(altshift); -- alt_bank = (offset >> slapstic.altshift) & 3;
-- }
else -- else
-- {
state <= ENA; -- state = ENABLED;
end if; -- }
-- break;
-- /* ALTERNATE3 state: wait for the final value to finish the transaction */
when ALT3 => -- case ALTERNATE3:
if (addr and mask_alt4) = val_alt4 then -- if (MATCHES_MASK_VALUE(offset, slapstic.alt4))
-- {
state <= DIS; -- state = DISABLED;
cur_bank <= alt_bank; -- current_bank = alt_bank;
end if; -- }
-- break;
-- /* BITWISE1 state: waiting for a bank to enter the BITWISE state */
when BIT1 => -- case BITWISE1:
-- if (offset == slapstic.bank[0] || offset == slapstic.bank[1] ||
if (addr = val_bank0) or (addr = val_bank1) or -- offset == slapstic.bank[2] || offset == slapstic.bank[3])
(addr = val_bank2) or (addr = val_bank3) then
-- {
state <= BIT2; -- state = BITWISE2;
bit_bank <= cur_bank; -- bit_bank = current_bank;
bit_xor <= "00"; -- bit_xor = 0;
end if; -- }
-- break;
-- /* BITWISE2 state: watch for twiddling and the escape mechanism */
when BIT2 => -- case BITWISE2:
-- /* check for clear bit 0 case */
if ( (addr(15 downto 2) & (addr(1 downto 0) xor bit_xor) ) -- if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2c0))
and mask_bit2c0) = val_bit2c0 then
-- {
bit_bank <= bit_bank and "10"; -- bit_bank &= ~1;
bit_xor <= bit_xor xor "11"; -- bit_xor ^= 3;
-- }
--
-- /* check for set bit 0 case */
elsif ( (addr(15 downto 2) & (addr(1 downto 0) xor bit_xor) ) -- else if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2s0))
and mask_bit2s0) = val_bit2s0 then
-- {
bit_bank <= bit_bank or "01"; -- bit_bank |= 1;
bit_xor <= bit_xor xor "11"; -- bit_xor ^= 3;
-- }
-- /* check for clear bit 1 case */
elsif ( (addr(15 downto 2) & (addr(1 downto 0) xor bit_xor) ) -- else if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2c1))
and mask_bit2c1) = val_bit2c1 then
-- {
bit_bank <= bit_bank and "01"; -- bit_bank &= ~2;
bit_xor <= bit_xor xor "11"; -- bit_xor ^= 3;
-- }
-- /* check for set bit 1 case */
elsif ( (addr(15 downto 2) & (addr(1 downto 0) xor bit_xor) ) -- else if (MATCHES_MASK_VALUE(offset ^ bit_xor, slapstic.bit2s1))
and mask_bit2s1) = val_bit2s1 then
-- {
bit_bank <= bit_bank or "10"; -- bit_bank |= 2;
bit_xor <= bit_xor xor "11"; -- bit_xor ^= 3;
-- }
-- /* check for escape case */
elsif (addr and mask_bit3) = val_bit3 then -- else if (MATCHES_MASK_VALUE(offset, slapstic.bit3))
-- {
state <= BIT3; -- state = BITWISE3;
end if; -- }
-- break;
-- /* BITWISE3 state: waiting for a bank to seal the deal */
when BIT3 => -- case BITWISE3:
-- if (offset == slapstic.bank[0] || offset == slapstic.bank[1] ||
if (addr = val_bank0) or (addr = val_bank1) or -- offset == slapstic.bank[2] || offset == slapstic.bank[3])
(addr = val_bank2) or (addr = val_bank3) then
-- {
state <= DIS; -- state = DISABLED;
cur_bank <= bit_bank; -- current_bank = bit_bank;
end if; -- }
-- break;
-- /* ADDITIVE1 state: look for add2 offset, or else fall back to ENABLED */
when ADD1 => -- case ADDITIVE1:
if (addr and mask_add2) = val_add2 then -- if (MATCHES_MASK_VALUE(offset, slapstic.add2))
-- {
state <= ADD2; -- state = ADDITIVE2;
add_bank <= cur_bank; -- add_bank = current_bank;
-- }
else -- else
-- {
state <= ENA; -- state = ENABLED;
end if; -- }
-- break;
-- /* ADDITIVE2 state: watch for twiddling and the escape mechanism */
when ADD2 => -- case ADDITIVE2:
if ((addr and mask_addp1) = val_addp1) and -- there is a case where we add 3 (both +1 and +2 cases matched) so since we don't execute sequentially
((addr and mask_addp2) = val_addp2) then -- like a CPU runing a C program but in parallel, we have to add one more test for that specific case
add_bank <= add_bank + 3;
-- /* check for add 1 case -- can intermix */
elsif (addr and mask_addp1) = val_addp1 then -- if (MATCHES_MASK_VALUE(offset, slapstic.addplus1))
-- {
add_bank <= add_bank + 1; -- add_bank = (add_bank + 1) & 3;
-- }
-- /* check for add 2 case -- can intermix */
elsif (addr and mask_addp2) = val_addp2 then -- if (MATCHES_MASK_VALUE(offset, slapstic.addplus2))
-- {
add_bank <= add_bank + 2; -- add_bank = (add_bank + 2) & 3;
-- }
-- /* check for escape case -- can intermix with the above */
elsif (addr and mask_add3) = val_add3 then -- if (MATCHES_MASK_VALUE(offset, slapstic.add3))
-- {
state <= ADD3; -- state = ADDITIVE3;
end if; -- }
-- break;
-- /* ADDITIVE3 state: waiting for a bank to seal the deal */
when ADD3 => -- case ADDITIVE3:
-- if (offset == slapstic.bank[0] || offset == slapstic.bank[1] ||
if (addr = val_bank0) or (addr = val_bank1) or -- offset == slapstic.bank[2] || offset == slapstic.bank[3])
(addr = val_bank2) or (addr = val_bank3) then
-- {
state <= DIS; -- state = DISABLED;
cur_bank <= add_bank; -- current_bank = add_bank;
end if; -- }
when others => null; -- break;
end case; -- }
end if; -- }
end if;
end if;
end process;
end RTL;

View File

@@ -0,0 +1,211 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- System Clock and Sync Generator (Atari custom chip 137419-103)
-- This SYNGEN was derived from System I SP-277 schematic
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity SYNGEN is
port(
I_CK : in std_logic; -- 7.159MHz clock
O_C0 : out std_logic := '0';
O_C1 : out std_logic := '0';
O_C2 : out std_logic := '0';
O_LMPDn : out std_logic := '0';
O_HBKn : out std_logic;
O_VIDBn : out std_logic; -- VIDBLANK
O_VRESn : out std_logic;
O_HSYNCn : out std_logic;
O_VSYNCn : out std_logic;
O_PFHSTn : out std_logic;
O_BUFCLRn : out std_logic;
O_VBLKn : out std_logic; -- VBLANK
O_VSCK : out std_logic;
O_CK0n : out std_logic; -- pin 4 RCLOCK
O_CK0 : out std_logic; -- pin 29 FCLOCK
O_2HDLn : out std_logic;
O_4HDLn : out std_logic;
O_4HDDn : out std_logic;
O_NXLn : out std_logic;
O_V : out std_logic_vector(7 downto 0);
O_H : out std_logic_vector(8 downto 0)
);
end SYNGEN;
architecture RTL of SYNGEN is
signal
sl_2HDLn,
sl_3A5,
sl_4HDDn,
sl_o13
: std_logic := '0';
signal
sl_VBLANKn,
sl_4HDLn,
sl_C0,
sl_C1,
sl_C2,
sl_HBLANKn,
sl_HSYNCn,
sl_LMPDn,
sl_NXLn,
sl_VRESn,
sl_o11,
sl_o12,
sl_o14,
sl_o15,
sl_o16,
sl_o17,
sl_o18,
sl_o19
: std_logic := '1';
signal
slv_5E_data
: std_logic_vector( 3 downto 0) := (others => '1');
signal
slv_5E_addr
: std_logic_vector( 7 downto 0) := (others => '1');
signal
slv_vcnt
: std_logic_vector( 7 downto 0) := x"EF"; --(others => '1');
signal
slv_hcnt
: std_logic_vector( 8 downto 0) := (others => '0');
begin
O_2HDLn <= sl_2HDLn;
O_4HDDn <= sl_4HDDn;
O_4HDLn <= sl_4HDLn;
O_BUFCLRn <= not sl_o11;
O_C0 <= sl_C0;
O_C1 <= sl_C1;
O_C2 <= sl_C2;
O_CK0 <= I_CK;
O_CK0n <= not I_CK;
O_H <= slv_hcnt;
O_HBKn <= sl_HBLANKn; -- From SP-313 this is /HBLANK
O_HSYNCn <= sl_HSYNCn;
O_LMPDn <= sl_LMPDn;
O_NXLn <= not sl_o19;
O_PFHSTn <= not sl_o12;
O_V <= slv_vcnt;
O_VBLKn <= sl_VBLANKn;
O_VIDBn <= sl_VBLANKn and sl_HBLANKn;
O_VRESn <= sl_VRESn;
O_VSCK <= sl_VBLANKn and sl_o13;
O_VSYNCn <= slv_5E_data(1);
p_7A_7D_7E : process
begin
wait until rising_edge(I_CK);
-- 7D
sl_2HDLn <= not slv_hcnt(1); -- 2H delayed x1 inverted
sl_4HDLn <= not slv_hcnt(2); -- 4H delayed x1 inverted
sl_4HDDn <= sl_4HDLn; -- 4H delayed x2
-- 7E
sl_NXLn <= not sl_o19;
sl_C2 <= sl_o18;
sl_C1 <= sl_o17;
sl_C0 <= sl_o16;
sl_LMPDn <= not sl_o15;
sl_HBLANKn <= not sl_o14;
sl_HSYNCn <= not sl_o13;
end process;
slv_5E_addr <= sl_3A5 & (slv_vcnt(7) and slv_vcnt(6)) & slv_vcnt(5 downto 0);
-- 82S129 256x4 TTL BIPOLAR PROM (Atari chip 136032.102)
u_PROM_5E : entity work.PROM_5E
port map (
CLK => I_CK,
ADDR => slv_5E_addr,
DATA => slv_5E_data
);
-- counters 4E, 5D, 6E, 6F
p_h_v_count : process
begin
wait until rising_edge(I_CK);
if sl_NXLn = '0' then
slv_hcnt <= (others=>'0');
if slv_5E_data(0) = '0' then
slv_vcnt <= (others=>'1');
else
slv_vcnt <= slv_vcnt + 1;
end if;
sl_VRESn <= slv_5E_data(0); -- F/F 3A output 9
sl_3A5 <= slv_5E_data(2); -- F/F 3A output 5
sl_VBLANKn <= not slv_5E_data(3); -- F/F 5B output 5
else
slv_hcnt <= slv_hcnt + 1;
end if;
end process;
-- Equations for PLA chip 7F Signetics 82S153 aka PLS153A (Atari custom chip 136032.103)
-- /o19 = /i1 & i2 & i3 & i7 & i8 & i9
-- o18 = i1 & /i2
-- o17 = i1 & /i2 & /i3 +
-- /i1 & i2 & /i3 +
-- i1 & /i2 & i3
-- o16 = /i2 +
-- i1 & i2 & /i3 +
-- /i1 & i2 & i3
-- /o15 = i3 & /i4 & /i5 & /i6 & /i7 & /i8 & /i9 +
-- i2 & /i3 & /i4 & /i5 & /i6 & /i7 & /i8 & /i9 +
-- /i2 & /i3 & i4 & /i5 & /i6 & /i7 & /i8 & /i9
-- /o14 = /i4 & /i5 & /i6 & /i7 & /i8 & /i9 +
-- i4 & i5 & /i6 & i7 & /i8 & i9 +
-- i6 & i7 & /i8 & i9 +
-- i8 & i9
-- o13 = /i4 & i5 & /i6 & /i7 & i8 & i9 +
-- /i5 & /i6 & /i7 & i8 & i9 +
-- i4 & i5 & i6 & i7 & /i8 & i9
-- /o12 = i4 & i5 & i6 & /i7 & i8 & i9
-- /o11 = /i1 & i2 & i3 & /i4 & /i5 & /i6 & /i7 & /i8 & /i9
sl_o19 <= ((not slv_hcnt(0)) and slv_hcnt(1) and slv_hcnt(2) and slv_hcnt(6) and slv_hcnt(7) and slv_hcnt(8));
sl_o18 <= slv_hcnt(0) and (not slv_hcnt(1)) ;
sl_o17 <= ( slv_hcnt(0) and (not slv_hcnt(1)) and (not slv_hcnt(2))) or
((not slv_hcnt(0)) and slv_hcnt(1) and (not slv_hcnt(2))) or
( slv_hcnt(0) and (not slv_hcnt(1)) and slv_hcnt(2));
sl_o16 <= (not slv_hcnt(1)) or
( slv_hcnt(0) and slv_hcnt(1) and (not slv_hcnt(2))) or
( (not slv_hcnt(0)) and slv_hcnt(1) and slv_hcnt(2));
sl_o15 <= (( slv_hcnt(2) and (not slv_hcnt(3)) and (not slv_hcnt(4)) and (not slv_hcnt(5)) and (not slv_hcnt(6)) and (not slv_hcnt(7)) and (not slv_hcnt(8))) or
( slv_hcnt(1) and (not slv_hcnt(2)) and (not slv_hcnt(3)) and (not slv_hcnt(4)) and (not slv_hcnt(5)) and (not slv_hcnt(6)) and (not slv_hcnt(7)) and (not slv_hcnt(8))) or
(( not slv_hcnt(1)) and (not slv_hcnt(2)) and slv_hcnt(3) and (not slv_hcnt(4)) and (not slv_hcnt(5)) and (not slv_hcnt(6)) and (not slv_hcnt(7)) and (not slv_hcnt(8))));
sl_o14 <= (((not slv_hcnt(3)) and (not slv_hcnt(4)) and (not slv_hcnt(5)) and (not slv_hcnt(6)) and (not slv_hcnt(7)) and (not slv_hcnt(8))) or
( slv_hcnt(3) and slv_hcnt(4) and (not slv_hcnt(5)) and slv_hcnt(6) and (not slv_hcnt(7)) and slv_hcnt(8)) or
( slv_hcnt(5) and slv_hcnt(6) and (not slv_hcnt(7)) and slv_hcnt(8)) or
( slv_hcnt(7) and slv_hcnt(8)));
sl_o13 <= ( (not slv_hcnt(3)) and slv_hcnt(4) and (not slv_hcnt(5)) and (not slv_hcnt(6)) and slv_hcnt(7) and slv_hcnt(8)) or
( (not slv_hcnt(4)) and (not slv_hcnt(5)) and (not slv_hcnt(6)) and slv_hcnt(7) and slv_hcnt(8)) or
( slv_hcnt(3) and slv_hcnt(4) and slv_hcnt(5) and slv_hcnt(6) and (not slv_hcnt(7)) and slv_hcnt(8));
sl_o12 <= ( slv_hcnt(3) and slv_hcnt(4) and slv_hcnt(5) and (not slv_hcnt(6)) and slv_hcnt(7) and slv_hcnt(8));
sl_o11 <= ((not slv_hcnt(0)) and slv_hcnt(1) and slv_hcnt(2) and (not slv_hcnt(3)) and (not slv_hcnt(4)) and (not slv_hcnt(5)) and (not slv_hcnt(6)) and (not slv_hcnt(7)) and (not slv_hcnt(8)));
end RTL;

View File

@@ -0,0 +1,74 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity TMS5220 is
port (
-- inputs
I_OSC : in std_logic; -- pin 6 typ 640KHz
I_WSn : in std_logic; -- pin 27 Write Select
I_RSn : in std_logic; -- pin 28 Read Select
I_DATA : in std_logic; -- pin 21 Serial Data In (alt function)
I_TEST : in std_logic; -- pin 20 Test use only
I_DBUS : in std_logic_vector(7 downto 0); -- pins 1,26,24,22,19,12,13,14
-- outputs
O_DBUS : out std_logic_vector(7 downto 0); -- pins 1,26,24,22,19,12,13,14
O_RDYn : out std_logic; -- pin 18 Transfer cycle complete
O_INTn : out std_logic; -- pin 17 Interrupt
O_M0 : out std_logic; -- pin 15 VSM command bit 0
O_M1 : out std_logic; -- pin 16 VSM command bit 1
O_ADD8 : out std_logic; -- pin 21 VSM Addr (alt function)
O_ADD4 : out std_logic; -- pin 23 VSM Addr
O_ADD2 : out std_logic; -- pin 25 VSM Addr
O_ADD1 : out std_logic; -- pin 2 VSM Addr
O_ROMCLK : out std_logic; -- pin 3 VSM clock
O_T11 : out std_logic; -- pin 7 Sync
O_IO : out std_logic; -- pin 9 Serial Data Out
O_PRMOUT : out std_logic; -- pin 10 Test use only
O_SPKR : out signed(7 downto 0) -- pin 8 Audio Output
);
end entity;
architecture RTL of TMS5220 is
signal rdy : std_logic := '0';
signal int_n : std_logic := '1';
signal dbus : std_logic_vector( 7 downto 0) := (others=>'0');
begin
-- FIXME implement TMS5220 core
O_DBUS <= dbus;
O_RDYn <= rdy;
O_INTn <= int_n;
O_SPKR <= (others=>'0'); -- speaker out
-- VSM memory bus driver (not implemented)
O_M0 <= '0';
O_M1 <= '0';
O_ADD8 <= '0';
O_ADD4 <= '0';
O_ADD2 <= '0';
O_ADD1 <= '0';
O_ROMCLK <= '0';
O_T11 <= '0'; -- sync
O_IO <= '0'; -- serial out
O_PRMOUT <= '0'; -- test use
end architecture;

View File

@@ -0,0 +1,936 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity VIDEO is
port(
I_MCKR : in std_logic; -- MCKR 7.159 MHz
I_ADDR : in std_logic_vector(14 downto 1);
I_DATA : in std_logic_vector(15 downto 0);
I_HSCRLDn : in std_logic;
I_CRAMn : in std_logic;
I_VRAMn : in std_logic;
I_VBUSn : in std_logic;
I_VRDTACK : in std_logic;
I_VBKACKn : in std_logic;
I_R_Wn : in std_logic;
I_LDSn : in std_logic;
I_UDSn : in std_logic;
O_VCPU : out std_logic;
O_VBKINTn : out std_logic;
O_VBLANKn : out std_logic;
O_1H : out std_logic;
O_2H : out std_logic;
O_32V : out std_logic;
O_DATA : out std_logic_vector(15 downto 0);
O_I : out std_logic_vector( 3 downto 0);
O_R : out std_logic_vector( 3 downto 0);
O_G : out std_logic_vector( 3 downto 0);
O_B : out std_logic_vector( 3 downto 0);
O_HSYNC : out std_logic;
O_VSYNC : out std_logic;
O_CSYNC : out std_logic;
-- external GFX ROMs
O_GP_EN : out std_logic;
O_GP_ADDR : out std_logic_vector(15 downto 0);
I_GP_DATA : in std_logic_vector(31 downto 0)
);
end VIDEO;
architecture RTL of VIDEO is
signal
sl_MATCH,
sl_VRDTACK,
sl_VBUS,
sl_1H,
sl_2H,
sl_4H,
-- sl_4HD3,
sl_6S6,
sl_6T8,
sl_6X6,
-- sl_6X8,
sl_6X8_en,
sl_7S7,
sl_9D12,
sl_9D4,
sl_9D7,
sl_9D9,
sl_ALC3,
sl_ALC3D,
sl_ALC4,
sl_ALC4D,
sl_CRA5,
sl_CRA7,
sl_H03,
sl_HFLP,
-- sl_HORZDL,
sl_MREFL,
sl_NXL,
sl_NXLDL,
sl_VCPU,
-- sl_VERTDL,
sl_VRAMWE
-- sl_PICTDL
: std_logic := '0';
signal
sl_GP_EN,
sl_GP_ADDR14,
sl_MCKF,
sl_HSCRLDn,
sl_VRAMn,
sl_LDSn,
sl_UDSn,
sl_BR_Wn,
sl_BW_Rn,
sl_4HD3_en,
sl_4HD3n,
sl_4HDDn,
sl_4HDLn,
sl_4Hn,
sl_6S9,
sl_BUFCLRn,
sl_ENDn,
sl_FLBAn,
sl_FLBBn,
sl_G8T,
sl_GLD,
sl_GLDn,
sl_HORZDLn,
sl_HORZDLn_tap,
sl_HSYNCn,
sl_LDABn,
sl_LINKn,
sl_LMPDn,
sl_MATCHDL,
sl_MC0,
sl_MC1,
sl_MFLP,
sl_MO_PFn,
sl_NEWMOn,
sl_NXLn,
sl_NXLn_star,
sl_PFHSTn,
-- sl_PICTDLn,
sl_PICTDLn_tap,
sl_VBKACKn,
sl_VBLANKn,
sl_VBLANKn_en,
sl_VERTDLn,
sl_VERTDLn_tap,
sl_VIDBLANKn,
sl_VMATCHn,
sl_VSYNCn
: std_logic := '1';
signal
slv_VAS,
slv_VAS_star
: std_logic_vector( 1 downto 0) := (others=>'0');
signal
slv_HSIZ,
slv_VSIZ
: std_logic_vector( 2 downto 0) := (others=>'0');
signal
sl_I,
sl_R,
sl_G,
sl_B,
slv_4E,
slv_PSEL,
slv_ctr_5R,
slv_sum_6L,
slv_shift_7N,
slv_shift_7P,
slv_4R_data
: std_logic_vector( 3 downto 0) := (others=>'0');
signal
slv_PFSR
: std_logic_vector( 6 downto 0) := (others=>'0');
signal
slv_ctr_4L_4M,
slv_MPIC,
slv_V,
slv_MPX,
slv_PFX,
slv_MOSR,
slv_ROM_6P,
slv_PROM_5L
: std_logic_vector( 7 downto 0) := (others=>'0');
signal
slv_PFH
: std_logic_vector( 8 downto 3) := (others=>'0');
signal
slv_H,
slv_adder_a,
slv_XPOS,
slv_YPOS,
slv_HPOS,
slv_sum_5D_5E
: std_logic_vector( 8 downto 0) := (others=>'0');
signal
slv_sum,
slv_CRA,
slv_LINK,
slv_GPC_CA
: std_logic_vector( 9 downto 0) := (others=>'0');
signal
slv_PFV,
slv_VRAM,
slv_VRA
: std_logic_vector(11 downto 0) := (others=>'0');
signal
slv_ROM_6P_addr
: std_logic_vector(13 downto 0) := (others=>'0');
signal
slv_MA
: std_logic_vector(14 downto 1) := (others=>'0');
signal
slv_CRAM,
slv_4C_4K,
slv_TILE,
slv_VBD,
slv_VRD
: std_logic_vector(15 downto 0) := (others=>'0');
signal
slv_GP_ADDR
: std_logic_vector(17 downto 0) := (others=>'0');
signal
slv_GP_DATA : std_logic_vector(31 downto 0) := (others=>'0');
begin
O_I <= sl_I;
O_R <= sl_R;
O_G <= sl_G;
O_B <= sl_B;
O_1H <= slv_H(0);
O_2H <= slv_H(1);
O_32V <= slv_V(5);
O_DATA <= slv_VBD;
O_VCPU <= sl_VCPU;
O_VBLANKn <= sl_VBLANKn;
O_HSYNC <= sl_HSYNCn;
O_VSYNC <= sl_VSYNCn;
O_CSYNC <= sl_HSYNCn and sl_VSYNCn;
O_GP_ADDR <= slv_GP_ADDR(15) & sl_GP_ADDR14 & slv_GP_ADDR(13 downto 0);
O_GP_EN <= sl_GP_EN;
sl_MCKF <= not I_MCKR;
-----------------------------
-- sheet 2 control signals --
-----------------------------
slv_MA <= I_ADDR;
sl_VBUS <= I_VBUSn;
sl_VRDTACK <= I_VRDTACK;
sl_VBKACKn <= I_VBKACKn;
sl_HSCRLDn <= I_HSCRLDn;
sl_VRAMn <= I_VRAMn;
sl_UDSn <= I_UDSn;
sl_LDSn <= I_LDSn;
sl_BR_Wn <= I_R_Wn;
sl_BW_Rn <= not I_R_Wn;
-----------------------
-- sheet 8 RAM banks --
-----------------------
-- at adress 900000-905FFF
u_VRAMS : entity work.VRAMS
port map (
I_CK => sl_MCKF,
I_VRAMWE => sl_VRAMWE,
I_SELB => sl_9D4,
I_SELA => sl_9D7,
I_UDSn => sl_9D9,
I_LDSn => sl_9D12,
I_VRA => slv_VRA,
I_VRD => slv_VBD,
O_VRD => slv_VRD
);
------------------------------------------
-- sheet 9 VRAM addr and data bus muxes --
------------------------------------------
-- 903800-903FFF R/W ------xx xxxxxxxx (Link to next object)
-- 8F, 8J latches sheet 9
-- D transfered to Q on the rising edge of clock if enable /G is low
p_8F_8J : process
begin
wait until rising_edge(I_MCKR);
if sl_LINKn = '0' then
slv_LINK <= slv_VRD(9 downto 0);
end if;
end process;
slv_VRA <= slv_VRAM when sl_NXLDL = '0' else "111111" & slv_VRAM( 5 downto 0); -- pullups RN7
-- 8C, 8E, 8D selectors create video RAM address high
-- 7L, 8L, 8K selectors create video RAM address low
slv_VRAM <=
slv_MA(12 downto 1) when slv_VAS = "11" else -- c3
'1' & slv_V(7 downto 3) & slv_H(8 downto 3) when slv_VAS = "10" else -- c2
sl_MC1 & sl_MC0 & slv_LINK(9 downto 0) when slv_VAS = "01" else -- c1
slv_PFH(8 downto 3) & slv_PFV(8 downto 3) when slv_VAS = "00"; -- c0
-- 7S latch
p_7S : process
begin
wait until rising_edge(I_MCKR);
sl_NXLDL <= sl_NXL;
slv_VAS(1) <= slv_VAS_star(1) and sl_NXLn;
sl_7S7 <= slv_VAS_star(1);
slv_VAS(0) <= slv_VAS_star(0);
sl_VCPU <= slv_VAS_star(0) and slv_VAS_star(1);
end process;
-- 9D selector SEL 0=A 1=B
sl_9D4 <= slv_MA(14) when sl_VCPU = '1' else sl_7S7;
sl_9D7 <= slv_MA(13) when sl_VCPU = '1' else slv_VAS(0);
sl_9D9 <= sl_UDSn when sl_VCPU = '1' else '0';
sl_9D12 <= sl_LDSn when sl_VCPU = '1' else '0';
-- gate 11J -- inverted for Xilinx Block RAMs
-- The FCLOCK is connected to the BRAM clock input to achieve the intended result, or else we
-- have timing problem as WE and FCLOCK become active simultaneously and WE signal is missed
sl_VRAMWE <= sl_VCPU and sl_VRDTACK and sl_BW_Rn; -- and sl_MCKF
-- 9E, 10E transceivers to/from 68K data bus
-- 9K, 10K transceivers to/from CRAM
-- DIR 0=B->A 1=A->B
-- VBD is driven by either
-- 68K data bus
-- CRAM data bus
-- VRAM data bus
-- else it holds its value (latches 9J,10J)
slv_VBD <=
I_DATA when sl_BW_Rn = '1' and sl_VBUS = '0' else -- VBUS write access from 68K
slv_CRAM when sl_BW_Rn = '0' and I_CRAMn = '0' else -- CRAM read access
slv_VRD when sl_BW_Rn = '0' and sl_VRAMn = '0' else -- VRAM read access
(others=>'0'); -- else floating
----------------------------
-- sheet 10
----------------------------
-- 902000-9027FF R/W -xxxxxxx xxxxxxxx (Tile index / Sprite)
-- 3C, 3K latch sheet 10
p_3C_3K : process
begin
wait until rising_edge(I_MCKR);
if sl_PICTDLn_tap = '0' then
slv_TILE <= sl_MREFL & slv_VRD(14 downto 0);
end if;
end process;
-- 903000-9037FF R/W xxxxxxxx x------- (Y position)
-- R/W -------- -x------ (Horizontal flip)
-- R/W -------- --xxx--- (Number of X tiles - 1)
-- R/W -------- -----xxx (Number of Y tiles - 1)
-- 5C, 5K latches sheet 10
p_5C_5K : process
begin
wait until rising_edge(I_MCKR);
if sl_VERTDLn_tap = '0' then
slv_YPOS <= slv_VRD(15 downto 7);
sl_MFLP <= slv_VRD(6);
slv_HSIZ <= slv_VRD( 5 downto 3);
slv_VSIZ <= slv_VRD( 2 downto 0);
end if;
end process;
-- adders 5D, 5E
slv_sum_5D_5E <= (slv_PFV(8 downto 0) + slv_YPOS) + (x"00" & sl_VBLANKn);
-- 4E latch
p_4E : process
begin
wait until rising_edge(I_MCKR);
if sl_H03 = '1' and sl_4H = '0' then
if sl_NEWMOn = '0' then
slv_4E <= slv_sum_5D_5E(2 downto 0) & sl_MATCH;
sl_MREFL <= sl_MFLP;
end if;
end if;
end process;
-- 3C, 3J, and 3D, 4K tristate outputs are muxed here
-- when MO/PF is active selects 3D, 4K outputs
-- when /4HDL is active selects 3C, 3J outputs
sl_HFLP <= slv_TILE(15) when sl_4HDLn = '0' else slv_4C_4K(15);
-- 3F selector is external because all ROMs are also external, address bits 17:15 below would decode to GCS0..5
slv_GP_ADDR(17 downto 3) <= slv_TILE(14 downto 8) & slv_MPIC when sl_4HDLn = '0' else '0' & slv_PFV(11 downto 10) & slv_4C_4K(11 downto 0);
-- 3E mux, SEL 0=A, 1=B
slv_GP_ADDR(2) <= slv_4E(3) when sl_4HDLn = '0' else slv_PFV(2);
slv_GP_ADDR(1) <= slv_4E(2) when sl_4HDLn = '0' else slv_PFV(1);
slv_GP_ADDR(0) <= slv_4E(1) when sl_4HDLn = '0' else slv_PFV(0);
sl_GP_EN <= slv_4E(0) when sl_4HDLn = '0' else '1';
-- bit 14 inverted as per XOR gate 4J, slv_GP_ADDR(17 downto 16) not decoded (ROMS at GCS2..5 not fitted)
sl_GP_ADDR14 <= (not slv_GP_ADDR(14));
-- adder 6L
slv_sum_6L <= ( ('1' & slv_VSIZ(2 downto 0)) + ( '1' & slv_sum_5D_5E(5 downto 3)) ) + ( "0001");
-- NAND gate 6T
sl_VMATCHn <= not (slv_sum_5D_5E(8) and slv_sum_5D_5E(7) and slv_sum_5D_5E(6) and slv_sum_6L(3));
-- PROM 5L is 82S147 512x8 TTL BIPOLAR PROM (Atari chip 136037.102)
-- Top 2 address bits tied low so only 128x8 used
u_5L : entity work.PROM_5L
port map (
CLK => I_MCKR,
ADDR(6) => sl_MFLP,
ADDR(5) => slv_HSIZ(2),
ADDR(4) => slv_HSIZ(1),
ADDR(3) => slv_HSIZ(0),
ADDR(2) => slv_sum_6L(2),
ADDR(1) => slv_sum_6L(1),
ADDR(0) => slv_sum_6L(0),
DATA => slv_PROM_5L
);
-- 4L, 4M counters
p_4L_4M : process
begin
wait until rising_edge(I_MCKR);
if sl_H03 = '1' and sl_4H = '0' then
if sl_NEWMOn = '0' then
slv_ctr_4L_4M <= slv_PROM_5L;
elsif sl_MREFL = '0' then
slv_ctr_4L_4M <= slv_ctr_4L_4M + 1;
else
slv_ctr_4L_4M <= slv_ctr_4L_4M - 1;
end if;
end if;
end process;
-- 3L, 3M adders
slv_MPIC <= slv_TILE(7 downto 0) + slv_ctr_4L_4M;
-- 5J, 5F, 4F counters
p_5J_5F_4F : process
begin
wait until rising_edge(I_MCKR);
if sl_H03 = '1' and sl_4H = '0' then
if sl_VSYNCn = '0' and sl_PFHSTn = '0' then
slv_PFV <= slv_VRD( 1 downto 0) & '0' & slv_VRD(15 downto 7);
elsif sl_PFHSTn = '0' and sl_VBLANKn = '1' then
slv_PFV <= slv_PFV + 1;
end if;
end if;
end process;
-- 4C, 4K latch
p_4C_4K : process
begin
wait until rising_edge(I_MCKR);
if sl_H03 = '1' and sl_4Hn = '0' then
slv_4C_4K <= slv_VRD;
end if;
end process;
sl_4HD3_en <= sl_4hn or sl_4hdln or sl_4hddn or (not sl_4hd3n);
-- 4D latch
p_4D : process
begin
-- rising edge sl_4HD3 in schema
wait until rising_edge(I_MCKR);
if sl_4HD3_en = '0' then
slv_PFSR(6 downto 4) <= not slv_4C_4K(14 downto 12);
end if;
end process;
-- remember that MO/PF is /4HDL inverted
sl_MO_PFn <= not sl_4HDLn;
--------------------------------------------------
-- sheet 11 - plane 0 and plane 1 ROMs and SLAG --
-- sheet 12 - plane 2 and plane 3 ROMs and SLAG --
-- ROMs total 256KB and are stored outside the FPGA
--------------------------------------------------
-- 1K Storage/Logic Array Graphics Shifter
u_1K : entity work.SLAGS
port map (
I_PHIN => I_MCKR,
I_A => slv_GP_DATA( 7 downto 0),
I_B => slv_GP_DATA(15 downto 8),
I_HLDAn => '1',
I_HLDBn => '1',
I_FLP => sl_HFLP,
I_MO_PFn => sl_MO_PFn,
I_LDn => sl_GLDn,
O_PFDA => slv_PFSR(0),
O_PFDB => slv_PFSR(1),
O_MODA => slv_MOSR(0),
O_MODB => slv_MOSR(1)
);
-- 2K Storage/Logic Array Graphics Shifter
u_2K : entity work.SLAGS
port map (
I_PHIN => I_MCKR,
I_A => slv_GP_DATA(23 downto 16),
I_B => slv_GP_DATA(31 downto 24),
I_HLDAn => '1',
I_HLDBn => '1',
I_FLP => sl_HFLP,
I_MO_PFn => sl_MO_PFn,
I_LDn => sl_GLDn,
O_PFDA => slv_PFSR(2),
O_PFDB => slv_PFSR(3),
O_MODA => slv_MOSR(2),
O_MODB => slv_MOSR(3)
);
-- Pullups RN3, RN4, RN5, RN6
slv_GP_DATA <= I_GP_DATA when sl_GP_EN = '1' else (others=>'1');
--------------------------------
-- sheet 13 Play Field Scroll --
--------------------------------
-- 12K Play Field Horizontal Scroll
u_12K : entity work.PFHS
port map (
I_CK => I_MCKR,
I_ST => sl_PFHSTn,
I_4H => sl_4H,
I_H03 => sl_H03,
I_HS => sl_HSCRLDn,
I_SPC => '1',
I_D => slv_VBD(8 downto 0),
I_PS(7) => slv_PFSR(6),
I_PS(6 downto 0) => slv_PFSR(6 downto 0),
O_PFM => open,
O_PFH => slv_PFH(8 downto 3),
O_XP => slv_PFX
);
-- Motion Object Horizontal Line Buffer
u_MOHLB : entity work.MOHLB
port map (
I_MCKR => I_MCKR,
I_LMPDn => sl_LMPDn,
I_LDABn => sl_LDABn,
I_BUFCLRn => sl_BUFCLRn,
I_HPOS => slv_HPOS,
I_MOSR => slv_MOSR,
O_MPX => slv_MPX
);
----------------------------
-- sheet 14
----------------------------
-- 902800-903000 R/W xxxxxxxx x------- (X position)
-- R/W -------- ----xxxx (Palette select)
-- 4N, 3N latches sheet 14
p_4N_3N : process
begin
wait until rising_edge(I_MCKR);
if sl_HORZDLn_tap = '0' then
slv_XPOS <= slv_VRD(15 downto 7);
slv_PSEL <= slv_VRD(3 downto 0);
end if;
end process;
-- 9S, 6M, 7M latches (Playfield X scroll at address 930000)
p_9S_6M_7M : process
begin
-- rising edge sl_HSCRLDn in schema
wait until rising_edge(I_MCKR);
if sl_HSCRLDn = '0' then
slv_adder_a <= not slv_VBD(8 downto 0); -- /PF256LD .. /PF1LD
end if;
end process;
-- 5N, 5P adders and gates 4T
slv_HPOS <= slv_XPOS + (slv_adder_a + "000000001"); -- add 2's complement to XPOS
-- 3P latch
p_3P : process
begin
-- rising edge sl_LDABn in schema
wait until rising_edge(I_MCKR);
if sl_LDABn = '0' then
slv_MOSR(7 downto 4) <= not slv_PSEL;
end if;
end process;
-- PROM 4R is 74S287 (256x4) TTL PROM "136037-103"
u_4R : entity work.PROM_4R
port map (
CLK => sl_MCKF,
ADDR(7 downto 3) => slv_HPOS(8 downto 4),
ADDR(2 downto 0) => slv_HSIZ(2 downto 0),
DATA => slv_4R_data
);
-- 5R counter
p_5R : process
begin
-- rising edge sl_4HD3 in schema
wait until rising_edge(I_MCKR);
if sl_4HD3_en = '0' then
if sl_NEWMOn = '0' then
slv_ctr_5R <= '0' & slv_4R_data(3 downto 1);
else
slv_ctr_5R <= slv_ctr_5R - 1;
end if;
end if;
end process;
sl_ENDn <= slv_ctr_5R(3) or slv_ctr_5R(2) or slv_ctr_5R(1) or slv_ctr_5R(0);
-- 6S F/F with async set/reset
p_6S6 : process(sl_NXLn, I_MCKR)
begin
if sl_NXLn = '0' then
sl_6S6 <= '0';
elsif rising_edge(I_MCKR) then
if sl_VERTDLn = '0' then
sl_6S6 <= not sl_VMATCHn;
end if;
end if;
end process;
p_6S9 : process(sl_VERTDLn, I_MCKR)
begin
if sl_VERTDLn = '0' then
sl_6S9 <= '1';
elsif rising_edge(I_MCKR) then
if sl_HORZDLn = '0' then
sl_6S9 <= slv_4R_data(0);
end if;
end if;
end process;
-- gate 4U
sl_MATCH <= sl_6S6 and sl_6S9;
sl_2H <= slv_H(1);
sl_1H <= slv_H(0);
-- gate 7T
sl_H03 <= sl_2H and sl_1H;
-- 6U latch with 7U PROM equations
p_6U : process
begin
wait until rising_edge(I_MCKR);
-- 82S147 512x8 TTL BIPOLAR PROM (Atari chip 136037.101)
-- These equations replace the 7U PROM
-- Minterms Sum of Products
-- D7 = A5 A1' + A5 A0 + A5 A2 + A6 A4 A3 A2' A1 A0' + A6 A5
-- D6 = A0' + A1 + A2 + A5
-- D5 = A1' A0 + A1 A0' + A5 A3 A2' A0 + A7 A4' A3 A2 A0 + A7 A5 A3 A0
-- D4 = A3' + A1' A0 + A1 A0' + A2 A0 + A5' A4 A2' A1' + A5 A0
-- D3 = A1' A0 + A1 A0' + A3 A2 + A5 A3 + A3' A0 + A4' A3 A1'
-- D2 = A2' + A0' + A1 + A8
-- D1 = A1' A0 + A2' A1 A0' + A7' A2 A0 + A4' A3 A2 A0 + A5 A3 A0
-- D0 = A1' + A2' A0 + A7 A0
sl_NEWMOn <= (sl_NEWMOn and (sl_4H or (not sl_2H) or sl_1H)) or
(sl_ENDn and sl_MATCHDL and sl_MATCH and (not sl_4H) and sl_2H and (not sl_1H)) or
(sl_ENDn and sl_NEWMOn);
sl_LDABn <= sl_NEWMOn or sl_4H or sl_2H or (not sl_1H);
sl_G8T <= (sl_2H xor sl_1H) or
( (sl_NEWMOn and sl_MATCH) and ( ((not sl_4H) and sl_1H) or (sl_NXLn and sl_1H) ) ) or
(sl_NXLn and (not sl_MATCHDL) and sl_MATCH and sl_4H and sl_1H);
sl_MC1 <= (sl_2H xor sl_1H) or
(not sl_MATCH) or
(sl_1H and (sl_4H or sl_NEWMOn)) or
((not sl_NEWMOn) and sl_MATCHDL and (not sl_4H) and (not sl_2H));
sl_MC0 <= (sl_2H xor sl_1H) or
(sl_MATCH and (sl_NEWMOn or sl_4H)) or
((not sl_MATCH) and sl_1H) or
((not sl_MATCHDL) and sl_MATCH and (not sl_2H));
sl_BUFCLRn <= sl_LMPDn or (not sl_4H) or sl_2H or (not sl_1H);
end process;
slv_VAS_star(1) <=
((not sl_2H) and sl_1H) or
((not sl_4H) and sl_2H and (not sl_1H)) or
((not sl_NXLn) and sl_4H and sl_1H) or
((not sl_MATCHDL) and sl_MATCH and sl_4H and sl_1H) or
(sl_NEWMOn and sl_MATCH and sl_1H);
slv_VAS_star(0) <=
(not sl_2H) or
((not sl_4H) and sl_1H) or
(sl_NXLn and sl_1H);
-- 8T selector
-- here we use the tap signals as master clock gates so that we can capture the
-- data we want at the same time as falling edge of the corresponding non tap signals
sl_LINKn <= sl_G8T or (not sl_MC1) or (not sl_MC0); -- 3
sl_VERTDLn_tap <= sl_G8T or (not sl_MC1) or ( sl_MC0); -- 2
sl_HORZDLn_tap <= sl_G8T or ( sl_MC1) or (not sl_MC0); -- 1
sl_PICTDLn_tap <= sl_G8T or ( sl_MC1) or ( sl_MC0); -- 0
-- 5S, 5T latches
p_5S_5T : process
begin
wait until rising_edge(I_MCKR);
-- Q outputs of 5S
sl_VERTDLn <= sl_VERTDLn_tap; -- 2
sl_HORZDLn <= sl_HORZDLn_tap; -- 1
-- sl_PICTDLn <= sl_PICTDLn_tap; -- 0
sl_FLBBn <= (sl_FLBAn xor sl_BUFCLRn);
-- Q outputs of 5T
sl_4H <= sl_4HD3n;
sl_4HD3n <= sl_4HDDn;
sl_NXLn <= sl_NXLn_star;
sl_GLD <= sl_H03;
end process;
-- /Q outputs of 5S
-- sl_VERTDL <= not sl_VERTDLn;
-- sl_HORZDL <= not sl_HORZDLn;
-- sl_PICTDL <= not sl_PICTDLn;
sl_FLBAn <= not sl_FLBBn;
-- /Q outputs of 5T
sl_4Hn <= not sl_4H;
-- sl_4HD3 <= not sl_4HD3n;
sl_NXL <= not sl_NXLn;
sl_GLDn <= not sl_GLD;
-- 14M F/F
p_14M : process(sl_VBKACKn, I_MCKR)
begin
if sl_VBKACKn = '0' then
O_VBKINTn <= '1';
elsif rising_edge(I_MCKR) then
sl_VBLANKn_en <= sl_VBLANKn;
if sl_VBLANKn = '0' and sl_VBLANKn_en = '1' then
O_VBKINTn <= '0';
end if;
end if;
end process;
u_8P : entity work.SYNGEN
port map (
I_CK => I_MCKR,
O_C0 => open, -- UNUSED
O_C1 => open, -- UNUSED
O_C2 => open, -- UNUSED
O_LMPDn => sl_LMPDn,
O_HBKn => open, -- UNUSED
O_VIDBn => sl_VIDBLANKn,
O_VRESn => open, -- UNUSED
O_HSYNCn => sl_HSYNCn,
O_VSYNCn => sl_VSYNCn,
O_PFHSTn => sl_PFHSTn,
O_BUFCLRn => open, -- UNUSED this /BUFCLR replaced by signal from PROM 7U
O_VBLKn => sl_VBLANKn,
O_VSCK => open, -- UNUSED
O_CK0n => open, -- same as MCKF
O_CK0 => open, -- same as MCKR
O_2HDLn => open, -- UNUSED
O_4HDLn => sl_4HDLn,
O_4HDDn => sl_4HDDn,
O_NXLn => sl_NXLn_star,
O_V => slv_V,
O_H => slv_H
);
-- clock generation, 14.31818 MHz xtal drives F/F
-- F/F divides xtal by 2 and generates:
-- MCKR (Master Clock Rising - 7.1591MHz)
-- MCKF (Master Clock Falling - inverted MCKR)
-- other clocks are copies of master clock
-- RCLOCK same as MCKR
-- FCLOCK same as MCKF
-- LBCKR same as MCKR
-- LBCKF same as MCKF
----------------------------
-- sheet 15
----------------------------
-- gates 6T, 9R
sl_6T8 <= not ((not slv_MPX(0)) and slv_MPX(1) and slv_MPX(2) and slv_MPX(3));
-- Graphic Priority Control
u_12M : entity work.GPC
port map (
I_CK => I_MCKR,
I_PFM => '0',
I_4H => sl_4H,
I_SEL => I_CRAMn,
-- AL serialised data
I_AL(1) => slv_shift_7P(3), -- APIX1
I_AL(0) => slv_shift_7N(3), -- APIX0
I_MA => slv_MA(10 downto 9),
-- I_D controls color for alphanumerics
I_D(3) => slv_VRD(15), -- to PROM MSB inside GPC
I_D(2) => slv_VRD(12), -- to ALC2 inside GPC
I_D(1) => slv_VRD(11), -- to ALC1 inside GPC
I_D(0) => slv_VRD(10), -- to ALC0 inside GPC
-- PF data
I_P(7) => sl_6T8,
I_P(6 downto 0) => slv_PFX(6 downto 0),
-- MO data
I_M(7) => sl_6T8,
I_M(6 downto 0) => slv_MPX(6 downto 0),
O_CA => slv_GPC_CA
);
-- at address 910000-9107FF
u_CRAMS : entity work.CRAMS
port map (
I_MCKR => I_MCKR,
I_UDSn => sl_UDSn,
I_LDSn => sl_LDSn,
I_CRAMn => I_CRAMn,
I_BR_Wn => sl_BR_Wn,
I_CRA => slv_CRA,
I_DB => slv_VBD,
O_DB => slv_CRAM
);
-- 9N, 10N latch color palette output
p_9N_10N : process
begin
wait until falling_edge(I_MCKR);
if I_CRAMn='1' then
if sl_VIDBLANKn = '0' then
sl_I <= (others=>'0');
sl_R <= (others=>'0');
sl_G <= (others=>'0');
sl_B <= (others=>'0');
else
-- UDS
sl_I <= slv_CRAM(15 downto 12); -- INT
sl_R <= slv_CRAM(11 downto 8); -- RED
-- LDS
sl_G <= slv_CRAM( 7 downto 4); -- GRN
sl_B <= slv_CRAM( 3 downto 0); -- BLU
end if;
end if;
end process;
slv_CRA(9 downto 8) <= slv_GPC_CA(9 downto 8);
-- 8M tristate buffer A>Y
slv_CRA(7 downto 0) <= slv_MA(8 downto 1) when I_CRAMn = '0' else sl_CRA7 & slv_GPC_CA(6) & sl_CRA5 & slv_GPC_CA(4 downto 0);
-- 8U dual 4:1 mux
sl_CRA7 <=
slv_GPC_CA(7) when slv_GPC_CA(9 downto 8) = "11" else
slv_GPC_CA(7) when slv_GPC_CA(9 downto 8) = "10" else
sl_6X6 when slv_GPC_CA(9 downto 8) = "01" else
sl_ALC4D when slv_GPC_CA(9 downto 8) = "00";
-- 8U dual 4:1 mux
sl_CRA5 <=
slv_GPC_CA(5) when slv_GPC_CA(9 downto 8) = "11" else
slv_GPC_CA(5) when slv_GPC_CA(9 downto 8) = "10" else
slv_GPC_CA(5) when slv_GPC_CA(9 downto 8) = "01" else
sl_ALC3D when slv_GPC_CA(9 downto 8) = "00";
-- 6X F/F
p_6X : process
begin
wait until falling_edge(I_MCKR);
sl_6X6 <= not slv_MPX(7);
-- sl_6X8 <= not sl_4H;
end process;
sl_6X8_en <= (not sl_4hn) or sl_4hdln or sl_4hddn or sl_4hd3n;
-- 6W F/F
p_6W : process
begin
wait until falling_edge(I_MCKR);
if sl_6X8_en = '0' then
sl_ALC4D <= sl_ALC4;
sl_ALC3D <= sl_ALC3;
end if;
end process;
-- Alphanumerics are handled by 4P, 7R, 6P, 7P, 7N and fed into GPC
p_4P_7R : process
begin
wait until rising_edge(I_MCKR);
if sl_H03 = '1' and sl_4H = '0' then
-- 4P latch
sl_ALC4 <= slv_VRD(14);
sl_ALC3 <= slv_VRD(13);
slv_ROM_6P_addr(13 downto 10) <= slv_VRD( 9 downto 6);
-- 7R latch
slv_ROM_6P_addr( 9 downto 4) <= slv_VRD( 5 downto 0);
sl_MATCHDL <= sl_MATCH;
end if;
end process;
-- unlatched low address bus
slv_ROM_6P_addr(3 downto 0) <= slv_V(2 downto 0) & sl_4Hn;
-- 6P ROM
u_6P : entity work.ROM_6P
port map (
CLK => I_MCKR,
ADDR => slv_ROM_6P_addr,
DATA => slv_ROM_6P
);
-- 7P, 7N shifters S1 S0 11=load 10=shift left 01=shift right 00=inhibit
p_7P_7N : process
begin
wait until falling_edge(I_MCKR);
if sl_H03 = '1'then -- load
slv_shift_7P <= slv_ROM_6P(7 downto 4);
slv_shift_7N <= slv_ROM_6P(3 downto 0);
elsif sl_H03 = '0' then -- shift msb
slv_shift_7P <= slv_shift_7P(2 downto 0) & '0'; --msb is APIX1
slv_shift_7N <= slv_shift_7N(2 downto 0) & '0'; --msb is APIX0
-- else inhibit
end if;
end process;
end RTL;

View File

@@ -0,0 +1,228 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
library ieee;
use ieee.std_logic_1164.all;
entity VRAMS is
port(
I_CK : in std_logic;
I_VRAMWE : in std_logic;
I_SELB : in std_logic;
I_SELA : in std_logic;
I_UDSn : in std_logic;
I_LDSn : in std_logic;
I_VRA : in std_logic_vector(11 downto 0);
I_VRD : in std_logic_vector(15 downto 0);
O_VRD : out std_logic_vector(15 downto 0)
);
end VRAMS;
architecture RTL of VRAMS is
signal
sl_PF_HI,
sl_MO_HI,
sl_AL_HI,
sl_PF_LO,
sl_MO_LO,
sl_AL_LO,
sl_PF_CSn,
sl_MO_CSn,
sl_AL_CSn
: std_logic := '1';
signal
sl_VRAMWE
: std_logic := '0';
signal
slv_PF,
slv_MO,
slv_AL
: std_logic_vector(15 downto 0) := (others=>'0');
begin
-------------------------
-- sheet 9 RAM decoder --
-------------------------
-- 9C decoders
sl_PF_CSn <= ( I_SELB ) or ( I_SELA );
sl_MO_CSn <= ( I_SELB ) or ( not I_SELA );
sl_AL_CSn <= ( not I_SELB ) or ( I_SELA );
-- Xilinx Block RAM chip selects
sl_PF_HI <= not (I_UDSn or sl_PF_CSn);
sl_MO_HI <= not (I_UDSn or sl_MO_CSn);
sl_AL_HI <= not (I_UDSn or sl_AL_CSn);
sl_PF_LO <= not (I_LDSn or sl_PF_CSn);
sl_MO_LO <= not (I_LDSn or sl_MO_CSn);
sl_AL_LO <= not (I_LDSn or sl_AL_CSn);
-----------------------
-- sheet 8 RAM banks --
-----------------------
sl_VRAMWE <= I_VRAMWE;
O_VRD <=
slv_PF when sl_PF_CSn = '0' else
slv_MO when sl_MO_CSn = '0' else
slv_AL when sl_AL_CSn = '0' else
-- slv_AL when sl_AL_CSn = '0' and (I_VRA < x"800" or I_VRA > x"F69") else -- disables reads from alphanumerics range 905000-905BB0
(others=>'Z'); -- floating
-- PF video RAMs 6D, 7D, 6J, 7J
p_7J_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_PF_LO,
data => I_VRD(3 downto 0),
wren => sl_VRAMWE,
q => slv_PF(3 downto 0)
);
p_6J_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_PF_LO,
data => I_VRD(7 downto 4),
wren => sl_VRAMWE,
q => slv_PF(7 downto 4)
);
p_7D_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_PF_HI,
data => I_VRD(11 downto 8),
wren => sl_VRAMWE,
q => slv_PF(11 downto 8)
);
p_6D_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_PF_HI,
data => I_VRD(15 downto 12),
wren => sl_VRAMWE,
q => slv_PF(15 downto 12)
);
-- MO video RAMs 6C, 7C, 6F, 7F
p_7F_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_MO_LO,
data => I_VRD(3 downto 0),
wren => sl_VRAMWE,
q => slv_MO(3 downto 0)
);
p_6F_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_MO_LO,
data => I_VRD(7 downto 4),
wren => sl_VRAMWE,
q => slv_MO(7 downto 4)
);
p_7C_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_MO_HI,
data => I_VRD(11 downto 8),
wren => sl_VRAMWE,
q => slv_MO(11 downto 8)
);
p_6C_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_MO_HI,
data => I_VRD(15 downto 12),
wren => sl_VRAMWE,
q => slv_MO(15 downto 12)
);
-- AL video RAMs 6E, 7E, 6K, 7K
p_7K_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_AL_LO,
data => I_VRD(3 downto 0),
wren => sl_VRAMWE,
q => slv_AL(3 downto 0)
);
p_6K_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_AL_LO,
data => I_VRD(7 downto 4),
wren => sl_VRAMWE,
q => slv_AL(7 downto 4)
);
p_7E_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_AL_HI,
data => I_VRD(11 downto 8),
wren => sl_VRAMWE,
q => slv_AL(11 downto 8)
);
p_6E_RAM : entity work.spram
generic map (
widthad_a => 12,
width_a => 4)
port map (
address => I_VRA,
clock => I_CK,-- and sl_AL_HI,
data => I_VRD(15 downto 12),
wren => sl_VRAMWE,
q => slv_AL(15 downto 12)
);
end RTL;

View File

@@ -0,0 +1,35 @@
# ================================================================================
#
# Build ID Verilog Module Script
# Jeff Wiencrot - 8/1/2011
#
# Generates a Verilog module that contains a timestamp,
# from the current build. These values are available from the build_date, build_time,
# physical_address, and host_name output ports of the build_id module in the build_id.v
# Verilog source file.
#
# ================================================================================
proc generateBuildID_Verilog {} {
# Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html)
set buildDate [ clock format [ clock seconds ] -format %y%m%d ]
set buildTime [ clock format [ clock seconds ] -format %H%M%S ]
# Create a Verilog file for output
set outputFileName "rtl/build_id.v"
set outputFile [open $outputFileName "w"]
# Output the Verilog source
puts $outputFile "`define BUILD_DATE \"$buildDate\""
puts $outputFile "`define BUILD_TIME \"$buildTime\""
close $outputFile
# Send confirmation message to the Messages window
post_message "Generated build identification Verilog module: [pwd]/$outputFileName"
post_message "Date: $buildDate"
post_message "Time: $buildTime"
}
# Comment out this line to prevent the process from automatically executing when the file is sourced:
generateBuildID_Verilog

View File

@@ -0,0 +1,461 @@
-- megafunction wizard: %ALTPLL%
-- GENERATION: STANDARD
-- VERSION: WM1.0
-- MODULE: altpll
-- ============================================================
-- File Name: pll_mist.vhd
-- Megafunction Name(s):
-- altpll
--
-- Simulation Library Files(s):
-- altera_mf
-- ============================================================
-- ************************************************************
-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
--
-- 13.1.0 Build 162 10/23/2013 SJ Web Edition
-- ************************************************************
--Copyright (C) 1991-2013 Altera Corporation
--Your use of Altera Corporation's design tools, logic functions
--and other software and tools, and its AMPP partner logic
--functions, and any output files from any of the foregoing
--(including device programming or simulation files), and any
--associated documentation or information are expressly subject
--to the terms and conditions of the Altera Program License
--Subscription Agreement, Altera MegaCore Function License
--Agreement, or other applicable license agreement, including,
--without limitation, that your use is for the sole purpose of
--programming logic devices manufactured by Altera and sold by
--Altera or its authorized distributors. Please refer to the
--applicable agreement for further details.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.all;
ENTITY pll_mist IS
PORT
(
areset : IN STD_LOGIC := '0';
inclk0 : IN STD_LOGIC := '0';
c0 : OUT STD_LOGIC ;
c1 : OUT STD_LOGIC ;
c2 : OUT STD_LOGIC ;
c3 : OUT STD_LOGIC ;
locked : OUT STD_LOGIC
);
END pll_mist;
ARCHITECTURE SYN OF pll_mist IS
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (4 DOWNTO 0);
SIGNAL sub_wire1 : STD_LOGIC ;
SIGNAL sub_wire2 : STD_LOGIC ;
SIGNAL sub_wire3 : STD_LOGIC ;
SIGNAL sub_wire4 : STD_LOGIC ;
SIGNAL sub_wire5 : STD_LOGIC ;
SIGNAL sub_wire6 : STD_LOGIC ;
SIGNAL sub_wire7 : STD_LOGIC_VECTOR (1 DOWNTO 0);
SIGNAL sub_wire8_bv : BIT_VECTOR (0 DOWNTO 0);
SIGNAL sub_wire8 : STD_LOGIC_VECTOR (0 DOWNTO 0);
COMPONENT altpll
GENERIC (
bandwidth_type : STRING;
clk0_divide_by : NATURAL;
clk0_duty_cycle : NATURAL;
clk0_multiply_by : NATURAL;
clk0_phase_shift : STRING;
clk1_divide_by : NATURAL;
clk1_duty_cycle : NATURAL;
clk1_multiply_by : NATURAL;
clk1_phase_shift : STRING;
clk2_divide_by : NATURAL;
clk2_duty_cycle : NATURAL;
clk2_multiply_by : NATURAL;
clk2_phase_shift : STRING;
clk3_divide_by : NATURAL;
clk3_duty_cycle : NATURAL;
clk3_multiply_by : NATURAL;
clk3_phase_shift : STRING;
compensate_clock : STRING;
inclk0_input_frequency : NATURAL;
intended_device_family : STRING;
lpm_hint : STRING;
lpm_type : STRING;
operation_mode : STRING;
pll_type : STRING;
port_activeclock : STRING;
port_areset : STRING;
port_clkbad0 : STRING;
port_clkbad1 : STRING;
port_clkloss : STRING;
port_clkswitch : STRING;
port_configupdate : STRING;
port_fbin : STRING;
port_inclk0 : STRING;
port_inclk1 : STRING;
port_locked : STRING;
port_pfdena : STRING;
port_phasecounterselect : STRING;
port_phasedone : STRING;
port_phasestep : STRING;
port_phaseupdown : STRING;
port_pllena : STRING;
port_scanaclr : STRING;
port_scanclk : STRING;
port_scanclkena : STRING;
port_scandata : STRING;
port_scandataout : STRING;
port_scandone : STRING;
port_scanread : STRING;
port_scanwrite : STRING;
port_clk0 : STRING;
port_clk1 : STRING;
port_clk2 : STRING;
port_clk3 : STRING;
port_clk4 : STRING;
port_clk5 : STRING;
port_clkena0 : STRING;
port_clkena1 : STRING;
port_clkena2 : STRING;
port_clkena3 : STRING;
port_clkena4 : STRING;
port_clkena5 : STRING;
port_extclk0 : STRING;
port_extclk1 : STRING;
port_extclk2 : STRING;
port_extclk3 : STRING;
self_reset_on_loss_lock : STRING;
width_clock : NATURAL
);
PORT (
areset : IN STD_LOGIC ;
clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0);
inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0);
locked : OUT STD_LOGIC
);
END COMPONENT;
BEGIN
sub_wire8_bv(0 DOWNTO 0) <= "0";
sub_wire8 <= To_stdlogicvector(sub_wire8_bv);
sub_wire5 <= sub_wire0(2);
sub_wire4 <= sub_wire0(0);
sub_wire2 <= sub_wire0(3);
sub_wire1 <= sub_wire0(1);
c1 <= sub_wire1;
c3 <= sub_wire2;
locked <= sub_wire3;
c0 <= sub_wire4;
c2 <= sub_wire5;
sub_wire6 <= inclk0;
sub_wire7 <= sub_wire8(0 DOWNTO 0) & sub_wire6;
altpll_component : altpll
GENERIC MAP (
bandwidth_type => "AUTO",
clk0_divide_by => 35,
clk0_duty_cycle => 50,
clk0_multiply_by => 83,
clk0_phase_shift => "0",
clk1_divide_by => 80,
clk1_duty_cycle => 50,
clk1_multiply_by => 83,
clk1_phase_shift => "0",
clk2_divide_by => 160,
clk2_duty_cycle => 50,
clk2_multiply_by => 83,
clk2_phase_shift => "0",
clk3_divide_by => 320,
clk3_duty_cycle => 50,
clk3_multiply_by => 83,
clk3_phase_shift => "0",
compensate_clock => "CLK0",
inclk0_input_frequency => 37037,
intended_device_family => "Cyclone III",
lpm_hint => "CBX_MODULE_PREFIX=pll_mist",
lpm_type => "altpll",
operation_mode => "NORMAL",
pll_type => "AUTO",
port_activeclock => "PORT_UNUSED",
port_areset => "PORT_USED",
port_clkbad0 => "PORT_UNUSED",
port_clkbad1 => "PORT_UNUSED",
port_clkloss => "PORT_UNUSED",
port_clkswitch => "PORT_UNUSED",
port_configupdate => "PORT_UNUSED",
port_fbin => "PORT_UNUSED",
port_inclk0 => "PORT_USED",
port_inclk1 => "PORT_UNUSED",
port_locked => "PORT_USED",
port_pfdena => "PORT_UNUSED",
port_phasecounterselect => "PORT_UNUSED",
port_phasedone => "PORT_UNUSED",
port_phasestep => "PORT_UNUSED",
port_phaseupdown => "PORT_UNUSED",
port_pllena => "PORT_UNUSED",
port_scanaclr => "PORT_UNUSED",
port_scanclk => "PORT_UNUSED",
port_scanclkena => "PORT_UNUSED",
port_scandata => "PORT_UNUSED",
port_scandataout => "PORT_UNUSED",
port_scandone => "PORT_UNUSED",
port_scanread => "PORT_UNUSED",
port_scanwrite => "PORT_UNUSED",
port_clk0 => "PORT_USED",
port_clk1 => "PORT_USED",
port_clk2 => "PORT_USED",
port_clk3 => "PORT_USED",
port_clk4 => "PORT_UNUSED",
port_clk5 => "PORT_UNUSED",
port_clkena0 => "PORT_UNUSED",
port_clkena1 => "PORT_UNUSED",
port_clkena2 => "PORT_UNUSED",
port_clkena3 => "PORT_UNUSED",
port_clkena4 => "PORT_UNUSED",
port_clkena5 => "PORT_UNUSED",
port_extclk0 => "PORT_UNUSED",
port_extclk1 => "PORT_UNUSED",
port_extclk2 => "PORT_UNUSED",
port_extclk3 => "PORT_UNUSED",
self_reset_on_loss_lock => "OFF",
width_clock => 5
)
PORT MAP (
areset => areset,
inclk => sub_wire7,
clk => sub_wire0,
locked => sub_wire3
);
END SYN;
-- ============================================================
-- CNX file retrieval info
-- ============================================================
-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0"
-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000"
-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1"
-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz"
-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low"
-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1"
-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0"
-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0"
-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0"
-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "0"
-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0"
-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0"
-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0"
-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0"
-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0"
-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8"
-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "35"
-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "80"
-- Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "160"
-- Retrieval info: PRIVATE: DIV_FACTOR3 NUMERIC "320"
-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000"
-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000"
-- Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000"
-- Retrieval info: PRIVATE: DUTY_CYCLE3 STRING "50.00000000"
-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "64.028572"
-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "28.012501"
-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "14.006250"
-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE3 STRING "7.003125"
-- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0"
-- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0"
-- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1"
-- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0"
-- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0"
-- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575"
-- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1"
-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000"
-- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz"
-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000"
-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1"
-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1"
-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz"
-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III"
-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1"
-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1"
-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1"
-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available"
-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0"
-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg"
-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg"
-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps"
-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT3 STRING "ps"
-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any"
-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0"
-- Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0"
-- Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0"
-- Retrieval info: PRIVATE: MIRROR_CLK3 STRING "0"
-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "83"
-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "83"
-- Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "83"
-- Retrieval info: PRIVATE: MULT_FACTOR3 NUMERIC "83"
-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1"
-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "64.00000000"
-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "28.00000000"
-- Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "14.00000000"
-- Retrieval info: PRIVATE: OUTPUT_FREQ3 STRING "7.00000000"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "0"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE3 STRING "0"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz"
-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT3 STRING "MHz"
-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1"
-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0"
-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000"
-- Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000"
-- Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000"
-- Retrieval info: PRIVATE: PHASE_SHIFT3 STRING "0.00000000"
-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0"
-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg"
-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg"
-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "deg"
-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT3 STRING "deg"
-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0"
-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1"
-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1"
-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0"
-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0"
-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0"
-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0"
-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll_mist.mif"
-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0"
-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1"
-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0"
-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0"
-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0"
-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000"
-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz"
-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500"
-- Retrieval info: PRIVATE: SPREAD_USE STRING "0"
-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0"
-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1"
-- Retrieval info: PRIVATE: STICKY_CLK1 STRING "1"
-- Retrieval info: PRIVATE: STICKY_CLK2 STRING "1"
-- Retrieval info: PRIVATE: STICKY_CLK3 STRING "1"
-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1"
-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1"
-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
-- Retrieval info: PRIVATE: USE_CLK0 STRING "1"
-- Retrieval info: PRIVATE: USE_CLK1 STRING "1"
-- Retrieval info: PRIVATE: USE_CLK2 STRING "1"
-- Retrieval info: PRIVATE: USE_CLK3 STRING "1"
-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0"
-- Retrieval info: PRIVATE: USE_CLKENA1 STRING "0"
-- Retrieval info: PRIVATE: USE_CLKENA2 STRING "0"
-- Retrieval info: PRIVATE: USE_CLKENA3 STRING "0"
-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0"
-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0"
-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
-- Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO"
-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "35"
-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50"
-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "83"
-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0"
-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "80"
-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50"
-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "83"
-- Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0"
-- Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "160"
-- Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50"
-- Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "83"
-- Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "0"
-- Retrieval info: CONSTANT: CLK3_DIVIDE_BY NUMERIC "320"
-- Retrieval info: CONSTANT: CLK3_DUTY_CYCLE NUMERIC "50"
-- Retrieval info: CONSTANT: CLK3_MULTIPLY_BY NUMERIC "83"
-- Retrieval info: CONSTANT: CLK3_PHASE_SHIFT STRING "0"
-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0"
-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037"
-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III"
-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll"
-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL"
-- Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO"
-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_USED"
-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED"
-- Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF"
-- Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5"
-- Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]"
-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]"
-- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset"
-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0"
-- Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1"
-- Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2"
-- Retrieval info: USED_PORT: c3 0 0 0 0 OUTPUT_CLK_EXT VCC "c3"
-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0"
-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked"
-- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0
-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0
-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0
-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0
-- Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1
-- Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2
-- Retrieval info: CONNECT: c3 0 0 0 0 @clk 0 0 1 3
-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0
-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.vhd TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.ppf TRUE
-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.inc FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.cmp FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist.bsf FALSE
-- Retrieval info: GEN_FILE: TYPE_NORMAL pll_mist_inst.vhd FALSE
-- Retrieval info: LIB_FILE: altera_mf
-- Retrieval info: CBX_MODULE_PREFIX: ON

View File

@@ -0,0 +1,72 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity EEP_14A is
port (
CLK : in std_logic;
WEn : in std_logic;
CEn : in std_logic;
OEn : in std_logic;
AD : in std_logic_vector(8 downto 0);
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0)
);
end entity;
-- EEPROM as RAM
architecture RTL of EEP_14A is
type RAM_ARRAY is array (0 to 511) of std_logic_vector(7 downto 0);
-- signal RAM : RAM_ARRAY:=(others=>(others=>'0'));
-- initial RAM contents
signal RAM : RAM_ARRAY := (
x"FF",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"03", -- 0x0000
x"FC",x"14",x"00",x"EB",x"FF",x"00",x"00",x"17",x"03",x"00",x"00",x"00",x"00",x"14",x"FF",x"00", -- 0x0010
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"03",x"FC",x"14", -- 0x0020
x"00",x"EB",x"FF",x"00",x"00",x"17",x"03",x"00",x"00",x"00",x"00",x"14",x"8C",x"51",x"B2",x"00", -- 0x0030
x"1F",x"1F",x"00",x"90",x"FC",x"4E",x"22",x"00",x"00",x"90",x"00",x"D2",x"9A",x"B4",x"00",x"B7", -- 0x0040
x"00",x"2E",x"9A",x"03",x"00",x"00",x"00",x"03",x"00",x"00",x"FC",x"EE",x"38",x"00",x"95",x"1F", -- 0x0050
x"40",x"1F",x"24",x"EC",x"00",x"1D",x"B0",x"1F",x"7A",x"C5",x"81",x"CF",x"00",x"0D",x"1C",x"20", -- 0x0060
x"45",x"F8",x"96",x"00",x"1A",x"90",x"54",x"B0",x"96",x"91",x"67",x"00",x"CC",x"1F",x"40",x"0C", -- 0x0070
x"04",x"86",x"00",x"1D",x"B0",x"19",x"36",x"FD",x"35",x"74",x"00",x"73",x"1C",x"20",x"0C",x"F7", -- 0x0080
x"AE",x"00",x"1A",x"90",x"91",x"42",x"1B",x"B6",x"97",x"00",x"55",x"04",x"26",x"B2",x"C5",x"00", -- 0x0090
x"00",x"00",x"C6",x"00",x"03",x"EF",x"36",x"97",x"00",x"31",x"7F",x"FF",x"00",x"B1",x"00",x"00", -- 0x00A0
x"00",x"90",x"49",x"68",x"FF",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x00B0
x"00",x"00",x"00",x"FF",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x00C0
x"00",x"00",x"FF",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x00D0
x"00",x"FF",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x00E0
x"FF",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"FF", -- 0x00F0
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"FF",x"00", -- 0x0100
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"FF",x"00",x"00", -- 0x0110
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"FF",x"00",x"00",x"00", -- 0x0120
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x0130
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x0140
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x0150
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x0160
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x0170
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x0180
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x0190
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x01A0
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x01B0
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x01C0
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00", -- 0x01D0
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"FF", -- 0x01E0
x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00",x"00" -- 0x01F0
);
-- attribute ram_style : string;
-- attribute ram_style of RAM : signal is "block";
begin
mem_proc : process
begin
wait until rising_edge(CLK);
DO <= (others=>'Z');
if CEn = '0' then
if OEn = '0' then
DO <= RAM(to_integer(unsigned(AD)));
elsif WEn = '0' then
RAM(to_integer(unsigned(AD))) <= DI;
end if;
end if;
end process;
end RTL;

View File

@@ -0,0 +1,41 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity PROM_4R is
port (
CLK : in std_logic;
ADDR : in std_logic_vector(7 downto 0);
DATA : out std_logic_vector(3 downto 0) := (others=>'0')
);
end entity;
architecture RTL of PROM_4R is
type ROM_ARRAY is array (0 to 255) of std_logic_vector(3 downto 0);
signal ROM : ROM_ARRAY := (
x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F", -- 0x0000
x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F", -- 0x0010
x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F", -- 0x0020
x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F", -- 0x0030
x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F", -- 0x0040
x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F", -- 0x0050
x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"B",x"B", -- 0x0060
x"1",x"3",x"5",x"7",x"7",x"7",x"7",x"7",x"1",x"3",x"3",x"3",x"3",x"3",x"3",x"3", -- 0x0070
x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0", -- 0x0080
x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0", -- 0x0090
x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0", -- 0x00A0
x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0", -- 0x00B0
x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0", -- 0x00C0
x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0",x"0", -- 0x00D0
x"0",x"0",x"0",x"0",x"0",x"0",x"D",x"F",x"0",x"0",x"0",x"0",x"9",x"B",x"D",x"F", -- 0x00E0
x"0",x"0",x"5",x"7",x"9",x"B",x"D",x"F",x"1",x"3",x"5",x"7",x"9",x"B",x"D",x"F" -- 0x00F0
);
attribute ram_style : string;
-- attribute ram_style of ROM : signal is "distributed";
begin
mem_proc : process
begin
wait until rising_edge(CLK);
DATA <= ROM(to_integer(unsigned(ADDR)));
end process;
end RTL;

View File

@@ -0,0 +1,41 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity PROM_5E is
port (
CLK : in std_logic;
ADDR : in std_logic_vector(7 downto 0);
DATA : out std_logic_vector(3 downto 0) := (others=>'1')
);
end entity;
architecture RTL of PROM_5E is
type ROM_ARRAY is array (0 to 255) of std_logic_vector(3 downto 0);
signal ROM : ROM_ARRAY := (
x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3", -- 0x0000
x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3", -- 0x0010
x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3", -- 0x0020
x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3", -- 0x0030
x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3", -- 0x0040
x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3", -- 0x0050
x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"3",x"B", -- 0x0060
x"B",x"B",x"B",x"9",x"9",x"9",x"9",x"B",x"B",x"B",x"B",x"B",x"B",x"B",x"B",x"F", -- 0x0070
x"F",x"F",x"F",x"F",x"F",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E", -- 0x0080
x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E", -- 0x0090
x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E", -- 0x00A0
x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E", -- 0x00B0
x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E", -- 0x00C0
x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E", -- 0x00D0
x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E", -- 0x00E0
x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"E",x"3" -- 0x00F0
);
attribute ram_style : string;
-- attribute ram_style of ROM : signal is "distributed";
begin
mem_proc : process
begin
wait until rising_edge(CLK);
DATA <= ROM(to_integer(unsigned(ADDR)));
end process;
end RTL;

View File

@@ -0,0 +1,33 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity PROM_5L is
port (
CLK : in std_logic;
ADDR : in std_logic_vector(6 downto 0);
DATA : out std_logic_vector(7 downto 0) := (others=>'0')
);
end entity;
architecture RTL of PROM_5L is
type ROM_ARRAY is array (0 to 127) of std_logic_vector(7 downto 0);
signal ROM : ROM_ARRAY := (
x"00",x"01",x"02",x"03",x"04",x"05",x"06",x"07",x"00",x"02",x"04",x"06",x"08",x"0A",x"0C",x"0E", -- 0x0000
x"00",x"03",x"06",x"09",x"0C",x"0F",x"12",x"15",x"00",x"04",x"08",x"0C",x"10",x"14",x"18",x"1C", -- 0x0010
x"00",x"05",x"0A",x"0F",x"14",x"19",x"1E",x"23",x"00",x"06",x"0C",x"12",x"18",x"1E",x"24",x"2A", -- 0x0020
x"00",x"07",x"0E",x"15",x"1C",x"23",x"2A",x"31",x"00",x"08",x"10",x"18",x"20",x"28",x"30",x"38", -- 0x0030
x"00",x"01",x"02",x"03",x"04",x"05",x"06",x"07",x"01",x"03",x"05",x"07",x"09",x"0B",x"0D",x"0F", -- 0x0040
x"02",x"05",x"08",x"0B",x"0E",x"11",x"14",x"17",x"03",x"07",x"0B",x"0F",x"13",x"17",x"1B",x"1F", -- 0x0050
x"04",x"09",x"0E",x"13",x"18",x"1D",x"22",x"27",x"05",x"0B",x"11",x"17",x"1D",x"23",x"29",x"2F", -- 0x0060
x"06",x"0D",x"14",x"1B",x"22",x"29",x"30",x"37",x"07",x"0F",x"17",x"1F",x"27",x"2F",x"37",x"3F" -- 0x0070
);
attribute ram_style : string;
-- attribute ram_style of ROM : signal is "distributed";
begin
mem_proc : process
begin
wait until rising_edge(CLK);
DATA <= ROM(to_integer(unsigned(ADDR)));
end process;
end RTL;

View File

@@ -0,0 +1,538 @@
library ieee;
use ieee.std_logic_1164.all,ieee.numeric_std.all;
entity ROM_6P is
port (
clk : in std_logic;
addr : in std_logic_vector(13 downto 0);
data : out std_logic_vector(7 downto 0)
);
end entity;
architecture prom of ROM_6P is
type rom is array(0 to 8191) of std_logic_vector(7 downto 0);
signal rom_data: rom := (
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"77",X"CC",X"FF",X"EE",X"EE",X"EE",X"FF",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"00",X"00",
X"FF",X"CC",X"FF",X"EE",X"EE",X"EE",X"FF",X"CC",X"EE",X"EE",X"FF",X"EE",X"FF",X"CC",X"00",X"00",
X"77",X"CC",X"FF",X"EE",X"FF",X"EE",X"EE",X"00",X"FF",X"EE",X"FF",X"EE",X"77",X"CC",X"00",X"00",
X"FF",X"CC",X"FF",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"FF",X"EE",X"FF",X"CC",X"00",X"00",
X"FF",X"EE",X"FF",X"EE",X"EE",X"00",X"FF",X"CC",X"EE",X"00",X"FF",X"EE",X"FF",X"EE",X"00",X"00",
X"FF",X"EE",X"FF",X"EE",X"EE",X"00",X"FF",X"CC",X"EE",X"00",X"EE",X"00",X"EE",X"00",X"00",X"00",
X"77",X"CC",X"FF",X"EE",X"FF",X"EE",X"EE",X"00",X"EE",X"EE",X"FF",X"EE",X"77",X"EE",X"00",X"00",
X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"FF",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"00",X"00",
X"33",X"CC",X"33",X"CC",X"33",X"CC",X"33",X"CC",X"33",X"CC",X"33",X"CC",X"33",X"CC",X"00",X"00",
X"00",X"EE",X"00",X"EE",X"00",X"EE",X"66",X"EE",X"66",X"EE",X"77",X"EE",X"33",X"CC",X"00",X"00",
X"EE",X"EE",X"EE",X"EE",X"FF",X"CC",X"FF",X"88",X"FF",X"CC",X"EE",X"EE",X"EE",X"EE",X"00",X"00",
X"EE",X"00",X"EE",X"00",X"EE",X"00",X"EE",X"00",X"EE",X"00",X"FF",X"EE",X"FF",X"EE",X"00",X"00",
X"EE",X"EE",X"FE",X"EE",X"FF",X"EE",X"FF",X"EE",X"FF",X"EE",X"FD",X"E6",X"DD",X"66",X"00",X"00",
X"EE",X"66",X"FF",X"66",X"FF",X"EE",X"FF",X"EE",X"FF",X"EE",X"DD",X"EE",X"CC",X"EE",X"00",X"00",
X"77",X"CC",X"FF",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"FF",X"EE",X"77",X"CC",X"00",X"00",
X"FF",X"CC",X"FF",X"EE",X"EE",X"EE",X"FF",X"CC",X"EE",X"00",X"EE",X"00",X"EE",X"00",X"00",X"00",
X"77",X"CC",X"FF",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"FF",X"EE",X"77",X"CC",X"00",X"EE",
X"FF",X"CC",X"FF",X"EE",X"EE",X"EE",X"FF",X"C8",X"FF",X"CC",X"EE",X"EE",X"EE",X"EE",X"00",X"00",
X"77",X"EE",X"FF",X"EE",X"EE",X"00",X"FF",X"EE",X"00",X"EE",X"FF",X"EE",X"FF",X"CC",X"00",X"00",
X"FF",X"EE",X"FF",X"EE",X"33",X"88",X"33",X"88",X"33",X"88",X"33",X"88",X"33",X"88",X"00",X"00",
X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"FF",X"EE",X"FF",X"EE",X"77",X"CC",X"00",X"00",
X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"66",X"CC",X"77",X"CC",X"33",X"88",X"33",X"88",X"00",X"00",
X"DD",X"66",X"FD",X"E6",X"FF",X"EE",X"FF",X"EE",X"FF",X"EE",X"FE",X"EE",X"EE",X"EE",X"00",X"00",
X"EC",X"E6",X"FE",X"EE",X"F7",X"EC",X"73",X"C8",X"F7",X"EC",X"FE",X"EE",X"EC",X"E6",X"00",X"00",
X"EE",X"EE",X"EE",X"EE",X"EE",X"EE",X"77",X"CC",X"33",X"88",X"33",X"88",X"33",X"88",X"00",X"00",
X"FF",X"EE",X"FF",X"EE",X"11",X"EE",X"77",X"CC",X"FF",X"00",X"FF",X"EE",X"FF",X"EE",X"00",X"00",
X"08",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"11",X"00",X"33",X"00",X"77",X"00",X"FF",X"11",X"FF",X"33",X"FF",X"77",X"FF",X"FF",X"FF",
X"88",X"00",X"CC",X"00",X"EE",X"00",X"FF",X"00",X"FF",X"88",X"FF",X"CC",X"FF",X"EE",X"FF",X"FF",
X"FF",X"FF",X"77",X"FF",X"33",X"FF",X"11",X"FF",X"00",X"FF",X"00",X"77",X"00",X"33",X"00",X"11",
X"FF",X"FF",X"FF",X"EE",X"FF",X"CC",X"FF",X"88",X"FF",X"00",X"EE",X"00",X"CC",X"00",X"88",X"00",
X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",X"F0",
X"33",X"00",X"33",X"00",X"33",X"00",X"11",X"00",X"11",X"00",X"00",X"00",X"33",X"00",X"00",X"00",
X"00",X"00",X"22",X"88",X"22",X"88",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"22",X"88",X"22",X"88",X"FF",X"EE",X"22",X"88",X"FF",X"EE",X"22",X"88",X"22",X"88",X"00",X"00",
X"11",X"00",X"F7",X"EC",X"D9",X"00",X"F7",X"EC",X"11",X"62",X"F7",X"EC",X"11",X"00",X"00",X"00",
X"E4",X"22",X"AA",X"44",X"E4",X"88",X"11",X"00",X"22",X"E4",X"44",X"AA",X"88",X"E4",X"00",X"00",
X"72",X"00",X"55",X"00",X"22",X"00",X"75",X"00",X"98",X"AA",X"C8",X"C4",X"77",X"AA",X"00",X"00",
X"11",X"88",X"10",X"88",X"00",X"88",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"88",X"11",X"00",X"22",X"00",X"22",X"00",X"22",X"00",X"11",X"00",X"00",X"88",X"00",X"00",
X"11",X"00",X"00",X"88",X"00",X"44",X"00",X"44",X"00",X"44",X"00",X"88",X"11",X"00",X"00",X"00",
X"00",X"00",X"11",X"00",X"55",X"44",X"22",X"88",X"22",X"88",X"55",X"44",X"11",X"00",X"00",X"00",
X"00",X"00",X"11",X"00",X"11",X"00",X"77",X"CC",X"11",X"00",X"11",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"11",X"88",X"00",X"88",X"11",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"77",X"CC",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"33",X"00",X"33",X"00",X"00",X"00",
X"00",X"11",X"00",X"32",X"00",X"64",X"00",X"C8",X"11",X"80",X"32",X"00",X"64",X"00",X"C8",X"00",
X"33",X"88",X"66",X"CC",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"66",X"CC",X"33",X"88",X"00",X"00",
X"11",X"88",X"33",X"88",X"77",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"77",X"EE",X"00",X"00",
X"77",X"CC",X"CC",X"66",X"00",X"EE",X"33",X"CC",X"77",X"88",X"EE",X"00",X"FF",X"EE",X"00",X"00",
X"77",X"EE",X"00",X"CC",X"11",X"88",X"33",X"CC",X"00",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"11",X"CC",X"33",X"CC",X"66",X"CC",X"CC",X"CC",X"FF",X"EE",X"00",X"CC",X"00",X"CC",X"00",X"00",
X"FF",X"CC",X"CC",X"00",X"FF",X"CC",X"00",X"66",X"00",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"33",X"CC",X"66",X"00",X"CC",X"00",X"FF",X"CC",X"CC",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"FF",X"EE",X"CC",X"66",X"00",X"CC",X"11",X"88",X"33",X"00",X"33",X"00",X"33",X"00",X"00",X"00",
X"77",X"CC",X"CC",X"66",X"CC",X"66",X"77",X"CC",X"CC",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"77",X"CC",X"CC",X"66",X"CC",X"66",X"77",X"EE",X"00",X"66",X"00",X"CC",X"77",X"88",X"00",X"00",
X"00",X"00",X"00",X"00",X"11",X"88",X"11",X"88",X"00",X"00",X"11",X"88",X"11",X"88",X"00",X"00",
X"11",X"00",X"33",X"00",X"77",X"EE",X"FF",X"EE",X"77",X"EE",X"33",X"00",X"11",X"00",X"00",X"00",
X"00",X"44",X"00",X"88",X"11",X"00",X"22",X"00",X"11",X"00",X"00",X"88",X"00",X"44",X"00",X"00",
X"00",X"00",X"00",X"00",X"77",X"CC",X"00",X"00",X"77",X"CC",X"00",X"00",X"00",X"00",X"00",X"00",
X"22",X"00",X"11",X"00",X"00",X"88",X"00",X"44",X"00",X"88",X"11",X"00",X"22",X"00",X"00",X"00",
X"33",X"CC",X"66",X"66",X"66",X"66",X"00",X"CC",X"11",X"88",X"11",X"88",X"00",X"00",X"11",X"88",
X"33",X"CC",X"44",X"22",X"99",X"99",X"AA",X"11",X"AA",X"11",X"99",X"99",X"44",X"22",X"33",X"CC",
X"33",X"88",X"66",X"CC",X"CC",X"66",X"CC",X"66",X"FF",X"EE",X"CC",X"66",X"CC",X"66",X"00",X"00",
X"FF",X"CC",X"CC",X"66",X"CC",X"66",X"FF",X"CC",X"CC",X"66",X"CC",X"66",X"FF",X"CC",X"00",X"00",
X"77",X"CC",X"CC",X"66",X"CC",X"00",X"CC",X"00",X"CC",X"00",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"FF",X"88",X"CC",X"CC",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"CC",X"CC",X"FF",X"88",X"00",X"00",
X"FF",X"EE",X"CC",X"00",X"CC",X"00",X"FF",X"88",X"CC",X"00",X"CC",X"00",X"FF",X"EE",X"00",X"00",
X"FF",X"EE",X"CC",X"00",X"CC",X"00",X"FF",X"88",X"CC",X"00",X"CC",X"00",X"CC",X"00",X"00",X"00",
X"33",X"EE",X"66",X"00",X"CC",X"00",X"CC",X"EE",X"CC",X"66",X"66",X"66",X"33",X"EE",X"00",X"00",
X"CC",X"66",X"CC",X"66",X"CC",X"66",X"FF",X"EE",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"00",X"00",
X"77",X"EE",X"11",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"77",X"EE",X"00",X"00",
X"00",X"66",X"00",X"66",X"00",X"66",X"00",X"66",X"CC",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"CC",X"66",X"CC",X"CC",X"DD",X"88",X"FF",X"00",X"FF",X"88",X"CC",X"CC",X"CC",X"66",X"00",X"00",
X"66",X"00",X"66",X"00",X"66",X"00",X"66",X"00",X"66",X"00",X"66",X"00",X"77",X"EE",X"00",X"00",
X"CC",X"66",X"EE",X"EE",X"FF",X"EE",X"FF",X"EE",X"DD",X"66",X"CC",X"66",X"CC",X"66",X"00",X"00",
X"CC",X"66",X"EE",X"66",X"FF",X"66",X"FF",X"EE",X"DD",X"EE",X"CC",X"EE",X"CC",X"66",X"00",X"00",
X"77",X"CC",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"FF",X"CC",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"FF",X"CC",X"CC",X"00",X"CC",X"00",X"00",X"00",
X"77",X"CC",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"DD",X"EE",X"CC",X"CC",X"77",X"AA",X"00",X"00",
X"FF",X"CC",X"CC",X"66",X"CC",X"66",X"CC",X"CC",X"FF",X"88",X"DD",X"CC",X"CC",X"EE",X"00",X"00",
X"77",X"88",X"CC",X"C4",X"CC",X"00",X"77",X"CC",X"00",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"77",X"EE",X"11",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"00",X"00",
X"CC",X"66",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"CC",X"66",X"77",X"CC",X"00",X"00",
X"CC",X"66",X"CC",X"66",X"CC",X"66",X"EE",X"EE",X"77",X"CC",X"33",X"88",X"11",X"00",X"00",X"00",
X"CC",X"66",X"CC",X"66",X"DD",X"66",X"FF",X"EE",X"FF",X"EE",X"EE",X"EE",X"CC",X"66",X"00",X"00",
X"CC",X"66",X"EE",X"EE",X"77",X"CC",X"33",X"88",X"77",X"CC",X"EE",X"EE",X"CC",X"66",X"00",X"00",
X"66",X"66",X"66",X"66",X"66",X"66",X"33",X"CC",X"11",X"88",X"11",X"88",X"11",X"88",X"00",X"00",
X"FF",X"EE",X"00",X"EE",X"11",X"CC",X"33",X"88",X"77",X"00",X"EE",X"00",X"FF",X"EE",X"00",X"00",
X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",
X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",
X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",
X"0F",X"0F",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"0F",X"0F",
X"44",X"00",X"44",X"44",X"44",X"88",X"55",X"66",X"22",X"99",X"44",X"22",X"00",X"44",X"00",X"FF",
X"00",X"00",X"00",X"00",X"33",X"EE",X"66",X"66",X"66",X"66",X"66",X"EE",X"33",X"66",X"00",X"00",
X"66",X"00",X"66",X"00",X"77",X"CC",X"66",X"66",X"66",X"66",X"66",X"66",X"77",X"CC",X"00",X"00",
X"00",X"00",X"00",X"00",X"33",X"CC",X"66",X"66",X"66",X"00",X"66",X"66",X"33",X"CC",X"00",X"00",
X"00",X"66",X"00",X"66",X"33",X"EE",X"66",X"66",X"66",X"66",X"66",X"66",X"33",X"EE",X"00",X"00",
X"00",X"00",X"00",X"00",X"33",X"CC",X"66",X"66",X"77",X"EE",X"66",X"00",X"33",X"CC",X"00",X"00",
X"11",X"CC",X"33",X"66",X"33",X"00",X"77",X"CC",X"33",X"00",X"33",X"00",X"33",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"33",X"EE",X"66",X"66",X"66",X"66",X"33",X"EE",X"00",X"66",X"33",X"CC",
X"66",X"00",X"66",X"00",X"77",X"CC",X"66",X"66",X"66",X"66",X"66",X"66",X"66",X"66",X"00",X"00",
X"11",X"88",X"00",X"00",X"33",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"33",X"CC",X"00",X"00",
X"00",X"CC",X"00",X"00",X"11",X"CC",X"00",X"CC",X"00",X"CC",X"00",X"CC",X"44",X"CC",X"33",X"88",
X"66",X"00",X"66",X"66",X"66",X"CC",X"77",X"88",X"77",X"88",X"66",X"CC",X"66",X"66",X"00",X"00",
X"33",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"11",X"88",X"33",X"CC",X"00",X"00",
X"00",X"00",X"00",X"00",X"FF",X"CC",X"DD",X"66",X"DD",X"66",X"DD",X"66",X"DD",X"66",X"00",X"00",
X"00",X"00",X"00",X"00",X"77",X"CC",X"66",X"66",X"66",X"66",X"66",X"66",X"66",X"66",X"00",X"00",
X"00",X"00",X"00",X"00",X"33",X"CC",X"66",X"66",X"66",X"66",X"66",X"66",X"33",X"CC",X"00",X"00",
X"00",X"00",X"00",X"00",X"77",X"CC",X"66",X"66",X"66",X"66",X"77",X"CC",X"66",X"00",X"66",X"00",
X"00",X"00",X"00",X"00",X"77",X"CC",X"CC",X"CC",X"CC",X"CC",X"77",X"CC",X"00",X"CC",X"00",X"EE",
X"00",X"00",X"00",X"00",X"77",X"CC",X"76",X"62",X"66",X"00",X"66",X"00",X"66",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"73",X"CC",X"66",X"00",X"73",X"EC",X"00",X"66",X"77",X"EC",X"00",X"00",
X"11",X"88",X"11",X"88",X"77",X"EE",X"11",X"88",X"11",X"88",X"11",X"88",X"00",X"EE",X"00",X"00",
X"00",X"00",X"00",X"00",X"66",X"66",X"66",X"66",X"66",X"66",X"66",X"EE",X"33",X"66",X"00",X"00",
X"00",X"00",X"00",X"00",X"66",X"66",X"66",X"66",X"66",X"66",X"33",X"CC",X"11",X"88",X"00",X"00",
X"00",X"00",X"00",X"00",X"DD",X"66",X"DD",X"66",X"DD",X"66",X"DD",X"66",X"76",X"CC",X"00",X"00",
X"00",X"00",X"00",X"00",X"CC",X"CC",X"77",X"88",X"33",X"00",X"77",X"88",X"CC",X"CC",X"00",X"00",
X"00",X"00",X"00",X"00",X"66",X"66",X"66",X"66",X"66",X"66",X"33",X"EE",X"00",X"66",X"33",X"CC",
X"00",X"00",X"00",X"00",X"77",X"EE",X"00",X"CC",X"11",X"88",X"33",X"00",X"77",X"EE",X"00",X"00",
X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",
X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",
X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"01",
X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",
X"00",X"72",X"00",X"F6",X"10",X"BA",X"77",X"FE",X"72",X"32",X"E4",X"32",X"C8",X"32",X"00",X"00",
X"F7",X"88",X"C4",X"88",X"F7",X"EC",X"C4",X"62",X"C4",X"62",X"C4",X"E4",X"F7",X"C8",X"00",X"00",
X"31",X"EE",X"72",X"00",X"E4",X"00",X"C4",X"00",X"E4",X"00",X"72",X"00",X"31",X"EE",X"00",X"00",
X"F7",X"C8",X"C4",X"E4",X"C4",X"72",X"C4",X"32",X"C4",X"72",X"C4",X"E4",X"F7",X"C8",X"00",X"00",
X"F7",X"88",X"C4",X"00",X"F7",X"00",X"C4",X"00",X"C4",X"00",X"C4",X"00",X"F7",X"EE",X"00",X"00",
X"F7",X"EE",X"C4",X"00",X"F7",X"88",X"C4",X"00",X"C4",X"00",X"C4",X"00",X"C4",X"00",X"00",X"00",
X"31",X"EE",X"72",X"00",X"E4",X"00",X"C4",X"00",X"E4",X"66",X"72",X"62",X"31",X"EC",X"00",X"00",
X"C4",X"62",X"C4",X"62",X"F7",X"EE",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"00",X"00",
X"73",X"EE",X"10",X"88",X"10",X"88",X"10",X"88",X"10",X"88",X"10",X"88",X"73",X"EE",X"00",X"00",
X"00",X"62",X"00",X"62",X"00",X"62",X"00",X"62",X"00",X"62",X"C4",X"62",X"73",X"EC",X"00",X"00",
X"D4",X"88",X"F5",X"80",X"F6",X"00",X"F5",X"80",X"D4",X"C8",X"C4",X"E4",X"C4",X"62",X"00",X"00",
X"C4",X"00",X"C4",X"00",X"C4",X"00",X"C4",X"00",X"C4",X"00",X"C4",X"00",X"F7",X"EE",X"00",X"00",
X"E4",X"62",X"F6",X"E6",X"D5",X"EA",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"00",X"00",
X"C4",X"62",X"E6",X"62",X"F7",X"62",X"D5",X"EA",X"C4",X"EE",X"C4",X"66",X"C4",X"22",X"00",X"00",
X"31",X"CC",X"62",X"62",X"C4",X"31",X"C4",X"31",X"C4",X"31",X"62",X"62",X"31",X"CC",X"00",X"00",
X"F7",X"88",X"C4",X"C4",X"C4",X"62",X"C4",X"62",X"C4",X"C4",X"F7",X"88",X"C4",X"00",X"00",X"00",
X"31",X"CC",X"62",X"62",X"C4",X"31",X"C4",X"31",X"C4",X"F5",X"62",X"62",X"31",X"F9",X"00",X"00",
X"F7",X"88",X"C4",X"C4",X"C4",X"62",X"C4",X"62",X"C4",X"C4",X"F7",X"88",X"C4",X"E6",X"00",X"00",
X"73",X"88",X"C4",X"00",X"73",X"C8",X"00",X"64",X"00",X"62",X"00",X"64",X"F7",X"C8",X"00",X"00",
X"F7",X"FF",X"10",X"88",X"10",X"88",X"10",X"88",X"10",X"88",X"10",X"88",X"10",X"88",X"00",X"00",
X"C4",X"62",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"73",X"CC",X"00",X"00",
X"C4",X"31",X"C4",X"72",X"C4",X"E4",X"D4",X"C8",X"F5",X"80",X"F6",X"00",X"E4",X"00",X"00",X"00",
X"C4",X"62",X"C4",X"62",X"C4",X"62",X"C4",X"62",X"D5",X"EA",X"F6",X"E6",X"E4",X"62",X"00",X"00",
X"E4",X"31",X"72",X"72",X"31",X"E4",X"10",X"C8",X"31",X"E4",X"72",X"72",X"E4",X"31",X"00",X"00",
X"E4",X"31",X"72",X"72",X"31",X"E4",X"10",X"C8",X"31",X"80",X"72",X"00",X"E4",X"00",X"00",X"00",
X"FF",X"EE",X"00",X"E4",X"10",X"C8",X"31",X"80",X"72",X"00",X"E4",X"00",X"FF",X"EE",X"00",X"00",
X"00",X"01",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"22",X"00",X"31",X"00",X"72",X"00",X"31",X"80",X"10",X"C8",X"11",X"80",X"00",X"C8",X"00",X"44",
X"11",X"00",X"33",X"88",X"77",X"CC",X"FF",X"EE",X"77",X"CC",X"33",X"88",X"11",X"00",X"00",X"00",
X"FF",X"EE",X"88",X"22",X"BB",X"AA",X"BB",X"AA",X"BB",X"AA",X"88",X"22",X"FF",X"EE",X"00",X"00",
X"FA",X"FA",X"F5",X"F5",X"FA",X"FA",X"F5",X"F5",X"FA",X"FA",X"F5",X"F5",X"FA",X"FA",X"F5",X"F5",
X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",X"0F",
X"03",X"0C",X"02",X"04",X"03",X"0C",X"01",X"08",X"01",X"08",X"01",X"0E",X"01",X"08",X"01",X"0E",
X"00",X"11",X"00",X"32",X"00",X"64",X"04",X"C8",X"13",X"80",X"21",X"00",X"42",X"08",X"84",X"00",
X"11",X"84",X"11",X"84",X"11",X"84",X"32",X"C2",X"74",X"E1",X"74",X"E1",X"32",X"C3",X"03",X"0E",
X"00",X"00",X"99",X"77",X"99",X"44",X"FF",X"77",X"99",X"44",X"99",X"44",X"99",X"77",X"00",X"00",
X"00",X"00",X"9B",X"99",X"22",X"55",X"22",X"55",X"33",X"DD",X"22",X"55",X"AA",X"55",X"00",X"00",
X"00",X"00",X"11",X"FF",X"00",X"44",X"00",X"44",X"00",X"44",X"00",X"44",X"EE",X"44",X"00",X"00",
X"00",X"00",X"44",X"88",X"44",X"88",X"77",X"88",X"44",X"88",X"44",X"88",X"44",X"88",X"00",X"00",
X"00",X"00",X"F7",X"33",X"88",X"44",X"F6",X"44",X"11",X"44",X"11",X"44",X"EE",X"33",X"00",X"00",
X"00",X"00",X"9B",X"9D",X"22",X"55",X"22",X"55",X"22",X"55",X"22",X"55",X"9B",X"9D",X"00",X"00",
X"00",X"00",X"EC",X"FF",X"22",X"88",X"E4",X"EE",X"88",X"88",X"44",X"88",X"22",X"FF",X"00",X"00",
X"00",X"00",X"88",X"9B",X"88",X"AA",X"88",X"AA",X"AA",X"BB",X"AA",X"AA",X"55",X"22",X"00",X"00",
X"00",X"00",X"99",X"EC",X"55",X"22",X"55",X"E4",X"DD",X"88",X"55",X"44",X"55",X"22",X"00",X"00",
X"00",X"00",X"FE",X"45",X"99",X"55",X"FA",X"55",X"CC",X"55",X"AA",X"55",X"99",X"45",X"00",X"00",
X"00",X"00",X"CE",X"FE",X"22",X"99",X"22",X"FA",X"22",X"CC",X"22",X"AA",X"CE",X"99",X"00",X"00",
X"00",X"00",X"88",X"99",X"88",X"AA",X"88",X"AA",X"88",X"BB",X"55",X"22",X"22",X"22",X"00",X"00",
X"00",X"00",X"99",X"00",X"55",X"00",X"55",X"00",X"DD",X"00",X"55",X"00",X"55",X"EE",X"00",X"00",
X"00",X"00",X"88",X"44",X"99",X"44",X"AA",X"22",X"CC",X"11",X"AA",X"11",X"99",X"11",X"00",X"00",
X"00",X"00",X"55",X"EC",X"55",X"22",X"99",X"E4",X"11",X"88",X"11",X"44",X"11",X"22",X"00",X"00",
X"00",X"00",X"BB",X"CC",X"AA",X"00",X"BB",X"88",X"AA",X"00",X"AA",X"00",X"BB",X"CC",X"00",X"00",
X"00",X"00",X"88",X"AA",X"88",X"AA",X"88",X"AA",X"AA",X"AA",X"AA",X"AA",X"55",X"22",X"00",X"00",
X"00",X"00",X"FF",X"33",X"11",X"44",X"22",X"44",X"44",X"77",X"88",X"44",X"FF",X"44",X"00",X"00",
X"00",X"00",X"33",X"D9",X"AA",X"55",X"BA",X"D9",X"BB",X"11",X"AA",X"99",X"AA",X"55",X"00",X"00",
X"00",X"00",X"CC",X"00",X"26",X"00",X"22",X"00",X"22",X"00",X"26",X"00",X"CC",X"00",X"00",X"00",
X"00",X"00",X"FF",X"44",X"88",X"44",X"EE",X"44",X"88",X"44",X"88",X"44",X"FF",X"77",X"00",X"00",
X"00",X"00",X"33",X"CC",X"22",X"00",X"33",X"88",X"22",X"00",X"22",X"00",X"AA",X"00",X"00",X"00",
X"00",X"00",X"00",X"70",X"10",X"F7",X"31",X"FC",X"73",X"C8",X"73",X"90",X"73",X"80",X"73",X"F0",
X"00",X"00",X"F0",X"00",X"FF",X"F0",X"F7",X"F7",X"F6",X"71",X"EC",X"31",X"C0",X"73",X"F0",X"73",
X"00",X"00",X"00",X"00",X"F0",X"F0",X"FF",X"FF",X"FF",X"B9",X"F9",X"FB",X"B1",X"FB",X"F1",X"FB",
X"00",X"00",X"00",X"00",X"B0",X"E0",X"FB",X"FC",X"B8",X"EC",X"90",X"EC",X"90",X"EC",X"90",X"EC",
X"00",X"00",X"00",X"00",X"F0",X"C0",X"FF",X"FC",X"F6",X"F7",X"F6",X"73",X"F6",X"31",X"F6",X"31",
X"00",X"00",X"00",X"00",X"F0",X"F0",X"FF",X"FF",X"E6",X"F6",X"EA",X"F6",X"F9",X"F6",X"D8",X"F6",
X"00",X"00",X"00",X"00",X"F0",X"70",X"FF",X"FF",X"76",X"F6",X"64",X"F6",X"C8",X"F6",X"80",X"F6",
X"00",X"00",X"00",X"00",X"B0",X"F0",X"FB",X"FF",X"B0",X"FC",X"10",X"EC",X"10",X"EC",X"10",X"FC",
X"00",X"00",X"00",X"00",X"F0",X"F0",X"FF",X"FF",X"F0",X"F3",X"20",X"73",X"72",X"73",X"F6",X"73",
X"00",X"00",X"00",X"00",X"F0",X"E0",X"FF",X"EC",X"F0",X"EC",X"90",X"C8",X"B1",X"80",X"B0",X"00",
X"73",X"FF",X"73",X"F0",X"73",X"80",X"73",X"F8",X"31",X"FF",X"10",X"FF",X"00",X"F0",X"00",X"00",
X"FF",X"F7",X"F3",X"F6",X"73",X"F6",X"F3",X"F6",X"FF",X"F6",X"FF",X"F6",X"F3",X"F6",X"73",X"F6",
X"FF",X"FB",X"F1",X"FB",X"31",X"FB",X"31",X"FB",X"31",X"FB",X"31",X"F9",X"31",X"D8",X"73",X"80",
X"90",X"EC",X"90",X"EC",X"90",X"EC",X"90",X"EC",X"F9",X"FC",X"FE",X"FF",X"EC",X"F6",X"C0",X"60",
X"F6",X"31",X"F6",X"31",X"F6",X"31",X"F6",X"B1",X"FE",X"F9",X"F7",X"F9",X"F7",X"B0",X"F6",X"00",
X"C8",X"F6",X"C8",X"F6",X"C8",X"F6",X"C8",X"F6",X"C8",X"F6",X"C8",X"F6",X"C0",X"F0",X"00",X"00",
X"00",X"F6",X"00",X"F6",X"00",X"F6",X"00",X"F6",X"30",X"F6",X"31",X"FF",X"30",X"F0",X"00",X"00",
X"10",X"FF",X"30",X"FD",X"72",X"FD",X"F6",X"FC",X"FC",X"FC",X"FC",X"FF",X"D0",X"F0",X"00",X"00",
X"EC",X"73",X"C8",X"73",X"90",X"F7",X"31",X"FB",X"F3",X"F3",X"FF",X"F3",X"F0",X"73",X"00",X"73",
X"80",X"00",X"80",X"00",X"80",X"00",X"80",X"00",X"80",X"00",X"B0",X"00",X"F2",X"00",X"F6",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"10",X"00",X"31",X"00",X"31",X"00",X"30",
X"73",X"E4",X"73",X"C0",X"73",X"80",X"F6",X"00",X"EC",X"00",X"C8",X"00",X"80",X"00",X"00",X"00",
X"72",X"00",X"60",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"10",X"00",X"10",X"00",X"10",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"EC",X"00",X"C8",X"00",X"80",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"73",X"00",X"73",X"00",X"73",X"00",X"F6",X"10",X"EC",X"31",X"C8",X"31",X"80",X"30",X"00",
X"EC",X"00",X"C8",X"00",X"80",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"66",X"33",X"77",X"77",X"33",X"EE",X"11",X"CC",X"33",X"EE",X"77",X"77",X"66",X"33",X"00",X"00",
X"00",X"00",X"00",X"77",X"00",X"FF",X"77",X"88",X"77",X"88",X"00",X"FF",X"00",X"77",X"00",X"00",
X"66",X"11",X"77",X"11",X"77",X"99",X"55",X"DD",X"44",X"FF",X"44",X"77",X"44",X"33",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",
X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",
X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",
X"08",X"00",X"08",X"00",X"08",X"00",X"08",X"00",X"08",X"00",X"08",X"00",X"08",X"00",X"08",X"00",
X"00",X"00",X"22",X"FF",X"11",X"00",X"00",X"88",X"99",X"44",X"CC",X"AA",X"AA",X"88",X"99",X"00",
X"00",X"00",X"33",X"88",X"77",X"CC",X"44",X"44",X"22",X"44",X"77",X"CC",X"77",X"CC",X"00",X"00",
X"00",X"00",X"77",X"FF",X"77",X"FF",X"44",X"44",X"44",X"44",X"77",X"CC",X"33",X"88",X"00",X"00",
X"00",X"00",X"33",X"88",X"77",X"CC",X"44",X"44",X"44",X"44",X"66",X"CC",X"22",X"88",X"00",X"00",
X"00",X"00",X"33",X"88",X"77",X"CC",X"44",X"44",X"44",X"44",X"77",X"FF",X"77",X"FF",X"00",X"00",
X"00",X"00",X"33",X"88",X"77",X"CC",X"55",X"44",X"55",X"44",X"55",X"CC",X"11",X"88",X"00",X"00",
X"00",X"00",X"00",X"88",X"77",X"EE",X"77",X"FF",X"00",X"99",X"00",X"BB",X"00",X"22",X"00",X"00",
X"00",X"00",X"11",X"88",X"BB",X"CC",X"AA",X"44",X"AA",X"44",X"FF",X"CC",X"77",X"CC",X"00",X"00",
X"00",X"00",X"77",X"FF",X"77",X"FF",X"00",X"44",X"00",X"44",X"77",X"CC",X"77",X"88",X"00",X"00",
X"00",X"00",X"00",X"00",X"44",X"44",X"77",X"DD",X"77",X"DD",X"44",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"44",X"00",X"88",X"00",X"88",X"44",X"FF",X"DD",X"77",X"DD",X"00",X"00",X"00",X"00",
X"00",X"00",X"77",X"FF",X"77",X"FF",X"11",X"88",X"33",X"CC",X"66",X"66",X"44",X"22",X"00",X"00",
X"00",X"00",X"00",X"00",X"44",X"11",X"77",X"FF",X"77",X"FF",X"44",X"00",X"00",X"00",X"00",X"00",
X"77",X"CC",X"77",X"CC",X"00",X"44",X"77",X"CC",X"00",X"44",X"77",X"CC",X"77",X"88",X"00",X"00",
X"00",X"00",X"77",X"CC",X"77",X"CC",X"00",X"44",X"00",X"44",X"77",X"CC",X"77",X"88",X"00",X"00",
X"00",X"00",X"33",X"88",X"77",X"CC",X"44",X"44",X"44",X"44",X"77",X"CC",X"33",X"88",X"00",X"00",
X"00",X"00",X"FF",X"CC",X"FF",X"CC",X"22",X"44",X"22",X"44",X"33",X"CC",X"11",X"88",X"00",X"00",
X"11",X"88",X"33",X"CC",X"22",X"44",X"22",X"44",X"FF",X"CC",X"FF",X"CC",X"88",X"00",X"00",X"00",
X"00",X"00",X"77",X"CC",X"77",X"CC",X"00",X"C4",X"00",X"44",X"00",X"44",X"00",X"C8",X"00",X"00",
X"00",X"00",X"54",X"C8",X"55",X"CC",X"55",X"44",X"55",X"44",X"77",X"44",X"72",X"00",X"00",X"00",
X"00",X"00",X"00",X"44",X"00",X"44",X"33",X"FF",X"77",X"FF",X"44",X"44",X"44",X"44",X"00",X"00",
X"00",X"00",X"33",X"CC",X"77",X"CC",X"44",X"00",X"22",X"00",X"77",X"CC",X"77",X"CC",X"00",X"00",
X"00",X"00",X"11",X"CC",X"33",X"CC",X"66",X"00",X"66",X"00",X"33",X"CC",X"11",X"CC",X"00",X"00",
X"33",X"CC",X"77",X"CC",X"44",X"00",X"73",X"CC",X"44",X"00",X"77",X"CC",X"33",X"CC",X"00",X"00",
X"44",X"44",X"66",X"CC",X"33",X"88",X"33",X"88",X"66",X"CC",X"44",X"44",X"00",X"00",X"00",X"00",
X"00",X"00",X"11",X"CC",X"BB",X"CC",X"AA",X"00",X"AA",X"00",X"FF",X"CC",X"77",X"CC",X"00",X"00",
X"00",X"00",X"44",X"44",X"66",X"44",X"77",X"44",X"55",X"CC",X"44",X"CC",X"44",X"44",X"00",X"00",
X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",
X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",
X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"FF",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"08",X"00",
X"00",X"07",X"00",X"7B",X"01",X"F6",X"12",X"ED",X"13",X"CE",X"13",X"CA",X"13",X"8C",X"13",X"8C",
X"0F",X"08",X"FF",X"84",X"3D",X"CA",X"12",X"ED",X"01",X"EF",X"01",X"E7",X"00",X"6F",X"00",X"6F",
X"13",X"8C",X"13",X"8C",X"13",X"CA",X"13",X"CE",X"12",X"ED",X"01",X"F6",X"00",X"7B",X"00",X"07",
X"00",X"6F",X"00",X"6F",X"01",X"E7",X"01",X"EF",X"12",X"ED",X"3D",X"CA",X"FF",X"84",X"0F",X"08",
X"00",X"00",X"00",X"00",X"00",X"01",X"00",X"13",X"00",X"37",X"00",X"07",X"00",X"01",X"00",X"01",
X"06",X"00",X"4E",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",
X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"16",X"00",X"7F",X"00",X"0F",
X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"ED",X"08",X"FF",X"8C",X"0F",X"0C",
X"00",X"07",X"00",X"7F",X"01",X"ED",X"13",X"CA",X"13",X"8C",X"01",X"08",X"00",X"00",X"00",X"01",
X"0F",X"00",X"FE",X"08",X"3F",X"8C",X"13",X"CE",X"12",X"CE",X"13",X"CE",X"37",X"8C",X"7F",X"08",
X"00",X"16",X"00",X"7B",X"01",X"F6",X"12",X"CF",X"13",X"8C",X"13",X"CB",X"13",X"FF",X"03",X"0F",
X"ED",X"00",X"CA",X"00",X"0C",X"06",X"00",X"4E",X"00",X"4E",X"0F",X"C6",X"FF",X"CE",X"0F",X"0E",
X"00",X"07",X"00",X"7F",X"01",X"ED",X"13",X"CA",X"13",X"8C",X"01",X"08",X"00",X"01",X"00",X"13",
X"0F",X"00",X"FF",X"08",X"3D",X"8C",X"12",X"CE",X"01",X"CE",X"01",X"CE",X"1F",X"8C",X"FF",X"08",
X"00",X"01",X"00",X"00",X"01",X"08",X"13",X"8C",X"13",X"8C",X"01",X"CF",X"00",X"7F",X"00",X"07",
X"1F",X"8C",X"01",X"CE",X"00",X"6F",X"00",X"6F",X"01",X"E7",X"1E",X"CE",X"FF",X"8C",X"0F",X"08",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"01",X"00",X"13",X"00",X"37",X"00",X"6F",X"01",X"CE",
X"03",X"08",X"37",X"08",X"7F",X"08",X"FF",X"08",X"BF",X"08",X"3F",X"08",X"37",X"08",X"37",X"08",
X"13",X"8C",X"37",X"0F",X"37",X"FF",X"07",X"0F",X"00",X"00",X"00",X"00",X"00",X"01",X"00",X"01",
X"37",X"08",X"3F",X"0C",X"FF",X"8C",X"3F",X"0C",X"37",X"08",X"7B",X"84",X"FF",X"CE",X"0F",X"0E",
X"03",X"0F",X"13",X"FF",X"13",X"8F",X"13",X"8C",X"13",X"8C",X"13",X"8F",X"13",X"FB",X"13",X"ED",
X"0F",X"0C",X"FF",X"8C",X"1E",X"8C",X"01",X"8C",X"00",X"0C",X"0E",X"00",X"FE",X"08",X"3F",X"8C",
X"01",X"0C",X"00",X"00",X"03",X"08",X"13",X"8C",X"13",X"CA",X"01",X"ED",X"00",X"7F",X"00",X"07",
X"13",X"CA",X"10",X"CE",X"01",X"CE",X"01",X"CE",X"13",X"CA",X"3F",X"84",X"EF",X"08",X"0E",X"00",
X"00",X"07",X"00",X"7F",X"01",X"CF",X"12",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8F",X"13",X"FB",
X"0F",X"00",X"FF",X"08",X"1F",X"8C",X"01",X"CA",X"01",X"CE",X"00",X"0C",X"0F",X"00",X"FF",X"08",
X"13",X"ED",X"13",X"8E",X"13",X"8C",X"13",X"8C",X"12",X"CA",X"01",X"ED",X"00",X"7F",X"00",X"07",
X"1F",X"8C",X"10",X"CE",X"01",X"CE",X"01",X"CE",X"03",X"CA",X"1F",X"8C",X"FF",X"08",X"0F",X"00",
X"03",X"0F",X"13",X"FF",X"13",X"87",X"13",X"08",X"13",X"08",X"03",X"00",X"00",X"00",X"00",X"01",
X"0F",X"0F",X"FF",X"EF",X"0F",X"6F",X"01",X"E7",X"12",X"CE",X"35",X"8C",X"7B",X"08",X"E7",X"00",
X"00",X"01",X"00",X"12",X"00",X"13",X"00",X"13",X"00",X"13",X"00",X"13",X"00",X"13",X"00",X"03",
X"CE",X"00",X"CA",X"00",X"8C",X"00",X"8C",X"00",X"8C",X"00",X"8C",X"00",X"8C",X"00",X"0C",X"00",
X"00",X"07",X"00",X"7B",X"01",X"E7",X"01",X"CF",X"01",X"CE",X"01",X"ED",X"00",X"7F",X"00",X"37",
X"0F",X"08",X"FF",X"84",X"3D",X"CA",X"12",X"CE",X"01",X"CE",X"01",X"CE",X"1E",X"CA",X"FF",X"84",
X"00",X"7A",X"01",X"C7",X"12",X"8C",X"13",X"8C",X"13",X"CA",X"12",X"ED",X"01",X"F7",X"00",X"0F",
X"F7",X"8C",X"3D",X"CE",X"03",X"E7",X"00",X"6F",X"00",X"6F",X"1E",X"ED",X"FF",X"CA",X"0F",X"0C",
X"00",X"07",X"00",X"7F",X"01",X"CF",X"12",X"8E",X"13",X"8C",X"13",X"8C",X"13",X"C8",X"01",X"CF",
X"0F",X"00",X"FF",X"08",X"3D",X"8C",X"12",X"CA",X"01",X"CE",X"01",X"CE",X"03",X"CE",X"3D",X"CE",
X"00",X"7F",X"00",X"07",X"01",X"08",X"13",X"8C",X"12",X"8C",X"01",X"CF",X"00",X"7F",X"00",X"07",
X"FE",X"CE",X"0F",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CA",X"1F",X"8C",X"FF",X"08",X"0F",X"00",
X"00",X"0F",X"00",X"7F",X"00",X"35",X"00",X"36",X"00",X"6B",X"00",X"6D",X"00",X"4E",X"01",X"C6",
X"0E",X"00",X"CE",X"00",X"ED",X"00",X"EF",X"00",X"E7",X"00",X"7E",X"08",X"7F",X"08",X"73",X"08",
X"01",X"CB",X"01",X"FF",X"12",X"8F",X"13",X"84",X"13",X"08",X"35",X"84",X"37",X"CE",X"07",X"0E",
X"3F",X"84",X"FF",X"8C",X"3D",X"8C",X"13",X"CA",X"13",X"CE",X"12",X"ED",X"37",X"EF",X"07",X"0F",
X"07",X"0F",X"37",X"FF",X"12",X"ED",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CF",X"01",X"FF",
X"01",X"CF",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"12",X"ED",X"37",X"FF",X"07",X"0F",
X"3D",X"CA",X"03",X"ED",X"00",X"6F",X"00",X"6F",X"00",X"6F",X"0F",X"ED",X"FF",X"CA",X"0F",X"0C",
X"0F",X"0E",X"FF",X"C6",X"3D",X"CE",X"12",X"CE",X"01",X"C6",X"00",X"0E",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"02",X"00",X"27",X"00",X"6F",X"1E",X"CF",X"FF",X"8E",X"0F",X"0C",
X"07",X"0F",X"37",X"FF",X"12",X"ED",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CE",
X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"12",X"ED",X"37",X"FF",X"07",X"0F",
X"0F",X"0F",X"FF",X"EF",X"0F",X"6B",X"00",X"27",X"03",X"03",X"27",X"00",X"6B",X"00",X"EF",X"00",
X"6B",X"00",X"27",X"00",X"03",X"00",X"00",X"03",X"00",X"27",X"0F",X"6B",X"FF",X"EF",X"0F",X"0F",
X"6B",X"00",X"27",X"00",X"03",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"08",X"00",X"08",X"00",
X"07",X"0F",X"37",X"EF",X"12",X"ED",X"01",X"CE",X"01",X"CE",X"1E",X"ED",X"FF",X"EF",X"0F",X"0F",
X"0F",X"0F",X"7F",X"EF",X"35",X"CA",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"1F",X"8C",X"FF",X"8C",
X"1F",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"35",X"CA",X"7F",X"EF",X"0F",X"0F",
X"00",X"0F",X"00",X"7F",X"00",X"16",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",
X"0F",X"0C",X"FF",X"8C",X"ED",X"08",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",
X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"ED",X"00",X"FF",X"8C",X"0F",X"0C",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"0F",X"0F",X"7F",X"EF",X"35",X"CA",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",
X"00",X"00",X"00",X"00",X"03",X"08",X"13",X"8C",X"13",X"CA",X"01",X"ED",X"00",X"7F",X"00",X"07",
X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"35",X"8C",X"7B",X"84",X"FE",X"08",X"0F",X"00",
X"0F",X"0F",X"3F",X"EF",X"12",X"CA",X"13",X"84",X"36",X"08",X"6D",X"00",X"CA",X"00",X"CE",X"00",
X"ED",X"00",X"E7",X"00",X"7E",X"08",X"7B",X"08",X"37",X"84",X"35",X"CA",X"7F",X"EF",X"0F",X"0F",
X"08",X"00",X"08",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"06",X"00",X"4E",X"00",X"4E",X"0F",X"C6",X"FF",X"CE",X"0F",X"0E",
X"0F",X"08",X"7F",X"8C",X"37",X"CA",X"37",X"CE",X"36",X"ED",X"27",X"EF",X"27",X"F6",X"27",X"7F",
X"00",X"0F",X"01",X"EF",X"12",X"CE",X"13",X"CE",X"35",X"CE",X"36",X"CE",X"6B",X"CE",X"6D",X"CE",
X"27",X"7B",X"27",X"37",X"27",X"35",X"27",X"13",X"27",X"12",X"7A",X"09",X"7F",X"08",X"0F",X"08",
X"C7",X"CE",X"C9",X"CE",X"8D",X"CE",X"81",X"CE",X"09",X"CE",X"12",X"ED",X"13",X"EF",X"03",X"0F",
X"07",X"0E",X"37",X"ED",X"12",X"EF",X"01",X"FE",X"01",X"FB",X"01",X"BF",X"01",X"BD",X"01",X"9F",
X"07",X"0F",X"37",X"EF",X"03",X"CA",X"09",X"8C",X"09",X"8C",X"85",X"8C",X"8D",X"8C",X"CB",X"8C",
X"01",X"9E",X"01",X"8D",X"01",X"8D",X"01",X"8C",X"01",X"8C",X"12",X"CA",X"37",X"EF",X"07",X"0F",
X"CF",X"8C",X"ED",X"8C",X"E7",X"8C",X"7E",X"8C",X"7B",X"8C",X"37",X"8C",X"35",X"8C",X"03",X"0C",
X"0F",X"08",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"08",X"00",X"08",X"00",
X"06",X"6F",X"6F",X"6F",X"37",X"E7",X"35",X"ED",X"12",X"CF",X"3D",X"ED",X"FF",X"E7",X"0F",X"0F",
X"00",X"07",X"01",X"7B",X"12",X"ED",X"13",X"CA",X"13",X"CA",X"13",X"ED",X"01",X"FF",X"00",X"7B",
X"0F",X"0E",X"FF",X"C6",X"3D",X"CE",X"12",X"CE",X"01",X"C6",X"08",X"0E",X"86",X"00",X"ED",X"08",
X"00",X"16",X"00",X"01",X"03",X"08",X"13",X"84",X"13",X"CA",X"13",X"ED",X"13",X"F7",X"03",X"0F",
X"FF",X"84",X"7B",X"CE",X"16",X"EF",X"01",X"E7",X"01",X"E7",X"1E",X"ED",X"FF",X"86",X"0F",X"08",
X"03",X"0F",X"13",X"FF",X"13",X"96",X"13",X"09",X"03",X"01",X"00",X"01",X"00",X"01",X"00",X"01",
X"0F",X"0F",X"FF",X"EF",X"ED",X"6B",X"CE",X"27",X"CE",X"03",X"CE",X"00",X"CE",X"00",X"CE",X"00",
X"0F",X"0F",X"3F",X"EF",X"12",X"CA",X"01",X"8C",X"01",X"8C",X"01",X"8C",X"01",X"8C",X"01",X"8C",
X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"CE",X"01",X"ED",X"01",X"F6",X"00",X"7B",X"00",X"07",
X"01",X"8C",X"01",X"8C",X"01",X"8C",X"01",X"8C",X"12",X"8C",X"3D",X"84",X"FE",X"08",X"0F",X"00",
X"0F",X"0F",X"7F",X"EF",X"35",X"CA",X"13",X"CA",X"12",X"CE",X"01",X"CE",X"01",X"ED",X"01",X"E7",
X"07",X"0F",X"37",X"EF",X"12",X"CA",X"13",X"8C",X"13",X"84",X"13",X"08",X"35",X"08",X"36",X"08",
X"00",X"6F",X"00",X"7E",X"00",X"7B",X"00",X"37",X"00",X"37",X"00",X"35",X"00",X"13",X"00",X"03",
X"27",X"00",X"6B",X"00",X"6D",X"00",X"4E",X"00",X"C6",X"00",X"CA",X"00",X"8C",X"00",X"0C",X"00",
X"0F",X"0B",X"7F",X"BF",X"7B",X"B5",X"37",X"1B",X"37",X"1B",X"37",X"1B",X"37",X"97",X"35",X"BD",
X"0C",X"0F",X"CF",X"EF",X"CB",X"E5",X"8C",X"4E",X"8D",X"C6",X"8D",X"CE",X"CB",X"CA",X"DA",X"8C",
X"13",X"BF",X"13",X"AF",X"13",X"EB",X"12",X"EF",X"01",X"ED",X"01",X"CE",X"01",X"CE",X"01",X"0E",
X"DF",X"8C",X"DF",X"84",X"FD",X"08",X"F7",X"08",X"7E",X"08",X"6F",X"00",X"6F",X"00",X"0F",X"00",
X"07",X"0F",X"37",X"EF",X"12",X"CE",X"01",X"ED",X"00",X"6F",X"00",X"7B",X"00",X"37",X"00",X"35",
X"03",X"0F",X"13",X"EF",X"01",X"C6",X"12",X"8C",X"35",X"08",X"6B",X"00",X"C6",X"00",X"CA",X"00",
X"00",X"13",X"00",X"35",X"00",X"6B",X"01",X"C6",X"12",X"8C",X"35",X"86",X"7F",X"EF",X"0F",X"0F",
X"CE",X"00",X"ED",X"00",X"6F",X"00",X"7B",X"08",X"37",X"84",X"35",X"CA",X"7F",X"EF",X"0F",X"0F",
X"03",X"0F",X"13",X"EF",X"01",X"C6",X"01",X"CA",X"12",X"8C",X"1B",X"84",X"B5",X"08",X"FA",X"08",
X"00",X"13",X"00",X"12",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"12",X"00",X"37",X"00",X"07",
X"EF",X"00",X"ED",X"00",X"CE",X"00",X"CE",X"00",X"CE",X"00",X"ED",X"00",X"FF",X"08",X"0F",X"08",
X"0F",X"0E",X"FF",X"CE",X"0F",X"CE",X"01",X"CE",X"13",X"CA",X"37",X"84",X"7E",X"08",X"ED",X"00",
X"00",X"13",X"00",X"37",X"00",X"7E",X"01",X"ED",X"12",X"CA",X"13",X"8F",X"13",X"FF",X"03",X"0F",
X"CA",X"00",X"84",X"00",X"08",X"06",X"00",X"4E",X"00",X"4E",X"0F",X"C6",X"FF",X"CE",X"0F",X"0E",
X"00",X"07",X"00",X"7F",X"01",X"ED",X"13",X"CA",X"13",X"8C",X"01",X"08",X"00",X"00",X"00",X"00",
X"0F",X"00",X"FF",X"08",X"3D",X"8C",X"12",X"CE",X"12",X"CE",X"13",X"CA",X"37",X"84",X"7E",X"08",
X"00",X"01",X"00",X"13",X"00",X"13",X"00",X"01",X"00",X"01",X"00",X"13",X"00",X"13",X"00",X"01",
X"ED",X"00",X"CA",X"00",X"8C",X"00",X"08",X"00",X"08",X"00",X"8C",X"00",X"8C",X"00",X"08",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"01",X"0C",X"12",X"CA",X"13",X"CE",X"12",X"CA",X"01",X"0C",
X"00",X"00",X"01",X"08",X"13",X"8C",X"13",X"8C",X"01",X"8C",X"01",X"8C",X"13",X"84",X"13",X"08",
X"01",X"08",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",X"13",X"8C",
X"13",X"8C",X"13",X"8C",X"12",X"8C",X"01",X"84",X"01",X"08",X"13",X"8C",X"13",X"8C",X"01",X"08",
X"00",X"0E",X"07",X"4E",X"27",X"4F",X"27",X"F7",X"7B",X"ED",X"FE",X"4E",X"2F",X"4E",X"27",X"4E",
X"27",X"4E",X"27",X"4F",X"27",X"F7",X"7B",X"ED",X"FE",X"4E",X"2F",X"4E",X"27",X"0E",X"07",X"00",
X"01",X"0C",X"01",X"8C",X"74",X"F1",X"10",X"C0",X"01",X"0C",X"03",X"0E",X"02",X"02",X"66",X"33",
X"01",X"0C",X"03",X"8E",X"74",X"F1",X"10",X"C0",X"01",X"84",X"12",X"C2",X"30",X"E0",X"01",X"04",
X"0E",X"0E",X"0E",X"0E",X"0F",X"0E",X"27",X"8C",X"52",X"48",X"E1",X"E0",X"B4",X"A4",X"43",X"48",
X"07",X"0C",X"0F",X"0E",X"3E",X"8E",X"5A",X"4A",X"79",X"C2",X"C3",X"68",X"D3",X"68",X"61",X"C0",
X"07",X"0C",X"0F",X"86",X"78",X"C2",X"5E",X"8F",X"7E",X"CF",X"78",X"C3",X"69",X"C3",X"38",X"83",
X"30",X"80",X"73",X"C8",X"97",X"2C",X"B5",X"A4",X"F6",X"EC",X"37",X"8C",X"43",X"48",X"33",X"88",
X"C0",X"30",X"F4",X"F2",X"F7",X"FE",X"D7",X"BE",X"F7",X"FE",X"73",X"EC",X"63",X"6C",X"30",X"C0",
X"09",X"02",X"1E",X"0E",X"28",X"C6",X"5A",X"CA",X"39",X"82",X"7A",X"42",X"24",X"84",X"03",X"08",
X"30",X"80",X"73",X"C8",X"F7",X"EC",X"F7",X"EC",X"F7",X"EC",X"73",X"C8",X"30",X"80",X"00",X"00",
X"60",X"C0",X"E4",X"E4",X"FE",X"EE",X"FF",X"EE",X"F7",X"EC",X"73",X"C8",X"31",X"80",X"10",X"00",
X"E8",X"00",X"FB",X"C0",X"FB",X"FE",X"FB",X"E8",X"FB",X"80",X"F8",X"00",X"C8",X"00",X"C8",X"00",
X"31",X"80",X"62",X"C8",X"62",X"C8",X"31",X"80",X"77",X"CC",X"31",X"00",X"31",X"00",X"31",X"00",
X"24",X"48",X"24",X"48",X"F7",X"FE",X"E5",X"7F",X"F7",X"FE",X"24",X"48",X"24",X"48",X"00",X"00",
X"00",X"00",X"00",X"00",X"0F",X"08",X"FF",X"84",X"FF",X"CA",X"3D",X"ED",X"03",X"E7",X"00",X"6B",
X"00",X"27",X"00",X"27",X"00",X"6B",X"03",X"E7",X"3D",X"ED",X"FF",X"CA",X"FF",X"84",X"0F",X"08",
X"00",X"00",X"00",X"00",X"01",X"0F",X"12",X"FF",X"35",X"FF",X"7B",X"CB",X"7E",X"0C",X"6D",X"00",
X"4E",X"00",X"4E",X"00",X"6D",X"00",X"7E",X"0C",X"7B",X"CB",X"35",X"FF",X"12",X"FF",X"01",X"0F",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"03",X"00",X"13",X"08",X"1F",X"8C",
X"FF",X"CE",X"FF",X"EF",X"0F",X"0F",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"0C",X"00",X"4E",X"00",X"4E",X"00",X"6D",X"0F",
X"7F",X"FF",X"7F",X"FF",X"6D",X"0F",X"4E",X"00",X"4E",X"00",X"0C",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"01",X"08",X"13",X"8C",X"13",X"CE",X"01",X"E7",X"00",X"6B",X"08",X"27",
X"08",X"27",X"8C",X"27",X"CF",X"6F",X"FE",X"ED",X"7F",X"CE",X"37",X"8C",X"03",X"08",X"00",X"00",
X"00",X"00",X"00",X"00",X"0F",X"08",X"7F",X"84",X"7F",X"CA",X"6D",X"ED",X"4E",X"6F",X"4E",X"7A",
X"4E",X"37",X"4E",X"35",X"4E",X"12",X"4E",X"01",X"6D",X"08",X"7F",X"8C",X"0F",X"0C",X"00",X"00",
X"00",X"00",X"00",X"00",X"01",X"08",X"13",X"8C",X"13",X"CE",X"01",X"E7",X"08",X"6B",X"8C",X"27",
X"8C",X"27",X"8C",X"27",X"8C",X"6B",X"CF",X"E7",X"7F",X"CE",X"37",X"8C",X"03",X"08",X"00",X"00",
X"00",X"00",X"00",X"00",X"01",X"08",X"13",X"8C",X"37",X"8C",X"6F",X"08",X"4E",X"00",X"4E",X"01",
X"4E",X"01",X"4E",X"01",X"4E",X"01",X"6D",X"13",X"7E",X"3F",X"37",X"EF",X"13",X"CE",X"01",X"0C",
X"00",X"00",X"00",X"00",X"00",X"00",X"08",X"00",X"8C",X"00",X"CE",X"00",X"6F",X"00",X"37",X"08",
X"13",X"8C",X"0F",X"CE",X"FF",X"EF",X"FF",X"EF",X"0F",X"0F",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"0E",X"00",X"6F",X"00",X"7F",X"00",X"5F",X"00",X"4F",X"00",X"4E",X"0C",X"4E",
X"4E",X"4E",X"6D",X"4F",X"7F",X"FF",X"7F",X"FF",X"6D",X"4F",X"4E",X"0E",X"0C",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"0F",X"0F",X"FF",X"EF",X"FF",X"EF",X"CB",X"2F",X"C6",X"27",X"4E",X"27",
X"4E",X"27",X"4E",X"27",X"CE",X"27",X"C8",X"6B",X"8D",X"EF",X"09",X"0F",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"01",X"0C",X"13",X"8D",X"37",X"8D",X"7E",X"09",X"6D",X"00",X"4E",X"00",
X"4E",X"00",X"4E",X"00",X"6F",X"01",X"37",X"3D",X"35",X"FF",X"12",X"FE",X"01",X"0F",X"00",X"00",
X"00",X"00",X"00",X"00",X"0F",X"08",X"FF",X"84",X"FF",X"CE",X"87",X"6F",X"8C",X"27",X"8C",X"27",
X"8C",X"27",X"8C",X"27",X"8C",X"27",X"8D",X"6F",X"1B",X"CE",X"13",X"84",X"01",X"08",X"00",X"00",
X"00",X"00",X"00",X"00",X"01",X"0F",X"12",X"FF",X"37",X"FF",X"7E",X"1F",X"6D",X"12",X"4E",X"01",
X"4E",X"01",X"4E",X"01",X"4F",X"01",X"6F",X"3D",X"37",X"FF",X"12",X"EF",X"01",X"0E",X"00",X"00",
X"00",X"00",X"00",X"00",X"03",X"0F",X"13",X"EF",X"01",X"6B",X"00",X"27",X"00",X"27",X"08",X"27",
X"84",X"27",X"CA",X"27",X"ED",X"27",X"7E",X"2F",X"37",X"A7",X"13",X"EF",X"01",X"EF",X"00",X"0F",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"0F",X"0E",X"7F",X"ED",
X"7F",X"FF",X"0F",X"3D",X"00",X"03",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"03",X"0C",X"37",X"CA",X"7F",X"ED",X"ED",X"6F",X"CE",X"2F",
X"8C",X"27",X"8C",X"27",X"8C",X"6B",X"CB",X"E7",X"F7",X"ED",X"7B",X"CA",X"07",X"0C",X"00",X"00",
X"00",X"00",X"00",X"00",X"03",X"0C",X"35",X"CA",X"7B",X"ED",X"7E",X"3E",X"6D",X"13",X"4E",X"12",
X"4E",X"12",X"4E",X"13",X"4E",X"35",X"6C",X"37",X"6F",X"7B",X"7B",X"EF",X"35",X"CE",X"03",X"0C",
X"00",X"00",X"00",X"00",X"07",X"08",X"7F",X"84",X"FF",X"CE",X"CB",X"6F",X"08",X"2F",X"08",X"27",
X"08",X"27",X"08",X"27",X"84",X"6B",X"8F",X"E7",X"FF",X"CE",X"FF",X"84",X"0F",X"08",X"00",X"00",
X"00",X"00",X"00",X"00",X"01",X"08",X"12",X"8C",X"37",X"8D",X"6F",X"1B",X"4E",X"13",X"4E",X"13",
X"4E",X"13",X"4E",X"13",X"4E",X"13",X"6F",X"1E",X"37",X"FF",X"12",X"FF",X"01",X"0F",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"08",X"00",X"87",X"03",X"FE",X"2F",X"3D",X"EB",X"03",X"E7",
X"16",X"EF",X"F7",X"EF",X"FF",X"CB",X"ED",X"0C",X"0E",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"0E",X"00",X"6D",X"0C",X"7F",X"CB",X"6D",X"F7",X"4E",X"3E",X"0C",X"27",X"00",X"27",
X"00",X"27",X"0C",X"27",X"4F",X"7B",X"7D",X"FF",X"7F",X"FE",X"7F",X"87",X"6D",X"08",X"0E",X"00",
X"00",X"00",X"00",X"03",X"00",X"27",X"0F",X"6B",X"FF",X"EF",X"FF",X"EF",X"8F",X"6B",X"8C",X"27",
X"00",X"00",X"0C",X"00",X"4E",X"00",X"6D",X"0F",X"7F",X"FF",X"7F",X"FF",X"6D",X"0F",X"4E",X"01",
X"4E",X"01",X"4E",X"01",X"4E",X"12",X"4E",X"13",X"6F",X"3F",X"7B",X"FE",X"35",X"ED",X"03",X"0E",
X"00",X"27",X"00",X"27",X"00",X"6B",X"01",X"E7",X"12",X"ED",X"13",X"EF",X"03",X"0F",X"00",X"00",
X"4E",X"00",X"4E",X"00",X"4E",X"00",X"6C",X"00",X"6F",X"00",X"3F",X"08",X"17",X"8C",X"03",X"08",
X"00",X"00",X"00",X"03",X"00",X"27",X"0F",X"6B",X"FF",X"EF",X"FF",X"EF",X"0F",X"6B",X"00",X"27",
X"00",X"00",X"0C",X"00",X"4E",X"00",X"6D",X"0F",X"7F",X"FF",X"7F",X"FF",X"6D",X"0F",X"4E",X"00",
X"8C",X"27",X"CA",X"27",X"EF",X"27",X"0F",X"27",X"00",X"27",X"00",X"6B",X"01",X"EF",X"01",X"0F",
X"4E",X"01",X"4E",X"12",X"4E",X"37",X"4E",X"07",X"4E",X"00",X"6D",X"00",X"7F",X"08",X"0F",X"08",
X"0C",X"01",X"00",X"12",X"00",X"37",X"00",X"07",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"4E",X"00",X"4E",X"03",X"4E",X"27",X"6D",X"6B",X"7F",X"EF",X"7F",X"EF",X"6D",X"6B",X"0E",X"07",
X"8C",X"03",X"8C",X"27",X"8F",X"6B",X"FF",X"EF",X"FF",X"EF",X"0F",X"6B",X"00",X"27",X"00",X"03",
X"0C",X"01",X"4E",X"01",X"6D",X"0F",X"7F",X"FF",X"7F",X"FF",X"6D",X"0F",X"4E",X"00",X"0C",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"03",X"00",X"27",X"00",X"27",X"0F",X"6B",
X"FF",X"EF",X"FF",X"EF",X"0F",X"6B",X"00",X"27",X"00",X"27",X"00",X"03",X"00",X"00",X"00",X"00",
X"7F",X"FF",X"7F",X"FF",X"6D",X"0F",X"4E",X"00",X"4C",X"00",X"0C",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"03",X"00",X"27",X"0F",X"6B",X"FF",X"EF",X"FF",X"EF",X"0F",X"6B",X"00",X"27",X"00",X"03",
X"00",X"00",X"00",X"00",X"01",X"0C",X"13",X"8C",X"37",X"8C",X"7E",X"08",X"6D",X"00",X"4E",X"00",
X"4E",X"00",X"6D",X"00",X"7E",X"0F",X"7B",X"FF",X"35",X"FF",X"03",X"0F",X"00",X"00",X"00",X"00",
X"CE",X"03",X"EB",X"03",X"3D",X"2F",X"12",X"EB",X"01",X"E7",X"00",X"6B",X"00",X"27",X"00",X"03",
X"0C",X"3D",X"4F",X"F7",X"7D",X"FE",X"7F",X"CB",X"7E",X"0C",X"6D",X"00",X"4E",X"00",X"0C",X"00",
X"00",X"03",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"4E",X"00",X"4E",X"00",X"4E",X"00",X"4E",X"00",X"6D",X"08",X"7F",X"8C",X"0F",X"0C",X"00",X"00",
X"00",X"03",X"0F",X"2F",X"FF",X"EF",X"1E",X"EF",X"7B",X"EF",X"FF",X"CA",X"FE",X"0C",X"CB",X"00",
X"0C",X"00",X"CB",X"00",X"F6",X"0C",X"3D",X"CA",X"FF",X"EF",X"FF",X"EF",X"0F",X"2F",X"00",X"03",
X"0E",X"00",X"6D",X"0F",X"7F",X"FF",X"6D",X"0F",X"0E",X"01",X"00",X"16",X"01",X"7B",X"12",X"FF",
X"01",X"F6",X"00",X"35",X"0E",X"01",X"6D",X"0F",X"7F",X"FF",X"7F",X"FF",X"6D",X"0F",X"0E",X"00",
X"00",X"00",X"00",X"03",X"00",X"27",X"0F",X"6B",X"FF",X"EF",X"1E",X"EF",X"7B",X"ED",X"FF",X"86",
X"ED",X"08",X"86",X"03",X"08",X"27",X"0F",X"2F",X"FF",X"EF",X"0F",X"6B",X"00",X"27",X"00",X"03",
X"00",X"00",X"0C",X"00",X"4E",X"00",X"6D",X"0F",X"7F",X"FF",X"6D",X"0F",X"4E",X"01",X"0C",X"16",
X"01",X"7B",X"16",X"FF",X"7B",X"ED",X"7F",X"87",X"7F",X"FF",X"0F",X"0F",X"00",X"00",X"00",X"00",
X"0C",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"01",X"00",X"00",X"00",X"00",X"00",X"00",
X"4E",X"02",X"4E",X"2F",X"6D",X"E7",X"7E",X"CE",X"7B",X"CB",X"7F",X"FF",X"6D",X"F7",X"0F",X"0F",
X"00",X"00",X"00",X"00",X"03",X"0C",X"37",X"CA",X"7F",X"CE",X"F6",X"E5",X"ED",X"6B",X"CE",X"27",
X"CA",X"27",X"8C",X"27",X"84",X"6B",X"09",X"E7",X"1A",X"ED",X"13",X"EF",X"03",X"0F",X"00",X"00",
X"00",X"00",X"00",X"00",X"0F",X"0C",X"7F",X"8C",X"7B",X"84",X"7E",X"09",X"6D",X"01",X"4E",X"12",
X"4E",X"13",X"4E",X"35",X"4E",X"37",X"6D",X"7B",X"7A",X"F6",X"37",X"EF",X"35",X"CE",X"03",X"0C",
X"00",X"00",X"00",X"00",X"01",X"0F",X"01",X"EF",X"00",X"6B",X"00",X"27",X"00",X"27",X"0F",X"6B",
X"FF",X"EF",X"FF",X"EF",X"0F",X"6B",X"00",X"27",X"00",X"27",X"00",X"6B",X"01",X"EF",X"01",X"0F",
X"00",X"03",X"00",X"03",X"00",X"27",X"0F",X"6B",X"FF",X"EF",X"0F",X"6B",X"00",X"27",X"00",X"03",
X"00",X"00",X"00",X"00",X"00",X"00",X"03",X"0F",X"35",X"FF",X"7B",X"FF",X"7E",X"0F",X"6D",X"00",
X"4E",X"00",X"4E",X"00",X"6D",X"00",X"7A",X"0F",X"35",X"FF",X"03",X"0F",X"00",X"00",X"00",X"00",
X"00",X"03",X"00",X"27",X"01",X"6B",X"1E",X"EF",X"F7",X"EF",X"FF",X"E3",X"CB",X"2F",X"0C",X"03",
X"00",X"00",X"0C",X"03",X"CB",X"2F",X"F7",X"EB",X"1E",X"EF",X"01",X"6B",X"00",X"27",X"00",X"03",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"07",X"03",X"7B",X"3D",X"FF",X"7F",X"ED",
X"7E",X"0E",X"3D",X"ED",X"03",X"7B",X"00",X"07",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"07",X"0F",X"6B",X"F7",X"EF",X"FF",X"EF",X"CB",X"6B",X"0C",X"06",X"87",X"6B",X"FF",X"EF",
X"FF",X"EF",X"C3",X"6B",X"0C",X"06",X"87",X"06",X"FE",X"6B",X"7B",X"EF",X"07",X"6B",X"00",X"07",
X"00",X"00",X"00",X"00",X"00",X"0F",X"0F",X"F7",X"7F",X"FF",X"7F",X"CB",X"1E",X"FF",X"01",X"1F",
X"0F",X"F7",X"7F",X"FF",X"7F",X"CB",X"1E",X"FF",X"01",X"3D",X"00",X"03",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"03",X"00",X"27",X"00",X"6B",X"03",X"EF",X"3D",X"EF",X"F7",X"A7",X"EF",X"0B",
X"CA",X"00",X"E5",X"00",X"3E",X"0B",X"13",X"A7",X"01",X"EB",X"00",X"6F",X"00",X"27",X"00",X"03",
X"0C",X"00",X"4E",X"00",X"6D",X"00",X"7E",X"08",X"7D",X"84",X"4F",X"CA",X"4E",X"6D",X"0C",X"37",
X"0C",X"3F",X"4F",X"F7",X"7D",X"ED",X"7F",X"8E",X"7E",X"08",X"6D",X"00",X"4E",X"00",X"0C",X"00",
X"CA",X"00",X"84",X"00",X"CB",X"03",X"F6",X"2F",X"3D",X"EB",X"03",X"E7",X"00",X"2F",X"00",X"03",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"0C",X"00",X"4E",X"03",X"6D",X"3D",
X"7F",X"FF",X"7F",X"FF",X"6D",X"3D",X"4E",X"03",X"0C",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"8C",X"27",X"CE",X"27",X"E7",X"27",X"7B",X"2F",X"35",X"EF",X"12",X"EF",X"01",X"0F",X"00",X"00",
X"00",X"00",X"00",X"00",X"0F",X"00",X"7E",X"08",X"7F",X"8C",X"5E",X"CE",X"4F",X"E7",X"4E",X"7B",
X"4E",X"35",X"4E",X"12",X"4E",X"01",X"4E",X"00",X"6D",X"08",X"7F",X"8C",X"0F",X"0C",X"00",X"00",
X"00",X"00",X"00",X"00",X"01",X"08",X"13",X"8C",X"13",X"CE",X"01",X"E7",X"00",X"6B",X"00",X"27",
X"08",X"27",X"8C",X"27",X"CF",X"6B",X"F6",X"E7",X"7B",X"CE",X"35",X"8C",X"03",X"08",X"00",X"00",
X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"06",X"06",X"6F",X"6F",
X"6F",X"7F",X"06",X"35",X"00",X"12",X"00",X"01",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"07",X"00",X"7A",X"08",X"7F",X"08",X"7A",X"08",X"07",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"0C",X"0C",X"CF",X"CE",X"7B",X"CE",X"07",X"0C",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"0F",X"0E",X"FF",X"EF",X"FF",X"EF",X"0F",X"0E",X"00",X"00",X"00",X"00",
X"00",X"00",X"00",X"00",X"06",X"07",X"6F",X"7B",X"6F",X"F7",X"06",X"0F",X"00",X"00",X"00",X"00",
X"27",X"00",X"3E",X"0E",X"FF",X"CE",X"3D",X"0E",X"1F",X"87",X"FF",X"EF",X"1E",X"8F",X"01",X"8C",
X"13",X"08",X"1F",X"87",X"7F",X"FF",X"1E",X"8F",X"07",X"CB",X"37",X"FF",X"07",X"C7",X"00",X"4E",
X"00",X"00",X"88",X"44",X"8E",X"40",X"03",X"C3",X"03",X"E3",X"03",X"C3",X"8E",X"40",X"88",X"44",
X"00",X"00",X"00",X"44",X"42",X"42",X"69",X"C3",X"70",X"E3",X"69",X"C3",X"42",X"42",X"00",X"44",
X"60",X"07",X"B4",X"0F",X"69",X"8F",X"5A",X"0C",X"69",X"8F",X"B4",X"0F",X"60",X"07",X"00",X"00",
X"61",X"0E",X"F0",X"87",X"96",X"4F",X"5F",X"C3",X"96",X"4F",X"F0",X"87",X"61",X"0E",X"00",X"00",
X"0F",X"0E",X"71",X"CB",X"F1",X"4B",X"B4",X"C3",X"F1",X"E9",X"71",X"4B",X"0F",X"0E",X"0F",X"08",
X"10",X"C0",X"53",X"2C",X"BF",X"B6",X"BE",X"FE",X"BF",X"B6",X"53",X"2C",X"10",X"C0",X"00",X"00",
X"10",X"F0",X"71",X"FE",X"F7",X"6C",X"B7",X"EC",X"B7",X"EC",X"F7",X"6C",X"71",X"FE",X"10",X"F0",
X"03",X"0F",X"24",X"82",X"7A",X"4A",X"39",X"A1",X"58",X"CA",X"24",X"C6",X"03",X"0F",X"00",X"00",
X"31",X"80",X"33",X"88",X"33",X"88",X"33",X"88",X"73",X"C8",X"77",X"CC",X"55",X"44",X"00",X"00",
X"10",X"EC",X"31",X"FE",X"73",X"FC",X"F7",X"C8",X"73",X"FC",X"31",X"FE",X"10",X"EC",X"00",X"00",
X"FF",X"FF",X"F0",X"F0",X"31",X"FE",X"31",X"EE",X"10",X"EC",X"00",X"E4",X"00",X"C4",X"00",X"40",
X"00",X"00",X"11",X"60",X"F1",X"F6",X"FF",X"99",X"11",X"F6",X"11",X"60",X"00",X"00",X"00",X"00",
X"00",X"31",X"00",X"72",X"00",X"E4",X"34",X"C8",X"13",X"00",X"43",X"80",X"84",X"08",X"08",X"00");
begin
process(clk)
begin
if rising_edge(clk) then
if addr(13) = '1' then
data <= (others=>'0');
else
data <= rom_data(to_integer(unsigned(addr)));
end if;
end if;
end process;
end architecture;

View File

@@ -0,0 +1,351 @@
//
// sdram.v
//
// sdram controller implementation for the MiST board
// https://github.com/mist-devel/mist-board
//
// Copyright (c) 2013 Till Harbaum <till@harbaum.org>
// Copyright (c) 2019 Gyorgy Szombathelyi
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
module sdram (
// interface to the MT48LC16M16 chip
inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus
output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus
output reg SDRAM_DQML, // two byte masks
output reg SDRAM_DQMH, // two byte masks
output reg [1:0] SDRAM_BA, // two banks
output SDRAM_nCS, // a single chip select
output SDRAM_nWE, // write enable
output SDRAM_nRAS, // row address select
output SDRAM_nCAS, // columns address select
// cpu/chipset interface
input init_n, // init signal after FPGA config to initialize RAM
input clk, // sdram clock
input port1_req,
output reg port1_ack,
input port1_we,
input [23:1] port1_a,
input [1:0] port1_ds,
input [15:0] port1_d,
output reg [15:0] port1_q,
input [19:1] cpu1_addr,
output reg [15:0] cpu1_q,
input [19:1] cpu2_addr,
output reg [15:0] cpu2_q,
input port2_req,
output reg port2_ack,
input port2_we,
input [23:1] port2_a,
input [1:0] port2_ds,
input [15:0] port2_d,
output reg [31:0] port2_q,
input [17:2] sp_addr,
output reg [31:0] sp_q
);
parameter MHZ = 16'd80; // 80 MHz default clock, set it to proper value to calculate refresh rate
localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 2 cycles@<100MHz
localparam BURST_LENGTH = 3'b001; // 000=1, 001=2, 010=4, 011=8
localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved
localparam CAS_LATENCY = 3'd2; // 2/3 allowed
localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed
localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write
localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH};
// 64ms/8192 rows = 7.8us
localparam RFRSH_CYCLES = 16'd78*MHZ/4'd10;
// ---------------------------------------------------------------------
// ------------------------ cycle state machine ------------------------
// ---------------------------------------------------------------------
/*
SDRAM state machine for 2 bank interleaved access
1 word burst, CL2
cmd issued registered
0 RAS0 cas1 - data0 read burst terminated
1 ras0
2 data1 returned
3 CAS0 data1 returned
4 RAS1 cas0
5 ras1
6 CAS1 data0 returned
*/
localparam STATE_RAS0 = 3'd0; // first state in cycle
localparam STATE_RAS1 = 3'd4; // Second ACTIVE command after RAS0 + tRRD (15ns)
localparam STATE_CAS0 = STATE_RAS0 + RASCAS_DELAY + 1'd1; // CAS phase - 3
localparam STATE_CAS1 = STATE_RAS1 + RASCAS_DELAY; // CAS phase - 6
localparam STATE_READ0 = 3'd0;// STATE_CAS0 + CAS_LATENCY + 2'd2; // 7
localparam STATE_READ1 = 3'd3;
localparam STATE_DS1b = 3'd0;
localparam STATE_READ1b = 3'd4;
localparam STATE_LAST = 3'd6;
reg [2:0] t;
always @(posedge clk) begin
t <= t + 1'd1;
if (t == STATE_LAST) t <= STATE_RAS0;
end
// ---------------------------------------------------------------------
// --------------------------- startup/reset ---------------------------
// ---------------------------------------------------------------------
// wait 1ms (32 8Mhz cycles) after FPGA config is done before going
// into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0)
reg [4:0] reset;
reg init = 1'b1;
always @(posedge clk, negedge init_n) begin
if(!init_n) begin
reset <= 5'h1f;
init <= 1'b1;
end else begin
if((t == STATE_LAST) && (reset != 0)) reset <= reset - 5'd1;
init <= !(reset == 0);
end
end
// ---------------------------------------------------------------------
// ------------------ generate ram control signals ---------------------
// ---------------------------------------------------------------------
// all possible commands
localparam CMD_INHIBIT = 4'b1111;
localparam CMD_NOP = 4'b0111;
localparam CMD_ACTIVE = 4'b0011;
localparam CMD_READ = 4'b0101;
localparam CMD_WRITE = 4'b0100;
localparam CMD_BURST_TERMINATE = 4'b0110;
localparam CMD_PRECHARGE = 4'b0010;
localparam CMD_AUTO_REFRESH = 4'b0001;
localparam CMD_LOAD_MODE = 4'b0000;
reg [3:0] sd_cmd; // current command sent to sd ram
reg [15:0] sd_din; // Fast Input register latching incoming SDRAM data
// drive control signals according to current command
assign SDRAM_nCS = sd_cmd[3];
assign SDRAM_nRAS = sd_cmd[2];
assign SDRAM_nCAS = sd_cmd[1];
assign SDRAM_nWE = sd_cmd[0];
reg [24:1] addr_latch[2];
reg [24:1] addr_latch_next[2];
reg [19:1] addr_last[2];
reg [17:2] addr_last2[2];
reg [15:0] din_latch[2];
reg [1:0] oe_latch;
reg [1:0] we_latch;
reg [1:0] ds[2];
reg port1_state;
reg port2_state;
localparam PORT_NONE = 2'd0;
localparam PORT_CPU1 = 2'd1;
localparam PORT_CPU2 = 2'd2;
localparam PORT_SP = 2'd1;
localparam PORT_REQ = 2'd3;
reg [1:0] next_port[2];
reg [1:0] port[2];
reg refresh;
reg [11:0] refresh_cnt;
reg need_refresh;
// PORT1: bank 0,1
always @(*) begin
if (refresh) begin
next_port[0] = PORT_NONE;
addr_latch_next[0] = addr_latch[1];
end else if (port1_req ^ port1_state) begin
next_port[0] = PORT_REQ;
addr_latch_next[0] = { 1'b0, port1_a };
end else if (cpu1_addr != addr_last[PORT_CPU1]) begin
next_port[0] = PORT_CPU1;
addr_latch_next[0] = { 5'd0, cpu1_addr };
end else if (cpu2_addr != addr_last[PORT_CPU2]) begin
next_port[0] = PORT_CPU2;
addr_latch_next[0] = { 5'd0, cpu2_addr };
end else begin
next_port[0] = PORT_NONE;
addr_latch_next[0] = addr_latch[0];
end
end
// PORT1: bank 2,3
always @(*) begin
if (port2_req ^ port2_state) begin
next_port[1] = PORT_REQ;
addr_latch_next[1] = { 1'b1, port2_a };
end else if (sp_addr != addr_last2[PORT_SP]) begin
next_port[1] = PORT_SP;
addr_latch_next[1] = { 1'b1, 6'd0, sp_addr, 1'b0 };
end else begin
next_port[1] = PORT_NONE;
addr_latch_next[1] = addr_latch[1];
end
end
always @(posedge clk) begin
// permanently latch ram data to reduce delays
sd_din <= SDRAM_DQ;
SDRAM_DQ <= 16'bZZZZZZZZZZZZZZZZ;
{ SDRAM_DQMH, SDRAM_DQML } <= 2'b11;
sd_cmd <= CMD_NOP; // default: idle
refresh_cnt <= refresh_cnt + 1'd1;
need_refresh <= (refresh_cnt >= RFRSH_CYCLES);
if(init) begin
// initialization takes place at the end of the reset phase
if(t == STATE_RAS0) begin
if(reset == 15) begin
sd_cmd <= CMD_PRECHARGE;
SDRAM_A[10] <= 1'b1; // precharge all banks
end
if(reset == 10 || reset == 8) begin
sd_cmd <= CMD_AUTO_REFRESH;
end
if(reset == 2) begin
sd_cmd <= CMD_LOAD_MODE;
SDRAM_A <= MODE;
SDRAM_BA <= 2'b00;
end
end
end else begin
// RAS phase
// bank 0,1
if(t == STATE_RAS0) begin
addr_latch[0] <= addr_latch_next[0];
port[0] <= next_port[0];
{ oe_latch[0], we_latch[0] } <= 2'b00;
if (next_port[0] != PORT_NONE) begin
sd_cmd <= CMD_ACTIVE;
SDRAM_A <= addr_latch_next[0][22:10];
SDRAM_BA <= addr_latch_next[0][24:23];
addr_last[next_port[0]] <= addr_latch_next[0][19:1];
if (next_port[0] == PORT_REQ) begin
{ oe_latch[0], we_latch[0] } <= { ~port1_we, port1_we };
ds[0] <= port1_ds;
din_latch[0] <= port1_d;
port1_state <= port1_req;
end else begin
{ oe_latch[0], we_latch[0] } <= 2'b10;
ds[0] <= 2'b11;
end
end
end
// bank 2,3
if(t == STATE_RAS1) begin
refresh <= 0;
addr_latch[1] <= addr_latch_next[1];
{ oe_latch[1], we_latch[1] } <= 2'b00;
port[1] <= next_port[1];
if (next_port[1] != PORT_NONE) begin
sd_cmd <= CMD_ACTIVE;
SDRAM_A <= addr_latch_next[1][22:10];
SDRAM_BA <= addr_latch_next[1][24:23];
addr_last2[next_port[1]] <= addr_latch_next[1][16:2];
if (next_port[1] == PORT_REQ) begin
{ oe_latch[1], we_latch[1] } <= { ~port1_we, port1_we };
ds[1] <= port2_ds;
din_latch[1] <= port2_d;
port2_state <= port2_req;
end else begin
{ oe_latch[1], we_latch[1] } <= 2'b10;
ds[1] <= 2'b11;
end
end else if (need_refresh && !oe_latch[0] & !we_latch[0]) begin
refresh <= 1;
refresh_cnt <= 0;
sd_cmd <= CMD_AUTO_REFRESH;
end
end
// CAS phase
if(t == STATE_CAS0 && (we_latch[0] || oe_latch[0])) begin
sd_cmd <= we_latch[0]?CMD_WRITE:CMD_READ;
{ SDRAM_DQMH, SDRAM_DQML } <= ~ds[0];
if (we_latch[0]) begin
SDRAM_DQ <= din_latch[0];
port1_ack <= port1_req;
end
SDRAM_A <= { 4'b0010, addr_latch[0][9:1] }; // auto precharge
SDRAM_BA <= addr_latch[0][24:23];
end
if(t == STATE_CAS1 && (we_latch[1] || oe_latch[1])) begin
sd_cmd <= we_latch[1]?CMD_WRITE:CMD_READ;
{ SDRAM_DQMH, SDRAM_DQML } <= ~ds[1];
if (we_latch[1]) begin
SDRAM_DQ <= din_latch[1];
port2_ack <= port2_req;
end
SDRAM_A <= { 4'b0010, addr_latch[1][9:1] }; // auto precharge
SDRAM_BA <= addr_latch[1][24:23];
end
// Data returned
if(t == STATE_READ0 && oe_latch[0]) begin
case(port[0])
PORT_REQ: begin port1_q <= sd_din; port1_ack <= port1_req; end
PORT_CPU1: begin cpu1_q <= sd_din; end
PORT_CPU2: begin cpu2_q <= sd_din; end
default: ;
endcase;
end
if(t == STATE_READ1 && oe_latch[1]) begin
case(port[1])
PORT_REQ: port2_q[15:0] <= sd_din;
PORT_SP : sp_q[15:0] <= sd_din;
default: ;
endcase;
end
//set DQM two cycles before the 2nd word in the burst
if(t == STATE_DS1b && oe_latch[1]) { SDRAM_DQMH, SDRAM_DQML } <= ~ds[1];
if(t == STATE_READ1b && oe_latch[1]) begin
case(port[1])
PORT_REQ: begin port2_q[31:16] <= sd_din; port2_ack <= port2_req; end
PORT_SP : begin sp_q[31:16] <= sd_din; end
default: ;
endcase;
end
end
end
endmodule

View File

@@ -0,0 +1,91 @@
LIBRARY ieee;
USE ieee.std_logic_1164.all;
LIBRARY altera_mf;
USE altera_mf.all;
ENTITY spram IS
GENERIC
(
init_file : string := "";
--numwords_a : natural;
widthad_a : natural;
width_a : natural := 8;
outdata_reg_a : string := "UNREGISTERED"
);
PORT
(
address : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
clock : IN STD_LOGIC ;
data : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
wren : IN STD_LOGIC ;
q : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
);
END spram;
ARCHITECTURE SYN OF spram IS
SIGNAL sub_wire0 : STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
COMPONENT altsyncram
GENERIC (
clock_enable_input_a : STRING;
clock_enable_output_a : STRING;
init_file : STRING;
intended_device_family : STRING;
lpm_hint : STRING;
lpm_type : STRING;
numwords_a : NATURAL;
operation_mode : STRING;
outdata_aclr_a : STRING;
outdata_reg_a : STRING;
power_up_uninitialized : STRING;
read_during_write_mode_port_a : STRING;
widthad_a : NATURAL;
width_a : NATURAL;
width_byteena_a : NATURAL
);
PORT (
wren_a : IN STD_LOGIC ;
clock0 : IN STD_LOGIC ;
address_a : IN STD_LOGIC_VECTOR (widthad_a-1 DOWNTO 0);
q_a : OUT STD_LOGIC_VECTOR (width_a-1 DOWNTO 0);
data_a : IN STD_LOGIC_VECTOR (width_a-1 DOWNTO 0)
);
END COMPONENT;
BEGIN
q <= sub_wire0(width_a-1 DOWNTO 0);
altsyncram_component : altsyncram
GENERIC MAP (
clock_enable_input_a => "BYPASS",
clock_enable_output_a => "BYPASS",
init_file => init_file,
intended_device_family => "Cyclone III",
lpm_hint => "ENABLE_RUNTIME_MOD=NO",
lpm_type => "altsyncram",
numwords_a => 2**widthad_a,
operation_mode => "SINGLE_PORT",
outdata_aclr_a => "NONE",
outdata_reg_a => outdata_reg_a,
power_up_uninitialized => "FALSE",
read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
widthad_a => widthad_a,
width_a => width_a,
width_byteena_a => 1
)
PORT MAP (
wren_a => wren,
clock0 => clock,
address_a => address,
data_a => data,
q_a => sub_wire0
);
END SYN;

186
common/Amiga/Amiga_Gary.sv Normal file
View File

@@ -0,0 +1,186 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 20:24:47 10/29/2015
// Design Name:
// Module Name: Gary
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module Gary(
output nVPA,
output nCDR,
output nCDW,
input nKRES,
input nMTR,
input nDKWD,
input nDKWE,
input nUDS,
input nLDS,
input RW,
input nAS,
input nBGACK,
input nDBR,
input nSEL0,
output nRGAE,
output nBLS,
output nRAME,
output nROME,
output nRTCR,
output nRTCW,
output reg nLATCH,
input nCDAC,
input C3,
input C1,
input nOVR,
input OVL,
input XRDY,
input nEXP,
input [23:17] A,
inout nRESET,
output nHALT,
output nDTACK,
output DKWEB,
output DKWDB,
output MTR0D,
output MTRXD
);
//internal registers
reg AS_14D0,nDBR_D0;
reg nDTACK_S, nCDR_S, nCDW_S,nBLS_S, MTR0_S;
reg [7:0]counter;
//generate processor clock
wire C7M = C3 ~^ C1; // c1 not xor c2 = 7mhz
wire C14M = C7M ^ ~nCDAC; //14MHZ
wire DS = ~nUDS | ~nLDS;
wire chipram = (~OVL & A[23:21]==3'b000
//| A[23:19]>5'b00001
);
wire rom = ( ( OVL & A[23:21]==3'b000 ) //rom overlay during start
| A[23:19]==5'b11111 //F80000-FFFFFF
| A[23:19]==5'b11100 ); //E00000-E7FFFF
wire clock = A[23:17]==7'b1101110; //clock: D80000-DB0000
wire cia = A[23:21]==3'b101; //cia: A00000-BFFFFF
wire chipset = (nEXP & //expansion selected
(A[23:20]==4'b1100 //C00000-CFFFFF
|A[23:19]==5'b11010))| //D00000-D7FFFF
A[23:18]==6'b110111; //chipset
wire ranger = ~nEXP & //expansion selected
(A[23:20]==4'b1100 //C00000-CFFFFF
|A[23:19]==5'b11010) //D00000-D7FFFF
;
//all others a bit later with AS_14D0
wire other =~chipram & ~rom & ~clock & ~ chipset & ~ranger & ~cia & ~AS_14D0;
//reset generation
assign nHALT = ~nKRES ? 0 : 1'bz;
assign nRESET = ~nKRES ? 0 : 1'bz;
//assign simple signals
assign DKWDB = ~nDKWD;
assign DKWEB = nDKWE & nRESET;
assign MTRXD = ~nMTR & nRESET;
assign MTR0D = MTR0_S ;
//select floppy motor
always @(negedge nSEL0 ,negedge nRESET)
begin
if( nRESET==0)
begin
MTR0_S <= 0;
end
else
begin
MTR0_S <= ~nMTR;
end
end
//decode address and generate the internal signals
always @(posedge C14M)
begin
//this replaces the nasty latch!
nLATCH <= C3;
AS_14D0 <= nAS;
nDBR_D0 <= nDBR;
if(nAS)
begin
nDTACK_S <=1;
nCDR_S <=1;
nCDW_S <=1;
nBLS_S <=1;
counter <=8'h00;
end
else
begin
//count 7Mhz-flanks: odd falling even rising
counter <=counter+1; // the cycle starts at S3: this time the first cycle is seen!
if(
((~nDBR | ~nDBR_D0) &( //blitting
chipram | chipset | ranger //Agnus
)
)
| cia //cia access
& nDTACK_S //not asserted
)
begin
nDTACK_S <= 1;
end
else
begin
nDTACK_S <= ~XRDY; //ready to rambo
end
//slow down blitter
nBLS_S <= ~(( chipram | ranger | chipset) & (counter[1:0]>=2'b00 & counter[1:0]<=2'b01));
//read from RAM / register
if( counter>=8'h01 //minimum wait
& RW //read
& nDBR_D0 & nDBR //no blitting
& (chipset | chipram | ranger) //agnus-select
& nCDR_S //not asseted
)
begin
nCDR_S <= 0;
end
//write to RAM / register
if( ~RW //write
& nDBR_D0 & nDBR //no blitting
& (chipset | chipram | ranger) //agnus-select
& nCDW_S //not asseted
)
begin
nCDW_S <= 0;
end
end
end
//output signal generation
assign nVPA = nOVR & ~nAS ? ~cia : 1'bz;
assign nDTACK = (nOVR & ~nAS ) ? nDTACK_S : 1'bz;
assign nROME = nOVR & ~nAS ? ~(rom & RW) : 1; //only on read!
assign nRTCR = nOVR & ~nAS ? ~(clock & RW & DS) : 1;
assign nRTCW = nOVR & ~nAS ? ~(clock & ~RW & DS) : 1;
assign nRAME = nOVR & ~nAS ? ~(chipram | ranger ) : 1;
assign nCDR = nOVR & ~nAS ? nCDR_S : 1;
assign nCDW = nOVR & ~nAS ? nCDW_S : 1;
assign nRGAE = nOVR & ~nAS ? ~chipset : 1;
assign nBLS = nOVR & ~nAS ? nBLS_S : 1;
endmodule

View File

@@ -0,0 +1,2 @@
# TG68K.C
switchable 68K CPU-Core

View File

@@ -0,0 +1,4 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) TG68K.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) TG68K_ALU.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) TG68K_Pack.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) TG68KdotC_Kernel.vhd ]

View File

@@ -0,0 +1,212 @@
-- (c) 2020 d18c7db(a)hotmail
--
-- This program is free software; you can redistribute it and/or modify it under
-- the terms of the GNU General Public License version 3 or, at your option,
-- any later version as published by the Free Software Foundation.
--
-- This program 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.
--
-- For full details, see the GNU General Public License at www.gnu.org/licenses
--
-- This file is a wrapper around the TG68KdotC_Kernel
-- to adapt it to the real chip pinout and signal timings
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
--pragma translate_off
use ieee.std_logic_textio.all;
use std.textio.all;
--pragma translate_on
entity TG68K is
port(
CLK : in std_logic;
RST : in std_logic;
clkena_ext : in std_logic;
DTACK : in std_logic;
VPA : in std_logic;
IPL : in std_logic_vector( 2 downto 0);
DI : in std_logic_vector(15 downto 0);
AS : out std_logic;
UDS : out std_logic;
LDS : out std_logic;
WR : out std_logic;
FC : out std_logic_vector( 2 downto 0);
ADDR : out std_logic_vector(23 downto 0);
DO : out std_logic_vector(15 downto 0);
cpusel : in std_logic_vector( 1 downto 0);
nRSTout : out std_logic
);
end TG68K;
architecture logic of TG68K is
signal clk_ena : std_logic:='0';
signal as_ena : std_logic:='0';
signal nUDS : std_logic:='0';
signal nLDS : std_logic:='0';
signal nWR : std_logic:='0';
signal clkena_in : std_logic:='0';
signal skipFetch : std_logic:='0';
signal phase : std_logic_vector( 1 downto 0):=(others=>'0');
signal busstate : std_logic_vector( 1 downto 0):=(others=>'0');
signal data_latch : std_logic_vector(15 downto 0):=(others=>'0');
signal addr_out : std_logic_vector(31 downto 0):=(others=>'0');
signal data_out : std_logic_vector(15 downto 0):=(others=>'0');
begin
--pragma translate_off
debug_writemem : process
file file_xx : TEXT open WRITE_MODE is "..\..\SIM\RAM.log";
variable s : line;
begin
wait until falling_edge(CLK);
if phase="11" and busstate="10" then -- mem read
if addr_out(23 downto 8) = x"0000" then
-- reading vector table
write(s, " R VECT "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_latch); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
elsif addr_out(23 downto 12) = x"038" then
-- Slapstic
write(s, " R SLAP "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_latch); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
end if;
end if;
if phase="11" and busstate="11" then -- mem write
case addr_out(23 downto 12) is
when x"038" =>
-- Slapstic
write(s, " W SLAP "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
when x"800" | x"801" =>
-- Program RAM
write(s, " W PROG "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
when x"802" =>
-- EEPROM
write(s, " W EROM "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
-- special
when x"803" =>
if addr_out(11 downto 0) = x"100" then
-- 803100 Watchdog reset
write(s, " W WDOG "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
elsif addr_out(11 downto 0) = x"12E" then
-- 80312E Sound CPU reset
write(s, " W SRST "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
elsif addr_out(11 downto 0) = x"140" then
-- 803140 VBLANK IRQ acknowledge
write(s, " W VBLK "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
elsif addr_out(11 downto 0) = x"150" then
-- 803150 EEPROM enable
write(s, " W EENA "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
elsif addr_out(11 downto 0) = x"170" then
-- 803170 Sound command write
write(s, " W WSND "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
else
write(s, " W XXXX "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
end if;
when x"900" | x"901" =>
-- PF RAM
write(s, " W PF "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
when x"902" | x"903" =>
-- MO RAM
write(s, " W MO "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
when x"904" =>
-- Spare RAM
write(s, "W SPAR ", right, 34); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- "); write(s, time'image(now), right, 18); writeline(file_xx,s);
when x"905" =>
-- PF Y scroll
if addr_out(11 downto 0) = x"F6E" then
write(s, " W YSCR "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
else
-- AL RAM
write(s, " W AL "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
end if;
when x"910" =>
-- Palette RAM
write(s, " W PAL "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
when x"930" =>
-- 930000 Playfield X scroll
write(s, " W XSCR "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
when others => null;
-- dump any other writes also
write(s, " W XXXX "); hwrite(s, addr_out); write(s, ": "); hwrite(s, data_out); write(s, " "); write(s, nUDS); write(s, nLDS); write(s, " -- ", right, 30); write(s, time'image(now), right, 18); writeline(file_xx,s);
end case;
end if;
end process;
--pragma translate_on
ADDR <= addr_out(23 downto 0);
DO<=data_out;
u_TG68K : entity work.TG68KdotC_Kernel
generic map(
SR_Read => 2, --0=>user, 1=>privileged, 2=>switchable with CPU(0)
VBR_Stackframe => 2, --0=>no, 1=>yes/extended, 2=>switchable with CPU(0)
extAddr_Mode => 2, --0=>no, 1=>yes, 2=>switchable with CPU(1)
MUL_Mode => 2, --0=>16Bit, 1=>32Bit, 2=>switchable with CPU(1), 3=>no MUL,
DIV_Mode => 2, --0=>16Bit, 1=>32Bit, 2=>switchable with CPU(1), 3=>no DIV,
BitField => 2 --0=>no, 1=>yes, 2=>switchable with CPU(1)
)
port map(
clk => CLK,
nReset => RST,
clkena_in => clkena_in,
data_in => data_latch,
IPL => IPL,
IPL_autovector => '1',
addr_out => addr_out,
data_write => data_out,
nWr => nWR,
nUDS => nUDS,
nLDS => nLDS,
nResetOut => nRSTout,
FC => FC,
CPU => cpusel,
busstate => busstate,
skipFetch => skipFetch,
VBR_out => open
);
clkena_in <= '1' when clkena_ext='1' and (busstate="01" or clk_ena='1') else '0';
AS <= '1' when busstate="01" else as_ena;
WR <= '1' when busstate="01" else as_ena or nWR;
UDS <= '1' when busstate="01" else as_ena or nUDS;
LDS <= '1' when busstate="01" else as_ena or nLDS;
process
begin
wait until rising_edge(CLK);
if RST='0' then
phase <= "00";
clk_ena <= '0';
as_ena <= '1';
else
clk_ena <= '0';
as_ena <= '1';
case phase is
when "00" =>
if busstate/="01" then
phase <= "01";
as_ena <= '0';
end if;
when "01" =>
phase <= "10";
as_ena <= '0';
when "10" =>
if DTACK='0' or VPA='0' then
phase <= "11";
data_latch <= DI;
else
as_ena <= '0';
end if;
when "11" =>
phase <= "00";
clk_ena <= '1';
when others => null;
end case;
end if;
end process;
end;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,180 @@
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- --
-- Copyright (c) 2009-2020 Tobias Gubener --
-- Patches by MikeJ, Till Harbaum, Rok Krajnk, ... --
-- Subdesign fAMpIGA by TobiFlex --
-- --
-- This source file 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. --
-- --
-- This source file 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 General Public License for more details. --
-- --
-- You should have received a copy of the GNU General Public License --
-- along with this program. If not, see <http://www.gnu.org/licenses/>. --
-- --
------------------------------------------------------------------------------
------------------------------------------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;
package TG68K_Pack is
type micro_states is (idle, nop, ld_nn, st_nn, ld_dAn1, ld_AnXn1, ld_AnXn2, st_dAn1, ld_AnXnbd1, ld_AnXnbd2, ld_AnXnbd3,
ld_229_1, ld_229_2, ld_229_3, ld_229_4, st_229_1, st_229_2, st_229_3, st_229_4,
st_AnXn1, st_AnXn2, bra1, bsr1, bsr2, nopnop, dbcc1, movem1, movem2, movem3,
andi, pack1, pack2, pack3, op_AxAy, cmpm, link1, link2, unlink1, unlink2, int1, int2, int3, int4, rte1, rte2, rte3,
rte4, rte5, rtd1, rtd2, trap00, trap0, trap1, trap2, trap3, cas1, cas2, cas21, cas22, cas23, cas24,
cas25, cas26, cas27, cas28, chk20, chk21, chk22, chk23, chk24,
trap4, trap5, trap6, movec1, movep1, movep2, movep3, movep4, movep5, rota1, bf1,
mul1, mul2, mul_end1, mul_end2, div1, div2, div3, div4, div_end1, div_end2);
constant opcMOVE : integer := 0; --
constant opcMOVEQ : integer := 1; --
constant opcMOVESR : integer := 2; --
constant opcADD : integer := 3; --
constant opcADDQ : integer := 4; --
constant opcOR : integer := 5; --
constant opcAND : integer := 6; --
constant opcEOR : integer := 7; --
constant opcCMP : integer := 8; --
constant opcROT : integer := 9; --
constant opcCPMAW : integer := 10;
constant opcEXT : integer := 11; --
constant opcABCD : integer := 12; --
constant opcSBCD : integer := 13; --
constant opcBITS : integer := 14; --
constant opcSWAP : integer := 15; --
constant opcScc : integer := 16; --
constant andiSR : integer := 17; --
constant eoriSR : integer := 18; --
constant oriSR : integer := 19; --
constant opcMULU : integer := 20; --
constant opcDIVU : integer := 21; --
constant dispouter : integer := 22; --
constant rot_nop : integer := 23; --
constant ld_rot_cnt : integer := 24; --
constant writePC_add : integer := 25; --
constant ea_data_OP1 : integer := 26; --
constant ea_data_OP2 : integer := 27; --
constant use_XZFlag : integer := 28; --
constant get_bfoffset : integer := 29; --
constant save_memaddr : integer := 30; --
constant opcCHK : integer := 31; --
constant movec_rd : integer := 32; --
constant movec_wr : integer := 33; --
constant Regwrena : integer := 34; --
constant update_FC : integer := 35; --
constant linksp : integer := 36; --
constant movepl : integer := 37; --
constant update_ld : integer := 38; --
constant OP1addr : integer := 39; --
constant write_reg : integer := 40; --
constant changeMode : integer := 41; --
constant ea_build : integer := 42; --
constant trap_chk : integer := 43; --
constant store_ea_data : integer := 44; --
constant addrlong : integer := 45; --
constant postadd : integer := 46; --
constant presub : integer := 47; --
constant subidx : integer := 48; --
constant no_Flags : integer := 49; --
constant use_SP : integer := 50; --
constant to_CCR : integer := 51; --
constant to_SR : integer := 52; --
constant OP2out_one : integer := 53; --
constant OP1out_zero : integer := 54; --
constant mem_addsub : integer := 55; --
constant addsub : integer := 56; --
constant directPC : integer := 57; --
constant direct_delta : integer := 58; --
constant directSR : integer := 59; --
constant directCCR : integer := 60; --
constant exg : integer := 61; --
constant get_ea_now : integer := 62; --
constant ea_to_pc : integer := 63; --
constant hold_dwr : integer := 64; --
constant to_USP : integer := 65; --
constant from_USP : integer := 66; --
constant write_lowlong : integer := 67; --
constant write_reminder : integer := 68; --
constant movem_action : integer := 69; --
constant briefext : integer := 70; --
constant get_2ndOPC : integer := 71; --
constant mem_byte : integer := 72; --
constant longaktion : integer := 73; --
constant opcRESET : integer := 74; --
constant opcBF : integer := 75; --
constant opcBFwb : integer := 76; --
constant opcPACK : integer := 77; --
constant opcUNPACK : integer := 78; --
constant hold_ea_data : integer := 79; --
constant store_ea_packdata : integer := 80; --
constant exec_BS : integer := 81; --
constant hold_OP2 : integer := 82; --
constant restore_ADDR : integer := 83; --
constant alu_exec : integer := 84; --
constant alu_move : integer := 85; --
constant alu_setFlags : integer := 86; --
constant opcCHK2 : integer := 87; --
constant opcEXTB : integer := 88; --
constant lastOpcBit : integer := 88;
component TG68K_ALU
generic(
MUL_Mode :integer; --0=>16Bit, 1=>32Bit, 2=>switchable with CPU(1), 3=>no MUL,
MUL_Hardware :integer; --0=>no, 1=>yes,
DIV_Mode :integer; --0=>16Bit, 1=>32Bit, 2=>switchable with CPU(1), 3=>no DIV,
BarrelShifter :integer --0=>no, 1=>yes, 2=>switchable with CPU(1)
);
port(
clk : in std_logic;
Reset : in std_logic;
CPU : in std_logic_vector(1 downto 0):="00"; -- 00->68000 01->68010 11->68020(only some parts - yet)
clkena_lw : in std_logic:='1';
execOPC : in bit;
decodeOPC : in bit;
exe_condition : in std_logic;
exec_tas : in std_logic;
long_start : in bit;
non_aligned : in std_logic;
movem_presub : in bit;
set_stop : in bit;
Z_error : in bit;
rot_bits : in std_logic_vector(1 downto 0);
exec : in bit_vector(lastOpcBit downto 0);
OP1out : in std_logic_vector(31 downto 0);
OP2out : in std_logic_vector(31 downto 0);
reg_QA : in std_logic_vector(31 downto 0);
reg_QB : in std_logic_vector(31 downto 0);
opcode : in std_logic_vector(15 downto 0);
-- datatype : in std_logic_vector(1 downto 0);
exe_opcode : in std_logic_vector(15 downto 0);
exe_datatype : in std_logic_vector(1 downto 0);
sndOPC : in std_logic_vector(15 downto 0);
last_data_read : in std_logic_vector(15 downto 0);
data_read : in std_logic_vector(15 downto 0);
FlagsSR : in std_logic_vector(7 downto 0);
micro_state : in micro_states;
bf_ext_in : in std_logic_vector(7 downto 0);
bf_ext_out : out std_logic_vector(7 downto 0);
bf_shift : in std_logic_vector(5 downto 0);
bf_width : in std_logic_vector(5 downto 0);
bf_ffo_offset : in std_logic_vector(31 downto 0);
bf_loffset : in std_logic_vector(4 downto 0);
set_V_Flag : buffer bit;
Flags : buffer std_logic_vector(7 downto 0);
c_out : buffer std_logic_vector(2 downto 0);
addsub_q : buffer std_logic_vector(31 downto 0);
ALUout : out std_logic_vector(31 downto 0)
);
end component;
end;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80pa.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80s.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80se.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80sed.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T8080se.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80_Reg.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80_MCode.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80_ALU.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80_Pack.vhd ]

View File

@@ -0,0 +1,64 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_sh2 #(parameter width=5, stages=32 )
(
input clk,
input en,
input ld,
input [width-1:0] din,
output [width-1:0] drop
);
genvar i;
generate
for( i=0; i<width; i=i+1) begin: shifter
jt51_sh1 #(.stages(stages)) u_sh1(
.clk ( clk ),
.en ( en ),
.ld ( ld ),
.din ( din[i] ),
.drop ( drop[i])
);
end
endgenerate
endmodule
module jt51_sh1 #(parameter stages=32)
(
input clk,
input en,
input ld,
input din,
output drop
);
reg [stages-1:0] shift;
assign drop = shift[0];
wire next = ld ? din : drop;
always @(posedge clk )
if( en )
shift <= {next, shift[stages-1:1]};
endmodule

View File

@@ -0,0 +1,63 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 9th 2017
*/
`timescale 1ns / 1ps
/*
input sampling rate must be the same as clk frequency
interpolate input signal accordingly to get the
right sampling rate.
Refer to sigmadelta.ods to see how the internal width (int_w)
was determined.
*/
module jt51_dac2 #(parameter width=16)
(
input clk,
input rst,
input signed [width-1:0] din,
output reg dout
);
parameter int_w = width+5;
reg [int_w-1:0] y, error, error_1, error_2;
wire [width-1:0] undin = { ~din[width-1], din[width-2:0] };
always @(*) begin
y <= undin + { error_1, 1'b0} - error_2;
dout <= ~y[int_w-1];
error <= y - {dout, {width{1'b0}}};
end
always @(posedge clk)
if( rst ) begin
error_1 <= {int_w{1'b0}};
error_2 <= {int_w{1'b0}};
end else begin
error_1 <= error;
error_2 <= error_1;
end
endmodule

View File

@@ -0,0 +1,189 @@
/* This file is part of jt51.
jt51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jt51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with jt51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 7th 2017
*/
`timescale 1ns / 1ps
module jt51_fir
#(parameter data_width=9, output_width=12, coeff_width=9,
addr_width=7, stages=81, acc_extra=1)
(
input clk,
input rst,
input sample,
input signed [data_width-1:0] left_in,
input signed [data_width-1:0] right_in,
input signed [coeff_width-1:0] coeff,
output reg [addr_width-1:0] cnt,
output reg signed [output_width-1:0] left_out,
output reg signed [output_width-1:0] right_out,
output reg sample_out
);
wire signed [data_width-1:0] mem_left, mem_right;
// pointers
reg [addr_width-1:0] addr_left, addr_right,
forward, rev, in_pointer;
reg update, last_sample;
reg [1:0] state;
parameter IDLE=2'b00, LEFT=2'b01, RIGHT=2'b10;
jt51_fir_ram #(.data_width(data_width),.addr_width(addr_width)) chain_left(
.clk ( clk ),
.data ( left_in ),
.addr ( addr_left ),
.we ( update ),
.q ( mem_left )
);
jt51_fir_ram #(.data_width(data_width),.addr_width(addr_width)) chain_right(
.clk ( clk ),
.data ( right_in ),
.addr ( addr_right),
.we ( update ),
.q ( mem_right)
);
always @(posedge clk)
if( rst )
{ update, last_sample } <= 2'b00;
else begin
last_sample <= sample;
update <= sample && !last_sample;
end
parameter mac_width=(data_width+1)+coeff_width;
parameter acc_width=output_width; // mac_width+3;
reg signed [acc_width-1:0] acc_left, acc_right;
//integer acc,mac;
wire [addr_width-1:0] next = cnt+1'b1;
reg signed [data_width:0] sum;
wire last_stage = cnt==(stages-1)/2;
reg signed [data_width-1:0] buffer_left, buffer_right;
always @(*) begin
if( state==LEFT) begin
if( last_stage )
sum = buffer_left;
else
sum = buffer_left + mem_left;
end
else begin
if( last_stage )
sum = buffer_right;
else
sum = buffer_right + mem_right;
end
end
wire signed [mac_width-1:0] mac = coeff*sum;
wire signed [acc_width-1:0] mac_trim = mac[mac_width-1:mac_width-acc_width];
//wire signed [acc_width-1:0] mac_trimx = (coeff*sum)>>>(mac_width-acc_width);
wire [addr_width-1:0]
in_pointer_next = in_pointer - 1'b1,
forward_next = forward+1'b1,
rev_next = rev-1'b1;
always @(*) begin
case( state )
default: begin
addr_left = update ? rev : in_pointer;
addr_right= in_pointer;
end
LEFT: begin
addr_left = forward_next;
addr_right= rev;
end
RIGHT: begin
if( cnt==(stages-1)/2 ) begin
addr_left = in_pointer_next;
addr_right= in_pointer_next;
end
else begin
addr_left = rev_next;
addr_right= forward;
end
end
endcase
end
always @(posedge clk)
if( rst ) begin
sample_out <= 1'b0;
state <= IDLE;
in_pointer <= 7'd0;
//addr_left <= in_pointer;
//addr_right<= in_pointer;
end else begin
case(state)
default: begin
if( update ) begin
state <= LEFT;
buffer_left <= left_in;
//addr_left <= rev;
end
cnt <= 6'd0;
acc_left <= {acc_width{1'b0}};
acc_right <= {acc_width{1'b0}};
rev <= in_pointer+stages-1'b1;
forward <= in_pointer;
sample_out <= 1'b0;
end
LEFT: begin
acc_left <= acc_left + mac_trim;
//addr_left <= forward_next;
buffer_right <= mem_right;
//addr_right <= rev;
forward<=forward_next;
state <= RIGHT;
end
RIGHT:
if( cnt==(stages-1)/2 ) begin
left_out <= acc_left;
right_out <= acc_right + mac_trim;
sample_out <= 1'b1;
in_pointer <= in_pointer_next;
//addr_left <= in_pointer_next;
//addr_right<= in_pointer_next;
state <= IDLE;
end else begin
acc_right <= acc_right + mac_trim;
//addr_right <= forward;
buffer_left <= mem_left;
//addr_left <= rev_next;
cnt<=next;
rev<=rev-1'b1;
state <= LEFT;
end
endcase
end
endmodule // jt51_fir8

View File

@@ -0,0 +1,83 @@
/* This file is part of jt51.
jt51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jt51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with jt51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 7th 2017
*/
`timescale 1ns / 1ps
module jt51_fir4
#(parameter data_width=9, output_width=12)
(
input clk,
input rst,
input sample,
input signed [data_width-1:0] left_in,
input signed [data_width-1:0] right_in,
output signed [output_width-1:0] left_out,
output signed [output_width-1:0] right_out,
output sample_out
);
parameter coeff_width=9;
parameter stages=21;
parameter addr_width=5;
parameter acc_extra=1;
reg signed [coeff_width-1:0] coeff;
wire [addr_width-1:0] cnt;
jt51_fir #(
.data_width (data_width),
.output_width(output_width),
.coeff_width (coeff_width),
.stages (stages),
.addr_width (addr_width),
.acc_extra (acc_extra)
) i_jt51_fir (
.clk (clk ),
.rst (rst ),
.sample (sample ),
.left_in (left_in ),
.right_in (right_in ),
.left_out (left_out ),
.right_out (right_out ),
.sample_out(sample_out),
.cnt (cnt ),
.coeff (coeff )
);
always @(*)
case( cnt )
5'd0: coeff = 9'd18;
5'd1: coeff = 9'd24;
5'd2: coeff = 9'd40;
5'd3: coeff = 9'd66;
5'd4: coeff = 9'd99;
5'd5: coeff = 9'd134;
5'd6: coeff = 9'd171;
5'd7: coeff = 9'd205;
5'd8: coeff = 9'd231;
5'd9: coeff = 9'd249;
5'd10: coeff = 9'd255;
default: coeff = 9'd0;
endcase
endmodule

View File

@@ -0,0 +1,111 @@
/* This file is part of jt51.
jt51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jt51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with jt51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 7th 2017
*/
`timescale 1ns / 1ps
module jt51_fir8
#(parameter data_width=9, output_width=12)
(
input clk,
input rst,
input sample,
input signed [data_width-1:0] left_in,
input signed [data_width-1:0] right_in,
output signed [output_width-1:0] left_out,
output signed [output_width-1:0] right_out,
output sample_out
);
parameter coeff_width=9;
parameter stages=81;
parameter addr_width=7;
parameter acc_extra=1;
reg signed [coeff_width-1:0] coeff;
wire [addr_width-1:0] cnt;
jt51_fir #(
.data_width (data_width),
.output_width(output_width),
.coeff_width (coeff_width),
.stages (stages),
.addr_width (addr_width),
.acc_extra (acc_extra)
) i_jt51_fir (
.clk (clk ),
.rst (rst ),
.sample (sample ),
.left_in (left_in ),
.right_in (right_in ),
.left_out (left_out ),
.right_out (right_out ),
.sample_out(sample_out),
.cnt (cnt ),
.coeff (coeff )
);
always @(*)
case( cnt )
7'd0: coeff = -9'd1;
7'd1: coeff = 9'd0;
7'd2: coeff = 9'd1;
7'd3: coeff = 9'd1;
7'd4: coeff = 9'd2;
7'd5: coeff = 9'd3;
7'd6: coeff = 9'd4;
7'd7: coeff = 9'd4;
7'd8: coeff = 9'd5;
7'd9: coeff = 9'd5;
7'd10: coeff = 9'd5;
7'd11: coeff = 9'd4;
7'd12: coeff = 9'd3;
7'd13: coeff = 9'd1;
7'd14: coeff = -9'd2;
7'd15: coeff = -9'd6;
7'd16: coeff = -9'd11;
7'd17: coeff = -9'd16;
7'd18: coeff = -9'd21;
7'd19: coeff = -9'd26;
7'd20: coeff = -9'd30;
7'd21: coeff = -9'd33;
7'd22: coeff = -9'd34;
7'd23: coeff = -9'd32;
7'd24: coeff = -9'd28;
7'd25: coeff = -9'd21;
7'd26: coeff = -9'd10;
7'd27: coeff = 9'd4;
7'd28: coeff = 9'd22;
7'd29: coeff = 9'd42;
7'd30: coeff = 9'd65;
7'd31: coeff = 9'd91;
7'd32: coeff = 9'd117;
7'd33: coeff = 9'd142;
7'd34: coeff = 9'd168;
7'd35: coeff = 9'd192;
7'd36: coeff = 9'd213;
7'd37: coeff = 9'd231;
7'd38: coeff = 9'd244;
7'd39: coeff = 9'd252;
7'd40: coeff = 9'd255;
default: coeff = 9'd0;
endcase // cnt
endmodule

View File

@@ -0,0 +1,43 @@
/* This file is part of jt51.
jt51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jt51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with jt51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 7th 2017
*/
`timescale 1ns / 1ps
module jt51_fir_ram
#(parameter data_width=8, parameter addr_width=7)
(
input [(data_width-1):0] data,
input [(addr_width-1):0] addr,
input we, clk,
output [(data_width-1):0] q
);
(* ramstyle = "no_rw_check" *) reg [data_width-1:0] ram[2**addr_width-1:0];
reg [addr_width-1:0] addr_reg;
always @ (posedge clk) begin
if (we)
ram[addr] <= data;
addr_reg <= addr;
end
assign q = ram[addr_reg];
endmodule

View File

@@ -0,0 +1,130 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 7th 2017
*/
`timescale 1ns / 1ps
module jt51_interpol(
input clk, // Use a clock at least 162*2 times faster than JT51 sampling rate
input rst,
input sample_in,
input signed [15:0] left_in,
input signed [15:0] right_in,
// mix in other sound sources, like ADPCM sound of arcade boards
// other sound sources should be at the same
// sampling frequency than the FM sound
// for best results
input signed [15:0] left_other,
input signed [15:0] right_other,
output signed [15:0] out_l,
output signed [15:0] out_r,
output sample_out
);
/* max_clk_count is chosen so as to divide the input clock to
obtain a 32xFs frequency.
Fs = JT51 sampling frequency, normally ~55kHz
32xFs = 1.78MHz
If this module's clock is 50MHz then
max_clk_count = 50/1.78=28
The division must be exact, otherwise samples will get out of sync
eventually and sound will get distorted.
max_clk_count*32 is the number of clock ticks that the FIR module
has to process the two sound channels. Each channels needs at least
162 clock ticks, so in total it needs just over 324 ticks.
(162 is the number of stages of the filter)
Using 50MHz and max_clk_count=28 gives 896 clock ticks, which is
more than enough.
*/
parameter max_clk_count = 7'd111;
reg [15:0] fir_left_in, fir_right_in, left_mux, right_mux;
reg fir_sample_in;
reg fir4_sample_in;
reg [2:0] state;
reg [6:0] cnt;
always @(*)
case( state )
3'd0: { left_mux, right_mux } <= { left_in, right_in};
3'd3: { left_mux, right_mux } <= { left_other, right_other};
default: { left_mux, right_mux } <= 32'd0;
endcase
always @(posedge clk)
if( rst ) begin
state <= 2'b0;
fir_sample_in <= 1'b0;
cnt <= 6'd0;
end else begin
fir4_sample_in <= ( cnt==0 || cnt==28 || cnt==56 || cnt==84 );
if( cnt==max_clk_count ) begin
cnt <= 6'd0;
state <= state+1'b1;
fir_sample_in <= 1'b1;
{fir_left_in,fir_right_in} <= { left_mux, right_mux };
end
else begin
cnt <= cnt + 1'b1;
fir_sample_in <= 1'b0;
end
end
localparam fir8_w=16; // at least 16
localparam fir4_w=16; // at least 16
wire [fir8_w-1:0] fir8_out_l, fir8_out_r;
wire [fir4_w-1:0] fir4_out_l, fir4_out_r;
assign out_l = fir4_out_l[15:0];
assign out_r = fir4_out_r[15:0];
//assign out_l = fir8_out_l[15:0];
//assign out_r = fir8_out_r[15:0];
//wire fir8_sample;
jt51_fir8 #(.data_width(16), .output_width(fir8_w)) u_fir8 (
.clk ( clk ),
.rst ( rst ),
.sample ( fir_sample_in ),
.left_in ( fir_left_in ),
.right_in ( fir_right_in ),
.left_out ( fir8_out_l ),
.right_out ( fir8_out_r )
// .sample_out ( fir8_sample )
);
jt51_fir4 #(.data_width(16), .output_width(fir4_w)) u_fir4 (
.clk ( clk ),
.rst ( rst ),
.sample ( fir4_sample_in),
.left_in ( fir8_out_l[fir8_w-1:fir8_w-16] ),
.right_in ( fir8_out_r[fir8_w-1:fir8_w-16] ),
.left_out ( fir4_out_l ),
.right_out ( fir4_out_r ),
.sample_out ( sample_out )
);
endmodule

View File

@@ -0,0 +1,53 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 7th 2017
*/
`timescale 1ns / 1ps
module jt51_sincf #(parameter win=1, wout=5)
(
input clk,
input [win-1:0] din,
output reg [wout-1:0] dout
);
reg [win-1:0] mem[23:0];
genvar i;
generate
for (i=23; i>0; i=i-1) begin: meminput
always @(posedge clk)
mem[i] <= mem[i-1];
end
endgenerate
always @(posedge clk) begin
mem[0] <= din;
dout <= mem[0] + mem[1] + mem[2] + mem[3] +
mem[4] + mem[5] + mem[6] + mem[7] +
mem[8] + mem[9] + mem[10] + mem[11] +
mem[12] + mem[13] + mem[14] + mem[15] +
mem[16] + mem[17] + mem[18] + mem[19] +
mem[20] + mem[21] + mem[22] + mem[23];
end
endmodule

View File

@@ -0,0 +1,23 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_acc.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_csr_ch.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_csr_op.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_eg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_exp2lin.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_exprom.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_kon.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_lfo.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_lfo_lfsr.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_lin2exp.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_mmr.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_mod.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_noise.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_noise_lfsr.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_op.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_pg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_phinc_rom.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_phrom.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_pm.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_reg.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_sh.v]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt51_timers.v]

358
common/Sound/jt51/jt51.v Normal file
View File

@@ -0,0 +1,358 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51(
input rst, // reset
input clk, // main clock
input cen, // clock enable
input cen_p1, // clock enable at half the speed
input cs_n, // chip select
input wr_n, // write
input a0,
input [7:0] din, // data in
output [7:0] dout, // data out
// peripheral control
output ct1,
output ct2,
output irq_n, // I do not synchronize this signal
// Low resolution output (same as real chip)
output sample, // marks new output sample
output signed [15:0] left,
output signed [15:0] right,
// Full resolution output
output signed [15:0] xleft,
output signed [15:0] xright,
// unsigned outputs for sigma delta converters, full resolution
output [15:0] dacleft,
output [15:0] dacright
);
assign dacleft = { ~xleft [15], xleft[14:0] };
assign dacright = { ~xright[15], xright[14:0] };
// Timers
wire [9:0] value_A;
wire [7:0] value_B;
wire load_A, load_B;
wire enable_irq_A, enable_irq_B;
wire clr_flag_A, clr_flag_B;
wire flag_A, flag_B, overflow_A;
wire zero;
jt51_timers u_timers(
.clk ( clk ),
.cen ( cen_p1 ),
.rst ( rst ),
.zero ( zero ),
.value_A ( value_A ),
.value_B ( value_B ),
.load_A ( load_A ),
.load_B ( load_B ),
.enable_irq_A( enable_irq_A ),
.enable_irq_B( enable_irq_B ),
.clr_flag_A ( clr_flag_A ),
.clr_flag_B ( clr_flag_B ),
.flag_A ( flag_A ),
.flag_B ( flag_B ),
.overflow_A ( overflow_A ),
.irq_n ( irq_n )
);
/*verilator tracing_off*/
`ifndef JT51_ONLYTIMERS
`define YM_TIMER_CTRL 8'h14
wire [1:0] rl_I;
wire [2:0] fb_II;
wire [2:0] con_I;
wire [6:0] kc_I;
wire [5:0] kf_I;
wire [2:0] pms_I;
wire [1:0] ams_VII;
wire [2:0] dt1_II;
wire [3:0] mul_VI;
wire [6:0] tl_VII;
wire [1:0] ks_III;
wire [4:0] arate_II;
wire amsen_VII;
wire [4:0] rate1_II;
wire [1:0] dt2_I;
wire [4:0] rate2_II;
wire [3:0] d1l_I;
wire [3:0] rrate_II;
wire [1:0] cur_op;
assign sample =zero;
wire keyon_II;
wire [7:0] lfo_freq;
wire [1:0] lfo_w;
wire lfo_rst;
wire [6:0] am;
wire [7:0] pm;
wire [6:0] amd, pmd;
wire m1_enters, m2_enters, c1_enters, c2_enters;
wire use_prevprev1,use_internal_x,use_internal_y, use_prev2,use_prev1;
jt51_lfo u_lfo(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ), // should it be cen_p1?
.zero ( zero ),
.lfo_rst ( lfo_rst ),
.lfo_freq ( lfo_freq ),
.lfo_w ( lfo_w ),
.lfo_amd ( amd ),
.lfo_pmd ( pmd ),
.am ( am ),
.pm_u ( pm )
);
wire [ 4:0] keycode_III;
wire [ 9:0] ph_X;
wire pg_rst_III;
jt51_pg u_pg(
.rst ( rst ),
.clk ( clk ), // P1
.cen ( cen_p1 ),
.zero ( zero ),
// Channel frequency
.kc_I ( kc_I ),
.kf_I ( kf_I ),
// Operator multiplying
.mul_VI ( mul_VI ),
// Operator detuning
.dt1_II ( dt1_II ),
.dt2_I ( dt2_I ),
// phase modulation from LFO
.pms_I ( pms_I ),
.pm ( pm ),
// phase operation
.pg_rst_III ( pg_rst_III ),
.keycode_III( keycode_III ),
.pg_phase_X ( ph_X )
);
`ifdef TEST_SUPPORT
wire test_eg, test_op0;
`endif
wire [9:0] eg_XI;
jt51_eg u_eg(
`ifdef TEST_SUPPORT
.test_eg ( test_eg ),
`endif
.rst ( rst ),
.clk ( clk ),
.cen ( cen_p1 ),
.zero ( zero ),
// envelope configuration
.keycode_III(keycode_III), // used in stage III
.arate_II ( arate_II ),
.rate1_II ( rate1_II ),
.rate2_II ( rate2_II ),
.rrate_II ( rrate_II ),
.d1l_I ( d1l_I ),
.ks_III ( ks_III ),
// envelope operation
.keyon_II ( keyon_II ),
.pg_rst_III ( pg_rst_III),
// envelope number
.tl_VII ( tl_VII ),
.am ( am ),
.ams_VII ( ams_VII ),
.amsen_VII ( amsen_VII ),
.eg_XI ( eg_XI )
);
wire signed [13:0] op_out;
jt51_op u_op(
`ifdef TEST_SUPPORT
.test_eg ( test_eg ),
.test_op0 ( test_op0 ),
`endif
.rst ( rst ),
.clk ( clk ),
.cen ( cen_p1 ),
.pg_phase_X ( ph_X ),
.con_I ( con_I ),
.fb_II ( fb_II ),
// volume
.eg_atten_XI ( eg_XI ),
// modulation
.m1_enters ( m1_enters ),
.c1_enters ( c1_enters ),
// Operator
.use_prevprev1 ( use_prevprev1 ),
.use_internal_x ( use_internal_x ),
.use_internal_y ( use_internal_y ),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 ),
.test_214 ( 1'b0 ),
`ifdef SIMULATION
.zero ( zero ),
`endif
// output data
.op_XVII ( op_out )
);
wire [4:0] nfrq;
wire [10:0] noise_out;
wire ne, op31_acc, op31_no;
jt51_noise u_noise(
.rst ( rst ),
.clk ( clk ),
.cen ( cen_p1 ),
.nfrq ( nfrq ),
.eg ( eg_XI ),
.out ( noise_out ),
.op31_no( op31_no )
);
jt51_acc u_acc(
.rst ( rst ),
.clk ( clk ),
.cen ( cen_p1 ),
.m1_enters ( m1_enters ),
.m2_enters ( m2_enters ),
.c1_enters ( c1_enters ),
.c2_enters ( c2_enters ),
.op31_acc ( op31_acc ),
.rl_I ( rl_I ),
.con_I ( con_I ),
.op_out ( op_out ),
.ne ( ne ),
.noise ( noise_out ),
.left ( left ),
.right ( right ),
.xleft ( xleft ),
.xright ( xright )
);
`else
assign left = 16'd0;
assign right = 16'd0;
assign xleft = 16'd0;
assign xright = 16'd0;
`endif
wire busy;
wire write = !cs_n && !wr_n;
assign dout = { busy, 5'h0, flag_B, flag_A };
/*verilator tracing_on*/
jt51_mmr u_mmr(
.rst ( rst ),
.clk ( clk ),
.cen ( cen_p1 ),
.a0 ( a0 ),
.write ( write ),
.din ( din ),
.busy ( busy ),
// CT
.ct1 ( ct1 ),
.ct2 ( ct2 ),
// LFO
.lfo_freq ( lfo_freq ),
.lfo_w ( lfo_w ),
.lfo_amd ( amd ),
.lfo_pmd ( pmd ),
.lfo_rst ( lfo_rst ),
// Noise
.ne ( ne ),
.nfrq ( nfrq ),
// Timers
.value_A ( value_A ),
.value_B ( value_B ),
.load_A ( load_A ),
.load_B ( load_B ),
.enable_irq_A( enable_irq_A ),
.enable_irq_B( enable_irq_B ),
.clr_flag_A ( clr_flag_A ),
.clr_flag_B ( clr_flag_B ),
.overflow_A ( overflow_A ),
`ifdef TEST_SUPPORT
// Test
.test_eg ( test_eg ),
.test_op0 ( test_op0 ),
`endif
// REG
.rl_I ( rl_I ),
.fb_II ( fb_II ),
.con_I ( con_I ),
.kc_I ( kc_I ),
.kf_I ( kf_I ),
.pms_I ( pms_I ),
.ams_VII ( ams_VII ),
.dt1_II ( dt1_II ),
.mul_VI ( mul_VI ),
.tl_VII ( tl_VII ),
.ks_III ( ks_III ),
.arate_II ( arate_II ),
.amsen_VII ( amsen_VII ),
.rate1_II ( rate1_II ),
.dt2_I ( dt2_I ),
.rate2_II ( rate2_II ),
.d1l_I ( d1l_I ),
.rrate_II ( rrate_II ),
.keyon_II ( keyon_II ),
.cur_op ( cur_op ),
.op31_no ( op31_no ),
.op31_acc ( op31_acc ),
.zero ( zero ),
.m1_enters ( m1_enters ),
.m2_enters ( m2_enters ),
.c1_enters ( c1_enters ),
.c2_enters ( c2_enters ),
// Operator
.use_prevprev1 ( use_prevprev1 ),
.use_internal_x ( use_internal_x ),
.use_internal_y ( use_internal_y ),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 )
);
`ifdef SIMULATION
`ifndef VERILATOR
integer fsnd;
initial begin
fsnd=$fopen("jt51.raw","wb");
end
always @(posedge zero) begin
$fwrite(fsnd,"%u", {xleft, xright});
end
`endif
`endif
endmodule

View File

@@ -0,0 +1,176 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.1 Date: 14- 4-2017
Version: 1.0 Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_acc(
input rst,
input clk,
input cen,
input m1_enters,
input m2_enters,
input c1_enters,
input c2_enters,
input op31_acc,
input [1:0] rl_I,
input [2:0] con_I,
input signed [13:0] op_out,
input ne, // noise enable
input signed [10:0] noise,
output signed [15:0] left,
output signed [15:0] right,
output reg signed [15:0] xleft, // exact outputs
output reg signed [15:0] xright
);
reg signed [13:0] op_val;
always @(*) begin
if( ne && op31_acc ) // cambiar a OP 31
op_val = { {2{noise[10]}}, noise, 1'd0 };
else
op_val = op_out;
end
reg sum_en;
always @(*) begin
case ( con_I )
3'd0,3'd1,3'd2,3'd3: sum_en = m2_enters;
3'd4: sum_en = m1_enters | m2_enters;
3'd5,3'd6: sum_en = ~c1_enters;
3'd7: sum_en = 1'b1;
default: sum_en = 1'bx;
endcase
end
wire ren = rl_I[1];
wire len = rl_I[0];
reg signed [16:0] pre_left, pre_right;
wire signed [15:0] total;
wire signed [16:0] total_ex = {total[15],total};
reg sum_all;
wire rst_sum = c2_enters;
//wire rst_sum = c1_enters;
//wire rst_sum = m1_enters;
//wire rst_sum = m2_enters;
function signed [15:0] lim16;
input signed [16:0] din;
lim16 = !din[16] && din[15] ? 16'h7fff :
( din[16] && !din[15] ? 16'h8000 : din[15:0] );
endfunction
always @(posedge clk) begin
if( rst ) begin
sum_all <= 1'b0;
end
else if(cen) begin
if( rst_sum ) begin
sum_all <= 1'b1;
if( !sum_all ) begin
pre_right <= ren ? total_ex : 17'd0;
pre_left <= len ? total_ex : 17'd0;
end
else begin
pre_right <= pre_right + (ren ? total_ex : 17'd0);
pre_left <= pre_left + (len ? total_ex : 17'd0);
end
end
if( c1_enters ) begin
sum_all <= 1'b0;
xleft <= lim16(pre_left);
xright <= lim16(pre_right);
end
end
end
reg signed [15:0] opsum;
wire signed [16:0] opsum10 = {{3{op_val[13]}},op_val}+{total[15],total};
always @(*) begin
if( rst_sum )
opsum = sum_en ? { {2{op_val[13]}}, op_val } : 16'd0;
else begin
if( sum_en )
if( opsum10[16]==opsum10[15] )
opsum = opsum10[15:0];
else begin
opsum = opsum10[16] ? 16'h8000 : 16'h7fff;
end
else
opsum = total;
end
end
jt51_sh #(.width(16),.stages(8)) u_acc(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( opsum ),
.drop ( total )
);
wire signed [9:0] left_man, right_man;
wire [2:0] left_exp, right_exp;
jt51_exp2lin left_reconstruct(
.lin( left ),
.man( left_man ),
.exp( left_exp )
);
jt51_exp2lin right_reconstruct(
.lin( right ),
.man( right_man ),
.exp( right_exp )
);
jt51_lin2exp left2exp(
.lin( xleft ),
.man( left_man ),
.exp( left_exp ) );
jt51_lin2exp right2exp(
.lin( xright ),
.man( right_man ),
.exp( right_exp ) );
`ifdef DUMPLEFT
reg skip;
wire signed [15:0] dump = left;
initial skip=1;
always @(posedge clk)
if( c1_enters && (!skip || dump) && cen) begin
$display("%d", dump );
skip <= 0;
end
`endif
endmodule

View File

@@ -0,0 +1,74 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 23-10-2019
*/
module jt51_csr_ch(
input rst,
input clk,
input cen,
input [ 7:0] din,
input up_rl_ch,
input up_fb_ch,
input up_con_ch,
input up_kc_ch,
input up_kf_ch,
input up_ams_ch,
input up_pms_ch,
output [1:0] rl,
output [2:0] fb,
output [2:0] con,
output [6:0] kc,
output [5:0] kf,
output [1:0] ams,
output [2:0] pms
);
wire [1:0] rl_in = din[7:6];
wire [2:0] fb_in = din[5:3];
wire [2:0] con_in = din[2:0];
wire [6:0] kc_in = din[6:0];
wire [5:0] kf_in = din[7:2];
wire [1:0] ams_in = din[1:0];
wire [2:0] pms_in = din[6:4];
wire [25:0] reg_in = {
up_rl_ch ? rl_in : rl,
up_fb_ch ? fb_in : fb,
up_con_ch ? con_in : con,
up_kc_ch ? kc_in : kc,
up_kf_ch ? kf_in : kf,
up_ams_ch ? ams_in : ams,
up_pms_ch ? pms_in : pms };
wire [25:0] reg_out;
assign { rl, fb, con, kc, kf, ams, pms } = reg_out;
jt51_sh #( .width(26), .stages(8)) u_regop(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( reg_in ),
.drop ( reg_out )
);
endmodule

View File

@@ -0,0 +1,104 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 23-10-2019
*/
module jt51_csr_op(
input rst,
input clk,
input cen,
input [ 7:0] din,
input up_dt1_op,
input up_mul_op,
input up_tl_op,
input up_ks_op,
input up_amsen_op,
input up_dt2_op,
input up_d1l_op,
input up_ar_op,
input up_d1r_op,
input up_d2r_op,
input up_rr_op,
output [2:0] dt1,
output [3:0] mul,
output [6:0] tl,
output [1:0] ks,
output amsen,
output [1:0] dt2,
output [3:0] d1l,
output [4:0] arate,
output [4:0] rate1,
output [4:0] rate2,
output [3:0] rrate
);
wire [2:0] dt1_in = din[6:4];
wire [3:0] mul_in = din[3:0];
wire [6:0] tl_in = din[6:0];
wire [1:0] ks_in = din[7:6];
wire amsen_in= din[7];
wire [1:0] dt2_in = din[7:6];
wire [3:0] d1l_in = din[7:4];
wire [4:0] ar_in = din[4:0];
wire [4:0] d1r_in = din[4:0];
wire [4:0] d2r_in = din[4:0];
wire [3:0] rr_in = din[3:0];
wire [30:0] reg0_in = {
up_dt1_op ? dt1_in : dt1, // 3
up_mul_op ? mul_in : mul, // 4
up_ks_op ? ks_in : ks, // 2
up_amsen_op ? amsen_in : amsen, // 1
up_dt2_op ? dt2_in : dt2, // 2
up_d1l_op ? d1l_in : d1l, // 4
up_ar_op ? ar_in : arate, // 5
up_d1r_op ? d1r_in : rate1, // 5
up_d2r_op ? d2r_in : rate2 }; // 5
wire [10:0] reg1_in = {
up_tl_op ? tl_in : tl, // 7
up_rr_op ? rr_in : rrate }; // 4
wire [30:0] reg0_out;
wire [10:0] reg1_out;
assign { dt1, mul, ks, amsen, dt2, d1l, arate, rate1, rate2, tl, rrate }
= {reg0_out, reg1_out};
// reset to zero
jt51_sh #( .width(31), .stages(32)) u_reg0op(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( reg0_in ),
.drop ( reg0_out )
);
// reset to one
jt51_sh #( .width(11), .stages(32), .rstval(1'b1)) u_reg1op(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( reg1_in ),
.drop ( reg1_out )
);
endmodule

440
common/Sound/jt51/jt51_eg.v Normal file
View File

@@ -0,0 +1,440 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_eg(
`ifdef TEST_SUPPORT
input test_eg,
`endif
input rst,
input clk,
input cen,
input zero,
// envelope configuration
input [4:0] keycode_III,
input [4:0] arate_II,
input [4:0] rate1_II,
input [4:0] rate2_II,
input [3:0] rrate_II,
input [3:0] d1l_I,
input [1:0] ks_III,
// envelope operation
input keyon_II,
output reg pg_rst_III,
// envelope number
input [6:0] tl_VII,
input [6:0] am,
input [1:0] ams_VII,
input amsen_VII,
output [9:0] eg_XI
);
// eg[9:6] -> direct attenuation (divide by 2)
// eg[5:0] -> mantisa attenuation (uses LUT)
// 1 LSB of eg is -0.09257 dB
localparam ATTACK=2'd0,
DECAY1=2'd1,
DECAY2=2'd2,
RELEASE=2'd3;
reg [4:0] d1level_II;
reg [2:0] cnt_V;
reg [5:0] rate_IV;
wire [9:0] eg_VI;
reg [9:0] eg_VII, eg_VIII;
wire [9:0] eg_II;
reg [11:0] sum_eg_tl_VII;
reg step_V, step_VI;
reg sum_up;
reg [5:0] rate_V;
reg [5:1] rate_VI;
// remember: { log_msb, pow_addr } <= log_val[11:0] + { tl, 5'd0 } + { eg, 2'd0 };
reg [1:0] eg_cnt_base;
reg [14:0] eg_cnt /*verilator public*/;
reg [8:0] am_final_VII;
always @(posedge clk) begin : envelope_counter
if( rst ) begin
eg_cnt_base <= 2'd0;
eg_cnt <=15'd0;
end
else if(cen) begin
if( zero ) begin
// envelope counter increases every 3 output samples,
// there is one sample every 32 clock ticks
if( eg_cnt_base == 2'd2 ) begin
eg_cnt <= eg_cnt + 1'b1;
eg_cnt_base <= 2'd0;
end
else eg_cnt_base <= eg_cnt_base + 1'b1;
end
end
end
wire cnt_out; // = all_cnt_last[3*31-1:3*30];
reg [6:0] pre_rate_III;
reg [4:0] cfg_III;
always @(*) begin : pre_rate_calc
if( cfg_III == 5'd0 )
pre_rate_III = 7'd0;
else
case( ks_III )
2'd3: pre_rate_III = { 1'b0, cfg_III, 1'b0 } + { 2'b0, keycode_III };
2'd2: pre_rate_III = { 1'b0, cfg_III, 1'b0 } + { 3'b0, keycode_III[4:1] };
2'd1: pre_rate_III = { 1'b0, cfg_III, 1'b0 } + { 4'b0, keycode_III[4:2] };
2'd0: pre_rate_III = { 1'b0, cfg_III, 1'b0 } + { 5'b0, keycode_III[4:3] };
endcase
end
reg [7:0] step_idx;
reg [1:0] state_in_III, state_in_IV, state_in_V, state_in_VI;
always @(*) begin : rate_step
if( rate_V[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x
if( rate_V[5:2]==4'hf && state_in_V == ATTACK)
step_idx = 8'b11111111; // Maximum attack speed, rates 60&61
else
case( rate_V[1:0] )
2'd0: step_idx = 8'b00000000;
2'd1: step_idx = 8'b10001000; // 2
2'd2: step_idx = 8'b10101010; // 4
2'd3: step_idx = 8'b11101110; // 6
endcase
end
else begin
if( rate_V[5:2]==4'd0 && state_in_V != ATTACK)
step_idx = 8'b11111110; // limit slowest decay rate_IV
else
case( rate_V[1:0] )
2'd0: step_idx = 8'b10101010; // 4
2'd1: step_idx = 8'b11101010; // 5
2'd2: step_idx = 8'b11101110; // 6
2'd3: step_idx = 8'b11111110; // 7
endcase
end
// a rate_IV of zero keeps the level still
step_V = rate_V[5:1]==5'd0 ? 1'b0 : step_idx[ cnt_V ];
end
wire ar_off_VI;
always @(posedge clk) if(cen) begin
// I
if( d1l_I == 4'd15 )
d1level_II <= 5'h10; // 48dB
else
d1level_II <= {1'b0,d1l_I};
end
// II
wire keyon_last_II;
wire keyon_now_II = !keyon_last_II && keyon_II;
wire keyoff_now_II = keyon_last_II && !keyon_II;
wire ar_off_II = keyon_now_II && (arate_II == 5'h1f);
wire [1:0] state_II;
always @(posedge clk) if(cen) begin
pg_rst_III <= keyon_now_II;
// trigger release
if( keyoff_now_II ) begin
cfg_III <= { rrate_II, 1'b1 };
state_in_III <= RELEASE;
end
else begin
// trigger 1st decay
if( keyon_now_II ) begin
cfg_III <= arate_II;
state_in_III <= ATTACK;
end
else begin : sel_rate
case ( state_II )
ATTACK: begin
if( eg_II==10'd0 ) begin
state_in_III <= DECAY1;
cfg_III <= rate1_II;
end
else begin
state_in_III <= state_II; // attack
cfg_III <= arate_II;
end
end
DECAY1: begin
if( eg_II[9:5] >= d1level_II ) begin
cfg_III <= rate2_II;
state_in_III <= DECAY2;
end
else begin
cfg_III <= rate1_II;
state_in_III <= state_II; // decay1
end
end
DECAY2: begin
cfg_III <= rate2_II;
state_in_III <= state_II; // decay2
end
RELEASE: begin
cfg_III <= { rrate_II, 1'b1 };
state_in_III <= state_II; // release
end
endcase
end
end
end
// III
always @(posedge clk) if(cen) begin
state_in_IV <= state_in_III;
rate_IV <= pre_rate_III[6] ? 6'd63 : pre_rate_III[5:0];
end
// IV
always @(posedge clk) if(cen) begin
state_in_V <= state_in_IV;
rate_V <= rate_IV;
if( state_in_IV == ATTACK )
case( rate_IV[5:2] )
4'h0: cnt_V <= eg_cnt[13:11];
4'h1: cnt_V <= eg_cnt[12:10];
4'h2: cnt_V <= eg_cnt[11: 9];
4'h3: cnt_V <= eg_cnt[10: 8];
4'h4: cnt_V <= eg_cnt[ 9: 7];
4'h5: cnt_V <= eg_cnt[ 8: 6];
4'h6: cnt_V <= eg_cnt[ 7: 5];
4'h7: cnt_V <= eg_cnt[ 6: 4];
4'h8: cnt_V <= eg_cnt[ 5: 3];
4'h9: cnt_V <= eg_cnt[ 4: 2];
4'ha: cnt_V <= eg_cnt[ 3: 1];
default: cnt_V <= eg_cnt[ 2: 0];
endcase
else
case( rate_IV[5:2] )
4'h0: cnt_V <= eg_cnt[14:12];
4'h1: cnt_V <= eg_cnt[13:11];
4'h2: cnt_V <= eg_cnt[12:10];
4'h3: cnt_V <= eg_cnt[11: 9];
4'h4: cnt_V <= eg_cnt[10: 8];
4'h5: cnt_V <= eg_cnt[ 9: 7];
4'h6: cnt_V <= eg_cnt[ 8: 6];
4'h7: cnt_V <= eg_cnt[ 7: 5];
4'h8: cnt_V <= eg_cnt[ 6: 4];
4'h9: cnt_V <= eg_cnt[ 5: 3];
4'ha: cnt_V <= eg_cnt[ 4: 2];
4'hb: cnt_V <= eg_cnt[ 3: 1];
default: cnt_V <= eg_cnt[ 2: 0];
endcase
end
// V
always @(posedge clk) if(cen) begin
state_in_VI <= state_in_V;
rate_VI <= rate_V[5:1];
sum_up <= cnt_V[0] != cnt_out;
step_VI <= step_V;
end
///////////////////////////////////////
// VI
reg [8:0] ar_sum0_VI;
reg [9:0] ar_result_VI, ar_sum_VI;
always @(*) begin : ar_calculation
casez( rate_VI[5:2] )
default: ar_sum0_VI = { 3'd0, eg_VI[9:4] } + 9'd1;
4'b1100: ar_sum0_VI = { 3'd0, eg_VI[9:4] } + 9'd1;
4'b1101: ar_sum0_VI = { 2'd0, eg_VI[9:3] } + 9'd1;
4'b111?: ar_sum0_VI = { 1'd0, eg_VI[9:2] } + 9'd1;
endcase
if( rate_VI[5:4] == 2'b11 )
ar_sum_VI = step_VI ? { ar_sum0_VI, 1'b0 } : { 1'b0, ar_sum0_VI };
else
ar_sum_VI = step_VI ? { 1'b0, ar_sum0_VI } : 10'd0;
ar_result_VI = ar_sum_VI<eg_VI ? eg_VI-ar_sum_VI : 10'd0;
end
always @(posedge clk) if(cen) begin
if( ar_off_VI )
eg_VII <= 10'd0;
else
if( state_in_VI == ATTACK ) begin
if( sum_up && eg_VI != 10'd0 )
if( rate_VI[5:1]==5'hf )
eg_VII <= 10'd0;
else
eg_VII <= ar_result_VI;
else
eg_VII <= eg_VI;
end
else begin : DECAY_SUM
if( sum_up ) begin
if ( eg_VI<= (10'd1023-10'd8) )
case( rate_VI[5:2] )
4'b1100: eg_VII <= eg_VI + { 8'd0, step_VI, ~step_VI }; // 12
4'b1101: eg_VII <= eg_VI + { 7'd0, step_VI, ~step_VI, 1'b0 }; // 13
4'b1110: eg_VII <= eg_VI + { 6'd0, step_VI, ~step_VI, 2'b0 }; // 14
4'b1111: eg_VII <= eg_VI + 10'd8;// 15
default: eg_VII <= eg_VI + { 8'd0, step_VI, 1'b0 };
endcase
else eg_VII <= 10'h3FF;
end
else eg_VII <= eg_VI;
end
end
// VII
always @(*) begin : sum_eg_and_tl
casez( {amsen_VII, ams_VII } )
3'b0??,3'b100: am_final_VII = 9'd0;
3'b101: am_final_VII = { 2'b00, am };
3'b110: am_final_VII = { 1'b0, am, 1'b0};
3'b111: am_final_VII = { am, 2'b0 };
endcase
`ifdef TEST_SUPPORT
if( test_eg && tl_VII!=7'd0 )
sum_eg_tl_VII = 12'd0;
else
`endif
sum_eg_tl_VII = { 2'b0, tl_VII, 3'd0 }
+ {2'b0, eg_VII}
+ {2'b0, am_final_VII, 1'b0 };
end
always @(posedge clk) if(cen) begin
eg_VIII <= sum_eg_tl_VII[11:10] > 2'b0 ? {10{1'b1}} : sum_eg_tl_VII[9:0];
end
jt51_sh #( .width(10), .stages(3) ) u_egpadding (
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( eg_VIII ),
.drop ( eg_XI )
);
// Shift registers
jt51_sh #( .width(10), .stages(32-7+2), .rstval(1'b1) ) u_eg1sh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( eg_VII ),
.drop ( eg_II )
);
jt51_sh #( .width(10), .stages(4), .rstval(1'b1) ) u_eg2sh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( eg_II ),
.drop ( eg_VI )
);
jt51_sh #( .width(1), .stages(4) ) u_aroffsh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( ar_off_II ),
.drop ( ar_off_VI )
);
jt51_sh #( .width(1), .stages(32) ) u_konsh(
.rst ( rst ),
.clk ( clk ),
.din ( keyon_II ),
.cen ( cen ),
.drop ( keyon_last_II )
);
jt51_sh #( .width(1), .stages(32) ) u_cntsh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( cnt_V[0] ),
.drop ( cnt_out )
);
jt51_sh #( .width(2), .stages(32-3+2), .rstval(1'b1) ) u_statesh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( state_in_III ),
.drop ( state_II )
);
`ifndef JT51_NODEBUG
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
wire [4:0] cnt;
sep32_cnt u_sep32_cnt (.clk(clk), .cen(cen), .zero(zero), .cnt(cnt));
sep32 #(.width(10),.stg(11)) sep_eg(
.clk ( clk ),
.cen ( cen ),
.mixed ( eg_XI ),
.cnt ( cnt )
);
sep32 #(.width(7),.stg(7)) sep_tl(
.clk ( clk ),
.cen ( cen ),
.mixed ( tl_VII ),
.cnt ( cnt )
);
sep32 #(.width(2),.stg(2)) sep_state(
.clk ( clk ),
.cen ( cen ),
.mixed ( state_II ),
.cnt ( cnt )
);
sep32 #(.width(5),.stg(6)) sep_rate(
.clk ( clk ),
.mixed ( rate_VI ),
.cnt ( cnt )
);
sep32 #(.width(9),.stg(7)) sep_amfinal(
.clk ( clk ),
.cen ( cen ),
.mixed ( am_final_VII ),
.cnt ( cnt )
);
/* verilator lint_on PINMISSING */
`endif
`endif
endmodule

View File

@@ -0,0 +1,42 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_exp2lin(
output reg signed [15:0] lin,
input signed [9:0] man,
input [2:0] exp
);
always @(*) begin
case( exp )
3'd7: lin = { man, 6'b0 };
3'd6: lin = { {1{man[9]}}, man, 5'b0 };
3'd5: lin = { {2{man[9]}}, man, 4'b0 };
3'd4: lin = { {3{man[9]}}, man, 3'b0 };
3'd3: lin = { {4{man[9]}}, man, 2'b0 };
3'd2: lin = { {5{man[9]}}, man, 1'b0 };
3'd1: lin = { {6{man[9]}}, man };
3'd0: lin = 16'd0;
endcase
end
endmodule

View File

@@ -0,0 +1,78 @@
`timescale 1ns / 1ps
/* This file is part of JT51.
JT51 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Based on hardware measurements and Sauraen VHDL version of OPN/OPN2,
which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-4-2017
*/
module jt51_exprom
(
input [4:0] addr,
input clk,
input cen,
output reg [44:0] exp
);
reg [44:0] explut[31:0];
initial
begin
explut[0] = 45'b111110101011010110001011010000010010111011011;
explut[1] = 45'b111101010011010101000011001100101110110101011;
explut[2] = 45'b111011111011010011110111001000110010101110011;
explut[3] = 45'b111010100101010010101111000100110010101000011;
explut[4] = 45'b111001001101010001100111000000110010100001011;
explut[5] = 45'b110111111011010000011110111101010010011011011;
explut[6] = 45'b110110100011001111010110111001010010010100100;
explut[7] = 45'b110101001011001110001110110101110010001110011;
explut[8] = 45'b110011111011001101000110110001110010001000011;
explut[9] = 45'b110010100011001011111110101110010010000010011;
explut[10] = 45'b110001010011001010111010101010010001111011011;
explut[11] = 45'b101111111011001001110010100110110001110101011;
explut[12] = 45'b101110101011001000101010100011001101101111011;
explut[13] = 45'b101101010101000111100110011111010001101001011;
explut[14] = 45'b101100000011000110100010011011110001100011011;
explut[15] = 45'b101010110011000101011110011000010001011101011;
explut[16] = 45'b101001100011000100011010010100101101010111011;
explut[17] = 45'b101000010011000011010010010001001101010001011;
explut[18] = 45'b100111000011000010010010001101101101001011011;
explut[19] = 45'b100101110011000001001110001010001101000101011;
explut[20] = 45'b100100100011000000001010000110010000111111011;
explut[21] = 45'b100011010010111111001010000011001100111001011;
explut[22] = 45'b100010000010111110000101111111101100110011011;
explut[23] = 45'b100000110010111101000001111100001100101101011;
explut[24] = 45'b011111101010111100000001111000101100101000010;
explut[25] = 45'b011110011010111011000001110101001100100010011;
explut[26] = 45'b011101001010111010000001110001110000011100011;
explut[27] = 45'b011100000010111001000001101110010000010110011;
explut[28] = 45'b011010110010111000000001101011001100010001011;
explut[29] = 45'b011001101010110111000001100111101100001011011;
explut[30] = 45'b011000100000110110000001100100010000000110010;
explut[31] = 45'b010111010010110101000001100001001100000000011;
end
always @ (posedge clk) if(cen) begin
exp <= explut[addr];
end
endmodule

View File

@@ -0,0 +1,69 @@
`timescale 1ns / 1ps
/* This file is part of JT51.
JT51 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
module jt51_kon(
input rst,
input clk,
input cen,
input [3:0] keyon_op,
input [2:0] keyon_ch,
input [1:0] cur_op,
input [2:0] cur_ch,
input up_keyon,
input csm,
input overflow_A,
output reg keyon_II
);
//reg csm_copy;
reg din;
wire drop;
reg [3:0] cur_op_hot;
always @(posedge clk) if (cen)
keyon_II <= (csm&&overflow_A) || drop;
always @(*) begin
case( cur_op )
2'd0: cur_op_hot = 4'b0001; // S1 / M1
2'd1: cur_op_hot = 4'b0100; // S3 / M2
2'd2: cur_op_hot = 4'b0010; // S2 / C1
2'd3: cur_op_hot = 4'b1000; // S4 / C2
endcase
din = keyon_ch==cur_ch && up_keyon ? |(keyon_op&cur_op_hot) : drop;
end
jt51_sh #(.width(1),.stages(32)) u_konch(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( din ),
.drop ( drop )
);
endmodule

View File

@@ -0,0 +1,271 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
/*
tab size 4
*/
module jt51_lfo(
input rst,
input clk,
input cen,
input zero,
input lfo_rst,
input [7:0] lfo_freq,
input [6:0] lfo_amd,
input [6:0] lfo_pmd,
input [1:0] lfo_w,
output reg [6:0] am,
output reg [7:0] pm_u
);
reg signed [7:0] pm;
always @(*) begin: signed_to_unsigned
if( pm[7] ) begin
pm_u[7] = pm[7];
pm_u[6:0] = ~pm[6:0];
end
else pm_u = pm;
end
wire [6:0] noise_am;
wire [7:0] noise_pm;
parameter b0=3;
reg [15+b0:0] base;
always @(posedge clk) begin : base_counter
if( rst ) begin
base <= {b0+16{1'b0}};
end
else if(cen) begin
if( zero ) base <= base + 1'b1;
end
end
reg sel_base;
reg [4:0] freq_sel;
always @(*) begin : base_mux
freq_sel = {1'b0,lfo_freq[7:4]}
+ ( lfo_w==2'd2 ? 5'b1 : 5'b0 );
case( freq_sel )
5'h10: sel_base = base[b0-1];
5'hf: sel_base = base[b0+0];
5'he: sel_base = base[b0+1];
5'hd: sel_base = base[b0+2];
5'hc: sel_base = base[b0+3];
5'hb: sel_base = base[b0+4];
5'ha: sel_base = base[b0+5];
5'h9: sel_base = base[b0+6];
5'h8: sel_base = base[b0+7];
5'h7: sel_base = base[b0+8];
5'h6: sel_base = base[b0+9];
5'h5: sel_base = base[b0+10];
5'h4: sel_base = base[b0+11];
5'h3: sel_base = base[b0+12];
5'h2: sel_base = base[b0+13];
5'h1: sel_base = base[b0+14];
5'h0: sel_base = base[b0+15];
default: sel_base = base[b0-1];
endcase
end
reg [7:0] cnt, cnt_lim;
reg signed [10:0] am_bresenham;
reg signed [ 9:0] pm_bresenham;
always @(*) begin : counter_limit
case( lfo_freq[3:0] )
4'hf: cnt_lim = 8'd66;
4'he: cnt_lim = 8'd68;
4'hd: cnt_lim = 8'd70;
4'hc: cnt_lim = 8'd73;
4'hb: cnt_lim = 8'd76;
4'ha: cnt_lim = 8'd79;
4'h9: cnt_lim = 8'd82;
4'h8: cnt_lim = 8'd85;
4'h7: cnt_lim = 8'd89;
4'h6: cnt_lim = 8'd93;
4'h5: cnt_lim = 8'd98;
4'h4: cnt_lim = 8'd102;
4'h3: cnt_lim = 8'd108;
4'h2: cnt_lim = 8'd114;
4'h1: cnt_lim = 8'd120;
4'h0: cnt_lim = 8'd128;
endcase
end
wire signed [7:0] pmd_min = (~{1'b0, lfo_pmd[6:0]})+8'b1;
reg lfo_clk, last_base, am_up, pm_up;
always @(posedge clk, posedge rst)
if( rst ) begin
last_base <= 1'd0;
lfo_clk <= 1'b0;
cnt <= 8'd0;
am <= 7'd0;
pm <= 8'd0;
am_up <= 1'b1;
pm_up <= 1'b1;
am_bresenham <= 11'd0;
pm_bresenham <= 10'd0;
end else begin
if( lfo_rst ) begin // synchronous reset
last_base <= 1'd0;
lfo_clk <= 1'b0;
cnt <= 8'd0;
am <= 7'd0;
pm <= 8'd0;
am_up <= 1'b1;
pm_up <= 1'b1;
am_bresenham <= 11'd0;
pm_bresenham <= 10'd0;
end else if ( cen ) begin
last_base <= sel_base;
if( last_base != sel_base ) begin
case( lfo_w )
2'd0: begin // AM sawtooth
if( am_bresenham > 0 ) begin
if( am == lfo_amd ) begin
am <= 7'd0;
am_bresenham <= 11'd0;
end
else begin
am <= am + 1'b1;
am_bresenham <= am_bresenham
- { 2'd0, cnt_lim, 1'b0} + {4'd0,lfo_amd};
end
end
else am_bresenham <= am_bresenham + {4'd0,lfo_amd};
if( pm_bresenham > 0 ) begin
if( pm == { 1'b0, lfo_pmd } ) begin
pm <= pmd_min;
pm_bresenham <= 10'd0;
end
else begin
pm <= pm + 1'b1;
pm_bresenham <= pm_bresenham
- {2'd0,cnt_lim} + {3'd0,lfo_pmd};
end
end
else pm_bresenham <= pm_bresenham + {3'b0,lfo_pmd};
end
2'd1: // AM square waveform
if( cnt == cnt_lim ) begin
cnt <= 8'd0;
lfo_clk <= ~lfo_clk;
am <= lfo_clk ? lfo_amd : 7'd0;
pm <= lfo_clk ? {1'b0, lfo_pmd } : pmd_min;
end
else cnt <= cnt + 1'd1;
2'd2: begin // AM triangle
if( am_bresenham > 0 ) begin
if( am == lfo_amd && am_up) begin
am_up <= 1'b0;
am_bresenham <= 11'd0;
end
else if( am == 7'd0 && !am_up) begin
am_up <= 1'b1;
am_bresenham <= 11'd0;
end
else begin
am <= am_up ? am+1'b1 : am-1'b1;
am_bresenham <= am_bresenham
- { 2'b0, cnt_lim, 1'b0} + {4'd0,lfo_amd};
end
end
else am_bresenham <= am_bresenham + {4'd0,lfo_amd};
if( pm_bresenham > 0 ) begin
if( pm == {1'b0, lfo_pmd} && pm_up) begin
pm_up <= 1'b0;
pm_bresenham <= 10'd0;
end
else if( pm == pmd_min && !pm_up) begin
pm_up <= 1'b1;
pm_bresenham <= 10'd0;
end
else begin
pm <= pm_up ? pm+1'b1 : pm-1'b1;
pm_bresenham <= pm_bresenham
- {2'd0,cnt_lim} + {3'd0,lfo_pmd};
end
end
else pm_bresenham <= pm_bresenham + {3'd0,lfo_pmd};
end
2'd3: begin
casez( lfo_amd ) // same as real chip
7'b1??????: am <= noise_am[6:0];
7'b01?????: am <= { 1'b0, noise_am[5:0] };
7'b001????: am <= { 2'b0, noise_am[4:0] };
7'b0001???: am <= { 3'b0, noise_am[3:0] };
7'b00001??: am <= { 4'b0, noise_am[2:0] };
7'b000001?: am <= { 5'b0, noise_am[1:0] };
7'b0000001: am <= { 6'b0, noise_am[0] };
default: am <= 7'd0;
endcase
casez( lfo_pmd )
7'b1??????: pm <= noise_pm;
7'b01?????: pm <= { {2{noise_pm[7]}}, noise_pm[5:0] };
7'b001????: pm <= { {3{noise_pm[7]}}, noise_pm[4:0] };
7'b0001???: pm <= { {4{noise_pm[7]}}, noise_pm[3:0] };
7'b00001??: pm <= { {5{noise_pm[7]}}, noise_pm[2:0] };
7'b000001?: pm <= { {6{noise_pm[7]}}, noise_pm[1:0] };
7'b0000001: pm <= { {7{noise_pm[7]}}, noise_pm[0] };
default: pm <= 8'd0;
endcase
end
endcase
end
end
end
genvar aux;
generate
for( aux=0; aux<7; aux=aux+1 ) begin : amnoise
jt51_lfo_lfsr #(.init(aux*aux+aux) ) u_noise_am(
.rst( rst ),
.clk( clk ),
.cen( cen ),
.base(sel_base),
.out( noise_am[aux] )
);
end
for( aux=0; aux<8; aux=aux+1 ) begin : pmnoise
jt51_lfo_lfsr #(.init(4*aux*aux-3*aux+40) ) u_noise_pm(
.rst( rst ),
.clk( clk ),
.cen( cen ),
.base(sel_base),
.out( noise_pm[aux] )
);
end
endgenerate
endmodule

View File

@@ -0,0 +1,50 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_lfo_lfsr #(parameter init=220 )(
input rst,
input clk,
input cen,
input base,
output out
);
reg [18:0] bb;
assign out = bb[18];
reg last_base;
always @(posedge clk, posedge rst) begin : base_counter
if( rst ) begin
bb <= init[18:0];
last_base <= 1'b0;
end
else if(cen) begin
last_base <= base;
if( last_base != base ) begin
bb[18:1] <= bb[17:0];
bb[0] <= ^{bb[0],bb[1],bb[14],bb[15],bb[17],bb[18]};
end
end
end
endmodule

View File

@@ -0,0 +1,97 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_lin2exp(
input [15:0] lin,
output reg [9:0] man,
output reg [2:0] exp
);
always @(*) begin
casez( lin[15:9] )
// negative numbers
7'b10?????: begin
man = lin[15:6];
exp = 3'd7;
end
7'b110????: begin
man = lin[14:5];
exp = 3'd6;
end
7'b1110???: begin
man = lin[13:4];
exp = 3'd5;
end
7'b11110??: begin
man = lin[12:3];
exp = 3'd4;
end
7'b111110?: begin
man = lin[11:2];
exp = 3'd3;
end
7'b1111110: begin
man = lin[10:1];
exp = 3'd2;
end
7'b1111111: begin
man = lin[ 9:0];
exp = 3'd1;
end
// positive numbers
7'b01?????: begin
man = lin[15:6];
exp = 3'd7;
end
7'b001????: begin
man = lin[14:5];
exp = 3'd6;
end
7'b0001???: begin
man = lin[13:4];
exp = 3'd5;
end
7'b00001??: begin
man = lin[12:3];
exp = 3'd4;
end
7'b000001?: begin
man = lin[11:2];
exp = 3'd3;
end
7'b0000001: begin
man = lin[10:1];
exp = 3'd2;
end
7'b0000000: begin
man = lin[ 9:0];
exp = 3'd1;
end
default: begin
man = lin[9:0];
exp = 3'd1;
end
endcase
end
endmodule

View File

@@ -0,0 +1,379 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_mmr(
input rst,
input clk,
input cen, // P1
input [7:0] din,
input write,
input a0,
output reg busy,
// CT
output reg ct1,
output reg ct2,
// Noise
output reg ne,
output reg [4:0] nfrq,
// LFO
output reg [7:0] lfo_freq,
output reg [1:0] lfo_w,
output reg [6:0] lfo_amd,
output reg [6:0] lfo_pmd,
output reg lfo_rst,
// Timers
output reg [9:0] value_A,
output reg [7:0] value_B,
output reg load_A,
output reg load_B,
output reg enable_irq_A,
output reg enable_irq_B,
output reg clr_flag_A,
output reg clr_flag_B,
input overflow_A,
`ifdef TEST_SUPPORT
// Test
output reg test_eg,
output reg test_op0,
`endif
// REG
output [1:0] rl_I,
output [2:0] fb_II,
output [2:0] con_I,
output [6:0] kc_I,
output [5:0] kf_I,
output [2:0] pms_I,
output [1:0] ams_VII,
output [2:0] dt1_II,
output [3:0] mul_VI,
output [6:0] tl_VII,
output [1:0] ks_III,
output [4:0] arate_II,
output amsen_VII,
output [4:0] rate1_II,
output [1:0] dt2_I,
output [4:0] rate2_II,
output [3:0] d1l_I,
output [3:0] rrate_II,
output keyon_II,
output [1:0] cur_op,
output op31_no,
output op31_acc,
output zero,
output m1_enters,
output m2_enters,
output c1_enters,
output c2_enters,
// Operator
output use_prevprev1,
output use_internal_x,
output use_internal_y,
output use_prev2,
output use_prev1
);
reg [7:0] selected_register, din_copy ;
reg up_rl, up_kc, up_kf, up_pms,
up_dt1, up_tl, up_ks, up_dt2,
up_d1l, up_keyon, up_amsen;
reg [1:0] up_op;
reg [2:0] up_ch;
wire busy_reg;
`ifdef SIMULATION
reg mmr_dump;
`endif
parameter REG_TEST = 8'h01,
REG_TEST2 = 8'h02,
REG_KON = 8'h08,
REG_NOISE = 8'h0f,
REG_CLKA1 = 8'h10,
REG_CLKA2 = 8'h11,
REG_CLKB = 8'h12,
REG_TIMER = 8'h14,
REG_LFRQ = 8'h18,
REG_PMDAMD = 8'h19,
REG_CTW = 8'h1b,
REG_DUMP = 8'h1f;
reg csm;
always @(posedge clk, posedge rst) begin : memory_mapped_registers
if( rst ) begin
selected_register <= 8'h0;
{ up_rl, up_kc, up_kf, up_pms, up_dt1, up_tl,
up_ks, up_amsen, up_dt2, up_d1l, up_keyon } <= 11'd0;
`ifdef TEST_SUPPORT
{ test_eg, test_op0 } <= 2'd0;
`endif
// noise
nfrq <= 5'b0;
ne <= 1'b0;
// timers
{ value_A, value_B } <= 18'd0;
{ clr_flag_B, clr_flag_A,
enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0;
// LFO
{ lfo_amd, lfo_pmd } <= 14'h0;
lfo_freq <= 8'd0;
lfo_w <= 2'd0;
lfo_rst <= 1'b0;
{ ct2, ct1 } <= 2'd0;
csm <= 1'b0;
din_copy <= 8'd0;
`ifdef SIMULATION
mmr_dump <= 1'b0;
`endif
end else begin
// WRITE IN REGISTERS
if( write ) begin
if( !a0 )
selected_register <= din;
else begin
din_copy <= din;
up_op <= selected_register[4:3]; // operator to update
up_ch <= selected_register[2:0]; // channel to update
up_rl <= 1'b0;
up_kc <= 1'b0;
up_kf <= 1'b0;
up_pms <= 1'b0;
up_dt1 <= 1'b0;
up_tl <= 1'b0;
up_ks <= 1'b0;
up_amsen <= 1'b0;
up_dt2 <= 1'b0;
up_d1l <= 1'b0;
up_keyon <= 1'b0;
// Global registers
if( selected_register < 8'h20 ) begin
case( selected_register)
// registros especiales
REG_TEST: lfo_rst <= 1'b1; // regardless of din
`ifdef TEST_SUPPORT
REG_TEST2: { test_op0, test_eg } <= din[1:0];
`endif
REG_KON: up_keyon <= 1'b1;
REG_NOISE: { ne, nfrq } <= { din[7], din[4:0] };
REG_CLKA1: value_A[9:2] <= din;
REG_CLKA2: value_A[1:0] <= din[1:0];
REG_CLKB: value_B <= din;
REG_TIMER: begin
csm <= din[7];
{ clr_flag_B, clr_flag_A,
enable_irq_B, enable_irq_A,
load_B, load_A } <= din[5:0];
end
REG_LFRQ: lfo_freq <= din;
REG_PMDAMD: begin
if( !din[7] )
lfo_amd <= din[6:0];
else
lfo_pmd <= din[6:0];
end
REG_CTW: begin
{ ct2, ct1 } <= din[7:6];
lfo_w <= din[1:0];
end
`ifdef SIMULATION
REG_DUMP:
mmr_dump <= 1'b1;
`endif
default:;
endcase
end else
// channel registers
if( selected_register < 8'h40 ) begin
case( selected_register[4:3] )
2'h0: up_rl <= 1'b1;
2'h1: up_kc <= 1'b1;
2'h2: up_kf <= 1'b1;
2'h3: up_pms<= 1'b1;
endcase
end
else
// operator registers
begin
case( selected_register[7:5] )
3'h2: up_dt1 <= 1'b1;
3'h3: up_tl <= 1'b1;
3'h4: up_ks <= 1'b1;
3'h5: up_amsen <= 1'b1;
3'h6: up_dt2 <= 1'b1;
3'h7: up_d1l <= 1'b1;
default:;
endcase
end
end
end
else begin /* clear once-only bits */
`ifdef SIMULATION
mmr_dump <= 1'b0;
`endif
csm <= 1'b0;
lfo_rst <= 1'b0;
{ clr_flag_B, clr_flag_A } <= 2'd0;
end
end
end
reg [4:0] busy_cnt; // busy lasts for 32 synth clock cycles
reg old_write;
always @(posedge clk)
if( rst ) begin
busy <= 1'b0;
busy_cnt <= 5'd0;
end
else begin
old_write <= write;
if (!old_write && write && a0 ) begin // only set for data writes
busy <= 1'b1;
busy_cnt <= 5'd0;
end
else if(cen) begin
if( busy_cnt == 5'd31 ) busy <= 1'b0;
busy_cnt <= busy_cnt+5'd1;
end
end
jt51_reg u_reg(
.rst ( rst ),
.clk ( clk ), // P1
.cen ( cen ), // P1
.din ( din_copy ),
.up_rl ( up_rl ),
.up_kc ( up_kc ),
.up_kf ( up_kf ),
.up_pms ( up_pms ),
.up_dt1 ( up_dt1 ),
.up_tl ( up_tl ),
.up_ks ( up_ks ),
.up_amsen ( up_amsen ),
.up_dt2 ( up_dt2 ),
.up_d1l ( up_d1l ),
.up_keyon ( up_keyon ),
.op ( up_op ), // operator to update
.ch ( up_ch ), // channel to update
.csm ( csm ),
.overflow_A ( overflow_A),
.busy ( busy_reg ),
.rl_I ( rl_I ),
.fb_II ( fb_II ),
.con_I ( con_I ),
.kc_I ( kc_I ),
.kf_I ( kf_I ),
.pms_I ( pms_I ),
.ams_VII ( ams_VII ),
.dt1_II ( dt1_II ),
.dt2_I ( dt2_I ),
.mul_VI ( mul_VI ),
.tl_VII ( tl_VII ),
.ks_III ( ks_III ),
.arate_II ( arate_II ),
.amsen_VII ( amsen_VII ),
.rate1_II ( rate1_II ),
.rate2_II ( rate2_II ),
.rrate_II ( rrate_II ),
.d1l_I ( d1l_I ),
.keyon_II ( keyon_II ),
.cur_op ( cur_op ),
.op31_no ( op31_no ),
.op31_acc ( op31_acc ),
.zero ( zero ),
.m1_enters ( m1_enters ),
.m2_enters ( m2_enters ),
.c1_enters ( c1_enters ),
.c2_enters ( c2_enters ),
// Operator
.use_prevprev1 ( use_prevprev1 ),
.use_internal_x ( use_internal_x ),
.use_internal_y ( use_internal_y ),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 )
);
`ifdef SIMULATION
`ifndef VERILATOR
integer fdump;
integer clk_count;
initial begin
clk_count=0;
fdump=$fopen("jt51_cmd.txt","w");
end
always @(posedge clk) clk_count <= clk_count+1;
always @(posedge write) begin
$fdisplay(fdump,"%d,%d,%X",clk_count,a0,din);
end
`endif
`endif
`ifndef JT51_NODEBUG
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
wire [4:0] cnt_aux;
sep32_cnt u_sep32_cnt (.clk(clk), .cen(cen), .zero(zero), .cnt(cnt_aux));
sep32 #(.width(2),.stg(1)) sep_rl (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( rl_I ));
sep32 #(.width(3),.stg(2)) sep_fb (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( fb_II ));
sep32 #(.width(3),.stg(1)) sep_con(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( con_I ));
sep32 #(.width(7),.stg(1)) sep_kc (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( kc_I ));
sep32 #(.width(6),.stg(1)) sep_kf (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( kf_I ));
sep32 #(.width(3),.stg(1)) sep_pms(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( pms_I ));
sep32 #(.width(2),.stg(7)) sep_ams(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( ams_VII ));
sep32 #(.width(3),.stg(2)) sep_dt1(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( dt1_II ));
sep32 #(.width(2),.stg(1)) sep_dt2(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( dt2_I ));
sep32 #(.width(4),.stg(6)) sep_mul(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( mul_VI ));
sep32 #(.width(7),.stg(7)) sep_tl (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( tl_VII ));
sep32 #(.width(2),.stg(3)) sep_ks (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( ks_III ));
sep32 #(.width(5),.stg(2)) sep_ar (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( arate_II ));
sep32 #(.width(1),.stg(7)) sep_ame(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( amsen_VII));
sep32 #(.width(5),.stg(2)) sep_dr1(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( rate1_II ));
sep32 #(.width(5),.stg(2)) sep_dr2(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( rate2_II ));
sep32 #(.width(4),.stg(2)) sep_rr (.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( rrate_II ));
sep32 #(.width(4),.stg(1)) sep_d1l(.clk(clk),.cnt(cnt_aux),.cen(cen),.mixed( d1l_I ));
`endif
`endif
endmodule

View File

@@ -0,0 +1,67 @@
`timescale 1ns / 1ps
/* This file is part of JT51.
JT51 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-4-2017
*/
module jt51_mod(
input m1_enters,
input m2_enters,
input c1_enters,
input c2_enters,
input [2:0] alg_I,
output reg use_prevprev1,
output reg use_internal_x,
output reg use_internal_y,
output reg use_prev2,
output reg use_prev1
);
reg [7:0] alg_hot;
always @(*) begin
case( alg_I )
3'd0: alg_hot = 8'h1; // D0
3'd1: alg_hot = 8'h2; // D1
3'd2: alg_hot = 8'h4; // D2
3'd3: alg_hot = 8'h8; // D3
3'd4: alg_hot = 8'h10; // D4
3'd5: alg_hot = 8'h20; // D5
3'd6: alg_hot = 8'h40; // D6
3'd7: alg_hot = 8'h80; // D7
default: alg_hot = 8'hx;
endcase
end
always @(*) begin
use_prevprev1 = m1_enters | (m2_enters&alg_hot[5]);
use_prev2 = (m2_enters&(|alg_hot[2:0])) | (c2_enters&alg_hot[3]);
use_internal_x = c2_enters & alg_hot[2];
use_internal_y = c2_enters & (|{alg_hot[4:3],alg_hot[1:0]});
use_prev1 = m1_enters | (m2_enters&alg_hot[1]) |
(c1_enters&(|{alg_hot[6:3],alg_hot[0]}) )|
(c2_enters&(|{alg_hot[5],alg_hot[2]}));
end
endmodule

View File

@@ -0,0 +1,95 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
/*
tab size 4
See xapp052.pdf from Xilinx
The NFRQ formula in the App. Note does not make sense:
Output rate is 55kHz but for NFRQ=1 the formula states that
the noise is 111kHz, twice the output rate per channel.
That would suggest that the noise for LEFT and RIGHT are
different but the rest of the system suggest that LEFT and
RIGHT outputs are calculated at the same time, based on the
same OP output.
Also, the block diagram states a 1 bit serial input from
EG to NOISE and that seems unnecessary too.
I have not been able to measure noise in actual chip because
operator 31 does not produce any output on my two chips.
*/
module jt51_noise(
input rst,
input clk,
input cen,
input [4:0] nfrq,
input [9:0] eg,
input op31_no,
output reg [10:0] out
);
reg base;
reg [3:0] cnt;
always @(posedge clk, posedge rst)
if( rst ) begin
cnt <= 4'b0;
end
else if(cen) begin
if( op31_no ) begin
if ( &cnt ) begin
cnt <= nfrq[4:1]; // we do not need to use nfrq[0]
// because I run it off P1, YM2151 probably ran off PM
// but the result is the same, as for NFREQ=31 the YM2151
// trips the noise output at each output sample, and for
// NFREQ=0 (or 1), the output trips every 16 samples
// so NFREQ[0] does not really add resolution
end
else cnt <= cnt + 4'b1;
base <= &cnt;
end
else base <= 1'b0;
end
wire rnd_sign;
always @(posedge clk) if(cen) begin
if( op31_no )
out <= { rnd_sign, {10{~rnd_sign}}^eg };
end
jt51_noise_lfsr #(.init(90)) u_lfsr (
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.base ( base ),
.out ( rnd_sign )
);
endmodule

View File

@@ -0,0 +1,48 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
// See xapp052.pdf from Xilinx
module jt51_noise_lfsr #(parameter init=14220 )(
input rst,
input clk,
input cen,
input base,
output out
);
reg [16:0] bb;
assign out = bb[16];
always @(posedge clk, posedge rst) begin : base_counter
if( rst ) begin
bb <= init[16:0];
end
else if(cen) begin
if( base ) begin
bb[16:1] <= bb[15:0];
bb[0] <= ~(bb[16]^bb[13]);
end
end
end
endmodule

344
common/Sound/jt51/jt51_op.v Normal file
View File

@@ -0,0 +1,344 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
// Pipeline operator
module jt51_op(
`ifdef TEST_SUPPORT
input test_eg,
input test_op0,
`endif
input rst,
input clk,
input cen, // P1
input [9:0] pg_phase_X,
input [2:0] con_I,
input [2:0] fb_II,
// volume
input [9:0] eg_atten_XI,
// modulation
input use_prevprev1,
input use_internal_x,
input use_internal_y,
input use_prev2,
input use_prev1,
input test_214,
input m1_enters,
input c1_enters,
`ifdef SIMULATION
input zero,
`endif
// output data
output signed [13:0] op_XVII
);
/* enters exits
m1 c1
m2 S4
c1 m1
S4 m2
*/
wire signed [13:0] prev1, prevprev1, prev2;
jt51_sh #( .width(14), .stages(8)) prev1_buffer(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( c1_enters ? op_XVII : prev1 ),
.drop ( prev1 )
);
jt51_sh #( .width(14), .stages(8)) prevprev1_buffer(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( c1_enters ? prev1 : prevprev1 ),
.drop ( prevprev1 )
);
jt51_sh #( .width(14), .stages(8)) prev2_buffer(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( m1_enters ? op_XVII : prev2 ),
.drop ( prev2 )
);
// REGISTER/CYCLE 1
// Creation of phase modulation (FM) feedback signal, before shifting
reg [13:0] x, y;
reg [14:0] xs, ys, pm_preshift_II;
reg m1_II;
always @(*) begin
x = ( {14{use_prevprev1}} & prevprev1 ) |
( {14{use_internal_x}} & op_XVII ) |
( {14{use_prev2}} & prev2 );
y = ( {14{use_prev1}} & prev1 ) |
( {14{use_internal_y}} & op_XVII );
xs = { x[13], x }; // sign-extend
ys = { y[13], y }; // sign-extend
end
always @(posedge clk) if(cen) begin
pm_preshift_II <= xs + ys; // carry is discarded
m1_II <= m1_enters;
end
/* REGISTER/CYCLE 2-7 (also YM2612 extra cycles 1-6)
Shifting of FM feedback signal, adding phase from PG to FM phase
In YM2203, phasemod_II is not registered at all, it is latched on the first edge
in add_pg_phase and the second edge is the output of add_pg_phase. In the YM2612, there
are 6 cycles worth of registers between the generated (non-registered) phasemod_II signal
and the input to add_pg_phase. */
reg [9:0] phasemod_II;
wire [9:0] phasemod_X;
always @(*) begin
// Shift FM feedback signal
if (!m1_II ) // Not m1
phasemod_II = pm_preshift_II[10:1]; // Bit 0 of pm_preshift_II is never used
else // m1
case( fb_II )
3'd0: phasemod_II = 10'd0;
3'd1: phasemod_II = { {4{pm_preshift_II[14]}}, pm_preshift_II[14:9] };
3'd2: phasemod_II = { {3{pm_preshift_II[14]}}, pm_preshift_II[14:8] };
3'd3: phasemod_II = { {2{pm_preshift_II[14]}}, pm_preshift_II[14:7] };
3'd4: phasemod_II = { pm_preshift_II[14], pm_preshift_II[14:6] };
3'd5: phasemod_II = pm_preshift_II[14:5];
3'd6: phasemod_II = pm_preshift_II[13:4];
3'd7: phasemod_II = pm_preshift_II[12:3];
default: phasemod_II = 10'dx;
endcase
end
// REGISTER/CYCLE 2-9
jt51_sh #( .width(10), .stages(8)) phasemod_sh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( phasemod_II ),
.drop ( phasemod_X )
);
// REGISTER/CYCLE 10
reg [ 9:0] phase;
// Sets the maximum number of fanouts for a register or combinational
// cell. The Quartus II software will replicate the cell and split
// the fanouts among the duplicates until the fanout of each cell
// is below the maximum.
reg [ 7:0] phaselo_XI, aux_X;
reg signbit_X;
always @(*) begin
phase = phasemod_X + pg_phase_X;
aux_X = phase[7:0] ^ {8{~phase[8]}};
signbit_X = phase[9];
end
always @(posedge clk) if(cen) begin
phaselo_XI <= aux_X;
end
wire [45:0] sta_XI;
jt51_phrom u_phrom(
.clk ( clk ),
.cen ( cen ),
.addr ( aux_X[5:1]),
.ph ( sta_XI )
);
// REGISTER/CYCLE 11
// Sine table
// Main sine table body
reg [18:0] stb;
reg [10:0] stf, stg;
reg [11:0] logsin;
reg [10:0] subtresult;
reg [11:0] atten_internal_XI;
always @(*) begin
//sta_XI = sinetable[ phaselo_XI[5:1] ];
// 2-bit row chooser
case( phaselo_XI[7:6] )
2'b00: stb = { 10'b0, sta_XI[29], sta_XI[25], 2'b0, sta_XI[18],
sta_XI[14], 1'b0, sta_XI[7] , sta_XI[3] };
2'b01: stb = { 6'b0 , sta_XI[37], sta_XI[34], 2'b0, sta_XI[28],
sta_XI[24], 2'b0, sta_XI[17], sta_XI[13], sta_XI[10], sta_XI[6], sta_XI[2] };
2'b10: stb = { 2'b0, sta_XI[43], sta_XI[41], 2'b0, sta_XI[36],
sta_XI[33], 2'b0, sta_XI[27], sta_XI[23], 1'b0, sta_XI[20],
sta_XI[16], sta_XI[12], sta_XI[9], sta_XI[5], sta_XI[1] };
2'b11: stb = {
sta_XI[45], sta_XI[44], sta_XI[42], sta_XI[40]
, sta_XI[39], sta_XI[38], sta_XI[35], sta_XI[32]
, sta_XI[31], sta_XI[30], sta_XI[26], sta_XI[22]
, sta_XI[21], sta_XI[19], sta_XI[15], sta_XI[11]
, sta_XI[8], sta_XI[4], sta_XI[0] };
default: stb = 19'dx;
endcase
// Fixed value to sum
stf = { stb[18:15], stb[12:11], stb[8:7], stb[4:3], stb[0] };
// Gated value to sum; bit 14 is indeed used twice
if( phaselo_XI[0] )
stg = { 2'b0, stb[14], stb[14:13], stb[10:9], stb[6:5], stb[2:1] };
else
stg = 11'd0;
// Sum to produce final logsin value
logsin = stf + stg; // Carry-out of 11-bit addition becomes 12th bit
// Invert-subtract logsin value from EG attenuation value, with inverted carry
// In the actual chip, the output of the above logsin sum is already inverted.
// The two LSBs go through inverters (so they're non-inverted); the eg_atten_XI signal goes through inverters.
// The adder is normal except the carry-in is 1. It's a 10-bit adder.
// The outputs are inverted outputs, including the carry bit.
//subtresult = not (('0' & not eg_atten_XI) - ('1' & logsin([11:2])));
// After a little pencil-and-paper, turns out this is equivalent to a regular adder!
subtresult = eg_atten_XI + logsin[11:2];
// Place all but carry bit into result; also two LSBs of logsin
// If addition overflowed, make it the largest value (saturate)
atten_internal_XI = { subtresult[9:0], logsin[1:0] } | {12{subtresult[10]}};
end
// Register cycle 12
// Exponential table
wire [44:0] exp_XII;
reg [11:0] totalatten_XII;
reg [12:0] etb;
reg [ 9:0] etf;
reg [ 2:0] etg;
jt51_exprom u_exprom(
.clk ( clk ),
.cen ( cen ),
.addr ( atten_internal_XI[5:1] ),
.exp ( exp_XII )
);
always @(posedge clk) if(cen) begin
totalatten_XII <= atten_internal_XI;
end
//wire [1:0] et_sel = totalatten_XII[7:6];
//wire [4:0] et_fine = totalatten_XII[5:1];
// Main sine table body
always @(*) begin
// 2-bit row chooser
case( totalatten_XII[7:6] )
2'b00: begin
etf = { 1'b1, exp_XII[44:36] };
etg = { 1'b1, exp_XII[35:34] };
end
2'b01: begin
etf = exp_XII[33:24];
etg = { 2'b10, exp_XII[23] };
end
2'b10: begin
etf = { 1'b0, exp_XII[22:14] };
etg = exp_XII[13:11];
end
2'b11: begin
etf = { 2'b00, exp_XII[10:3] };
etg = exp_XII[2:0];
end
endcase
end
reg [9:0] mantissa_XIII;
reg [3:0] exponent_XIII;
always @(posedge clk) if(cen) begin
//RESULT
mantissa_XIII <= etf + { 7'd0, totalatten_XII[0] ? 3'd0 : etg }; //carry-out discarded
exponent_XIII <= totalatten_XII[11:8];
end
// REGISTER/CYCLE 13
// Introduce test bit as MSB, 2's complement & Carry-out discarded
reg [12:0] shifter, shifter_2, shifter_3;
always @(*) begin
// Floating-point to integer, and incorporating sign bit
// Two-stage shifting of mantissa_XIII by exponent_XIII
shifter = { 3'b001, mantissa_XIII };
case( ~exponent_XIII[1:0] )
2'b00: shifter_2 = { 1'b0, shifter[12:1] }; // LSB discarded
2'b01: shifter_2 = shifter;
2'b10: shifter_2 = { shifter[11:0], 1'b0 };
2'b11: shifter_2 = { shifter[10:0], 2'b0 };
endcase
case( ~exponent_XIII[3:2] )
2'b00: shifter_3 = {12'b0, shifter_2[12] };
2'b01: shifter_3 = { 8'b0, shifter_2[12:8] };
2'b10: shifter_3 = { 4'b0, shifter_2[12:4] };
2'b11: shifter_3 = shifter_2;
endcase
end
reg signed [13:0] op_XIII;
wire signbit_XIII;
always @(*) begin
op_XIII = ({ test_214, shifter_3 } ^ {14{signbit_XIII}}) + {13'd0, signbit_XIII};
end
jt51_sh #( .width(14), .stages(4)) out_padding(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( op_XIII ), // note op_XIII was not latched, is a comb output
.drop ( op_XVII )
);
jt51_sh #( .width(1), .stages(3)) shsignbit(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( signbit_X ),
.drop ( signbit_XIII )
);
/////////////////// Debug
`ifndef JT51_NODEBUG
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
wire [4:0] cnt;
sep32_cnt u_sep32_cnt (.clk(clk), .cen(cen), .zero(zero), .cnt(cnt));
sep32 #(.width(14),.stg(17)) sep_op(
.clk ( clk ),
.cen ( cen ),
.mixed ( op_XVII ),
.cnt ( cnt )
);
/* verilator lint_on PINMISSING */
`endif
`endif
endmodule

300
common/Sound/jt51/jt51_pg.v Normal file
View File

@@ -0,0 +1,300 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_pg(
input rst,
input clk,
input cen /* direct_enable */,
input zero,
// Channel frequency
input [6:0] kc_I,
input [5:0] kf_I,
// Operator multiplying
input [3:0] mul_VI,
// Operator detuning
input [2:0] dt1_II,
input [1:0] dt2_I,
// phase modulation from LFO
input [7:0] pm,
input [2:0] pms_I,
// phase operation
input pg_rst_III,
output reg [ 4:0] keycode_III,
output [ 9:0] pg_phase_X
);
wire [19:0] ph_VII;
reg [19:0] phase_base_VI, phase_step_VII, ph_VIII;
reg [17:0] phase_base_IV, phase_base_V;
wire pg_rst_VII;
wire [11:0] phinc_III;
reg [ 9:0] phinc_addr_III;
reg [13:0] keycode_II;
reg [5:0] dt1_kf_III;
reg [ 2:0] dt1_kf_IV;
reg [4:0] pow2;
reg [4:0] dt1_offset_V;
reg [2:0] pow2ind_IV;
reg [2:0] dt1_III, dt1_IV, dt1_V;
jt51_phinc_rom u_phinctable(
// .clk ( clk ),
.keycode( phinc_addr_III[9:0] ),
.phinc ( phinc_III )
);
always @(*) begin : calcpow2
case( pow2ind_IV )
3'd0: pow2 = 5'd16;
3'd1: pow2 = 5'd17;
3'd2: pow2 = 5'd19;
3'd3: pow2 = 5'd20;
3'd4: pow2 = 5'd22;
3'd5: pow2 = 5'd24;
3'd6: pow2 = 5'd26;
3'd7: pow2 = 5'd29;
endcase
end
reg [5:0] dt1_limit, dt1_unlimited;
reg [4:0] dt1_limited_IV;
always @(*) begin : dt1_limit_mux
case( dt1_IV[1:0] )
default: dt1_limit = 6'd8;
2'd1: dt1_limit = 6'd8;
2'd2: dt1_limit = 6'd16;
2'd3: dt1_limit = 6'd22;
endcase
case( dt1_kf_IV )
3'd0: dt1_unlimited = { 5'd0, pow2[4] }; // <2
3'd1: dt1_unlimited = { 4'd0, pow2[4:3] }; // <4
3'd2: dt1_unlimited = { 3'd0, pow2[4:2] }; // <8
3'd3: dt1_unlimited = { 2'd0, pow2[4:1] };
3'd4: dt1_unlimited = { 1'd0, pow2[4:0] };
3'd5: dt1_unlimited = { pow2[4:0], 1'd0 };
default:dt1_unlimited = 6'd0;
endcase
dt1_limited_IV = dt1_unlimited > dt1_limit ?
dt1_limit[4:0] : dt1_unlimited[4:0];
end
reg signed [8:0] mod_I;
always @(*) begin
case( pms_I ) // comprobar en silicio
3'd0: mod_I = 9'd0;
3'd1: mod_I = { 7'd0, pm[6:5] };
3'd2: mod_I = { 6'd0, pm[6:4] };
3'd3: mod_I = { 5'd0, pm[6:3] };
3'd4: mod_I = { 4'd0, pm[6:2] };
3'd5: mod_I = { 3'd0, pm[6:1] };
3'd6: mod_I = { 1'd0, pm[6:0], 1'b0 };
3'd7: mod_I = { pm[6:0], 2'b0 };
endcase
end
reg [3:0] octave_III;
wire [12:0] keycode_I;
jt51_pm u_pm(
// Channel frequency
.kc_I ( kc_I ),
.kf_I ( kf_I ),
.add ( ~pm[7] ),
.mod_I ( mod_I ),
.kcex ( keycode_I )
);
// limit value at which we add +64 to the keycode
// I assume this is to avoid the note==3 violation somehow
parameter dt2_lim2 = 8'd11 + 8'd64;
parameter dt2_lim3 = 8'd31 + 8'd64;
// I
always @(posedge clk) if(cen) begin : phase_calculation
case ( dt2_I )
2'd0: keycode_II <= { 1'b0, keycode_I } +
(keycode_I[7:6]==2'd3 ? 14'd64:14'd0);
2'd1: keycode_II <= { 1'b0, keycode_I } + 14'd512 +
(keycode_I[7:6]==2'd3 ? 14'd64:14'd0);
2'd2: keycode_II <= { 1'b0, keycode_I } + 14'd628 +
(keycode_I[7:0]>dt2_lim2 ? 14'd64:14'd0);
2'd3: keycode_II <= { 1'b0, keycode_I } + 14'd800 +
(keycode_I[7:0]>dt2_lim3 ? 14'd64:14'd0);
endcase
end
// II
always @(posedge clk) if(cen) begin
phinc_addr_III <= keycode_II[9:0];
octave_III <= keycode_II[13:10];
keycode_III <= keycode_II[12:8];
case( dt1_II[1:0] )
2'd1: dt1_kf_III <= keycode_II[13:8] - (6'b1<<2);
2'd2: dt1_kf_III <= keycode_II[13:8] + (6'b1<<2);
2'd3: dt1_kf_III <= keycode_II[13:8] + (6'b1<<3);
default:dt1_kf_III <= keycode_II[13:8];
endcase
dt1_III <= dt1_II;
end
// III
always @(posedge clk) if(cen) begin
case( octave_III )
4'd0: phase_base_IV <= { 8'd0, phinc_III[11:2] };
4'd1: phase_base_IV <= { 7'd0, phinc_III[11:1] };
4'd2: phase_base_IV <= { 6'd0, phinc_III[11:0] };
4'd3: phase_base_IV <= { 5'd0, phinc_III[11:0], 1'b0 };
4'd4: phase_base_IV <= { 4'd0, phinc_III[11:0], 2'b0 };
4'd5: phase_base_IV <= { 3'd0, phinc_III[11:0], 3'b0 };
4'd6: phase_base_IV <= { 2'd0, phinc_III[11:0], 4'b0 };
4'd7: phase_base_IV <= { 1'd0, phinc_III[11:0], 5'b0 };
4'd8: phase_base_IV <= { phinc_III[11:0], 6'b0 };
default:phase_base_IV <= 18'd0;
endcase
pow2ind_IV <= dt1_kf_III[2:0];
dt1_IV <= dt1_III;
dt1_kf_IV <= dt1_kf_III[5:3];
end
// IV LIMIT_BASE
always @(posedge clk) if(cen) begin
if( phase_base_IV > 18'd82976 )
phase_base_V <= 18'd82976;
else
phase_base_V <= phase_base_IV;
dt1_offset_V <= dt1_limited_IV;
dt1_V <= dt1_IV;
end
// V APPLY_DT1
always @(posedge clk) if(cen) begin
if( dt1_V[1:0]==2'd0 )
phase_base_VI <= {2'b0, phase_base_V};
else begin
if( !dt1_V[2] )
phase_base_VI <= {2'b0, phase_base_V} + { 15'd0, dt1_offset_V };
else
phase_base_VI <= {2'b0, phase_base_V} - { 15'd0, dt1_offset_V };
end
end
// VI APPLY_MUL
always @(posedge clk) if(cen) begin
if( mul_VI==4'd0 )
phase_step_VII <= { 1'b0, phase_base_VI[19:1] };
else
phase_step_VII <= phase_base_VI * mul_VI;
end
// VII have same number of stages as jt51_envelope
always @(posedge clk, posedge rst) begin
if( rst )
ph_VIII <= 20'd0;
else if(cen) begin
ph_VIII <= pg_rst_VII ? 20'd0 : ph_VII + phase_step_VII;
`ifdef DISPLAY_STEP
$display( "%d", phase_step_VII );
`endif
end
end
// VIII
reg [19:0] ph_IX;
always @(posedge clk, posedge rst) begin
if( rst )
ph_IX <= 20'd0;
else if(cen) begin
ph_IX <= ph_VIII[19:0];
end
end
// IX
reg [19:0] ph_X;
assign pg_phase_X = ph_X[19:10];
always @(posedge clk, posedge rst) begin
if( rst ) begin
ph_X <= 20'd0;
end else if(cen) begin
ph_X <= ph_IX;
end
end
jt51_sh #( .width(20), .stages(32-3) ) u_phsh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( ph_X ),
.drop ( ph_VII )
);
jt51_sh #( .width(1), .stages(4) ) u_pgrstsh(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( pg_rst_III),
.drop ( pg_rst_VII)
);
`ifndef JT51_NODEBUG
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
wire [4:0] cnt;
sep32_cnt u_sep32_cnt (.clk(clk), .cen(cen), .zero(zero), .cnt(cnt));
// wire zero_VIII;
//
// jt51_sh #(.width(1),.stages(7)) u_sep_aux(
// .clk ( clk ),
// .din ( zero ),
// .drop ( zero_VIII )
// );
//
// sep32 #(.width(1),.stg(8)) sep_ref(
// .clk ( clk ),
// .cen(cen),
// .mixed ( zero_VIII ),
// .cnt ( cnt )
// );
sep32 #(.width(10),.stg(10)) sep_ph(
.clk ( clk ),
.cen(cen),
.mixed ( pg_phase_X ),
.cnt ( cnt )
);
/* verilator lint_on PINMISSING */
`endif
`endif
endmodule

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
`timescale 1ns / 1ps
/* This file is part of JT51.
JT51 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-4-2017
*/
module jt51_phrom
(
input [4:0] addr,
input clk,
input cen,
output reg [45:0] ph
);
reg [45:0] sinetable[31:0];
initial
begin
sinetable[5'd0 ] = 46'b0001100000100100010001000010101010101001010010;
sinetable[5'd1 ] = 46'b0001100000110100000100000010010001001101000001;
sinetable[5'd2 ] = 46'b0001100000110100000100110010001011001101100000;
sinetable[5'd3 ] = 46'b0001110000010000000000110010110001001101110010;
sinetable[5'd4 ] = 46'b0001110000010000001100000010111010001101101001;
sinetable[5'd5 ] = 46'b0001110000010100001001100010000000101101111010;
sinetable[5'd6 ] = 46'b0001110000010100001101100010010011001101011010;
sinetable[5'd7 ] = 46'b0001110000011100000101010010111000101111111100;
sinetable[5'd8 ] = 46'b0001110000111000000001110010101110001101110111;
sinetable[5'd9 ] = 46'b0001110000111000010100111000011101011010100110;
sinetable[5'd10] = 46'b0001110000111100011000011000111100001001111010;
sinetable[5'd11] = 46'b0001110000111100011100111001101011001001110111;
sinetable[5'd12] = 46'b0100100001010000010001011001001000111010110111;
sinetable[5'd13] = 46'b0100100001010100010001001001110001111100101010;
sinetable[5'd14] = 46'b0100100001010100010101101101111110100101000110;
sinetable[5'd15] = 46'b0100100011100000001000011001010110101101111001;
sinetable[5'd16] = 46'b0100100011100100001000101011100101001011101111;
sinetable[5'd17] = 46'b0100100011101100000111011010000001011010110001;
sinetable[5'd18] = 46'b0100110011001000000111101010000010111010111111;
sinetable[5'd19] = 46'b0100110011001100001011011110101110110110000001;
sinetable[5'd20] = 46'b0100110011101000011010111011001010001101110001;
sinetable[5'd21] = 46'b0100110011101101011010110101111001010100001111;
sinetable[5'd22] = 46'b0111000010000001010111000101010101010110010111;
sinetable[5'd23] = 46'b0111000010000101010111110111110101010010111011;
sinetable[5'd24] = 46'b0111000010110101101000101100001000010000011001;
sinetable[5'd25] = 46'b0111010010011001100100011110100100010010010010;
sinetable[5'd26] = 46'b0111010010111010100101100101000000110100100011;
sinetable[5'd27] = 46'b1010000010011010101101011101100001110010011010;
sinetable[5'd28] = 46'b1010000010111111111100100111010100010000111001;
sinetable[5'd29] = 46'b1010010111110100110010001100111001010110100000;
sinetable[5'd30] = 46'b1011010111010011111011011110000100110010100001;
sinetable[5'd31] = 46'b1110011011110001111011100111100001110110100111;
end
always @ (posedge clk) if(cen)
ph <= sinetable[addr];
endmodule

View File

@@ -0,0 +1,95 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_pm(
input [6:0] kc_I,
input [5:0] kf_I,
input [8:0] mod_I,
input add,
output reg [12:0] kcex
);
reg [9:0] lim;
reg [13:0] kcex0, kcex1;
reg [1:0] extra;
reg [6:0] kcin;
reg carry;
always @(*) begin: kc_input_cleaner
{ carry, kcin } = kc_I[1:0]==2'd3 ? { 1'b0, kc_I } + 8'd1 : {1'b0,kc_I};
end
always @(*) begin : addition
lim = { 1'd0, mod_I } + { 4'd0, kf_I };
case( kcin[3:0] )
default:
if( lim>=10'd448 ) extra = 2'd2;
else if( lim>=10'd256 ) extra = 2'd1;
else extra = 2'd0;
4'd1,4'd5,4'd9,4'd13:
if( lim>=10'd384 ) extra = 2'd2;
else if( lim>=10'd192 ) extra = 2'd1;
else extra = 2'd0;
4'd2,4'd6,4'd10,4'd14:
if( lim>=10'd512 ) extra = 2'd3;
else if( lim>=10'd320 ) extra = 2'd2;
else if( lim>=10'd128 ) extra = 2'd1;
else extra = 2'd0;
endcase
kcex0 = {1'b0,kcin,kf_I} + { 6'd0, extra, 6'd0 } + { 5'd0, mod_I };
kcex1 = kcex0[7:6]==2'd3 ? kcex0 + 14'd64 : kcex0;
end
reg signed [9:0] slim;
reg [1:0] sextra;
reg [13:0] skcex0, skcex1;
always @(*) begin : subtraction
slim = { 1'd0, mod_I } - { 4'd0, kf_I };
case( kcin[3:0] )
default:
if( slim>=10'sd449 ) sextra = 2'd3;
else if( slim>=10'sd257 ) sextra = 2'd2;
else if( slim>=10'sd65 ) sextra = 2'd1;
else sextra = 2'd0;
4'd1,4'd5,4'd9,4'd13:
if( slim>=10'sd321 ) sextra = 2'd2;
else if( slim>=10'sd129 ) sextra = 2'd1;
else sextra = 2'd0;
4'd2,4'd6,4'd10,4'd14:
if( slim>=10'sd385 ) sextra = 2'd2;
else if( slim>=10'sd193 ) sextra = 2'd1;
else sextra = 2'd0;
endcase
skcex0 = {1'b0,kcin,kf_I} - { 6'd0, sextra, 6'd0 } - { 5'd0, mod_I };
skcex1 = skcex0[7:6]==2'd3 ? skcex0 - 14'd64 : skcex0;
end
always @(*) begin : mux
if ( add )
kcex = kcex1[13] | carry ? {3'd7, 4'd14, 6'd63} : kcex1[12:0];
else
kcex = carry ? {3'd7, 4'd14, 6'd63} : (skcex1[13] ? 13'd0 : skcex1[12:0]);
end
endmodule

View File

@@ -0,0 +1,303 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_reg(
input rst,
input clk,
input cen, // P1
input [7:0] din,
input up_rl,
input up_kc,
input up_kf,
input up_pms,
input up_dt1,
input up_tl,
input up_ks,
input up_amsen,
input up_dt2,
input up_d1l,
input up_keyon,
input [1:0] op, // operator to update
input [2:0] ch, // channel to update
input csm,
input overflow_A,
output reg busy,
output [1:0] rl_I,
output [2:0] fb_II,
output [2:0] con_I,
output [6:0] kc_I,
output [5:0] kf_I,
output [2:0] pms_I,
output [1:0] ams_VII,
output [2:0] dt1_II,
output [3:0] mul_VI,
output [6:0] tl_VII,
output [1:0] ks_III,
output amsen_VII,
output [4:0] arate_II,
output [4:0] rate1_II,
output [4:0] rate2_II,
output [3:0] rrate_II,
output [1:0] dt2_I,
output [3:0] d1l_I,
output keyon_II,
// Pipeline order
output reg zero,
output reg m1_enters,
output reg m2_enters,
output reg c1_enters,
output reg c2_enters,
// Operator
output use_prevprev1,
output use_internal_x,
output use_internal_y,
output use_prev2,
output use_prev1,
output [1:0] cur_op,
output reg op31_no,
output reg op31_acc
);
reg kon, koff;
reg [1:0] csm_state;
reg [4:0] csm_cnt;
wire csm_kon = csm_state[0];
wire csm_koff = csm_state[1];
always @(*) begin
m1_enters = cur_op == 2'b00;
m2_enters = cur_op == 2'b01;
c1_enters = cur_op == 2'b10;
c2_enters = cur_op == 2'b11;
end
wire up = up_rl | up_kc | up_kf | up_pms | up_dt1 | up_tl |
up_ks | up_amsen | up_dt2 | up_d1l | up_keyon;
reg [4:0] cur;
always @(posedge clk) if(cen) begin
op31_no <= cur == 5'o10;
op31_acc <= cur == 5'o16;
end
assign cur_op = cur[4:3];
wire [4:0] req_I = { op, ch };
wire [4:0] req_II = req_I + 5'd1;
wire [4:0] req_III = req_II + 5'd1;
wire [4:0] req_IV = req_III + 5'd1;
wire [4:0] req_V = req_IV + 5'd1;
wire [4:0] req_VI = req_V + 5'd1;
wire [4:0] req_VII = req_VI + 5'd1;
wire update_op_I = cur == req_I;
wire update_op_II = cur == req_II;
wire update_op_III = cur == req_III;
wire update_op_IV = cur == req_IV;
wire update_op_V = cur == req_V;
wire update_op_VI = cur == req_VI;
wire update_op_VII = cur == req_VII;
wire up_rl_ch = up_rl & update_op_I;
wire up_fb_ch = up_rl & update_op_II;
wire up_con_ch = up_rl & update_op_I;
wire up_kc_ch = up_kc & update_op_I;
wire up_kf_ch = up_kf & update_op_I;
wire up_pms_ch = up_pms & update_op_I;
wire up_ams_ch = up_pms & update_op_VII;
wire up_dt1_op = up_dt1 & update_op_II; // DT1, MUL
wire up_mul_op = up_dt1 & update_op_VI; // DT1, MUL
wire up_tl_op = up_tl & update_op_VII;
wire up_ks_op = up_ks & update_op_III; // KS, AR
wire up_amsen_op= up_amsen & update_op_VII; // AMS-EN, D1R
wire up_dt2_op = up_dt2 & update_op_I; // DT2, D2R
wire up_d1l_op = up_d1l & update_op_I; // D1L, RR
wire up_ar_op = up_ks & update_op_II; // KS, AR
wire up_d1r_op = up_amsen & update_op_II; // AMS-EN, D1R
wire up_d2r_op = up_dt2 & update_op_II; // DT2, D2R
wire up_rr_op = up_d1l & update_op_II; // D1L, RR
wire [4:0] next = cur+5'd1;
always @(posedge clk, posedge rst) begin : up_counter
if( rst ) begin
cur <= 5'h0;
zero <= 1'b0;
busy <= 1'b0;
end
else if(cen) begin
cur <= next;
zero <= next== 5'd0;
if( &cur ) busy <= up && !busy;
end
end
wire [2:0] cur_ch = cur[2:0];
wire [3:0] keyon_op = din[6:3];
wire [2:0] keyon_ch = din[2:0];
jt51_kon u_kon (
.rst (rst ),
.clk (clk ),
.cen (cen ),
.keyon_op (keyon_op ),
.keyon_ch (keyon_ch ),
.cur_op (cur_op ),
.cur_ch (cur_ch ),
.up_keyon (up_keyon && busy ),
.csm (csm ),
.overflow_A(overflow_A),
.keyon_II (keyon_II )
);
jt51_mod u_mod(
.alg_I ( con_I ),
.m1_enters ( m1_enters ),
.m2_enters ( m2_enters ),
.c1_enters ( c1_enters ),
.c2_enters ( c2_enters ),
.use_prevprev1 ( use_prevprev1 ),
.use_internal_x( use_internal_x ),
.use_internal_y( use_internal_y ),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 )
);
jt51_csr_op u_csr_op(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ), // P1
.din ( din ),
.up_dt1_op ( up_dt1_op ),
.up_mul_op ( up_mul_op ),
.up_tl_op ( up_tl_op ),
.up_ks_op ( up_ks_op ),
.up_amsen_op ( up_amsen_op ),
.up_dt2_op ( up_dt2_op ),
.up_d1l_op ( up_d1l_op ),
.up_ar_op ( up_ar_op ),
.up_d1r_op ( up_d1r_op ),
.up_d2r_op ( up_d2r_op ),
.up_rr_op ( up_rr_op ),
.dt1 ( dt1_II ),
.mul ( mul_VI ),
.tl ( tl_VII ),
.ks ( ks_III ),
.amsen ( amsen_VII ),
.dt2 ( dt2_I ),
.d1l ( d1l_I ),
.arate ( arate_II ),
.rate1 ( rate1_II ),
.rate2 ( rate2_II ),
.rrate ( rrate_II )
);
jt51_csr_ch u_csr_ch(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.din ( din ),
.up_rl_ch ( up_rl_ch ),
.up_fb_ch ( up_fb_ch ),
.up_con_ch ( up_con_ch ),
.up_kc_ch ( up_kc_ch ),
.up_kf_ch ( up_kf_ch ),
.up_ams_ch ( up_ams_ch ),
.up_pms_ch ( up_pms_ch ),
.rl ( rl_I ),
.fb ( fb_II ),
.con ( con_I ),
.kc ( kc_I ),
.kf ( kf_I ),
.ams ( ams_VII ),
.pms ( pms_I )
);
//////////////////// Debug
`ifndef JT51_NODEBUG
`ifdef SIMULATION
/* verilator lint_off PINMISSING */
wire [4:0] cnt_aux;
sep32_cnt u_sep32_cnt (.clk(clk), .cen(cen), .zero(zero), .cnt(cnt_aux));
sep32 #(.width(7),.stg(1)) sep_tl(
.clk ( clk ),
.cen ( cen ),
.mixed ( tl_VII ),
.cnt ( cnt_aux )
);
sep32 #(.width(5),.stg(1)) sep_ar(
.clk ( clk ),
.cen ( cen ),
.mixed ( arate_II ),
.cnt ( cnt_aux )
);
sep32 #(.width(4),.stg(1)) sep_d1l(
.clk ( clk ),
.cen ( cen ),
.mixed ( d1l_I ),
.cnt ( cnt_aux )
);
sep32 #(.width(4),.stg(1)) sep_rr(
.clk ( clk ),
.cen ( cen ),
.mixed ( rrate_II ),
.cnt ( cnt_aux )
);
sep32 #(.width(1),.stg(1)) sep_amsen(
.clk ( clk ),
.cen ( cen ),
.mixed ( amsen_VII ),
.cnt ( cnt_aux )
);
/* verilator lint_on PINMISSING */
`endif
`endif
endmodule

View File

@@ -0,0 +1,46 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_sh #(parameter width=5, stages=32, rstval=1'b0 ) (
input rst,
input clk,
input cen,
input [width-1:0] din,
output [width-1:0] drop
);
reg [stages-1:0] bits[width-1:0];
genvar i;
generate
for (i=0; i < width; i=i+1) begin: bit_shifter
always @(posedge clk, posedge rst) begin
if(rst)
bits[i] <= {stages{rstval}};
else if(cen)
bits[i] <= {bits[i][stages-2:0], din[i]};
end
assign drop[i] = bits[i][stages-1];
end
endgenerate
endmodule

View File

@@ -0,0 +1,106 @@
/* This file is part of JT51.
JT51 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT51 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT51. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-10-2016
*/
`timescale 1ns / 1ps
module jt51_timers(
input rst,
input clk,
input cen,
input zero,
input [9:0] value_A,
input [7:0] value_B,
input load_A,
input load_B,
input clr_flag_A,
input clr_flag_B,
input enable_irq_A,
input enable_irq_B,
output flag_A,
output flag_B,
output overflow_A,
output irq_n
);
assign irq_n = ~( (flag_A&enable_irq_A) | (flag_B&enable_irq_B) );
jt51_timer #(.counter_width(10)) timer_A(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.zero ( zero ),
.start_value( value_A ),
.load ( load_A ),
.clr_flag ( clr_flag_A),
.flag ( flag_A ),
.overflow ( overflow_A)
);
jt51_timer #(.counter_width(12)) timer_B(
.rst ( rst ),
.clk ( clk ),
.cen ( cen ),
.zero ( zero ),
.start_value( {value_B,4'b0}),
.load ( load_B ),
.clr_flag ( clr_flag_B ),
.flag ( flag_B ),
.overflow ( )
);
endmodule
module jt51_timer #(parameter counter_width = 10 )
(
input rst,
input clk,
input cen,
input zero,
input [counter_width-1:0] start_value,
input load,
input clr_flag,
output reg flag,
output reg overflow
);
reg last_load;
reg [counter_width-1:0] cnt, next;
always@(posedge clk, posedge rst)
if( rst )
flag <= 1'b0;
else /*if(cen)*/ begin
if( clr_flag )
flag <= 1'b0;
else if(overflow) flag<=1'b1;
end
always @(*) begin
{overflow, next } = { 1'b0, cnt } + 1'b1;
end
always @(posedge clk) if(cen && zero) begin : counter
last_load <= load;
if( (load && !last_load) || overflow ) begin
cnt <= start_value;
end
else if( last_load ) cnt <= next;
end
endmodule