From 6d57e8bf7769d4851513837b05ac1969cf0f212f Mon Sep 17 00:00:00 2001 From: Gehstock Date: Fri, 18 May 2018 16:48:33 +0200 Subject: [PATCH] Convert Apple 2 WXEDA -> MiST --- Apple - 2_MiST/AppleII_MiST.qpf | 30 + Apple - 2_MiST/AppleII_MiST.qsf | 203 +++ Apple - 2_MiST/README.MD | 197 ++ Apple - 2_MiST/clean.bat | 38 + Apple - 2_MiST/rtl/AppleII_MiST.sv | 193 ++ Apple - 2_MiST/rtl/CLK28MPLL.qip | 5 + Apple - 2_MiST/rtl/CLK28MPLL.vhd | 376 ++++ Apple - 2_MiST/rtl/PS2_Ctrl.vhd | 147 ++ Apple - 2_MiST/rtl/apple2.vhd | 286 +++ Apple - 2_MiST/rtl/build_id.tcl | 35 + Apple - 2_MiST/rtl/build_id.v | 2 + Apple - 2_MiST/rtl/character_rom.vhd | 539 ++++++ Apple - 2_MiST/rtl/cpu6502.vhd | 1598 +++++++++++++++++ Apple - 2_MiST/rtl/dac.vhd | 65 + Apple - 2_MiST/rtl/disk_ii.vhd | 288 +++ Apple - 2_MiST/rtl/disk_ii_rom.vhd | 58 + Apple - 2_MiST/rtl/hq2x.sv | 454 +++++ Apple - 2_MiST/rtl/keyboard.vhd | 390 ++++ Apple - 2_MiST/rtl/main_roms.vhd | 2075 ++++++++++++++++++++++ Apple - 2_MiST/rtl/mist_io.v | 491 +++++ Apple - 2_MiST/rtl/osd.v | 179 ++ Apple - 2_MiST/rtl/pll.qip | 4 + Apple - 2_MiST/rtl/pll.v | 376 ++++ Apple - 2_MiST/rtl/ram.qip | 3 + Apple - 2_MiST/rtl/ram.v | 172 ++ Apple - 2_MiST/rtl/roms/apple_II.rom | Bin 0 -> 12288 bytes Apple - 2_MiST/rtl/roms/bios.a65 | 255 +++ Apple - 2_MiST/rtl/roms/bios.rom | Bin 0 -> 12288 bytes Apple - 2_MiST/rtl/roms/slot6.rom | Bin 0 -> 256 bytes Apple - 2_MiST/rtl/scan_converter.vhd | 229 +++ Apple - 2_MiST/rtl/scandoubler.v | 195 ++ Apple - 2_MiST/rtl/spi_controller.vhd | 471 +++++ Apple - 2_MiST/rtl/timing_generator.vhd | 150 ++ Apple - 2_MiST/rtl/vga_controller.vhd | 291 +++ Apple - 2_MiST/rtl/video_generator.vhd | 221 +++ Apple - 2_MiST/rtl/video_mixer.sv | 242 +++ Apple - 2_MiST/snapshot/AppleII_MiST.rbf | Bin 0 -> 280752 bytes 37 files changed, 10258 insertions(+) create mode 100644 Apple - 2_MiST/AppleII_MiST.qpf create mode 100644 Apple - 2_MiST/AppleII_MiST.qsf create mode 100644 Apple - 2_MiST/README.MD create mode 100644 Apple - 2_MiST/clean.bat create mode 100644 Apple - 2_MiST/rtl/AppleII_MiST.sv create mode 100644 Apple - 2_MiST/rtl/CLK28MPLL.qip create mode 100644 Apple - 2_MiST/rtl/CLK28MPLL.vhd create mode 100644 Apple - 2_MiST/rtl/PS2_Ctrl.vhd create mode 100644 Apple - 2_MiST/rtl/apple2.vhd create mode 100644 Apple - 2_MiST/rtl/build_id.tcl create mode 100644 Apple - 2_MiST/rtl/build_id.v create mode 100644 Apple - 2_MiST/rtl/character_rom.vhd create mode 100644 Apple - 2_MiST/rtl/cpu6502.vhd create mode 100644 Apple - 2_MiST/rtl/dac.vhd create mode 100644 Apple - 2_MiST/rtl/disk_ii.vhd create mode 100644 Apple - 2_MiST/rtl/disk_ii_rom.vhd create mode 100644 Apple - 2_MiST/rtl/hq2x.sv create mode 100644 Apple - 2_MiST/rtl/keyboard.vhd create mode 100644 Apple - 2_MiST/rtl/main_roms.vhd create mode 100644 Apple - 2_MiST/rtl/mist_io.v create mode 100644 Apple - 2_MiST/rtl/osd.v create mode 100644 Apple - 2_MiST/rtl/pll.qip create mode 100644 Apple - 2_MiST/rtl/pll.v create mode 100644 Apple - 2_MiST/rtl/ram.qip create mode 100644 Apple - 2_MiST/rtl/ram.v create mode 100644 Apple - 2_MiST/rtl/roms/apple_II.rom create mode 100644 Apple - 2_MiST/rtl/roms/bios.a65 create mode 100644 Apple - 2_MiST/rtl/roms/bios.rom create mode 100644 Apple - 2_MiST/rtl/roms/slot6.rom create mode 100644 Apple - 2_MiST/rtl/scan_converter.vhd create mode 100644 Apple - 2_MiST/rtl/scandoubler.v create mode 100644 Apple - 2_MiST/rtl/spi_controller.vhd create mode 100644 Apple - 2_MiST/rtl/timing_generator.vhd create mode 100644 Apple - 2_MiST/rtl/vga_controller.vhd create mode 100644 Apple - 2_MiST/rtl/video_generator.vhd create mode 100644 Apple - 2_MiST/rtl/video_mixer.sv create mode 100644 Apple - 2_MiST/snapshot/AppleII_MiST.rbf diff --git a/Apple - 2_MiST/AppleII_MiST.qpf b/Apple - 2_MiST/AppleII_MiST.qpf new file mode 100644 index 00000000..8ccbb8a1 --- /dev/null +++ b/Apple - 2_MiST/AppleII_MiST.qpf @@ -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 = 14:22:52 May 18, 2018 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "13.1" +DATE = "14:22:52 May 18, 2018" + +# Revisions + +PROJECT_REVISION = "AppleII_MiST" diff --git a/Apple - 2_MiST/AppleII_MiST.qsf b/Apple - 2_MiST/AppleII_MiST.qsf new file mode 100644 index 00000000..f8f6171b --- /dev/null +++ b/Apple - 2_MiST/AppleII_MiST.qsf @@ -0,0 +1,203 @@ +# -------------------------------------------------------------------------- # +# +# 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 = 14:29:19 May 18, 2018 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# AppleII_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 ORIGINAL_QUARTUS_VERSION 13.1 +set_global_assignment -name PROJECT_CREATION_TIME_DATE "19:15:38 MAY 09, 2018" +set_global_assignment -name LAST_QUARTUS_VERSION 13.1 +set_global_assignment -name VHDL_FILE rtl/video_generator.vhd +set_global_assignment -name VHDL_FILE rtl/vga_controller.vhd +set_global_assignment -name VHDL_FILE rtl/timing_generator.vhd +set_global_assignment -name VHDL_FILE rtl/spi_controller.vhd +set_global_assignment -name VHDL_FILE rtl/PS2_Ctrl.vhd +set_global_assignment -name VHDL_FILE rtl/main_roms.vhd +set_global_assignment -name VHDL_FILE rtl/keyboard.vhd +set_global_assignment -name VHDL_FILE rtl/disk_ii_rom.vhd +set_global_assignment -name VHDL_FILE rtl/disk_ii.vhd +set_global_assignment -name VHDL_FILE rtl/cpu6502.vhd +set_global_assignment -name QIP_FILE rtl/CLK28MPLL.qip +set_global_assignment -name VHDL_FILE rtl/character_rom.vhd +set_global_assignment -name VHDL_FILE rtl/apple2.vhd +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files +set_global_assignment -name VERILOG_FILE rtl/pll.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/video_mixer.sv +set_global_assignment -name VERILOG_FILE rtl/scandoubler.v +set_global_assignment -name VERILOG_FILE rtl/osd.v +set_global_assignment -name VERILOG_FILE rtl/mist_io.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/hq2x.sv +set_global_assignment -name VHDL_FILE rtl/dac.vhd +set_global_assignment -name QIP_FILE rtl/ram.qip +set_global_assignment -name SYSTEMVERILOG_FILE rtl/AppleII_MiST.sv + +# 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 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 +set_location_assignment PLL_1 -to "pll:pll|altpll:altpll_component" + +# 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 AppleII_MiST +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144 +set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8 + +# Fitter Assignments +# ================== +set_global_assignment -name DEVICE EP3C25E144C8 +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 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_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_FLASH_NCE_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 + +# Power Estimation Assignments +# ============================ +set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" +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(AppleII_MiST) + + # start DESIGN_PARTITION(Top) + # --------------------------- + + # Incremental Compilation Assignments + # =================================== + 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 + + # end DESIGN_PARTITION(Top) + # ------------------------- + +# end ENTITY(AppleII_MiST) +# ------------------------ +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Apple - 2_MiST/README.MD b/Apple - 2_MiST/README.MD new file mode 100644 index 00000000..9fa65e10 --- /dev/null +++ b/Apple - 2_MiST/README.MD @@ -0,0 +1,197 @@ +Apple II on MiST + + +This is a reconstruction of an 1980s-era Apple ][+ implemented in VHDL for +FPGAs. + +Stephen A. Edwards, sedwards@cs.columbia.edu +http://www1.cs.columbia.edu/~sedwards +------------------------------ +The current implementation uses the Altera DE1/DE2 board and takes +advantage of its off-chip SRAM, VGA DAC, SD card, audio CODEC, and +PS/2 keyboard interface. + +It was designed to be fairly easy to port: the apple2.vhd file should +be implementation-agnostic: it only assumes the external availability +of 48K of RAM and a keyboard. + +It contains a simple read-only Disk II emulator that expects +"nibblized" disk images written raw onto an SD or MMC card (i.e., it +does not use a FAT or any other type of filesystem). + +The VGA controller (not part of an original Apple) doubles each line +and interprets the Apple's NTSC-compatible color signals to produce a color +640 X 480 VGA display with non-standard dot timing. +------------------------------ +To compile under Altera's Quartus software, open the +apple2fpga_DE1.qpf or apple2fpga_DE2.qpf project file and compile. +------------------------------ +VHDL files, in order of elaboration: + +timing_generator.vhd Timing signal generation, video counters +character_rom.vhd The beautiful 5 X 8 uppercase-only text font +video_generator.vhd Text, lores, and hires mode shift registers +main_roms.vhd D000-FFFF ROMs: Applesoft and the Monitor +cpu6502.vhd The 6502 CPU core +apple2.vhd Top-level of the Apple: mostly address decode +disk_ii_rom.vhd C600-C6FF ROM: Disk II bootstrap ROM +disk_ii.vhd Read-only Disk II emulator +vga_controller.vhd NTSC-to-VGA color interpolation, line doubler +PS2_Ctrl.vhd Low-level PS/2 keyboard interface +keyboard.vhd PS/2 keyboard-to-Apple interface +spi_controller.vhd SD/MMC card controller: reads raw tracks +i2c_controller.vhd Simple I2C bus driver; initializes the codec +wm8731_audio.vhd Controller for the Wolfson WM8731 audio codec +DE1_TOP.vhd Top-level entity for the Altera DE1 board +DE2_TOP.vhd Top-level entity for the Altera DE2 board +CLK28MPLL.vhd Altera-specific configuration for 28 MHz PLL + +Other files: + +dsk2nib.c Converts a 140K .dsk image file to the raw 228K + .nib format used by the Disk II emulator + +dsknib.sln Visual C++ Express 2008 solution file for + generating dsknib.exe under Windows + +dsknib.vcproj Visual C++ Express 2008 project file for + generating dsknib.exe under Windows + +makenibs A shell (e.g., bash) script that assembles + collections of .dsk files into a file suitable + for directly writing onto an SD card + +rom2vhdl Script to convert raw ROM files into + synthesizable VHDL code. Used to produce main_roms.vhd + +apple2fpga_DE1.qpf DE1 board project file for Altera's Quartus +apple2fpga_DE2.qpf DE2 board project file for Altera's Quartus +DE1_TOP.qsf Mostly pin assignments for Altera's Quartus +DE1_TOP.sof A compiled bitstream for the DE1 board: the + result of compiling all the VHDL files in + Quartus; suitable for programming if you have a + DE1 board. +DE2_TOP.qsf Mostly pin assignments for Altera's Quartus +DE2_TOP.sof A compiled bitstream for the DE2 board: the + result of compiling all the VHDL files in + Quartus; suitable for programming if you have a + DE2 board. + +dos33master.nib Bootable disk image: Apple DOS 3.3 system master + +bios.a65 6502 assembly source for a "fake" BIOS +bios.rom Binary data for the "fake" BIOS + +Makefile Rules for creating the .zip, .vhd files, etc. +------------------------------ +Disk images + +The system expects a sequence of "nibblized" (227K) disk images on the +SD card starting at block 0. Switches on the DE1/DE2 board selects +which image appears to be in the drive; the image number is displayed +in hex on two of the seven-segment displays. + +Most Apple II disk images are in 140K .dsk files, which stores only +the disk's logical data, i.e., is not encoded. dsk2nib.c is a small C +program that expands .dsk files to .nib files. + +I used the "makenibs" script to find all the .dsk files in a tree of +directories, assemble them into an image suitable for downloading to +the SD card, and print an image number/file name cross-listing. + +To write .nib images to an SD/MMC card under Linux, I use + +dd if=dos33master.nib of=/dev/sdd + +Of course, your card may appear as something other than /dev/sdd. + +Under Windows, you can use dd.exe (http://www.chrysocome.net/dd): + +dd.exe if=dos33master.nib of=\\?\Device\Harddiskx\Partition0 + +where the correct "Harddiskx" can be determined using the dd.exe +"--list" option: + +dd.exe --list + +------------------------------ +ROMs + +This archive does NOT include a copy of the Apple ][+'s ROMs, which +are copyright Apple Computer. Instead, it includes a very trivial +BIOS that beeps, displays a text screen, then cycles through some +lores and hires graphics patterns when keys are pressed. This should +be enough to verify the graphics, sound, and keyboard are working (but +not the disk emulator). Source for this BIOS is in the bios.a65 file, +which I assembled using the xa65 cross-assembler. + +The system requires two ROM images: a 12K image of the system roms +(memory from 0xD000 - 0xFFFF) and a 256-byte image of the Disk II +controller bootstrap ROM (memory from 0xc600 - 0xc6ff if the card is +in the usual slot 6). + +Once you obtain them, run the "rom2vhdl" script to convert the binary +files into .vhd files that hold the data. The Makefile contains rules +for doing this. +------------------------------ +Operation + +For the DE1 board: +KEY[3] Reset +KEY[2..0] Game Port +SW[9] B&W/Color Display +SW[8..0] Disk Image # (0 to 511) +HEX[2..3] Disk Image # (0 to 255 => 00 to FF hex) +HEX[1..0] Track # (0 to 35 => 00 to 23 hex) +LEDR[9..0] PC[15..6] (CPU Program Counter in 64-byte page unit) +LEDG[3] Unused +LEDG[2] Disk Drive #2 Activity +LEDG[1] Disk Drive #1 Activity +LEDG[0] Speaker Activity + +For the DE2 board: +KEY[3] Reset +KEY[2..0] Game Port +SW[17] B&W/Color Display +SW[16..10] Unused +SW[9..0] Disk Image # (0 to 1023) +HEX[7..6] Disk Image # (0 to 255 => 00 to FF hex) +HEX[5..4] Track # (0 to 35 => 00 to 23 hex) +HEX[3..0] PC[15..0] (CPU Program Counter, 0000 to FFFF hex) +LEDR[17..16] Unused +LEDR[15..0] PC[15..12] (CPU Program Counter in 4Kbyte page unit decoded) +LEDG[8] Disk Drive #1 Activity +LEDG[7..4] Analog Joystick Activity +LEDG[3..1] Unused +LEDG[0] Speaker Activity + +------------------------------ +Credits: + +Peter Wendrich supplied the 6502 core: + +-- cpu65xx_fast.vhdl, part of FPGA-64, is made available strictly for personal +-- educational purposes. Distributed with apple2fgpa with permission. +-- +-- Copyright 2005-2008 by Peter Wendrich (pwsoft@syntiac.com). +-- All rights reserved. +-- http://www.syntiac.com/fpga64.html + +The low-level PS/2 keyboard controller is from ALSE: + +-- PS2_Ctrl.vhd +-- ------------------------------------------------ +-- Simplified PS/2 Controller (kbd, mouse...) +-- ------------------------------------------------ +-- Only the Receive function is implemented ! +-- (c) ALSE. http://www.alse-fr.com + +Michel Stempin (michel.stempin@wanadoo.fr): + - ported apple2fpga to the Altera DE1 board + - added SD/SDHC to MMC Flash disk comptatibility + - added i18n + French keymap + +I adapted the Apple ][ keyboard emulation from Alex Freed's FPGApple: +http://mirrow.com/FPGApple/ + + diff --git a/Apple - 2_MiST/clean.bat b/Apple - 2_MiST/clean.bat new file mode 100644 index 00000000..748b4d5b --- /dev/null +++ b/Apple - 2_MiST/clean.bat @@ -0,0 +1,38 @@ +@echo off +del /s *.bak +del /s *.orig +del /s *.rej +del /s *~ +rmdir /s /q db +rmdir /s /q incremental_db +rmdir /s /q output_files +rmdir /s /q simulation +rmdir /s /q greybox_tmp +rmdir /s /q hc_output +rmdir /s /q .qsys_edit +rmdir /s /q hps_isw_handoff +rmdir /s /q sys\.qsys_edit +rmdir /s /q sys\vip +cd sys +for /d %%i in (*_sim) do rmdir /s /q "%%~nxi" +cd .. +for /d %%i in (*_sim) do rmdir /s /q "%%~nxi" +del build_id.v +del c5_pin_model_dump.txt +del PLLJ_PLLSPE_INFO.txt +del /s *.qws +del /s *.ppf +del /s *.ddb +del /s *.csv +del /s *.cmp +del /s *.sip +del /s *.spd +del /s *.bsf +del /s *.f +del /s *.sopcinfo +del /s *.xml +del *.cdf +del *.rpt +del /s new_rtl_netlist +del /s old_rtl_netlist +pause diff --git a/Apple - 2_MiST/rtl/AppleII_MiST.sv b/Apple - 2_MiST/rtl/AppleII_MiST.sv new file mode 100644 index 00000000..2d7b6a5a --- /dev/null +++ b/Apple - 2_MiST/rtl/AppleII_MiST.sv @@ -0,0 +1,193 @@ +module AppleII_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, + output SPI_DO, + input SPI_DI, + input SPI_SS2, + input SPI_SS3, + input CONF_DATA0, + input CLOCK_27 +); + +`include "rtl\build_id.v" + +localparam CONF_STR = { + "Apple II;;", + "O12,Screen Type , Green, White, Color;", + "O34,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;", + "T6,Reset;", + "V,v1.00.",`BUILD_DATE +}; + +wire CLK_28M, CLK_14M, CLK_7M; +wire pll_locked; + +pll pll +( + .inclk0(CLOCK_27), + .areset(0), + .c0(CLK_28M), + .c1(CLK_14M), + .c2(CLK_7M), + .locked(pll_locked) +); + +wire [31:0] status; +wire [1:0] buttons; +wire [1:0] switches; +wire power_on_reset; +wire reset = power_on_reset | status[0] | status[6] | buttons[1]; +wire [22:0] flash_clk; +wire scandoubler_disable; +wire ypbpr; +wire ps2_kbd_clk, ps2_kbd_data; +wire [9:0] audio; +wire hsync,vsync; +assign LED = 1; +wire blankn = ~(hblank | vblank); +wire hblank, vblank; +wire hs, vs; +wire VIDEO, COLOR_LINE, LD194, speaker; +wire read; +wire [7:0] K; +wire [9:0] r,g,b; + + +always @(CLK_14M) begin + if (flash_clk[22] == 1'b1) power_on_reset = 1'b0; +end + +always @(CLK_14M) begin + //rising_edge(CLK_14M) then flash_clk <= flash_clk + 1; +end + +video_mixer #(.LINE_LENGTH(640), .HALF_DEPTH(0)) video_mixer ( + .clk_sys(CLK_28M), + .ce_pix(CLK_7M), + .ce_pix_actual(CLK_7M), + .SPI_SCK(SPI_SCK), + .SPI_SS3(SPI_SS3), + .SPI_DI(SPI_DI), + .R(status[2:1] ? r[9:4] : 5'b0), + .G(g[9:4]), + .B(status[2:1] ? b[9:4] : 5'b0), + .HSync(hs), + .VSync(vs), + .VGA_R(VGA_R), + .VGA_G(VGA_G), + .VGA_B(VGA_B), + .VGA_VS(VGA_VS), + .VGA_HS(VGA_HS), + .scandoubler_disable(1'b1), + .scanlines(scandoubler_disable ? 2'b00 : {status[4:3] == 3, status[4:3] == 2}), + .hq2x(status[4:3]==1), + .ypbpr_full(1), + .line_start(0), + .mono(0) + ); + +mist_io #(.STRLEN(($size(CONF_STR)>>3))) mist_io ( + .clk_sys (CLK_28M ), + .conf_str (CONF_STR ), + .SPI_SCK (SPI_SCK ), + .CONF_DATA0 (CONF_DATA0 ), + .SPI_SS2 (SPI_SS2 ), + .SPI_DO (SPI_DO ), + .SPI_DI (SPI_DI ), + .buttons (buttons ), + .switches (switches ), + .scandoubler_disable(scandoubler_disable), + .ypbpr (ypbpr ), + .ps2_kbd_clk (ps2_kbd_clk ), + .ps2_kbd_data (ps2_kbd_data ), + .status (status ) + ); + + wire ram_we; + wire [13:0]ram_address; + wire [7:0]ram_data; + wire [7:0]ram_q; + +ram ram( + .clock(CLK_14M), + .address(ram_address), + .data(ram_data), + .q(ram_q), + .wren(ram_we) + ); + +apple2 apple2 ( + .CLK_14M (CLK_14M), + .CLK_2M (),//: out std_logic; + .PRE_PHASE_ZERO (),//: out std_logic; + .FLASH_CLK (),//: in std_logic; -- approx. 2 Hz flashing char clock + .reset (reset), + .ADDR (),//: out unsigned(15 downto 0); -- CPU address + .ram_addr (ram_address),//: out unsigned(15 downto 0); -- RAM address + .D (ram_data),//: out unsigned(7 downto 0); -- Data to RAM + .ram_do (ram_q),//: in unsigned(7 downto 0); -- Data from RAM + .PD (),//: in unsigned(7 downto 0); -- Data to CPU from peripherals + .ram_we (ram_we),//: out std_logic; -- RAM write enable + .VIDEO (VIDEO), + .COLOR_LINE (COLOR_LINE), + .HBL (hblank), + .VBL (vblank), + .LD194 (LD194), + .K (K), + .READ_KEY (read), + .AN (),//: out std_logic_vector(3 downto 0); -- Annunciator outputs +// GAMEPORT input bits: +// 7 6 5 4 3 2 1 0 +// pdl3 pdl2 pdl1 pdl0 pb3 pb2 pb1 casette + .GAMEPORT (),//: in std_logic_vector(7 downto 0); + .PDL_STROBE (),//: out std_logic; -- Pulses high when C07x read + .STB (),//: out std_logic; -- Pulses high when C04x read + .IO_SELECT (),//: out std_logic_vector(7 downto 0); + .DEVICE_SELECT (),//: out std_logic_vector(7 downto 0); + .pcDebugOut (),//: out unsigned(15 downto 0); + .opcodeDebugOut (),//: out unsigned(7 downto 0); + .speaker (speaker) + ); + +keyboard keyboard ( + .PS2_Clk (ps2_kbd_clk), + .PS2_Data (ps2_kbd_data), + .CLK_14M (CLK_14M), + .reset (reset), + .read (read), + .K (K), + ); + +vga_controller vga_controller ( + .CLK_28M (CLK_28M), + .VIDEO (VIDEO), + .COLOR_LINE (COLOR_LINE), + .COLOR (status[2:1]==2), + .HBL (hblank), + .VBL (vblank), + .LD194 (LD194), + .VGA_HS (hs), + .VGA_VS (vs), + .VGA_R (r), + .VGA_G (g), + .VGA_B (b), + ); + +dac dac ( + .CLK_DAC (CLK_28M), + .RST (), + .IN_DAC (speaker & 15'b0), + .OUT_DAC (AUDIO_L) + ); + +assign AUDIO_R = AUDIO_L; + + +endmodule diff --git a/Apple - 2_MiST/rtl/CLK28MPLL.qip b/Apple - 2_MiST/rtl/CLK28MPLL.qip new file mode 100644 index 00000000..cc9b8ee1 --- /dev/null +++ b/Apple - 2_MiST/rtl/CLK28MPLL.qip @@ -0,0 +1,5 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "8.0" +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "CLK28MPLL.vhd"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "CLK28MPLL.cmp"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "CLK28MPLL.ppf"] diff --git a/Apple - 2_MiST/rtl/CLK28MPLL.vhd b/Apple - 2_MiST/rtl/CLK28MPLL.vhd new file mode 100644 index 00000000..fd691165 --- /dev/null +++ b/Apple - 2_MiST/rtl/CLK28MPLL.vhd @@ -0,0 +1,376 @@ +-- megafunction wizard: %ALTPLL% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altpll + +-- ============================================================ +-- File Name: CLK28MPLL.vhd +-- Megafunction Name(s): +-- altpll +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 8.0 Build 215 05/29/2008 SJ Full Version +-- ************************************************************ + + +--Copyright (C) 1991-2008 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 CLK28MPLL IS + PORT + ( + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + c1 : OUT STD_LOGIC + ); +END CLK28MPLL; + + +ARCHITECTURE SYN OF clk28mpll IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (5 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC ; + SIGNAL sub_wire2 : STD_LOGIC ; + SIGNAL sub_wire3 : STD_LOGIC ; + SIGNAL sub_wire4 : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL sub_wire5_bv : BIT_VECTOR (0 DOWNTO 0); + SIGNAL sub_wire5 : STD_LOGIC_VECTOR (0 DOWNTO 0); + + + + COMPONENT altpll + GENERIC ( + 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; + compensate_clock : STRING; + inclk0_input_frequency : NATURAL; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + operation_mode : 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 + ); + PORT ( + inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); + clk : OUT STD_LOGIC_VECTOR (5 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + sub_wire5_bv(0 DOWNTO 0) <= "0"; + sub_wire5 <= To_stdlogicvector(sub_wire5_bv); + sub_wire2 <= sub_wire0(1); + sub_wire1 <= sub_wire0(0); + c0 <= sub_wire1; + c1 <= sub_wire2; + sub_wire3 <= inclk0; + sub_wire4 <= sub_wire5(0 DOWNTO 0) & sub_wire3; + + altpll_component : altpll + GENERIC MAP ( + clk0_divide_by => 250, + clk0_duty_cycle => 50, + clk0_multiply_by => 143, + clk0_phase_shift => "0", + clk1_divide_by => 500, + clk1_duty_cycle => 50, + clk1_multiply_by => 143, + clk1_phase_shift => "0", + compensate_clock => "CLK0", + inclk0_input_frequency => 20000, + intended_device_family => "Cyclone II", + lpm_hint => "CBX_MODULE_PREFIX=CLK28MPLL", + lpm_type => "altpll", + operation_mode => "NORMAL", + port_activeclock => "PORT_UNUSED", + port_areset => "PORT_UNUSED", + 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_UNUSED", + 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_UNUSED", + port_clk3 => "PORT_UNUSED", + 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" + ) + PORT MAP ( + inclk => sub_wire4, + clk => sub_wire0 + ); + + + +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 "0" +-- 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_CUSTOM STRING "0" +-- 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 "1" +-- 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 "e0" +-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "6" +-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "18" +-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1" +-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +-- 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 "1" +-- 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 "50.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 II" +-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "0" +-- 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 "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: MULT_FACTOR0 NUMERIC "5" +-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "1" +-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "28.60000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "14.30000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "0" +-- 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_SHIFT_STEP_ENABLED_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "ps" +-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +-- Retrieval info: PRIVATE: PLL_ENA_CHECK STRING "0" +-- 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 "CLK14MPLL.mif" +-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "0" +-- 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: 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_CLKENA0 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA1 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: CLK0_DIVIDE_BY NUMERIC "250" +-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "143" +-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "500" +-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "143" +-- Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_UNUSED" +-- 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_UNUSED" +-- 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_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +-- 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: USED_PORT: @clk 0 0 6 0 OUTPUT_CLK_EXT VCC "@clk[5..0]" +-- Retrieval info: USED_PORT: @extclk 0 0 4 0 OUTPUT_CLK_EXT VCC "@extclk[3..0]" +-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" +-- 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: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +-- 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: @inclk 0 0 1 1 GND 0 0 0 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL.vhd TRUE FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL.ppf TRUE FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL.inc FALSE FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL.cmp TRUE FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL.bsf FALSE FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL_inst.vhd FALSE FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL_waveforms.html FALSE FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL CLK28MPLL_wave*.jpg FALSE FALSE +-- Retrieval info: LIB_FILE: altera_mf +-- Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Apple - 2_MiST/rtl/PS2_Ctrl.vhd b/Apple - 2_MiST/rtl/PS2_Ctrl.vhd new file mode 100644 index 00000000..6421c754 --- /dev/null +++ b/Apple - 2_MiST/rtl/PS2_Ctrl.vhd @@ -0,0 +1,147 @@ +-- PS2_Ctrl.vhd +-- ------------------------------------------------ +-- Simplified PS/2 Controller (kbd, mouse...) +-- ------------------------------------------------ +-- Only the Receive function is implemented ! +-- (c) ALSE. http://www.alse-fr.com + +library IEEE; +use IEEE.Std_Logic_1164.all; +use IEEE.Numeric_Std.all; + +-- -------------------------------------- + Entity PS2_Ctrl is +-- -------------------------------------- + generic (FilterSize : positive := 8); + port( Clk : in std_logic; -- System Clock + Reset : in std_logic; -- System Reset + PS2_Clk : in std_logic; -- Keyboard Clock Line + PS2_Data : in std_logic; -- Keyboard Data Line + DoRead : in std_logic; -- From outside when reading the scan code + Scan_Err : out std_logic; -- To outside : Parity or Overflow error + Scan_DAV : out std_logic; -- To outside when a scan code has arrived + Scan_Code : out unsigned(7 downto 0) -- Eight bits Data Out + ); +end PS2_Ctrl; + +-- -------------------------------------- + Architecture ALSE_RTL of PS2_Ctrl is +-- -------------------------------------- +-- (c) ALSE. http://www.alse-fr.com +-- Author : Bert Cuzeau. +-- Fully synchronous solution, same Filter on PS2_Clk. +-- Still as compact as "Plain_wrong"... +-- Possible improvement : add TIMEOUT on PS2_Clk while shifting +-- Note: PS2_Data is resynchronized though this should not be +-- necessary (qualified by Fall_Clk and does not change at that time). +-- Note the tricks to correctly interpret 'H' as '1' in RTL simulation. + + signal PS2_Datr : std_logic; + + subtype Filter_t is std_logic_vector(FilterSize-1 downto 0); + signal Filter : Filter_t; + signal Fall_Clk : std_logic; + signal Bit_Cnt : unsigned(3 downto 0); + signal Parity : std_logic; + signal Scan_DAVi : std_logic; + + signal S_Reg : unsigned(8 downto 0); + + signal PS2_Clk_f : std_logic; + + Type State_t is (Idle, Shifting); + signal State : State_t; + +begin + +Scan_DAV <= Scan_DAVi; + +-- This filters digitally the raw clock signal coming from the keyboard : +-- * Eight consecutive PS2_Clk=1 makes the filtered_clock go high +-- * Eight consecutive PS2_Clk=0 makes the filtered_clock go low +-- Implies a (FilterSize+1) x Tsys_clock delay on Fall_Clk wrt Data +-- Also in charge of the re-synchronization of PS2_Data + +process (Clk,Reset) +begin + if Reset='1' then + PS2_Datr <= '0'; + PS2_Clk_f <= '0'; + Filter <= (others=>'0'); + Fall_Clk <= '0'; + elsif rising_edge (Clk) then + PS2_Datr <= PS2_Data and PS2_Data; -- also turns 'H' into '1' + Fall_Clk <= '0'; + Filter <= (PS2_Clk and PS2_CLK) & Filter(Filter'high downto 1); + if Filter = Filter_t'(others=>'1') then + PS2_Clk_f <= '1'; + elsif Filter = Filter_t'(others=>'0') then + PS2_Clk_f <= '0'; + if PS2_Clk_f = '1' then + Fall_Clk <= '1'; + end if; + end if; + end if; +end process; + + +-- This simple State Machine reads in the Serial Data +-- coming from the PS/2 peripheral. + +process(Clk,Reset) +begin + + if Reset='1' then + State <= Idle; + Bit_Cnt <= (others => '0'); + S_Reg <= (others => '0'); + Scan_Code <= (others => '0'); + Parity <= '0'; + Scan_Davi <= '0'; + Scan_Err <= '0'; + + elsif rising_edge (Clk) then + + if DoRead='1' then + Scan_Davi <= '0'; -- note: this assgnmnt can be overriden + end if; + + case State is + + when Idle => + Parity <= '0'; + Bit_Cnt <= (others => '0'); + -- note that we dont need to clear the Shift Register + if Fall_Clk='1' and PS2_Datr='0' then -- Start bit + Scan_Err <= '0'; + State <= Shifting; + end if; + + when Shifting => + if Bit_Cnt >= 9 then + if Fall_Clk='1' then -- Stop Bit + -- Error is (wrong Parity) or (Stop='0') or Overflow + Scan_Err <= (not Parity) or (not PS2_Datr) or Scan_DAVi; + Scan_Davi <= '1'; + Scan_Code <= S_Reg(7 downto 0); + State <= Idle; + end if; + elsif Fall_Clk='1' then + Bit_Cnt <= Bit_Cnt + 1; + S_Reg <= PS2_Datr & S_Reg (S_Reg'high downto 1); -- Shift right + Parity <= Parity xor PS2_Datr; + end if; + + when others => -- never reached + State <= Idle; + + end case; + + --Scan_Err <= '0'; -- to create an on-purpose error on Scan_Err ! + + end if; + +end process; + +end ALSE_RTL; + diff --git a/Apple - 2_MiST/rtl/apple2.vhd b/Apple - 2_MiST/rtl/apple2.vhd new file mode 100644 index 00000000..f3b697c1 --- /dev/null +++ b/Apple - 2_MiST/rtl/apple2.vhd @@ -0,0 +1,286 @@ +------------------------------------------------------------------------------- +-- +-- Top level of an Apple ][+ +-- +-- Stephen A. Edwards, sedwards@cs.columbia.edu +-- +------------------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity apple2 is + port ( + CLK_14M : in std_logic; -- 14.31818 MHz master clock + CLK_2M : out std_logic; + PRE_PHASE_ZERO : out std_logic; + FLASH_CLK : in std_logic; -- approx. 2 Hz flashing char clock + reset : in std_logic; + ADDR : out unsigned(15 downto 0); -- CPU address + ram_addr : out unsigned(15 downto 0); -- RAM address + D : out unsigned(7 downto 0); -- Data to RAM + ram_do : in unsigned(7 downto 0); -- Data from RAM + PD : in unsigned(7 downto 0); -- Data to CPU from peripherals + ram_we : out std_logic; -- RAM write enable + VIDEO : out std_logic; + COLOR_LINE : out std_logic; + HBL : out std_logic; + VBL : out std_logic; + LD194 : out std_logic; + K : in unsigned(7 downto 0); -- Keyboard data + READ_KEY : out std_logic; -- Processor has read key + AN : out std_logic_vector(3 downto 0); -- Annunciator outputs + -- GAMEPORT input bits: + -- 7 6 5 4 3 2 1 0 + -- pdl3 pdl2 pdl1 pdl0 pb3 pb2 pb1 casette + GAMEPORT : in std_logic_vector(7 downto 0); + PDL_STROBE : out std_logic; -- Pulses high when C07x read + STB : out std_logic; -- Pulses high when C04x read + IO_SELECT : out std_logic_vector(7 downto 0); + DEVICE_SELECT : out std_logic_vector(7 downto 0); + pcDebugOut : out unsigned(15 downto 0); + opcodeDebugOut : out unsigned(7 downto 0); + speaker : out std_logic -- One-bit speaker output + ); +end apple2; + +architecture rtl of apple2 is + + -- Clocks + signal CLK_7M : std_logic; + signal Q3, RAS_N, CAS_N, AX : std_logic; + signal PHASE_ZERO, PRE_PHASE_ZERO_sig : std_logic; + signal COLOR_REF : std_logic; + + -- From the timing generator + signal VIDEO_ADDRESS : unsigned(15 downto 0); + signal LDPS_N : std_logic; + signal H0, VA, VB, VC, V2, V4 : std_logic; + signal BLANK, LD194_I : std_logic; + + signal HIRES : std_logic; -- from video generator B11 p6 + + -- Soft switches + signal soft_switches : std_logic_vector(7 downto 0) := "00000000"; + signal TEXT_MODE : std_logic; + signal MIXED_MODE : std_logic; + signal PAGE2 : std_logic; + signal HIRES_MODE : std_logic; + + -- CPU signals + signal D_IN : unsigned(7 downto 0); + signal A : unsigned(15 downto 0); + signal we : std_logic; + + -- Main ROM signals + signal rom_out : unsigned(7 downto 0); + signal rom_addr : unsigned(13 downto 0); + + -- Address decoder signals + signal RAM_SELECT : std_logic := '1'; + signal KEYBOARD_SELECT : std_logic := '0'; + signal SPEAKER_SELECT : std_logic; + signal SOFTSWITCH_SELECT : std_logic; + signal ROM_SELECT : std_logic; + signal GAMEPORT_SELECT : std_logic; + signal IO_STROBE : std_logic; + + -- Speaker signal + signal speaker_sig : std_logic := '0'; + + signal DL : unsigned(7 downto 0); -- Latched RAM data + +begin + + CLK_2M <= Q3; + PRE_PHASE_ZERO <= PRE_PHASE_ZERO_sig; + + ram_addr <= A when PHASE_ZERO = '1' else VIDEO_ADDRESS; + ram_we <= we and not RAS_N when PHASE_ZERO = '1' else '0'; + + -- Latch RAM data on the rising edge of RAS + RAM_data_latch : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if AX = '1' and CAS_N = '0' and RAS_N = '0' then + DL <= ram_do; + end if; + end if; + end process; + + ADDR <= A; + + -- Address decoding + rom_addr <= (A(13) and A(12)) & (not A(12)) & A(11 downto 0); + + address_decoder: process (A) + begin + ROM_SELECT <= '0'; + RAM_SELECT <= '0'; + KEYBOARD_SELECT <= '0'; + READ_KEY <= '0'; + SPEAKER_SELECT <= '0'; + SOFTSWITCH_SELECT <= '0'; + GAMEPORT_SELECT <= '0'; + PDL_STROBE <= '0'; + STB <= '0'; + IO_SELECT <= (others => '0'); + DEVICE_SELECT <= (others => '0'); + IO_STROBE <= '0'; + case A(15 downto 14) is + when "00" | "01" | "10" => -- 0000 - BFFF + RAM_SELECT <= '1'; + when "11" => -- C000 - FFFF + case A(13 downto 12) is + when "00" => -- C000 - CFFF + case A(11 downto 8) is + when x"0" => -- C000 - C0FF + case A(7 downto 4) is + when x"0" => -- C000 - C00F + KEYBOARD_SELECT <= '1'; + when x"1" => -- C010 - C01F + READ_KEY <= '1'; + when x"3" => -- C030 - C03F + SPEAKER_SELECT <= '1'; + when x"4" => + STB <= '1'; + when x"5" => -- C050 - C05F + SOFTSWITCH_SELECT <= '1'; + when x"6" => -- C060 - C06F + GAMEPORT_SELECT <= '1'; + when x"7" => -- C070 - C07F + PDL_STROBE <= '1'; + when x"8" | x"9" | x"A" | -- C080 - C0FF + x"B" | x"C" | x"D" | x"E" | x"F" => + DEVICE_SELECT(TO_INTEGER(A(6 downto 4))) <= '1'; + when others => null; + end case; + when x"1" | x"2" | x"3" | -- C100 - C7FF + x"4" | x"5" | x"6" | x"7" => + IO_SELECT(TO_INTEGER(A(10 downto 8))) <= '1'; + when x"8" | x"9" | x"A" | -- C800 - CFFF + x"B" | x"C" | x"D" | x"E" | x"F" => + IO_STROBE <= '1'; + when others => null; + end case; + when "01" | "10" | "11" => -- D000 - FFFF + ROM_SELECT <= '1'; + when others => + null; + end case; + when others => null; + end case; + end process address_decoder; + + speaker_ctrl: process (Q3) + begin + if rising_edge(Q3) then + if PRE_PHASE_ZERO_sig = '1' and SPEAKER_SELECT = '1' then + speaker_sig <= not speaker_sig; + end if; + end if; + end process speaker_ctrl; + + softswitches: process (Q3) + begin + if rising_edge(Q3) then + if PRE_PHASE_ZERO_sig = '1' and SOFTSWITCH_SELECT = '1' then + soft_switches(TO_INTEGER(A(3 downto 1))) <= A(0); + end if; + end if; + end process softswitches; + + TEXT_MODE <= soft_switches(0); + MIXED_MODE <= soft_switches(1); + PAGE2 <= soft_switches(2); + HIRES_MODE <= soft_switches(3); + AN <= soft_switches(7 downto 4); + + speaker <= speaker_sig; + + D_IN <= DL when RAM_SELECT = '1' else -- RAM + K when KEYBOARD_SELECT = '1' else -- Keyboard + GAMEPORT(TO_INTEGER(A(2 downto 0))) & "0000000" -- Gameport + when GAMEPORT_SELECT = '1' else + rom_out when ROM_SELECT = '1' else -- ROMs + PD; -- Peripherals + + LD194 <= LD194_I; + + timing : entity work.timing_generator port map ( + CLK_14M => CLK_14M, + CLK_7M => CLK_7M, + CAS_N => CAS_N, + RAS_N => RAS_N, + Q3 => Q3, + AX => AX, + PHI0 => PHASE_ZERO, + PRE_PHI0 => PRE_PHASE_ZERO_sig, + COLOR_REF => COLOR_REF, + TEXT_MODE => TEXT_MODE, + PAGE2 => PAGE2, + HIRES => HIRES, + VIDEO_ADDRESS => VIDEO_ADDRESS, + H0 => H0, + VA => VA, + VB => VB, + VC => VC, + V2 => V2, + V4 => V4, + VBL => VBL, + HBL => HBL, + BLANK => BLANK, + LDPS_N => LDPS_N, + LD194 => LD194_I); + + video_display : entity work.video_generator port map ( + CLK_14M => CLK_14M, + CLK_7M => CLK_7M, + AX => AX, + CAS_N => CAS_N, + TEXT_MODE => TEXT_MODE, + PAGE2 => PAGE2, + HIRES_MODE => HIRES_MODE, + MIXED_MODE => MIXED_MODE, + H0 => H0, + VA => VA, + VB => VB, + VC => VC, + V2 => V2, + V4 => V4, + BLANK => BLANK, + DL => DL, + LDPS_N => LDPS_N, + LD194 => LD194_I, + FLASH_CLK => FLASH_CLK, + HIRES => HIRES, + VIDEO => VIDEO, + COLOR_LINE => COLOR_LINE); + + cpu : entity work.cpu65xx + generic map ( + pipelineOpcode => false, + pipelineAluMux => false, + pipelineAluOut => false) + port map ( + clk => Q3, + enable => not PRE_PHASE_ZERO_sig, + reset => reset, + nmi_n => '1', + irq_n => '1', + di => D_IN, + do => D, + addr => A, + we => we, + debugPc => pcDebugOut, + debugOpcode => opcodeDebugOut + ); + + -- Original Apple had asynchronous ROMs. We use a synchronous ROM + -- that needs its address earlier, hence the odd clock. + roms : entity work.main_roms port map ( + addr => rom_addr, + clk => CLK_14M, + dout => rom_out); + +end rtl; diff --git a/Apple - 2_MiST/rtl/build_id.tcl b/Apple - 2_MiST/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Apple - 2_MiST/rtl/build_id.tcl @@ -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 \ No newline at end of file diff --git a/Apple - 2_MiST/rtl/build_id.v b/Apple - 2_MiST/rtl/build_id.v new file mode 100644 index 00000000..fa4fc18c --- /dev/null +++ b/Apple - 2_MiST/rtl/build_id.v @@ -0,0 +1,2 @@ +`define BUILD_DATE "180506" +`define BUILD_TIME "191822" diff --git a/Apple - 2_MiST/rtl/character_rom.vhd b/Apple - 2_MiST/rtl/character_rom.vhd new file mode 100644 index 00000000..33c50729 --- /dev/null +++ b/Apple - 2_MiST/rtl/character_rom.vhd @@ -0,0 +1,539 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity character_rom is + + port ( + addr : in unsigned(8 downto 0); + clk : in std_logic; + dout : out unsigned(4 downto 0)); +end character_rom; + +architecture rtl of character_rom is + type rom_array is array (0 to 511) of unsigned(4 downto 0); + + constant ROM : rom_array := ( + "01110", + "10001", + "10101", + "11101", + "01101", + "00001", + "11110", + "00000", + "00100", + "01010", + "10001", + "10001", + "11111", + "10001", + "10001", + "00000", + "01111", + "10001", + "10001", + "01111", + "10001", + "10001", + "01111", + "00000", + "01110", + "10001", + "00001", + "00001", + "00001", + "10001", + "01110", + "00000", + "01111", + "10001", + "10001", + "10001", + "10001", + "10001", + "01111", + "00000", + "11111", + "00001", + "00001", + "01111", + "00001", + "00001", + "11111", + "00000", + "11111", + "00001", + "00001", + "01111", + "00001", + "00001", + "00001", + "00000", + "11110", + "00001", + "00001", + "00001", + "11001", + "10001", + "11110", + "00000", + "10001", + "10001", + "10001", + "11111", + "10001", + "10001", + "10001", + "00000", + "01110", + "00100", + "00100", + "00100", + "00100", + "00100", + "01110", + "00000", + "10000", + "10000", + "10000", + "10000", + "10000", + "10001", + "01110", + "00000", + "10001", + "01001", + "00101", + "00011", + "00101", + "01001", + "10001", + "00000", + "00001", + "00001", + "00001", + "00001", + "00001", + "00001", + "11111", + "00000", + "10001", + "11011", + "10101", + "10101", + "10001", + "10001", + "10001", + "00000", + "10001", + "10001", + "10011", + "10101", + "11001", + "10001", + "10001", + "00000", + "01110", + "10001", + "10001", + "10001", + "10001", + "10001", + "01110", + "00000", + "01111", + "10001", + "10001", + "01111", + "00001", + "00001", + "00001", + "00000", + "01110", + "10001", + "10001", + "10001", + "10101", + "01001", + "10110", + "00000", + "01111", + "10001", + "10001", + "01111", + "00101", + "01001", + "10001", + "00000", + "01110", + "10001", + "00001", + "01110", + "10000", + "10001", + "01110", + "00000", + "11111", + "00100", + "00100", + "00100", + "00100", + "00100", + "00100", + "00000", + "10001", + "10001", + "10001", + "10001", + "10001", + "10001", + "01110", + "00000", + "10001", + "10001", + "10001", + "10001", + "10001", + "01010", + "00100", + "00000", + "10001", + "10001", + "10001", + "10101", + "10101", + "11011", + "10001", + "00000", + "10001", + "10001", + "01010", + "00100", + "01010", + "10001", + "10001", + "00000", + "10001", + "10001", + "01010", + "00100", + "00100", + "00100", + "00100", + "00000", + "11111", + "10000", + "01000", + "00100", + "00010", + "00001", + "11111", + "00000", + "11111", + "00011", + "00011", + "00011", + "00011", + "00011", + "11111", + "00000", + "00000", + "00001", + "00010", + "00100", + "01000", + "10000", + "00000", + "00000", + "11111", + "11000", + "11000", + "11000", + "11000", + "11000", + "11111", + "00000", + "00000", + "00000", + "00100", + "01010", + "10001", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "11111", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00100", + "00100", + "00100", + "00100", + "00100", + "00000", + "00100", + "00000", + "01010", + "01010", + "01010", + "00000", + "00000", + "00000", + "00000", + "00000", + "01010", + "01010", + "11111", + "01010", + "11111", + "01010", + "01010", + "00000", + "00100", + "11110", + "00101", + "01110", + "10100", + "01111", + "00100", + "00000", + "00011", + "10011", + "01000", + "00100", + "00010", + "11001", + "11000", + "00000", + "00010", + "00101", + "00101", + "00010", + "10101", + "01001", + "10110", + "00000", + "00100", + "00100", + "00100", + "00000", + "00000", + "00000", + "00000", + "00000", + "00100", + "00010", + "00001", + "00001", + "00001", + "00010", + "00100", + "00000", + "00100", + "01000", + "10000", + "10000", + "10000", + "01000", + "00100", + "00000", + "00100", + "10101", + "01110", + "00100", + "01110", + "10101", + "00100", + "00000", + "00000", + "00100", + "00100", + "11111", + "00100", + "00100", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00100", + "00100", + "00010", + "00000", + "00000", + "00000", + "00000", + "11111", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00000", + "00100", + "00000", + "00000", + "10000", + "01000", + "00100", + "00010", + "00001", + "00000", + "00000", + "01110", + "10001", + "11001", + "10101", + "10011", + "10001", + "01110", + "00000", + "00100", + "00110", + "00100", + "00100", + "00100", + "00100", + "01110", + "00000", + "01110", + "10001", + "10000", + "01100", + "00010", + "00001", + "11111", + "00000", + "11111", + "10000", + "01000", + "01100", + "10000", + "10001", + "01110", + "00000", + "01000", + "01100", + "01010", + "01001", + "11111", + "01000", + "01000", + "00000", + "11111", + "00001", + "01111", + "10000", + "10000", + "10001", + "01110", + "00000", + "11100", + "00010", + "00001", + "01111", + "10001", + "10001", + "01110", + "00000", + "11111", + "10000", + "01000", + "00100", + "00010", + "00010", + "00010", + "00000", + "01110", + "10001", + "10001", + "01110", + "10001", + "10001", + "01110", + "00000", + "01110", + "10001", + "10001", + "11110", + "10000", + "01000", + "00111", + "00000", + "00000", + "00000", + "00100", + "00000", + "00100", + "00000", + "00000", + "00000", + "00000", + "00000", + "00100", + "00000", + "00100", + "00100", + "00010", + "00000", + "01000", + "00100", + "00010", + "00001", + "00010", + "00100", + "01000", + "00000", + "00000", + "00000", + "11111", + "00000", + "11111", + "00000", + "00000", + "00000", + "00010", + "00100", + "01000", + "10000", + "01000", + "00100", + "00010", + "00000", + "01110", + "10001", + "01000", + "00100", + "00100", + "00000", + "00100", + "00000"); + +begin + + process (clk) + begin + if rising_edge(clk) then + dout <= ROM(TO_INTEGER(addr)); + end if; + end process; + +end rtl; diff --git a/Apple - 2_MiST/rtl/cpu6502.vhd b/Apple - 2_MiST/rtl/cpu6502.vhd new file mode 100644 index 00000000..1c521ffb --- /dev/null +++ b/Apple - 2_MiST/rtl/cpu6502.vhd @@ -0,0 +1,1598 @@ +-- ----------------------------------------------------------------------- +-- +-- FPGA 64 +-- +-- A fully functional commodore 64 implementation in a single FPGA +-- +-- ----------------------------------------------------------------------- +-- +-- Table driven, cycle exact 6502/6510 core +-- +-- ----------------------------------------------------------------------- +-- +-- cpu65xx_fast.vhdl, part of FPGA-64, is made available strictly for personal +-- educational purposes. Distributed with apple2fgpa with permission. +-- +-- Copyright 2005-2008 by Peter Wendrich (pwsoft@syntiac.com). +-- All rights reserved. +-- http://www.syntiac.com/fpga64.html +-- +-- ----------------------------------------------------------------------- + +library IEEE; +use ieee.std_logic_1164.ALL; +use ieee.numeric_std.ALL; + +entity cpu65xx is + generic ( + pipelineOpcode : boolean; + pipelineAluMux : boolean; + pipelineAluOut : boolean + ); + port ( + clk : in std_logic; + enable : in std_logic; + reset : in std_logic; + nmi_n : in std_logic; + irq_n : in std_logic; + so_n : in std_logic := '1'; + + di : in unsigned(7 downto 0); + do : out unsigned(7 downto 0); + addr : out unsigned(15 downto 0); + we : out std_logic; + + debugOpcode : out unsigned(7 downto 0); + debugPc : out unsigned(15 downto 0); + debugA : out unsigned(7 downto 0); + debugX : out unsigned(7 downto 0); + debugY : out unsigned(7 downto 0); + debugS : out unsigned(7 downto 0) + ); +end cpu65xx; + +-- ----------------------------------------------------------------------- + +-- Store Zp (3) => fetch, cycle2, cycleEnd +-- Store Zp,x (4) => fetch, cycle2, preWrite, cycleEnd +-- Read Zp,x (4) => fetch, cycle2, cycleRead, cycleRead2 +-- Rmw Zp,x (6) => fetch, cycle2, cycleRead, cycleRead2, cycleRmw, cycleEnd +-- Store Abs (4) => fetch, cycle2, cycle3, cycleEnd +-- Store Abs,x (5) => fetch, cycle2, cycle3, preWrite, cycleEnd +-- Rts (6) => fetch, cycle2, cycle3, cycleRead, cycleJump, cycleIncrEnd +-- Rti (6) => fetch, cycle2, stack1, stack2, stack3, cycleJump +-- Jsr (6) => fetch, cycle2, .. cycle5, cycle6, cycleJump +-- Jmp abs (-) => fetch, cycle2, .., cycleJump +-- Jmp (ind) (-) => fetch, cycle2, .., cycleJump +-- Brk / irq (6) => fetch, cycle2, stack2, stack3, stack4 +-- ----------------------------------------------------------------------- + +architecture fast of cpu65xx is +-- Statemachine + type cpuCycles is ( + opcodeFetch, -- New opcode is read and registers updated + cycle2, + cycle3, + cyclePreIndirect, + cycleIndirect, + cycleBranchTaken, + cycleBranchPage, + cyclePreRead, -- Cycle before read while doing zeropage indexed addressing. + cycleRead, -- Read cycle + cycleRead2, -- Second read cycle after page-boundary crossing. + cycleRmw, -- Calculate ALU output for read-modify-write instr. + cyclePreWrite, -- Cycle before write when doing indexed addressing. + cycleWrite, -- Write cycle for zeropage or absolute addressing. + cycleStack1, + cycleStack2, + cycleStack3, + cycleStack4, + cycleJump, -- Last cycle of Jsr, Jmp. Next fetch address is target addr. + cycleEnd + ); + signal theCpuCycle : cpuCycles; + signal nextCpuCycle : cpuCycles; + signal updateRegisters : boolean; + signal processIrq : std_logic; + signal nmiReg: std_logic; + signal nmiEdge: std_logic; + signal irqReg : std_logic; -- Delay IRQ input with one clock cycle. + signal soReg : std_logic; -- SO pin edge detection + +-- Opcode decoding + constant opcUpdateA : integer := 0; + constant opcUpdateX : integer := 1; + constant opcUpdateY : integer := 2; + constant opcUpdateS : integer := 3; + constant opcUpdateN : integer := 4; + constant opcUpdateV : integer := 5; + constant opcUpdateD : integer := 6; + constant opcUpdateI : integer := 7; + constant opcUpdateZ : integer := 8; + constant opcUpdateC : integer := 9; + + constant opcSecondByte : integer := 10; + constant opcAbsolute : integer := 11; + constant opcZeroPage : integer := 12; + constant opcIndirect : integer := 13; + constant opcStackAddr : integer := 14; -- Push/Pop address + constant opcStackData : integer := 15; -- Push/Pop status/data + constant opcJump : integer := 16; + constant opcBranch : integer := 17; + constant indexX : integer := 18; + constant indexY : integer := 19; + constant opcStackUp : integer := 20; + constant opcWrite : integer := 21; + constant opcRmw : integer := 22; + constant opcIncrAfter : integer := 23; -- Insert extra cycle to increment PC (RTS) + constant opcRti : integer := 24; + constant opcIRQ : integer := 25; + + constant opcInA : integer := 26; + constant opcInE : integer := 27; + constant opcInX : integer := 28; + constant opcInY : integer := 29; + constant opcInS : integer := 30; + constant opcInT : integer := 31; + constant opcInH : integer := 32; + constant opcInClear : integer := 33; + constant aluMode1From : integer := 34; + -- + constant aluMode1To : integer := 37; + constant aluMode2From : integer := 38; + -- + constant aluMode2To : integer := 40; + -- + constant opcInCmp : integer := 41; + constant opcInCpx : integer := 42; + constant opcInCpy : integer := 43; + + + subtype addrDef is unsigned(0 to 15); + -- + -- is Interrupt -----------------+ + -- instruction is RTI ----------------+| + -- PC++ on last cycle (RTS) ---------------+|| + -- RMW --------------+||| + -- Write -------------+|||| + -- Pop/Stack up -------------+||||| + -- Branch ---------+ |||||| + -- Jump ----------+| |||||| + -- Push or Pop data -------+|| |||||| + -- Push or Pop addr ------+||| |||||| + -- Indirect -----+|||| |||||| + -- ZeroPage ----+||||| |||||| + -- Absolute ---+|||||| |||||| + -- PC++ on cycle2 --+||||||| |||||| + -- |AZI||JBXY|WM||| + constant immediate : addrDef := "1000000000000000"; + constant implied : addrDef := "0000000000000000"; + -- Zero page + constant readZp : addrDef := "1010000000000000"; + constant writeZp : addrDef := "1010000000010000"; + constant rmwZp : addrDef := "1010000000001000"; + -- Zero page indexed + constant readZpX : addrDef := "1010000010000000"; + constant writeZpX : addrDef := "1010000010010000"; + constant rmwZpX : addrDef := "1010000010001000"; + constant readZpY : addrDef := "1010000001000000"; + constant writeZpY : addrDef := "1010000001010000"; + constant rmwZpY : addrDef := "1010000001001000"; + -- Zero page indirect + constant readIndX : addrDef := "1001000010000000"; + constant writeIndX : addrDef := "1001000010010000"; + constant rmwIndX : addrDef := "1001000010001000"; + constant readIndY : addrDef := "1001000001000000"; + constant writeIndY : addrDef := "1001000001010000"; + constant rmwIndY : addrDef := "1001000001001000"; + -- |AZI||JBXY|WM|| + -- Absolute + constant readAbs : addrDef := "1100000000000000"; + constant writeAbs : addrDef := "1100000000010000"; + constant rmwAbs : addrDef := "1100000000001000"; + constant readAbsX : addrDef := "1100000010000000"; + constant writeAbsX : addrDef := "1100000010010000"; + constant rmwAbsX : addrDef := "1100000010001000"; + constant readAbsY : addrDef := "1100000001000000"; + constant writeAbsY : addrDef := "1100000001010000"; + constant rmwAbsY : addrDef := "1100000001001000"; + -- PHA PHP + constant push : addrDef := "0000010000000000"; + -- PLA PLP + constant pop : addrDef := "0000010000100000"; + -- Jumps + constant jsr : addrDef := "1000101000000000"; + constant jumpAbs : addrDef := "1000001000000000"; + constant jumpInd : addrDef := "1100001000000000"; + constant relative : addrDef := "1000000100000000"; + -- Specials + constant rts : addrDef := "0000101000100100"; + constant rti : addrDef := "0000111000100010"; + constant brk : addrDef := "1000111000000001"; +-- constant : unsigned(0 to 0) := "0"; + constant xxxxxxxx : addrDef := "----------0---00"; + + -- A = accu + -- E = Accu | 0xEE (for ANE, LXA) + -- X = index X + -- Y = index Y + -- S = Stack pointer + -- H = indexH + -- + -- AEXYSTHc + constant aluInA : unsigned(0 to 7) := "10000000"; + constant aluInE : unsigned(0 to 7) := "01000000"; + constant aluInEXT : unsigned(0 to 7) := "01100100"; + constant aluInET : unsigned(0 to 7) := "01000100"; + constant aluInX : unsigned(0 to 7) := "00100000"; + constant aluInXH : unsigned(0 to 7) := "00100010"; + constant aluInY : unsigned(0 to 7) := "00010000"; + constant aluInYH : unsigned(0 to 7) := "00010010"; + constant aluInS : unsigned(0 to 7) := "00001000"; + constant aluInT : unsigned(0 to 7) := "00000100"; + constant aluInAX : unsigned(0 to 7) := "10100000"; + constant aluInAXH : unsigned(0 to 7) := "10100010"; + constant aluInAT : unsigned(0 to 7) := "10000100"; + constant aluInXT : unsigned(0 to 7) := "00100100"; + constant aluInST : unsigned(0 to 7) := "00001100"; + constant aluInSet : unsigned(0 to 7) := "00000000"; + constant aluInClr : unsigned(0 to 7) := "00000001"; + constant aluInXXX : unsigned(0 to 7) := "--------"; + + -- Most of the aluModes are just like the opcodes. + -- aluModeInp -> input is output. calculate N and Z + -- aluModeCmp -> Compare for CMP, CPX, CPY + -- aluModeFlg -> input to flags needed for PLP, RTI and CLC, SEC, CLV + -- aluModeInc -> for INC but also INX, INY + -- aluModeDec -> for DEC but also DEX, DEY + + subtype aluMode1 is unsigned(0 to 3); + subtype aluMode2 is unsigned(0 to 2); + subtype aluMode is unsigned(0 to 9); + + -- Logic/Shift ALU + constant aluModeInp : aluMode1 := "0000"; + constant aluModeP : aluMode1 := "0001"; + constant aluModeInc : aluMode1 := "0010"; + constant aluModeDec : aluMode1 := "0011"; + constant aluModeFlg : aluMode1 := "0100"; + constant aluModeBit : aluMode1 := "0101"; + -- 0110 + -- 0111 + constant aluModeLsr : aluMode1 := "1000"; + constant aluModeRor : aluMode1 := "1001"; + constant aluModeAsl : aluMode1 := "1010"; + constant aluModeRol : aluMode1 := "1011"; + -- 1100 + -- 1101 + -- 1110 + constant aluModeAnc : aluMode1 := "1111"; + + -- Arithmetic ALU + constant aluModePss : aluMode2 := "000"; + constant aluModeCmp : aluMode2 := "001"; + constant aluModeAdc : aluMode2 := "010"; + constant aluModeSbc : aluMode2 := "011"; + constant aluModeAnd : aluMode2 := "100"; + constant aluModeOra : aluMode2 := "101"; + constant aluModeEor : aluMode2 := "110"; + constant aluModeArr : aluMode2 := "111"; + + + constant aluInp : aluMode := aluModeInp & aluModePss & "---"; + constant aluP : aluMode := aluModeP & aluModePss & "---"; + constant aluInc : aluMode := aluModeInc & aluModePss & "---"; + constant aluDec : aluMode := aluModeDec & aluModePss & "---"; + constant aluFlg : aluMode := aluModeFlg & aluModePss & "---"; + constant aluBit : aluMode := aluModeBit & aluModeAnd & "---"; + constant aluRor : aluMode := aluModeRor & aluModePss & "---"; + constant aluLsr : aluMode := aluModeLsr & aluModePss & "---"; + constant aluRol : aluMode := aluModeRol & aluModePss & "---"; + constant aluAsl : aluMode := aluModeAsl & aluModePss & "---"; + + constant aluCmp : aluMode := aluModeInp & aluModeCmp & "100"; + constant aluCpx : aluMode := aluModeInp & aluModeCmp & "010"; + constant aluCpy : aluMode := aluModeInp & aluModeCmp & "001"; + constant aluAdc : aluMode := aluModeInp & aluModeAdc & "---"; + constant aluSbc : aluMode := aluModeInp & aluModeSbc & "---"; + constant aluAnd : aluMode := aluModeInp & aluModeAnd & "---"; + constant aluOra : aluMode := aluModeInp & aluModeOra & "---"; + constant aluEor : aluMode := aluModeInp & aluModeEor & "---"; + + constant aluSlo : aluMode := aluModeAsl & aluModeOra & "---"; + constant aluSre : aluMode := aluModeLsr & aluModeEor & "---"; + constant aluRra : aluMode := aluModeRor & aluModeAdc & "---"; + constant aluRla : aluMode := aluModeRol & aluModeAnd & "---"; + constant aluDcp : aluMode := aluModeDec & aluModeCmp & "100"; + constant aluIsc : aluMode := aluModeInc & aluModeSbc & "---"; + constant aluAnc : aluMode := aluModeAnc & aluModeAnd & "---"; + constant aluArr : aluMode := aluModeRor & aluModeArr & "---"; + constant aluSbx : aluMode := aluModeInp & aluModeCmp & "110"; + + constant aluXXX : aluMode := (others => '-'); + + + -- Stack operations. Push/Pop/None + constant stackInc : unsigned(0 to 0) := "0"; + constant stackDec : unsigned(0 to 0) := "1"; + constant stackXXX : unsigned(0 to 0) := "-"; + + subtype decodedBitsDef is unsigned(0 to 43); + type opcodeInfoTableDef is array(0 to 255) of decodedBitsDef; + constant opcodeInfoTable : opcodeInfoTableDef := ( + -- +------- Update register A + -- |+------ Update register X + -- ||+----- Update register Y + -- |||+---- Update register S + -- |||| +-- Update Flags + -- |||| | + -- |||| _|__ + -- |||| / \ + -- AXYS NVDIZC addressing aluInput aluMode + "0000" & "000100" & brk & aluInXXX & aluP, -- 00 BRK + "1000" & "100010" & readIndX & aluInT & aluOra, -- 01 ORA (zp,x) + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 02 *** JAM *** + "1000" & "100011" & rmwIndX & aluInT & aluSlo, -- 03 iSLO (zp,x) + "0000" & "000000" & readZp & aluInXXX & aluXXX, -- 04 iNOP zp + "1000" & "100010" & readZp & aluInT & aluOra, -- 05 ORA zp + "0000" & "100011" & rmwZp & aluInT & aluAsl, -- 06 ASL zp + "1000" & "100011" & rmwZp & aluInT & aluSlo, -- 07 iSLO zp + "0000" & "000000" & push & aluInXXX & aluP, -- 08 PHP + "1000" & "100010" & immediate & aluInT & aluOra, -- 09 ORA imm + "1000" & "100011" & implied & aluInA & aluAsl, -- 0A ASL accu + "1000" & "100011" & immediate & aluInT & aluAnc, -- 0B iANC imm + "0000" & "000000" & readAbs & aluInXXX & aluXXX, -- 0C iNOP abs + "1000" & "100010" & readAbs & aluInT & aluOra, -- 0D ORA abs + "0000" & "100011" & rmwAbs & aluInT & aluAsl, -- 0E ASL abs + "1000" & "100011" & rmwAbs & aluInT & aluSlo, -- 0F iSLO abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- 10 BPL + "1000" & "100010" & readIndY & aluInT & aluOra, -- 11 ORA (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 12 *** JAM *** + "1000" & "100011" & rmwIndY & aluInT & aluSlo, -- 13 iSLO (zp),y + "0000" & "000000" & readZpX & aluInXXX & aluXXX, -- 14 iNOP zp,x + "1000" & "100010" & readZpX & aluInT & aluOra, -- 15 ORA zp,x + "0000" & "100011" & rmwZpX & aluInT & aluAsl, -- 16 ASL zp,x + "1000" & "100011" & rmwZpX & aluInT & aluSlo, -- 17 iSLO zp,x + "0000" & "000001" & implied & aluInClr & aluFlg, -- 18 CLC + "1000" & "100010" & readAbsY & aluInT & aluOra, -- 19 ORA abs,y + "0000" & "000000" & implied & aluInXXX & aluXXX, -- 1A iNOP implied + "1000" & "100011" & rmwAbsY & aluInT & aluSlo, -- 1B iSLO abs,y + "0000" & "000000" & readAbsX & aluInXXX & aluXXX, -- 1C iNOP abs,x + "1000" & "100010" & readAbsX & aluInT & aluOra, -- 1D ORA abs,x + "0000" & "100011" & rmwAbsX & aluInT & aluAsl, -- 1E ASL abs,x + "1000" & "100011" & rmwAbsX & aluInT & aluSlo, -- 1F iSLO abs,x + -- AXYS NVDIZC addressing aluInput aluMode + "0000" & "000000" & jsr & aluInXXX & aluXXX, -- 20 JSR + "1000" & "100010" & readIndX & aluInT & aluAnd, -- 21 AND (zp,x) + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 22 *** JAM *** + "1000" & "100011" & rmwIndX & aluInT & aluRla, -- 23 iRLA (zp,x) + "0000" & "110010" & readZp & aluInT & aluBit, -- 24 BIT zp + "1000" & "100010" & readZp & aluInT & aluAnd, -- 25 AND zp + "0000" & "100011" & rmwZp & aluInT & aluRol, -- 26 ROL zp + "1000" & "100011" & rmwZp & aluInT & aluRla, -- 27 iRLA zp + "0000" & "111111" & pop & aluInT & aluFlg, -- 28 PLP + "1000" & "100010" & immediate & aluInT & aluAnd, -- 29 AND imm + "1000" & "100011" & implied & aluInA & aluRol, -- 2A ROL accu + "1000" & "100011" & immediate & aluInT & aluAnc, -- 2B iANC imm + "0000" & "110010" & readAbs & aluInT & aluBit, -- 2C BIT abs + "1000" & "100010" & readAbs & aluInT & aluAnd, -- 2D AND abs + "0000" & "100011" & rmwAbs & aluInT & aluRol, -- 2E ROL abs + "1000" & "100011" & rmwAbs & aluInT & aluRla, -- 2F iRLA abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- 30 BMI + "1000" & "100010" & readIndY & aluInT & aluAnd, -- 31 AND (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 32 *** JAM *** + "1000" & "100011" & rmwIndY & aluInT & aluRla, -- 33 iRLA (zp),y + "0000" & "000000" & readZpX & aluInXXX & aluXXX, -- 34 iNOP zp,x + "1000" & "100010" & readZpX & aluInT & aluAnd, -- 35 AND zp,x + "0000" & "100011" & rmwZpX & aluInT & aluRol, -- 36 ROL zp,x + "1000" & "100011" & rmwZpX & aluInT & aluRla, -- 37 iRLA zp,x + "0000" & "000001" & implied & aluInSet & aluFlg, -- 38 SEC + "1000" & "100010" & readAbsY & aluInT & aluAnd, -- 39 AND abs,y + "0000" & "000000" & implied & aluInXXX & aluXXX, -- 3A iNOP implied + "1000" & "100011" & rmwAbsY & aluInT & aluRla, -- 3B iRLA abs,y + "0000" & "000000" & readAbsX & aluInXXX & aluXXX, -- 3C iNOP abs,x + "1000" & "100010" & readAbsX & aluInT & aluAnd, -- 3D AND abs,x + "0000" & "100011" & rmwAbsX & aluInT & aluRol, -- 3E ROL abs,x + "1000" & "100011" & rmwAbsX & aluInT & aluRla, -- 3F iRLA abs,x + -- AXYS NVDIZC addressing aluInput aluMode + "0000" & "111111" & rti & aluInT & aluFlg, -- 40 RTI + "1000" & "100010" & readIndX & aluInT & aluEor, -- 41 EOR (zp,x) + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 42 *** JAM *** + "1000" & "100011" & rmwIndX & aluInT & aluSre, -- 43 iSRE (zp,x) + "0000" & "000000" & readZp & aluInXXX & aluXXX, -- 44 iNOP zp + "1000" & "100010" & readZp & aluInT & aluEor, -- 45 EOR zp + "0000" & "100011" & rmwZp & aluInT & aluLsr, -- 46 LSR zp + "1000" & "100011" & rmwZp & aluInT & aluSre, -- 47 iSRE zp + "0000" & "000000" & push & aluInA & aluInp, -- 48 PHA + "1000" & "100010" & immediate & aluInT & aluEor, -- 49 EOR imm + "1000" & "100011" & implied & aluInA & aluLsr, -- 4A LSR accu + "1000" & "100011" & immediate & aluInAT & aluLsr, -- 4B iALR imm + "0000" & "000000" & jumpAbs & aluInXXX & aluXXX, -- 4C JMP abs + "1000" & "100010" & readAbs & aluInT & aluEor, -- 4D EOR abs + "0000" & "100011" & rmwAbs & aluInT & aluLsr, -- 4E LSR abs + "1000" & "100011" & rmwAbs & aluInT & aluSre, -- 4F iSRE abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- 50 BVC + "1000" & "100010" & readIndY & aluInT & aluEor, -- 51 EOR (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 52 *** JAM *** + "1000" & "100011" & rmwIndY & aluInT & aluSre, -- 53 iSRE (zp),y + "0000" & "000000" & readZpX & aluInXXX & aluXXX, -- 54 iNOP zp,x + "1000" & "100010" & readZpX & aluInT & aluEor, -- 55 EOR zp,x + "0000" & "100011" & rmwZpX & aluInT & aluLsr, -- 56 LSR zp,x + "1000" & "100011" & rmwZpX & aluInT & aluSre, -- 57 SRE zp,x + "0000" & "000100" & implied & aluInClr & aluXXX, -- 58 CLI + "1000" & "100010" & readAbsY & aluInT & aluEor, -- 59 EOR abs,y + "0000" & "000000" & implied & aluInXXX & aluXXX, -- 5A iNOP implied + "1000" & "100011" & rmwAbsY & aluInT & aluSre, -- 5B iSRE abs,y + "0000" & "000000" & readAbsX & aluInXXX & aluXXX, -- 5C iNOP abs,x + "1000" & "100010" & readAbsX & aluInT & aluEor, -- 5D EOR abs,x + "0000" & "100011" & rmwAbsX & aluInT & aluLsr, -- 5E LSR abs,x + "1000" & "100011" & rmwAbsX & aluInT & aluSre, -- 5F SRE abs,x + -- AXYS NVDIZC addressing aluInput aluMode + "0000" & "000000" & rts & aluInXXX & aluXXX, -- 60 RTS + "1000" & "110011" & readIndX & aluInT & aluAdc, -- 61 ADC (zp,x) + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 62 *** JAM *** + "1000" & "110011" & rmwIndX & aluInT & aluRra, -- 63 iRRA (zp,x) + "0000" & "000000" & readZp & aluInXXX & aluXXX, -- 64 iNOP zp + "1000" & "110011" & readZp & aluInT & aluAdc, -- 65 ADC zp + "0000" & "100011" & rmwZp & aluInT & aluRor, -- 66 ROR zp + "1000" & "110011" & rmwZp & aluInT & aluRra, -- 67 iRRA zp + "1000" & "100010" & pop & aluInT & aluInp, -- 68 PLA + "1000" & "110011" & immediate & aluInT & aluAdc, -- 69 ADC imm + "1000" & "100011" & implied & aluInA & aluRor, -- 6A ROR accu + "1000" & "110011" & immediate & aluInAT & aluArr, -- 6B iARR imm + "0000" & "000000" & jumpInd & aluInXXX & aluXXX, -- 6C JMP indirect + "1000" & "110011" & readAbs & aluInT & aluAdc, -- 6D ADC abs + "0000" & "100011" & rmwAbs & aluInT & aluRor, -- 6E ROR abs + "1000" & "110011" & rmwAbs & aluInT & aluRra, -- 6F iRRA abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- 70 BVS + "1000" & "110011" & readIndY & aluInT & aluAdc, -- 71 ADC (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 72 *** JAM *** + "1000" & "110011" & rmwIndY & aluInT & aluRra, -- 73 iRRA (zp),y + "0000" & "000000" & readZpX & aluInXXX & aluXXX, -- 74 iNOP zp,x + "1000" & "110011" & readZpX & aluInT & aluAdc, -- 75 ADC zp,x + "0000" & "100011" & rmwZpX & aluInT & aluRor, -- 76 ROR zp,x + "1000" & "110011" & rmwZpX & aluInT & aluRra, -- 77 iRRA zp,x + "0000" & "000100" & implied & aluInSet & aluXXX, -- 78 SEI + "1000" & "110011" & readAbsY & aluInT & aluAdc, -- 79 ADC abs,y + "0000" & "000000" & implied & aluInXXX & aluXXX, -- 7A iNOP implied + "1000" & "110011" & rmwAbsY & aluInT & aluRra, -- 7B iRRA abs,y + "0000" & "000000" & readAbsX & aluInXXX & aluXXX, -- 7C iNOP abs,x + "1000" & "110011" & readAbsX & aluInT & aluAdc, -- 7D ADC abs,x + "0000" & "100011" & rmwAbsX & aluInT & aluRor, -- 7E ROR abs,x + "1000" & "110011" & rmwAbsX & aluInT & aluRra, -- 7F iRRA abs,x + -- AXYS NVDIZC addressing aluInput aluMode + "0000" & "000000" & immediate & aluInXXX & aluXXX, -- 80 iNOP imm + "0000" & "000000" & writeIndX & aluInA & aluInp, -- 81 STA (zp,x) + "0000" & "000000" & immediate & aluInXXX & aluXXX, -- 82 iNOP imm + "0000" & "000000" & writeIndX & aluInAX & aluInp, -- 83 iSAX (zp,x) + "0000" & "000000" & writeZp & aluInY & aluInp, -- 84 STY zp + "0000" & "000000" & writeZp & aluInA & aluInp, -- 85 STA zp + "0000" & "000000" & writeZp & aluInX & aluInp, -- 86 STX zp + "0000" & "000000" & writeZp & aluInAX & aluInp, -- 87 iSAX zp + "0010" & "100010" & implied & aluInY & aluDec, -- 88 DEY + "0000" & "000000" & immediate & aluInXXX & aluXXX, -- 84 iNOP imm + "1000" & "100010" & implied & aluInX & aluInp, -- 8A TXA + "1000" & "100010" & immediate & aluInEXT & aluInp, -- 8B iANE imm + "0000" & "000000" & writeAbs & aluInY & aluInp, -- 8C STY abs + "0000" & "000000" & writeAbs & aluInA & aluInp, -- 8D STA abs + "0000" & "000000" & writeAbs & aluInX & aluInp, -- 8E STX abs + "0000" & "000000" & writeAbs & aluInAX & aluInp, -- 8F iSAX abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- 90 BCC + "0000" & "000000" & writeIndY & aluInA & aluInp, -- 91 STA (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- 92 *** JAM *** + "0000" & "000000" & writeIndY & aluInAXH & aluInp, -- 93 iAHX (zp),y + "0000" & "000000" & writeZpX & aluInY & aluInp, -- 94 STY zp,x + "0000" & "000000" & writeZpX & aluInA & aluInp, -- 95 STA zp,x + "0000" & "000000" & writeZpY & aluInX & aluInp, -- 96 STX zp,y + "0000" & "000000" & writeZpY & aluInAX & aluInp, -- 97 iSAX zp,y + "1000" & "100010" & implied & aluInY & aluInp, -- 98 TYA + "0000" & "000000" & writeAbsY & aluInA & aluInp, -- 99 STA abs,y + "0001" & "000000" & implied & aluInX & aluInp, -- 9A TXS + "0001" & "000000" & writeAbsY & aluInAXH & aluInp, -- 9B iSHS abs,y + "0000" & "000000" & writeAbsX & aluInYH & aluInp, -- 9C iSHY abs,x + "0000" & "000000" & writeAbsX & aluInA & aluInp, -- 9D STA abs,x + "0000" & "000000" & writeAbsY & aluInXH & aluInp, -- 9E iSHX abs,y + "0000" & "000000" & writeAbsY & aluInAXH & aluInp, -- 9F iAHX abs,y + -- AXYS NVDIZC addressing aluInput aluMode + "0010" & "100010" & immediate & aluInT & aluInp, -- A0 LDY imm + "1000" & "100010" & readIndX & aluInT & aluInp, -- A1 LDA (zp,x) + "0100" & "100010" & immediate & aluInT & aluInp, -- A2 LDX imm + "1100" & "100010" & readIndX & aluInT & aluInp, -- A3 LAX (zp,x) + "0010" & "100010" & readZp & aluInT & aluInp, -- A4 LDY zp + "1000" & "100010" & readZp & aluInT & aluInp, -- A5 LDA zp + "0100" & "100010" & readZp & aluInT & aluInp, -- A6 LDX zp + "1100" & "100010" & readZp & aluInT & aluInp, -- A7 iLAX zp + "0010" & "100010" & implied & aluInA & aluInp, -- A8 TAY + "1000" & "100010" & immediate & aluInT & aluInp, -- A9 LDA imm + "0100" & "100010" & implied & aluInA & aluInp, -- AA TAX + "1100" & "100010" & immediate & aluInET & aluInp, -- AB iLXA imm + "0010" & "100010" & readAbs & aluInT & aluInp, -- AC LDY abs + "1000" & "100010" & readAbs & aluInT & aluInp, -- AD LDA abs + "0100" & "100010" & readAbs & aluInT & aluInp, -- AE LDX abs + "1100" & "100010" & readAbs & aluInT & aluInp, -- AF iLAX abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- B0 BCS + "1000" & "100010" & readIndY & aluInT & aluInp, -- B1 LDA (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- B2 *** JAM *** + "1100" & "100010" & readIndY & aluInT & aluInp, -- B3 iLAX (zp),y + "0010" & "100010" & readZpX & aluInT & aluInp, -- B4 LDY zp,x + "1000" & "100010" & readZpX & aluInT & aluInp, -- B5 LDA zp,x + "0100" & "100010" & readZpY & aluInT & aluInp, -- B6 LDX zp,y + "1100" & "100010" & readZpY & aluInT & aluInp, -- B7 iLAX zp,y + "0000" & "010000" & implied & aluInClr & aluFlg, -- B8 CLV + "1000" & "100010" & readAbsY & aluInT & aluInp, -- B9 LDA abs,y + "0100" & "100010" & implied & aluInS & aluInp, -- BA TSX + "1101" & "100010" & readAbsY & aluInST & aluInp, -- BB iLAS abs,y + "0010" & "100010" & readAbsX & aluInT & aluInp, -- BC LDY abs,x + "1000" & "100010" & readAbsX & aluInT & aluInp, -- BD LDA abs,x + "0100" & "100010" & readAbsY & aluInT & aluInp, -- BE LDX abs,y + "1100" & "100010" & readAbsY & aluInT & aluInp, -- BF iLAX abs,y + -- AXYS NVDIZC addressing aluInput aluMode + "0000" & "100011" & immediate & aluInT & aluCpy, -- C0 CPY imm + "0000" & "100011" & readIndX & aluInT & aluCmp, -- C1 CMP (zp,x) + "0000" & "000000" & immediate & aluInXXX & aluXXX, -- C2 iNOP imm + "0000" & "100011" & rmwIndX & aluInT & aluDcp, -- C3 iDCP (zp,x) + "0000" & "100011" & readZp & aluInT & aluCpy, -- C4 CPY zp + "0000" & "100011" & readZp & aluInT & aluCmp, -- C5 CMP zp + "0000" & "100010" & rmwZp & aluInT & aluDec, -- C6 DEC zp + "0000" & "100011" & rmwZp & aluInT & aluDcp, -- C7 iDCP zp + "0010" & "100010" & implied & aluInY & aluInc, -- C8 INY + "0000" & "100011" & immediate & aluInT & aluCmp, -- C9 CMP imm + "0100" & "100010" & implied & aluInX & aluDec, -- CA DEX + "0100" & "100011" & immediate & aluInT & aluSbx, -- CB SBX imm + "0000" & "100011" & readAbs & aluInT & aluCpy, -- CC CPY abs + "0000" & "100011" & readAbs & aluInT & aluCmp, -- CD CMP abs + "0000" & "100010" & rmwAbs & aluInT & aluDec, -- CE DEC abs + "0000" & "100011" & rmwAbs & aluInT & aluDcp, -- CF iDCP abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- D0 BNE + "0000" & "100011" & readIndY & aluInT & aluCmp, -- D1 CMP (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- D2 *** JAM *** + "0000" & "100011" & rmwIndY & aluInT & aluDcp, -- D3 iDCP (zp),y + "0000" & "000000" & readZpX & aluInXXX & aluXXX, -- D4 iNOP zp,x + "0000" & "100011" & readZpX & aluInT & aluCmp, -- D5 CMP zp,x + "0000" & "100010" & rmwZpX & aluInT & aluDec, -- D6 DEC zp,x + "0000" & "100011" & rmwZpX & aluInT & aluDcp, -- D7 iDCP zp,x + "0000" & "001000" & implied & aluInClr & aluXXX, -- D8 CLD + "0000" & "100011" & readAbsY & aluInT & aluCmp, -- D9 CMP abs,y + "0000" & "000000" & implied & aluInXXX & aluXXX, -- DA iNOP implied + "0000" & "100011" & rmwAbsY & aluInT & aluDcp, -- DB iDCP abs,y + "0000" & "000000" & readAbsX & aluInXXX & aluXXX, -- DC iNOP abs,x + "0000" & "100011" & readAbsX & aluInT & aluCmp, -- DD CMP abs,x + "0000" & "100010" & rmwAbsX & aluInT & aluDec, -- DE DEC abs,x + "0000" & "100011" & rmwAbsX & aluInT & aluDcp, -- DF iDCP abs,x + -- AXYS NVDIZC addressing aluInput aluMode + "0000" & "100011" & immediate & aluInT & aluCpx, -- E0 CPX imm + "1000" & "110011" & readIndX & aluInT & aluSbc, -- E1 SBC (zp,x) + "0000" & "000000" & immediate & aluInXXX & aluXXX, -- E2 iNOP imm + "1000" & "110011" & rmwIndX & aluInT & aluIsc, -- E3 iISC (zp,x) + "0000" & "100011" & readZp & aluInT & aluCpx, -- E4 CPX zp + "1000" & "110011" & readZp & aluInT & aluSbc, -- E5 SBC zp + "0000" & "100010" & rmwZp & aluInT & aluInc, -- E6 INC zp + "1000" & "110011" & rmwZp & aluInT & aluIsc, -- E7 iISC zp + "0100" & "100010" & implied & aluInX & aluInc, -- E8 INX + "1000" & "110011" & immediate & aluInT & aluSbc, -- E9 SBC imm + "0000" & "000000" & implied & aluInXXX & aluXXX, -- EA NOP + "1000" & "110011" & immediate & aluInT & aluSbc, -- EB SBC imm (illegal opc) + "0000" & "100011" & readAbs & aluInT & aluCpx, -- EC CPX abs + "1000" & "110011" & readAbs & aluInT & aluSbc, -- ED SBC abs + "0000" & "100010" & rmwAbs & aluInT & aluInc, -- EE INC abs + "1000" & "110011" & rmwAbs & aluInT & aluIsc, -- EF iISC abs + "0000" & "000000" & relative & aluInXXX & aluXXX, -- F0 BEQ + "1000" & "110011" & readIndY & aluInT & aluSbc, -- F1 SBC (zp),y + "----" & "------" & xxxxxxxx & aluInXXX & aluXXX, -- F2 *** JAM *** + "1000" & "110011" & rmwIndY & aluInT & aluIsc, -- F3 iISC (zp),y + "0000" & "000000" & readZpX & aluInXXX & aluXXX, -- F4 iNOP zp,x + "1000" & "110011" & readZpX & aluInT & aluSbc, -- F5 SBC zp,x + "0000" & "100010" & rmwZpX & aluInT & aluInc, -- F6 INC zp,x + "1000" & "110011" & rmwZpX & aluInT & aluIsc, -- F7 iISC zp,x + "0000" & "001000" & implied & aluInSet & aluXXX, -- F8 SED + "1000" & "110011" & readAbsY & aluInT & aluSbc, -- F9 SBC abs,y + "0000" & "000000" & implied & aluInXXX & aluXXX, -- FA iNOP implied + "1000" & "110011" & rmwAbsY & aluInT & aluIsc, -- FB iISC abs,y + "0000" & "000000" & readAbsX & aluInXXX & aluXXX, -- FC iNOP abs,x + "1000" & "110011" & readAbsX & aluInT & aluSbc, -- FD SBC abs,x + "0000" & "100010" & rmwAbsX & aluInT & aluInc, -- FE INC abs,x + "1000" & "110011" & rmwAbsX & aluInT & aluIsc -- FF iISC abs,x + ); + signal opcInfo : decodedBitsDef; + signal nextOpcInfo : decodedBitsDef; -- Next opcode (decoded) + signal nextOpcInfoReg : decodedBitsDef; -- Next opcode (decoded) pipelined + signal theOpcode : unsigned(7 downto 0); + signal nextOpcode : unsigned(7 downto 0); + +-- Program counter + signal PC : unsigned(15 downto 0); -- Program counter + +-- Address generation + type nextAddrDef is ( + nextAddrHold, + nextAddrIncr, + nextAddrIncrL, -- Increment low bits only (zeropage accesses) + nextAddrIncrH, -- Increment high bits only (page-boundary) + nextAddrDecrH, -- Decrement high bits (branch backwards) + nextAddrPc, + nextAddrIrq, + nextAddrReset, + nextAddrAbs, + nextAddrAbsIndexed, + nextAddrZeroPage, + nextAddrZPIndexed, + nextAddrStack, + nextAddrRelative + ); + signal nextAddr : nextAddrDef; + signal myAddr : unsigned(15 downto 0); + signal myAddrIncr : unsigned(15 downto 0); + signal myAddrIncrH : unsigned(7 downto 0); + signal myAddrDecrH : unsigned(7 downto 0); + signal theWe : std_logic; + + signal irqActive : std_logic; + +-- Output register + signal doReg : unsigned(7 downto 0); + +-- Buffer register + signal T : unsigned(7 downto 0); + +-- General registers + signal A: unsigned(7 downto 0); -- Accumulator + signal X: unsigned(7 downto 0); -- Index X + signal Y: unsigned(7 downto 0); -- Index Y + signal S: unsigned(7 downto 0); -- stack pointer + +-- Status register + signal C: std_logic; -- Carry + signal Z: std_logic; -- Zero flag + signal I: std_logic; -- Interrupt flag + signal D: std_logic; -- Decimal mode + signal V: std_logic; -- Overflow + signal N: std_logic; -- Negative + +-- ALU + -- ALU input + signal aluInput : unsigned(7 downto 0); + signal aluCmpInput : unsigned(7 downto 0); + -- ALU output + signal aluRegisterOut : unsigned(7 downto 0); + signal aluRmwOut : unsigned(7 downto 0); + signal aluC : std_logic; + signal aluZ : std_logic; + signal aluV : std_logic; + signal aluN : std_logic; + -- Pipeline registers + signal aluInputReg : unsigned(7 downto 0); + signal aluCmpInputReg : unsigned(7 downto 0); + signal aluRmwReg : unsigned(7 downto 0); + signal aluNineReg : unsigned(7 downto 0); + signal aluCReg : std_logic; + signal aluZReg : std_logic; + signal aluVReg : std_logic; + signal aluNReg : std_logic; + +-- Indexing + signal indexOut : unsigned(8 downto 0); + +begin +processAluInput: process(clk, opcInfo, A, X, Y, T, S) + variable temp : unsigned(7 downto 0); + begin + temp := (others => '1'); + if opcInfo(opcInA) = '1' then + temp := temp and A; + end if; + if opcInfo(opcInE) = '1' then + temp := temp and (A or X"EE"); + end if; + if opcInfo(opcInX) = '1' then + temp := temp and X; + end if; + if opcInfo(opcInY) = '1' then + temp := temp and Y; + end if; + if opcInfo(opcInS) = '1' then + temp := temp and S; + end if; + if opcInfo(opcInT) = '1' then + temp := temp and T; + end if; + if opcInfo(opcInClear) = '1' then + temp := (others => '0'); + end if; + if rising_edge(clk) then + aluInputReg <= temp; + end if; + + aluInput <= temp; + if pipelineAluMux then + aluInput <= aluInputReg; + end if; + end process; + +processCmpInput: process(clk, opcInfo, A, X, Y) + variable temp : unsigned(7 downto 0); + begin + temp := (others => '1'); + if opcInfo(opcInCmp) = '1' then + temp := temp and A; + end if; + if opcInfo(opcInCpx) = '1' then + temp := temp and X; + end if; + if opcInfo(opcInCpy) = '1' then + temp := temp and Y; + end if; + if rising_edge(clk) then + aluCmpInputReg <= temp; + end if; + + aluCmpInput <= temp; + if pipelineAluMux then + aluCmpInput <= aluCmpInputReg; + end if; + end process; + + -- ALU consists of two parts + -- Read-Modify-Write or index instructions: INC/DEC/ASL/LSR/ROR/ROL + -- Accumulator instructions: ADC, SBC, EOR, AND, EOR, ORA + -- Some instructions are both RMW and accumulator so for most + -- instructions the rmw results are routed through accu alu too. +processAlu: process(clk, opcInfo, aluInput, aluCmpInput, A, T, irqActive, N, V, D, I, Z, C) + variable lowBits: unsigned(5 downto 0); + variable nineBits: unsigned(8 downto 0); + variable rmwBits: unsigned(8 downto 0); + + variable varC : std_logic; + variable varZ : std_logic; + variable varV : std_logic; + variable varN : std_logic; + begin + lowBits := (others => '-'); + nineBits := (others => '-'); + rmwBits := (others => '-'); + varV := aluInput(6); -- Default for BIT / PLP / RTI + + -- Shift unit + case opcInfo(aluMode1From to aluMode1To) is + when aluModeInp => + rmwBits := C & aluInput; + when aluModeP => + rmwBits := C & N & V & '1' & (not irqActive) & D & I & Z & C; + when aluModeInc => + rmwBits := C & (aluInput + 1); + when aluModeDec => + rmwBits := C & (aluInput - 1); + when aluModeAsl => + rmwBits := aluInput & "0"; + when aluModeFlg => + rmwBits := aluInput(0) & aluInput; + when aluModeLsr => + rmwBits := aluInput(0) & "0" & aluInput(7 downto 1); + when aluModeRol => + rmwBits := aluInput & C; + when aluModeRoR => + rmwBits := aluInput(0) & C & aluInput(7 downto 1); + when aluModeAnc => + rmwBits := (aluInput(7) and A(7)) & aluInput; + when others => + rmwBits := C & aluInput; + end case; + + -- ALU + case opcInfo(aluMode2From to aluMode2To) is + when aluModeAdc => + lowBits := ("0" & A(3 downto 0) & rmwBits(8)) + ("0" & rmwBits(3 downto 0) & "1"); + ninebits := ("0" & A) + ("0" & rmwBits(7 downto 0)) + (B"00000000" & rmwBits(8)); + when aluModeSbc => + lowBits := ("0" & A(3 downto 0) & rmwBits(8)) + ("0" & (not rmwBits(3 downto 0)) & "1"); + ninebits := ("0" & A) + ("0" & (not rmwBits(7 downto 0))) + (B"00000000" & rmwBits(8)); + when aluModeCmp => + ninebits := ("0" & aluCmpInput) + ("0" & (not rmwBits(7 downto 0))) + "000000001"; + when aluModeAnd => + ninebits := rmwBits(8) & (A and rmwBits(7 downto 0)); + when aluModeEor => + ninebits := rmwBits(8) & (A xor rmwBits(7 downto 0)); + when aluModeOra => + ninebits := rmwBits(8) & (A or rmwBits(7 downto 0)); + when others => + ninebits := rmwBits; + end case; + + if (opcInfo(aluMode1From to aluMode1To) = aluModeFlg) then + varZ := rmwBits(1); + elsif ninebits(7 downto 0) = X"00" then + varZ := '1'; + else + varZ := '0'; + end if; + + case opcInfo(aluMode2From to aluMode2To) is + when aluModeAdc => + -- decimal mode low bits correction, is done after setting Z flag. + if D = '1' then + if lowBits(5 downto 1) > 9 then + ninebits(3 downto 0) := ninebits(3 downto 0) + 6; + if lowBits(5) = '0' then + ninebits(8 downto 4) := ninebits(8 downto 4) + 1; + end if; + end if; + end if; + when others => + null; + end case; + + if (opcInfo(aluMode1From to aluMode1To) = aluModeBit) + or (opcInfo(aluMode1From to aluMode1To) = aluModeFlg) then + varN := rmwBits(7); + else + varN := nineBits(7); + end if; + varC := ninebits(8); + if opcInfo(aluMode2From to aluMode2To) = aluModeArr then + varC := aluInput(7); + varV := aluInput(7) xor aluInput(6); + end if; + + case opcInfo(aluMode2From to aluMode2To) is + when aluModeAdc => + -- decimal mode high bits correction, is done after setting Z and N flags + varV := (A(7) xor ninebits(7)) and (rmwBits(7) xor ninebits(7)); + if D = '1' then + if ninebits(8 downto 4) > 9 then + ninebits(8 downto 4) := ninebits(8 downto 4) + 6; + varC := '1'; + end if; + end if; + when aluModeSbc => + varV := (A(7) xor ninebits(7)) and ((not rmwBits(7)) xor ninebits(7)); + if D = '1' then + -- Check for borrow (lower 4 bits) + if lowBits(5) = '0' then + ninebits(3 downto 0) := ninebits(3 downto 0) - 6; + end if; + -- Check for borrow (upper 4 bits) + if ninebits(8) = '0' then + ninebits(8 downto 4) := ninebits(8 downto 4) - 6; + end if; + end if; + when aluModeArr => + if D = '1' then + if (("0" & aluInput(3 downto 0)) + ("0000" & aluInput(0))) > 5 then + ninebits(3 downto 0) := ninebits(3 downto 0) + 6; + end if; + if (("0" & aluInput(7 downto 4)) + ("0000" & aluInput(4))) > 5 then + ninebits(8 downto 4) := ninebits(8 downto 4) + 6; + varC := '1'; + else + varC := '0'; + end if; + end if; + when others => + null; + end case; + + if rising_edge(clk) then + aluRmwReg <= rmwBits(7 downto 0); + aluNineReg <= ninebits(7 downto 0); + aluCReg <= varC; + aluZReg <= varZ; + aluVReg <= varV; + aluNReg <= varN; + end if; + + aluRmwOut <= rmwBits(7 downto 0); + aluRegisterOut <= ninebits(7 downto 0); + aluC <= varC; + aluZ <= varZ; + aluV <= varV; + aluN <= varN; + if pipelineAluOut then + aluRmwOut <= aluRmwReg; + aluRegisterOut <= aluNineReg; + aluC <= aluCReg; + aluZ <= aluZReg; + aluV <= aluVReg; + aluN <= aluNReg; + end if; + end process; + +calcInterrupt: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + if theCpuCycle = cycleStack4 + or reset = '1' then + nmiReg <= '1'; + end if; + + if nextCpuCycle /= cycleBranchTaken + and nextCpuCycle /= opcodeFetch then + irqReg <= irq_n; + nmiEdge <= nmi_n; + if (nmiEdge = '1') and (nmi_n = '0') then + nmiReg <= '0'; + end if; + end if; + -- The 'or opcInfo(opcSetI)' prevents NMI immediately after BRK or IRQ. + -- Presumably this is done in the real 6502/6510 to prevent a double IRQ. + processIrq <= not ((nmiReg and (irqReg or I)) or opcInfo(opcIRQ)); + end if; + end if; + end process; + +calcNextOpcode: process(clk, di, reset, processIrq) + variable myNextOpcode : unsigned(7 downto 0); + begin + -- Next opcode is read from input unless a reset or IRQ is pending. + myNextOpcode := di; + if reset = '1' then + myNextOpcode := X"4C"; + elsif processIrq = '1' then + myNextOpcode := X"00"; + end if; + + nextOpcode <= myNextOpcode; + end process; + + nextOpcInfo <= opcodeInfoTable(to_integer(nextOpcode)); + process(clk) + begin + if rising_edge(clk) then + nextOpcInfoReg <= nextOpcInfo; + end if; + end process; + + -- Read bits and flags from opcodeInfoTable and store in opcInfo. + -- This info is used to control the execution of the opcode. +calcOpcInfo: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + if (reset = '1') or (theCpuCycle = opcodeFetch) then + opcInfo <= nextOpcInfo; + if pipelineOpcode then + opcInfo <= nextOpcInfoReg; + end if; + end if; + end if; + end if; + end process; + +calcTheOpcode: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + if theCpuCycle = opcodeFetch then + irqActive <= '0'; + if processIrq = '1' then + irqActive <= '1'; + end if; + -- Fetch opcode + theOpcode <= nextOpcode; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- State machine +-- ----------------------------------------------------------------------- + process(enable, theCpuCycle, opcInfo) + begin + updateRegisters <= false; + if enable = '1' then + if opcInfo(opcRti) = '1' then + if theCpuCycle = cycleRead then + updateRegisters <= true; + end if; + elsif theCpuCycle = opcodeFetch then + updateRegisters <= true; + end if; + end if; + end process; + + debugOpcode <= theOpcode; + process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + theCpuCycle <= nextCpuCycle; + end if; + if reset = '1' then + theCpuCycle <= cycle2; + end if; + end if; + end process; + + -- Determine the next cpu cycle. After the last cycle we always + -- go to opcodeFetch to get the next opcode. +calcNextCpuCycle: process(theCpuCycle, opcInfo, theOpcode, indexOut, T, N, V, C, Z) + begin + nextCpuCycle <= opcodeFetch; + + case theCpuCycle is + when opcodeFetch => + nextCpuCycle <= cycle2; + when cycle2 => + if opcInfo(opcBranch) = '1' then + if (N = theOpcode(5) and theOpcode(7 downto 6) = "00") + or (V = theOpcode(5) and theOpcode(7 downto 6) = "01") + or (C = theOpcode(5) and theOpcode(7 downto 6) = "10") + or (Z = theOpcode(5) and theOpcode(7 downto 6) = "11") then + -- Branch condition is true + nextCpuCycle <= cycleBranchTaken; + end if; + elsif (opcInfo(opcStackUp) = '1') then + nextCpuCycle <= cycleStack1; + elsif opcInfo(opcStackAddr) = '1' + and opcInfo(opcStackData) = '1' then + nextCpuCycle <= cycleStack2; + elsif opcInfo(opcStackAddr) = '1' then + nextCpuCycle <= cycleStack1; + elsif opcInfo(opcStackData) = '1' then + nextCpuCycle <= cycleWrite; + elsif opcInfo(opcAbsolute) = '1' then + nextCpuCycle <= cycle3; + elsif opcInfo(opcIndirect) = '1' then + if opcInfo(indexX) = '1' then + nextCpuCycle <= cyclePreIndirect; + else + nextCpuCycle <= cycleIndirect; + end if; + elsif opcInfo(opcZeroPage) = '1' then + if opcInfo(opcWrite) = '1' then + if (opcInfo(indexX) = '1') + or (opcInfo(indexY) = '1') then + nextCpuCycle <= cyclePreWrite; + else + nextCpuCycle <= cycleWrite; + end if; + else + if (opcInfo(indexX) = '1') + or (opcInfo(indexY) = '1') then + nextCpuCycle <= cyclePreRead; + else + nextCpuCycle <= cycleRead2; + end if; + end if; + elsif opcInfo(opcJump) = '1' then + nextCpuCycle <= cycleJump; + end if; + when cycle3 => + nextCpuCycle <= cycleRead; + if opcInfo(opcWrite) = '1' then + if (opcInfo(indexX) = '1') + or (opcInfo(indexY) = '1') then + nextCpuCycle <= cyclePreWrite; + else + nextCpuCycle <= cycleWrite; + end if; + end if; + if (opcInfo(opcIndirect) = '1') + and (opcInfo(indexX) = '1') then + if opcInfo(opcWrite) = '1' then + nextCpuCycle <= cycleWrite; + else + nextCpuCycle <= cycleRead2; + end if; + end if; + when cyclePreIndirect => + nextCpuCycle <= cycleIndirect; + when cycleIndirect => + nextCpuCycle <= cycle3; + when cycleBranchTaken => + if indexOut(8) /= T(7) then + -- Page boundary crossing during branch. + nextCpuCycle <= cycleBranchPage; + end if; + when cyclePreRead => + if opcInfo(opcZeroPage) = '1' then + nextCpuCycle <= cycleRead2; + end if; + when cycleRead => + if opcInfo(opcJump) = '1' then + nextCpuCycle <= cycleJump; + elsif indexOut(8) = '1' then + -- Page boundary crossing while indexed addressing. + nextCpuCycle <= cycleRead2; + elsif opcInfo(opcRmw) = '1' then + nextCpuCycle <= cycleRmw; + if opcInfo(indexX) = '1' + or opcInfo(indexY) = '1' then + -- 6510 needs extra cycle for indexed addressing + -- combined with RMW indexing + nextCpuCycle <= cycleRead2; + end if; + end if; + when cycleRead2 => + if opcInfo(opcRmw) = '1' then + nextCpuCycle <= cycleRmw; + end if; + when cycleRmw => + nextCpuCycle <= cycleWrite; + when cyclePreWrite => + nextCpuCycle <= cycleWrite; + when cycleStack1 => + nextCpuCycle <= cycleRead; + if opcInfo(opcStackAddr) = '1' then + nextCpuCycle <= cycleStack2; + end if; + when cycleStack2 => + nextCpuCycle <= cycleStack3; + if opcInfo(opcRti) = '1' then + nextCpuCycle <= cycleRead; + end if; + if opcInfo(opcStackData) = '0' + and opcInfo(opcStackUp) = '1' then + nextCpuCycle <= cycleJump; + end if; + when cycleStack3 => + nextCpuCycle <= cycleRead; + if opcInfo(opcStackData) = '0' + or opcInfo(opcStackUp) = '1' then + nextCpuCycle <= cycleJump; + elsif opcInfo(opcStackAddr) = '1' then + nextCpuCycle <= cycleStack4; + end if; + when cycleStack4 => + nextCpuCycle <= cycleRead; + when cycleJump => + if opcInfo(opcIncrAfter) = '1' then + -- Insert extra cycle + nextCpuCycle <= cycleEnd; + end if; + when others => + null; + end case; + end process; + +-- ----------------------------------------------------------------------- +-- T register +-- ----------------------------------------------------------------------- +calcT: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + case theCpuCycle is + when cycle2 => + T <= di; + when cycleStack1 | cycleStack2 => + if opcInfo(opcStackUp) = '1' then + -- Read from stack + T <= di; + end if; + when cycleIndirect | cycleRead | cycleRead2 => + T <= di; + when others => + null; + end case; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- A register +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateA) = '1' then + A <= aluRegisterOut; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- X register +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateX) = '1' then + X <= aluRegisterOut; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- Y register +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateY) = '1' then + Y <= aluRegisterOut; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- C flag +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateC) = '1' then + C <= aluC; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- Z flag +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateZ) = '1' then + Z <= aluZ; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- I flag +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateI) = '1' then + I <= aluInput(2); + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- D flag +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateD) = '1' then + D <= aluInput(3); + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- V flag +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateV) = '1' then + V <= aluV; + end if; + end if; + if enable = '1' then + if soReg = '1' and so_n = '0' then + V <= '1'; + end if; + soReg <= so_n; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- N flag +-- ----------------------------------------------------------------------- + process(clk) + begin + if rising_edge(clk) then + if updateRegisters then + if opcInfo(opcUpdateN) = '1' then + N <= aluN; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- Stack pointer +-- ----------------------------------------------------------------------- + process(clk) + variable sIncDec : unsigned(7 downto 0); + variable updateFlag : boolean; + begin + if rising_edge(clk) then + + if opcInfo(opcStackUp) = '1' then + sIncDec := S + 1; + else + sIncDec := S - 1; + end if; + + if enable = '1' then + updateFlag := false; + case nextCpuCycle is + when cycleStack1 => + if (opcInfo(opcStackUp) = '1') + or (opcInfo(opcStackData) = '1') then + updateFlag := true; + end if; + when cycleStack2 => + updateFlag := true; + when cycleStack3 => + updateFlag := true; + when cycleStack4 => + updateFlag := true; + when cycleRead => + if opcInfo(opcRti) = '1' then + updateFlag := true; + end if; + when cycleWrite => + if opcInfo(opcStackData) = '1' then + updateFlag := true; + end if; + when others => + null; + end case; + if updateFlag then + S <= sIncDec; + end if; + end if; + if updateRegisters then + if opcInfo(opcUpdateS) = '1' then + S <= aluRegisterOut; + end if; + end if; + end if; + end process; + +-- ----------------------------------------------------------------------- +-- Data out +-- ----------------------------------------------------------------------- +--calcDo: process(cpuNo, theCpuCycle, aluOut, PC, T) +calcDo: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + doReg <= aluRmwOut; + if opcInfo(opcInH) = '1' then + -- For illegal opcodes SHA, SHX, SHY, SHS + doReg <= aluRmwOut and myAddrIncrH; + end if; + + case nextCpuCycle is + when cycleStack2 => + if opcInfo(opcIRQ) = '1' + and irqActive = '0' then + doReg <= myAddrIncr(15 downto 8); + else + doReg <= PC(15 downto 8); + end if; + when cycleStack3 => + doReg <= PC(7 downto 0); + when cycleRmw => +-- do <= T; -- Read-modify-write write old value first. + doReg <= di; -- Read-modify-write write old value first. + when others => null; + end case; + end if; + end if; + end process; + do <= doReg; + + + +-- ----------------------------------------------------------------------- +-- Write enable +-- ----------------------------------------------------------------------- +calcWe: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + theWe <= '0'; + case nextCpuCycle is + when cycleStack1 => + if opcInfo(opcStackUp) = '0' + and ((opcInfo(opcStackAddr) = '0') + or (opcInfo(opcStackData) = '1')) then + theWe <= '1'; + end if; + when cycleStack2 | cycleStack3 | cycleStack4 => + if opcInfo(opcStackUp) = '0' then + theWe <= '1'; + end if; + when cycleRmw => + theWe <= '1'; + when cycleWrite => + theWe <= '1'; + when others => + null; + end case; + end if; + end if; + end process; + we <= theWe; + +-- ----------------------------------------------------------------------- +-- Program counter +-- ----------------------------------------------------------------------- +calcPC: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + case theCpuCycle is + when opcodeFetch => + PC <= myAddr; + when cycle2 => + if irqActive = '0' then + if opcInfo(opcSecondByte) = '1' then + PC <= myAddrIncr; + else + PC <= myAddr; + end if; + end if; + when cycle3 => + if opcInfo(opcAbsolute) = '1' then + PC <= myAddrIncr; + end if; + when others => + null; + end case; + end if; + end if; + end process; + debugPc <= PC; + +-- ----------------------------------------------------------------------- +-- Address generation +-- ----------------------------------------------------------------------- +calcNextAddr: process(theCpuCycle, opcInfo, indexOut, T, reset) + begin + nextAddr <= nextAddrIncr; + case theCpuCycle is + when cycle2 => + if opcInfo(opcStackAddr) = '1' + or opcInfo(opcStackData) = '1' then + nextAddr <= nextAddrStack; + elsif opcInfo(opcAbsolute) = '1' then + nextAddr <= nextAddrIncr; + elsif opcInfo(opcZeroPage) = '1' then + nextAddr <= nextAddrZeroPage; + elsif opcInfo(opcIndirect) = '1' then + nextAddr <= nextAddrZeroPage; + elsif opcInfo(opcSecondByte) = '1' then + nextAddr <= nextAddrIncr; + else + nextAddr <= nextAddrHold; + end if; + when cycle3 => + if (opcInfo(opcIndirect) = '1') + and (opcInfo(indexX) = '1') then + nextAddr <= nextAddrAbs; + else + nextAddr <= nextAddrAbsIndexed; + end if; + when cyclePreIndirect => + nextAddr <= nextAddrZPIndexed; + when cycleIndirect => + nextAddr <= nextAddrIncrL; + when cycleBranchTaken => + nextAddr <= nextAddrRelative; + when cycleBranchPage => + if T(7) = '0' then + nextAddr <= nextAddrIncrH; + else + nextAddr <= nextAddrDecrH; + end if; + when cyclePreRead => + nextAddr <= nextAddrZPIndexed; + when cycleRead => + nextAddr <= nextAddrPc; + if opcInfo(opcJump) = '1' then + -- Emulate 6510 bug, jmp(xxFF) fetches from same page. + -- Replace with nextAddrIncr if emulating 65C02 or later cpu. + nextAddr <= nextAddrIncrL; + elsif indexOut(8) = '1' then + nextAddr <= nextAddrIncrH; + elsif opcInfo(opcRmw) = '1' then + nextAddr <= nextAddrHold; + end if; + when cycleRead2 => + nextAddr <= nextAddrPc; + if opcInfo(opcRmw) = '1' then + nextAddr <= nextAddrHold; + end if; + when cycleRmw => + nextAddr <= nextAddrHold; + when cyclePreWrite => + nextAddr <= nextAddrHold; + if opcInfo(opcZeroPage) = '1' then + nextAddr <= nextAddrZPIndexed; + elsif indexOut(8) = '1' then + nextAddr <= nextAddrIncrH; + end if; + when cycleWrite => + nextAddr <= nextAddrPc; + when cycleStack1 => + nextAddr <= nextAddrStack; + when cycleStack2 => + nextAddr <= nextAddrStack; + when cycleStack3 => + nextAddr <= nextAddrStack; + if opcInfo(opcStackData) = '0' then + nextAddr <= nextAddrPc; + end if; + when cycleStack4 => + nextAddr <= nextAddrIrq; + when cycleJump => + nextAddr <= nextAddrAbs; + when others => + null; + end case; + if reset = '1' then + nextAddr <= nextAddrReset; + end if; + end process; + +indexAlu: process(opcInfo, myAddr, T, X, Y) + begin + if opcInfo(indexX) = '1' then + indexOut <= (B"0" & T) + (B"0" & X); + elsif opcInfo(indexY) = '1' then + indexOut <= (B"0" & T) + (B"0" & Y); + elsif opcInfo(opcBranch) = '1' then + indexOut <= (B"0" & T) + (B"0" & myAddr(7 downto 0)); + else + indexOut <= B"0" & T; + end if; + end process; + +calcAddr: process(clk) + begin + if rising_edge(clk) then + if enable = '1' then + case nextAddr is + when nextAddrIncr => myAddr <= myAddrIncr; + when nextAddrIncrL => myAddr(7 downto 0) <= myAddrIncr(7 downto 0); + when nextAddrIncrH => myAddr(15 downto 8) <= myAddrIncrH; + when nextAddrDecrH => myAddr(15 downto 8) <= myAddrDecrH; + when nextAddrPc => myAddr <= PC; + when nextAddrIrq => + myAddr <= X"FFFE"; + if nmiReg = '0' then + myAddr <= X"FFFA"; + end if; + when nextAddrReset => myAddr <= X"FFFC"; + when nextAddrAbs => myAddr <= di & T; + when nextAddrAbsIndexed => myAddr <= di & indexOut(7 downto 0); + when nextAddrZeroPage => myAddr <= "00000000" & di; + when nextAddrZPIndexed => myAddr <= "00000000" & indexOut(7 downto 0); + when nextAddrStack => myAddr <= "00000001" & S; + when nextAddrRelative => myAddr(7 downto 0) <= indexOut(7 downto 0); + when others => null; + end case; + end if; + end if; + end process; + + myAddrIncr <= myAddr + 1; + myAddrIncrH <= myAddr(15 downto 8) + 1; + myAddrDecrH <= myAddr(15 downto 8) - 1; + + addr <= myAddr; + + debugA <= A; + debugX <= X; + debugY <= Y; + debugS <= S; + +end architecture; + + diff --git a/Apple - 2_MiST/rtl/dac.vhd b/Apple - 2_MiST/rtl/dac.vhd new file mode 100644 index 00000000..1af6b8c1 --- /dev/null +++ b/Apple - 2_MiST/rtl/dac.vhd @@ -0,0 +1,65 @@ +-- +-- DAC.vhd +-- +-- Digital to analog convertor. +-- +-- Copyright (C)2001 SEILEBOST +-- All rights reserved. +-- +-- $Id: DAC.vhd, v0.2 2001/11/02 00:00:00 SEILEBOST $ +-- +-- from XAPP154.pdf & XAPP154.ZIP (XILINX APPLICATION) +-- +-- DAC 8 Bits ( method : sigma delta) +-- 2^N clock to convert with N = width of input +-- Ex : Bus 8 bits => 256 CLOCK master to convert an value. +-- Theorem Shannon : 2 x Fmax x 256 =< 16 MHz => Fmax = 31250 Hz +-- band of sound : 0 -> 20000 Hz : Ok !! + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.STD_LOGIC_ARITH.ALL; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +entity DAC is + Port ( CLK_DAC : in std_logic; + RST : in std_logic; + IN_DAC : in std_logic_vector(7 downto 0); + OUT_DAC : out std_logic ); +end DAC; + +architecture Behavioral of DAC is + +signal DeltaAdder : std_logic_vector(9 downto 0); +signal SigmaAdder : std_logic_vector(9 downto 0); +signal SigmaLatch : std_logic_vector(9 downto 0); +signal DeltaB : std_logic_vector(9 downto 0); + +begin + PROCESS(SigmaLatch, DeltaB) + BEGIN + DeltaB <= TRANSPORT ( SigmaLatch(9) & SigmaLatch(9) & "00000000"); + END PROCESS; + + PROCESS(IN_DAC, DeltaB, DeltaAdder) + BEGIN + DeltaAdder <= IN_DAC + DeltaB; + END PROCESS; + + PROCESS(DeltaAdder, SigmaLatch) + BEGIN + SigmaAdder <= DeltaAdder + SigmaLatch; + END PROCESS; + + PROCESS(CLK_DAC, RST) + BEGIN + if (RST = '1') then + SigmaLatch <= "0100000000"; + OUT_DAC <= '1'; + elsif (CLK_DAC'event and CLK_DAC = '1') then + SigmaLatch <= SigmaAdder; + OUT_DAC <= SigmaLatch(9); + end if; + END PROCESS; + +end Behavioral; diff --git a/Apple - 2_MiST/rtl/disk_ii.vhd b/Apple - 2_MiST/rtl/disk_ii.vhd new file mode 100644 index 00000000..8497abf2 --- /dev/null +++ b/Apple - 2_MiST/rtl/disk_ii.vhd @@ -0,0 +1,288 @@ +------------------------------------------------------------------------------- +-- +-- Disk II emulator +-- +-- This is read-only and only feeds "pre-nibblized" data to the processor +-- It has a single-track buffer and only supports one drive (1). +-- +-- Stephen A. Edwards, sedwards@cs.columbia.edu +-- +------------------------------------------------------------------------------- +-- +-- Each track is represented as 0x1A00 bytes +-- Each disk image consists of 35 * 0x1A00 bytes = 0x38A00 (227.5 K) +-- +-- X = $60 for slot 6 +-- +-- Off On +-- C080,X C081,X Phase 0 Head Stepper Motor Control +-- C082,X C083,X Phase 1 +-- C084,X C085,X Phase 2 +-- C086,X C087,X Phase 3 +-- C088,X C089,X Motor On +-- C08A,X C08B,X Select Drive 2 (select drive 1 when off) +-- C08C,X C08D,X Q6 (Shift/load?) +-- C08E,X C08F,X Q7 (Write request to drive) +-- +-- +-- Q7 Q6 +-- 0 0 Read +-- 0 1 Sense write protect +-- 1 0 Write +-- 1 1 Load Write Latch +-- +-- Reading a byte: +-- LDA $C08E,X set read mode +-- ... +-- READ LDA $C08C,X +-- BPL READ +-- +-- Sense write protect: +-- LDA $C08D,X +-- LDA $C08E,X +-- BMI PROTECTED +-- +-- Writing +-- STA $C08F,X set write mode +-- .. +-- LDA DATA +-- STA $C08D,X load byte to write +-- STA $C08C,X write byte to disk +-- +-- Data bytes must be written in 32 cycle loops. +-- +-- There are 70 phases for the head stepper and and 35 tracks, +-- i.e., two phase changes per track. +-- +-- The disk spins at 300 rpm; one new bit arrives every 4 us +-- The processor's clock is 1 MHz = 1 us, so it takes 8 * 4 = 32 cycles +-- for a new byte to arrive +-- +-- This corresponds to dividing the 2 MHz signal by 64 to get the byte clock +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity disk_ii is + port ( + CLK_14M : in std_logic; + CLK_2M : in std_logic; + PRE_PHASE_ZERO : in std_logic; + IO_SELECT : in std_logic; -- e.g., C600 - C6FF ROM + DEVICE_SELECT : in std_logic; -- e.g., C0E0 - C0EF I/O locations + RESET : in std_logic; + A : in unsigned(15 downto 0); + D_IN : in unsigned(7 downto 0); -- From 6502 + D_OUT : out unsigned(7 downto 0); -- To 6502 + TRACK : out unsigned(5 downto 0); -- Current track (0-34) + track_addr : out unsigned(13 downto 0); + D1_ACTIVE : out std_logic; -- Disk 1 motor on + D2_ACTIVE : out std_logic; -- Disk 2 motor on + ram_write_addr : in unsigned(13 downto 0); -- Address for track RAM + ram_di : in unsigned(7 downto 0); -- Data to track RAM + ram_we : in std_logic -- RAM write enable + ); +end disk_ii; + +architecture rtl of disk_ii is + + signal motor_phase : std_logic_vector(3 downto 0); + signal drive_on : std_logic; + signal drive2_select : std_logic; + signal q6, q7 : std_logic; + + signal rom_dout : unsigned(7 downto 0); + + -- Current phase of the head. This is in half-steps to assign + -- a unique position to the case, say, when both phase 0 and phase 1 are + -- on simultaneously. phase(7 downto 2) is the track number + signal phase : unsigned(7 downto 0); -- 0 - 139 + + -- Storage for one track worth of data in "nibblized" form + type track_ram is array(0 to 6655) of unsigned(7 downto 0); + -- Double-ported RAM for holding a track + signal track_memory : track_ram; + signal ram_do : unsigned(7 downto 0); + + -- Lower bit indicates whether disk data is "valid" or not + -- RAM address is track_byte_addr(14 downto 1) + -- This makes it look to the software like new data is constantly + -- being read into the shift register, which indicates the data is + -- not yet ready. + signal track_byte_addr : unsigned(14 downto 0); + signal read_disk : std_logic; -- When C08C accessed + +begin + + interpret_io : process (CLK_2M) + begin + if rising_edge(CLK_2M) then + if reset = '1' then + motor_phase <= (others => '0'); + drive_on <= '0'; + drive2_select <= '0'; + q6 <= '0'; + q7 <= '0'; + else + if PRE_PHASE_ZERO = '1' and DEVICE_SELECT = '1' then + if A(3) = '0' then -- C080 - C087 + motor_phase(TO_INTEGER(A(2 downto 1))) <= A(0); + else + case A(2 downto 1) is + when "00" => drive_on <= A(0); -- C088 - C089 + when "01" => drive2_select <= A(0); -- C08A - C08B + when "10" => q6 <= A(0); -- C08C - C08D + when "11" => q7 <= A(0); -- C08E - C08F + when others => null; + end case; + end if; + end if; + end if; + end if; + end process; + + D1_ACTIVE <= drive_on and not drive2_select; + D2_ACTIVE <= drive_on and drive2_select; + + -- There are two cases: + -- + -- Current phase is odd (between two poles) + -- | + -- V + -- -3-2-1 0 1 2 3 + -- X X X X + -- 0 1 2 3 + -- + -- + -- Current phase is even (under a pole) + -- | + -- V + -- -4-3-2-1 0 1 2 3 4 + -- X X X X X + -- 0 1 2 3 0 + -- + + update_phase : process (CLK_14M) + variable phase_change : integer; + variable new_phase : integer; + variable rel_phase : std_logic_vector(3 downto 0); + begin + if rising_edge(CLK_14M) then + if reset = '1' then + phase <= TO_UNSIGNED(70, 8); -- Deliberately odd to test reset + else + phase_change := 0; + new_phase := TO_INTEGER(phase); + rel_phase := motor_phase; + case phase(2 downto 1) is + when "00" => + rel_phase := rel_phase(1 downto 0) & rel_phase(3 downto 2); + when "01" => + rel_phase := rel_phase(2 downto 0) & rel_phase(3); + when "10" => null; + when "11" => + rel_phase := rel_phase(0) & rel_phase(3 downto 1); + when others => null; + end case; + + if phase(0) = '1' then -- Phase is odd + case rel_phase is + when "0000" => phase_change := 0; + when "0001" => phase_change := -3; + when "0010" => phase_change := -1; + when "0011" => phase_change := -2; + when "0100" => phase_change := 1; + when "0101" => phase_change := -1; + when "0110" => phase_change := 0; + when "0111" => phase_change := -1; + when "1000" => phase_change := 3; + when "1001" => phase_change := 0; + when "1010" => phase_change := 1; + when "1011" => phase_change := -3; + when "1111" => phase_change := 0; + when others => null; + end case; + else -- Phase is even + case rel_phase is + when "0000" => phase_change := 0; + when "0001" => phase_change := -2; + when "0010" => phase_change := 0; + when "0011" => phase_change := -1; + when "0100" => phase_change := 2; + when "0101" => phase_change := 0; + when "0110" => phase_change := 1; + when "0111" => phase_change := 0; + when "1000" => phase_change := 0; + when "1001" => phase_change := 1; + when "1010" => phase_change := 2; + when "1011" => phase_change := -2; + when "1111" => phase_change := 0; + when others => null; + end case; + end if; + + if new_phase + phase_change <= 0 then + new_phase := 0; + elsif new_phase + phase_change > 139 then + new_phase := 139; + else + new_phase := new_phase + phase_change; + end if; + phase <= TO_UNSIGNED(new_phase, 8); + end if; + end if; + end process; + + TRACK <= phase(7 downto 2); + + -- Dual-ported RAM holding the contents of the track + track_storage : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if ram_we = '1' then + track_memory(to_integer(ram_write_addr)) <= ram_di; + end if; + ram_do <= track_memory(to_integer(track_byte_addr(14 downto 1))); + end if; + end process; + + -- Go to the next byte when the disk is accessed or if the counter times out + read_head : process (CLK_2M) + variable byte_delay : unsigned(5 downto 0); -- Accounts for disk spin rate + begin + if rising_edge(CLK_2M) then + if reset = '1' then + track_byte_addr <= (others => '0'); + byte_delay := (others => '0'); + else + byte_delay := byte_delay - 1; + if (read_disk = '1' and PRE_PHASE_ZERO = '1') or byte_delay = 0 then + byte_delay := (others => '0'); + if track_byte_addr = X"33FE" then + track_byte_addr <= (others => '0'); + else + track_byte_addr <= track_byte_addr + 1; + end if; + end if; + end if; + end if; + end process; + + rom : entity work.disk_ii_rom port map ( + addr => A(7 downto 0), + clk => CLK_14M, + dout => rom_dout); + + read_disk <= '1' when DEVICE_SELECT = '1' and A(3 downto 0) = x"C" else + '0'; -- C08C + + D_OUT <= rom_dout when IO_SELECT = '1' else + ram_do when read_disk = '1' and track_byte_addr(0) = '0' else + (others => '0'); + + track_addr <= track_byte_addr(14 downto 1); + +end rtl; diff --git a/Apple - 2_MiST/rtl/disk_ii_rom.vhd b/Apple - 2_MiST/rtl/disk_ii_rom.vhd new file mode 100644 index 00000000..4711adab --- /dev/null +++ b/Apple - 2_MiST/rtl/disk_ii_rom.vhd @@ -0,0 +1,58 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity disk_ii_rom is + port ( + addr : in unsigned(7 downto 0); + clk : in std_logic; + dout : out unsigned(7 downto 0)); +end disk_ii_rom; + +architecture rtl of disk_ii_rom is + type rom_array is array(0 to 255) of unsigned(7 downto 0); + + constant ROM : rom_array := ( + X"a2", X"20", X"a0", X"00", X"a2", X"03", X"86", X"3c", + X"8a", X"0a", X"24", X"3c", X"f0", X"10", X"05", X"3c", + X"49", X"ff", X"29", X"7e", X"b0", X"08", X"4a", X"d0", + X"fb", X"98", X"9d", X"56", X"03", X"c8", X"e8", X"10", + X"e5", X"20", X"58", X"ff", X"ba", X"bd", X"00", X"01", + X"0a", X"0a", X"0a", X"0a", X"85", X"2b", X"aa", X"bd", + X"8e", X"c0", X"bd", X"8c", X"c0", X"bd", X"8a", X"c0", + X"bd", X"89", X"c0", X"a0", X"50", X"bd", X"80", X"c0", + X"98", X"29", X"03", X"0a", X"05", X"2b", X"aa", X"bd", + X"81", X"c0", X"a9", X"56", X"20", X"a8", X"fc", X"88", + X"10", X"eb", X"85", X"26", X"85", X"3d", X"85", X"41", + X"a9", X"08", X"85", X"27", X"18", X"08", X"bd", X"8c", + X"c0", X"10", X"fb", X"49", X"d5", X"d0", X"f7", X"bd", + X"8c", X"c0", X"10", X"fb", X"c9", X"aa", X"d0", X"f3", + X"ea", X"bd", X"8c", X"c0", X"10", X"fb", X"c9", X"96", + X"f0", X"09", X"28", X"90", X"df", X"49", X"ad", X"f0", + X"25", X"d0", X"d9", X"a0", X"03", X"85", X"40", X"bd", + X"8c", X"c0", X"10", X"fb", X"2a", X"85", X"3c", X"bd", + X"8c", X"c0", X"10", X"fb", X"25", X"3c", X"88", X"d0", + X"ec", X"28", X"c5", X"3d", X"d0", X"be", X"a5", X"40", + X"c5", X"41", X"d0", X"b8", X"b0", X"b7", X"a0", X"56", + X"84", X"3c", X"bc", X"8c", X"c0", X"10", X"fb", X"59", + X"d6", X"02", X"a4", X"3c", X"88", X"99", X"00", X"03", + X"d0", X"ee", X"84", X"3c", X"bc", X"8c", X"c0", X"10", + X"fb", X"59", X"d6", X"02", X"a4", X"3c", X"91", X"26", + X"c8", X"d0", X"ef", X"bc", X"8c", X"c0", X"10", X"fb", + X"59", X"d6", X"02", X"d0", X"87", X"a0", X"00", X"a2", + X"56", X"ca", X"30", X"fb", X"b1", X"26", X"5e", X"00", + X"03", X"2a", X"5e", X"00", X"03", X"2a", X"91", X"26", + X"c8", X"d0", X"ee", X"e6", X"27", X"e6", X"3d", X"a5", + X"3d", X"cd", X"00", X"08", X"a6", X"2b", X"90", X"db", + X"4c", X"01", X"08", X"00", X"00", X"00", X"00", X"00"); + +begin + +process (clk) + begin + if rising_edge(clk) then + dout <= ROM(TO_INTEGER(addr)); + end if; + end process; + +end rtl; diff --git a/Apple - 2_MiST/rtl/hq2x.sv b/Apple - 2_MiST/rtl/hq2x.sv new file mode 100644 index 00000000..f17732b6 --- /dev/null +++ b/Apple - 2_MiST/rtl/hq2x.sv @@ -0,0 +1,454 @@ +// +// +// Copyright (c) 2012-2013 Ludvig Strigeus +// Copyright (c) 2017 Sorgelig +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on + +`define BITS_TO_FIT(N) ( \ + N <= 2 ? 0 : \ + N <= 4 ? 1 : \ + N <= 8 ? 2 : \ + N <= 16 ? 3 : \ + N <= 32 ? 4 : \ + N <= 64 ? 5 : \ + N <= 128 ? 6 : \ + N <= 256 ? 7 : \ + N <= 512 ? 8 : \ + N <=1024 ? 9 : 10 ) + +module hq2x_in #(parameter LENGTH, parameter DWIDTH) +( + input clk, + + input [AWIDTH:0] rdaddr, + input rdbuf, + output[DWIDTH:0] q, + + input [AWIDTH:0] wraddr, + input wrbuf, + input [DWIDTH:0] data, + input wren +); + + localparam AWIDTH = `BITS_TO_FIT(LENGTH); + wire [DWIDTH:0] out[2]; + assign q = out[rdbuf]; + + hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]); + hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]); +endmodule + + +module hq2x_out #(parameter LENGTH, parameter DWIDTH) +( + input clk, + + input [AWIDTH:0] rdaddr, + input [1:0] rdbuf, + output[DWIDTH:0] q, + + input [AWIDTH:0] wraddr, + input [1:0] wrbuf, + input [DWIDTH:0] data, + input wren +); + + localparam AWIDTH = `BITS_TO_FIT(LENGTH*2); + wire [DWIDTH:0] out[4]; + assign q = out[rdbuf]; + + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf2(clk,data,rdaddr,wraddr,wren && (wrbuf == 2),out[2]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf3(clk,data,rdaddr,wraddr,wren && (wrbuf == 3),out[3]); +endmodule + + +module hq2x_buf #(parameter NUMWORDS, parameter AWIDTH, parameter DWIDTH) +( + input clock, + input [DWIDTH:0] data, + input [AWIDTH:0] rdaddress, + input [AWIDTH:0] wraddress, + input wren, + output [DWIDTH:0] q +); + + altsyncram altsyncram_component ( + .address_a (wraddress), + .clock0 (clock), + .data_a (data), + .wren_a (wren), + .address_b (rdaddress), + .q_b(q), + .aclr0 (1'b0), + .aclr1 (1'b0), + .addressstall_a (1'b0), + .addressstall_b (1'b0), + .byteena_a (1'b1), + .byteena_b (1'b1), + .clock1 (1'b1), + .clocken0 (1'b1), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .data_b ({(DWIDTH+1){1'b1}}), + .eccstatus (), + .q_a (), + .rden_a (1'b1), + .rden_b (1'b1), + .wren_b (1'b0)); + defparam + altsyncram_component.address_aclr_b = "NONE", + altsyncram_component.address_reg_b = "CLOCK0", + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_input_b = "BYPASS", + altsyncram_component.clock_enable_output_b = "BYPASS", + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = NUMWORDS, + altsyncram_component.numwords_b = NUMWORDS, + altsyncram_component.operation_mode = "DUAL_PORT", + altsyncram_component.outdata_aclr_b = "NONE", + altsyncram_component.outdata_reg_b = "UNREGISTERED", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE", + altsyncram_component.widthad_a = AWIDTH+1, + altsyncram_component.widthad_b = AWIDTH+1, + altsyncram_component.width_a = DWIDTH+1, + altsyncram_component.width_b = DWIDTH+1, + altsyncram_component.width_byteena_a = 1; + +endmodule + +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +module DiffCheck +( + input [17:0] rgb1, + input [17:0] rgb2, + output result +); + + wire [5:0] r = rgb1[5:1] - rgb2[5:1]; + wire [5:0] g = rgb1[11:7] - rgb2[11:7]; + wire [5:0] b = rgb1[17:13] - rgb2[17:13]; + wire [6:0] t = $signed(r) + $signed(b); + wire [6:0] gx = {g[5], g}; + wire [7:0] y = $signed(t) + $signed(gx); + wire [6:0] u = $signed(r) - $signed(b); + wire [7:0] v = $signed({g, 1'b0}) - $signed(t); + + // if y is inside (-24..24) + wire y_inside = (y < 8'h18 || y >= 8'he8); + + // if u is inside (-4, 4) + wire u_inside = (u < 7'h4 || u >= 7'h7c); + + // if v is inside (-6, 6) + wire v_inside = (v < 8'h6 || v >= 8'hfA); + assign result = !(y_inside && u_inside && v_inside); +endmodule + +module InnerBlend +( + input [8:0] Op, + input [5:0] A, + input [5:0] B, + input [5:0] C, + output [5:0] O +); + + function [8:0] mul6x3; + input [5:0] op1; + input [2:0] op2; + begin + mul6x3 = 9'd0; + if(op2[0]) mul6x3 = mul6x3 + op1; + if(op2[1]) mul6x3 = mul6x3 + {op1, 1'b0}; + if(op2[2]) mul6x3 = mul6x3 + {op1, 2'b00}; + end + endfunction + + wire OpOnes = Op[4]; + wire [8:0] Amul = mul6x3(A, Op[7:5]); + wire [8:0] Bmul = mul6x3(B, {Op[3:2], 1'b0}); + wire [8:0] Cmul = mul6x3(C, {Op[1:0], 1'b0}); + wire [8:0] At = Amul; + wire [8:0] Bt = (OpOnes == 0) ? Bmul : {3'b0, B}; + wire [8:0] Ct = (OpOnes == 0) ? Cmul : {3'b0, C}; + wire [9:0] Res = {At, 1'b0} + Bt + Ct; + assign O = Op[8] ? A : Res[9:4]; +endmodule + +module Blend +( + input [5:0] rule, + input disable_hq2x, + input [17:0] E, + input [17:0] A, + input [17:0] B, + input [17:0] D, + input [17:0] F, + input [17:0] H, + output [17:0] Result +); + + reg [1:0] input_ctrl; + reg [8:0] op; + localparam BLEND0 = 9'b1_xxx_x_xx_xx; // 0: A + localparam BLEND1 = 9'b0_110_0_10_00; // 1: (A * 12 + B * 4) >> 4 + localparam BLEND2 = 9'b0_100_0_10_10; // 2: (A * 8 + B * 4 + C * 4) >> 4 + localparam BLEND3 = 9'b0_101_0_10_01; // 3: (A * 10 + B * 4 + C * 2) >> 4 + localparam BLEND4 = 9'b0_110_0_01_01; // 4: (A * 12 + B * 2 + C * 2) >> 4 + localparam BLEND5 = 9'b0_010_0_11_11; // 5: (A * 4 + (B + C) * 6) >> 4 + localparam BLEND6 = 9'b0_111_1_xx_xx; // 6: (A * 14 + B + C) >> 4 + localparam AB = 2'b00; + localparam AD = 2'b01; + localparam DB = 2'b10; + localparam BD = 2'b11; + wire is_diff; + DiffCheck diff_checker(rule[1] ? B : H, rule[0] ? D : F, is_diff); + + always @* begin + case({!is_diff, rule[5:2]}) + 1,17: {op, input_ctrl} = {BLEND1, AB}; + 2,18: {op, input_ctrl} = {BLEND1, DB}; + 3,19: {op, input_ctrl} = {BLEND1, BD}; + 4,20: {op, input_ctrl} = {BLEND2, DB}; + 5,21: {op, input_ctrl} = {BLEND2, AB}; + 6,22: {op, input_ctrl} = {BLEND2, AD}; + + 8: {op, input_ctrl} = {BLEND0, 2'bxx}; + 9: {op, input_ctrl} = {BLEND0, 2'bxx}; + 10: {op, input_ctrl} = {BLEND0, 2'bxx}; + 11: {op, input_ctrl} = {BLEND1, AB}; + 12: {op, input_ctrl} = {BLEND1, AB}; + 13: {op, input_ctrl} = {BLEND1, AB}; + 14: {op, input_ctrl} = {BLEND1, DB}; + 15: {op, input_ctrl} = {BLEND1, BD}; + + 24: {op, input_ctrl} = {BLEND2, DB}; + 25: {op, input_ctrl} = {BLEND5, DB}; + 26: {op, input_ctrl} = {BLEND6, DB}; + 27: {op, input_ctrl} = {BLEND2, DB}; + 28: {op, input_ctrl} = {BLEND4, DB}; + 29: {op, input_ctrl} = {BLEND5, DB}; + 30: {op, input_ctrl} = {BLEND3, BD}; + 31: {op, input_ctrl} = {BLEND3, DB}; + default: {op, input_ctrl} = 11'bx; + endcase + + // Setting op[8] effectively disables HQ2X because blend will always return E. + if (disable_hq2x) op[8] = 1; + end + + // Generate inputs to the inner blender. Valid combinations. + // 00: E A B + // 01: E A D + // 10: E D B + // 11: E B D + wire [17:0] Input1 = E; + wire [17:0] Input2 = !input_ctrl[1] ? A : + !input_ctrl[0] ? D : B; + + wire [17:0] Input3 = !input_ctrl[0] ? B : D; + InnerBlend inner_blend1(op, Input1[5:0], Input2[5:0], Input3[5:0], Result[5:0]); + InnerBlend inner_blend2(op, Input1[11:6], Input2[11:6], Input3[11:6], Result[11:6]); + InnerBlend inner_blend3(op, Input1[17:12], Input2[17:12], Input3[17:12], Result[17:12]); +endmodule + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +module Hq2x #(parameter LENGTH, parameter HALF_DEPTH) +( + input clk, + input ce_x4, + input [DWIDTH:0] inputpixel, + input mono, + input disable_hq2x, + input reset_frame, + input reset_line, + input [1:0] read_y, + input [AWIDTH+1:0] read_x, + output [DWIDTH:0] outpixel +); + + +localparam AWIDTH = `BITS_TO_FIT(LENGTH); +localparam DWIDTH = HALF_DEPTH ? 8 : 17; + +wire [5:0] hqTable[256] = '{ + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39, + 19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 35, 35, 23, 15, 7, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43, + 19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 51, 35, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 35, 35, 23, 61, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 7, 35, 23, 61, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 58, 23, 15, 51, 35, 23, 61, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 39, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 39, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 7, 35, 23, 15, 7, 43 +}; + +reg [17:0] Prev0, Prev1, Prev2, Curr0, Curr1, Next0, Next1, Next2; +reg [17:0] A, B, D, F, G, H; +reg [7:0] pattern, nextpatt; +reg [1:0] i; +reg [7:0] y; + +wire curbuf = y[0]; +reg prevbuf = 0; +wire iobuf = !curbuf; + +wire diff0, diff1; +DiffCheck diffcheck0(Curr1, (i == 0) ? Prev0 : (i == 1) ? Curr0 : (i == 2) ? Prev2 : Next1, diff0); +DiffCheck diffcheck1(Curr1, (i == 0) ? Prev1 : (i == 1) ? Next0 : (i == 2) ? Curr2 : Next2, diff1); + +wire [7:0] new_pattern = {diff1, diff0, pattern[7:2]}; + +wire [17:0] X = (i == 0) ? A : (i == 1) ? Prev1 : (i == 2) ? Next1 : G; +wire [17:0] blend_result; +Blend blender(hqTable[nextpatt], disable_hq2x, Curr0, X, B, D, F, H, blend_result); + +reg Curr2_addr1; +reg [AWIDTH:0] Curr2_addr2; +wire [17:0] Curr2 = HALF_DEPTH ? h2rgb(Curr2tmp) : Curr2tmp; +wire [DWIDTH:0] Curr2tmp; + +reg [AWIDTH:0] wrin_addr2; +reg [DWIDTH:0] wrpix; +reg wrin_en; + +function [17:0] h2rgb; + input [8:0] v; +begin + h2rgb = mono ? {v[5:3],v[2:0], v[5:3],v[2:0], v[5:3],v[2:0]} : {v[8:6],v[8:6],v[5:3],v[5:3],v[2:0],v[2:0]}; +end +endfunction + +function [8:0] rgb2h; + input [17:0] v; +begin + rgb2h = mono ? {3'b000, v[17:15], v[14:12]} : {v[17:15], v[11:9], v[5:3]}; +end +endfunction + +hq2x_in #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_in +( + .clk(clk), + + .rdaddr(Curr2_addr2), + .rdbuf(Curr2_addr1), + .q(Curr2tmp), + + .wraddr(wrin_addr2), + .wrbuf(iobuf), + .data(wrpix), + .wren(wrin_en) +); + +reg [1:0] wrout_addr1; +reg [AWIDTH+1:0] wrout_addr2; +reg wrout_en; +reg [DWIDTH:0] wrdata; + +hq2x_out #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_out +( + .clk(clk), + + .rdaddr(read_x), + .rdbuf(read_y), + .q(outpixel), + + .wraddr(wrout_addr2), + .wrbuf(wrout_addr1), + .data(wrdata), + .wren(wrout_en) +); + +always @(posedge clk) begin + reg [AWIDTH:0] offs; + reg old_reset_line; + reg old_reset_frame; + + wrout_en <= 0; + wrin_en <= 0; + + if(ce_x4) begin + + pattern <= new_pattern; + + if(~&offs) begin + if (i == 0) begin + Curr2_addr1 <= prevbuf; + Curr2_addr2 <= offs; + end + if (i == 1) begin + Prev2 <= Curr2; + Curr2_addr1 <= curbuf; + Curr2_addr2 <= offs; + end + if (i == 2) begin + Next2 <= HALF_DEPTH ? h2rgb(inputpixel) : inputpixel; + wrpix <= inputpixel; + wrin_addr2 <= offs; + wrin_en <= 1; + end + if (i == 3) begin + offs <= offs + 1'd1; + end + + if(HALF_DEPTH) wrdata <= rgb2h(blend_result); + else wrdata <= blend_result; + + wrout_addr1 <= {curbuf, i[1]}; + wrout_addr2 <= {offs, i[1]^i[0]}; + wrout_en <= 1; + end + + if(i==3) begin + nextpatt <= {new_pattern[7:6], new_pattern[3], new_pattern[5], new_pattern[2], new_pattern[4], new_pattern[1:0]}; + {A, G} <= {Prev0, Next0}; + {B, F, H, D} <= {Prev1, Curr2, Next1, Curr0}; + {Prev0, Prev1} <= {Prev1, Prev2}; + {Curr0, Curr1} <= {Curr1, Curr2}; + {Next0, Next1} <= {Next1, Next2}; + end else begin + nextpatt <= {nextpatt[5], nextpatt[3], nextpatt[0], nextpatt[6], nextpatt[1], nextpatt[7], nextpatt[4], nextpatt[2]}; + {B, F, H, D} <= {F, H, D, B}; + end + + i <= i + 1'b1; + if(old_reset_line && ~reset_line) begin + old_reset_frame <= reset_frame; + offs <= 0; + i <= 0; + y <= y + 1'd1; + prevbuf <= curbuf; + if(old_reset_frame & ~reset_frame) begin + y <= 0; + prevbuf <= 0; + end + end + + old_reset_line <= reset_line; + end +end + +endmodule // Hq2x diff --git a/Apple - 2_MiST/rtl/keyboard.vhd b/Apple - 2_MiST/rtl/keyboard.vhd new file mode 100644 index 00000000..4c5a72b4 --- /dev/null +++ b/Apple - 2_MiST/rtl/keyboard.vhd @@ -0,0 +1,390 @@ +------------------------------------------------------------------------------- +-- +-- PS/2 Keyboard interface for the Apple ][ +-- +-- Stephen A. Edwards, sedwards@cs.columbia.edu +-- After an original by Alex Freed +-- i18n & French keyboard by Michel Stempin +-- +------------------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity keyboard is + + generic ( + KEYMAP : string := "EN-us" -- English US keymap + -- KEYMAP : string := "FR-fr" -- French keymap + ); + + port ( + PS2_Clk : in std_logic; -- From PS/2 port + PS2_Data : in std_logic; -- From PS/2 port + CLK_14M : in std_logic; + read : in std_logic; -- Read strobe + reset : in std_logic; + K : out unsigned(7 downto 0) -- Latched, decoded keyboard data + ); +end keyboard; + +architecture rtl of keyboard is + + signal code, latched_code : unsigned(7 downto 0); + signal code_available : std_logic; + signal ascii : unsigned(7 downto 0); -- decoded + signal shifted_code : unsigned(11 downto 0); + + signal key_pressed : std_logic; -- Key pressed & not read + signal ctrl, shift, alt : std_logic; + + -- Special PS/2 keyboard codes + constant KEY_UP_CODE : unsigned(7 downto 0) := X"F0"; + constant EXTENDED_CODE : unsigned(7 downto 0) := X"E0"; + constant LEFT_SHIFT : unsigned(7 downto 0) := X"12"; + constant RIGHT_SHIFT : unsigned(7 downto 0) := X"59"; + constant LEFT_CTRL : unsigned(7 downto 0) := X"14"; + constant ALT_GR : unsigned(7 downto 0) := X"11"; + + type states is (IDLE, + HAVE_CODE, + DECODE, + GOT_KEY_UP_CODE, + GOT_KEY_UP2, + GOT_KEY_UP3, + KEY_UP, + NORMAL_KEY + ); + + signal state, next_state : states; + +begin + + ps2_controller : entity work.PS2_Ctrl port map ( + Clk => CLK_14M, + Reset => reset, + PS2_Clk => PS2_Clk, + PS2_Data => PS2_Data, + DoRead => code_available, + Scan_DAV => code_available, + Scan_Code => code); + + K <= key_pressed & "00" & ascii(4 downto 0) when ctrl = '1' else + key_pressed & ascii(6 downto 0); + + shift_ctrl : process (CLK_14M, reset) + begin + if reset = '1' then + shift <= '0'; + ctrl <= '0'; + elsif rising_edge(CLK_14M) then + if state = HAVE_CODE then + if code = LEFT_SHIFT or code = RIGHT_SHIFT then + shift <= '1'; + elsif code = LEFT_CTRL then + ctrl <= '1'; + elsif code = ALT_GR then + alt <= '1'; + end if; + elsif state = KEY_UP then + if code = LEFT_SHIFT or code = RIGHT_SHIFT then + shift <= '0'; + elsif code = LEFT_CTRL then + ctrl <= '0'; + elsif code = ALT_GR then + alt <= '0'; + end if; + end if; + end if; + end process shift_ctrl; + + fsm : process (CLK_14M, reset) + begin + if reset = '1' then + state <= IDLE; + latched_code <= (others => '0'); + key_pressed <= '0'; + elsif rising_edge(CLK_14M) then + state <= next_state; + if read = '1' then key_pressed <= '0'; end if; + if state = NORMAL_KEY then + latched_code <= code ; + key_pressed <= '1'; + end if; + end if; + end process fsm; + + fsm_next_state : process (code, code_available, state) + begin + next_state <= state; + case state is + when IDLE => + if code_available = '1' then next_state <= HAVE_CODE; end if; + + when HAVE_CODE => + next_state <= DECODE; + + when DECODE => + if code = KEY_UP_CODE then + next_state <= GOT_KEY_UP_CODE; + elsif code = EXTENDED_CODE then -- Treat extended codes as normal + next_state <= IDLE; + elsif code = LEFT_SHIFT or code = RIGHT_SHIFT or code = LEFT_CTRL then + next_state <= IDLE; + else + next_state <= NORMAL_KEY; + end if; + + when GOT_KEY_UP_CODE => + next_state <= GOT_KEY_UP2; + + when GOT_KEY_UP2 => + next_state <= GOT_KEY_UP3; + + when GOT_KEY_UP3 => + if code_available = '1' then + next_state <= KEY_UP; + end if; + + when KEY_UP | NORMAL_KEY => + next_state <= IDLE; + end case; + end process fsm_next_state; + + -- PS/2 scancode to ASCII translation + + shifted_code <= "00" & alt & shift & latched_code; + + EN_us: if KEYMAP = "EN-us" generate + with shifted_code select + ascii <= + X"08" when X"066", -- Backspace ("backspace" key) + X"08" when X"166", -- Backspace ("backspace" key) + X"09" when X"00d", -- Horizontal Tab + X"09" when X"10d", -- Horizontal Tab + X"0d" when X"05a", -- Carriage return ("enter" key) + X"0d" when X"15a", -- Carriage return ("enter" key) + X"1b" when X"076", -- Escape ("esc" key) + X"1b" when X"176", -- Escape ("esc" key) + X"20" when X"029", -- Space + X"20" when X"129", -- Space + X"21" when X"116", -- ! + X"22" when X"152", -- " + X"23" when X"126", -- # + X"24" when X"125", -- $ + X"25" when X"12e", -- + X"26" when X"13d", -- + X"27" when X"052", -- + X"28" when X"146", -- + X"29" when X"145", -- + X"2a" when X"13e", -- * + X"2b" when X"155", -- + + X"2c" when X"041", -- , + X"2d" when X"04e", -- - + X"2e" when X"049", -- . + X"2f" when X"04a", -- / + X"30" when X"045", -- 0 + X"31" when X"016", -- 1 + X"32" when X"01e", -- 2 + X"33" when X"026", -- 3 + X"34" when X"025", -- 4 + X"35" when X"02e", -- 5 + X"36" when X"036", -- 6 + X"37" when X"03d", -- 7 + X"38" when X"03e", -- 8 + X"39" when X"046", -- 9 + X"3a" when X"14c", -- : + X"3b" when X"04c", -- ; + X"3c" when X"141", -- < + X"3d" when X"055", -- = + X"3e" when X"149", -- > + X"3f" when X"14a", -- ? + X"40" when X"11e", -- @ + X"41" when X"11c", -- A + X"42" when X"132", -- B + X"43" when X"121", -- C + X"44" when X"123", -- D + X"45" when X"124", -- E + X"46" when X"12b", -- F + X"47" when X"134", -- G + X"48" when X"133", -- H + X"49" when X"143", -- I + X"4a" when X"13b", -- J + X"4b" when X"142", -- K + X"4c" when X"14b", -- L + X"4d" when X"13a", -- M + X"4e" when X"131", -- N + X"4f" when X"144", -- O + X"50" when X"14d", -- P + X"51" when X"115", -- Q + X"52" when X"12d", -- R + X"53" when X"11b", -- S + X"54" when X"12c", -- T + X"55" when X"13c", -- U + X"56" when X"12a", -- V + X"57" when X"11d", -- W + X"58" when X"122", -- X + X"59" when X"135", -- Y + X"5a" when X"11a", -- Z + X"5b" when X"054", -- [ + X"5c" when X"05d", -- \ + X"5d" when X"05b", -- ] + X"5e" when X"136", -- ^ + X"5f" when X"14e", -- _ + X"60" when X"00e", -- ` + X"41" when X"01c", -- A + X"42" when X"032", -- B + X"43" when X"021", -- C + X"44" when X"023", -- D + X"45" when X"024", -- E + X"46" when X"02b", -- F + X"47" when X"034", -- G + X"48" when X"033", -- H + X"49" when X"043", -- I + X"4a" when X"03b", -- J + X"4b" when X"042", -- K + X"4c" when X"04b", -- L + X"4d" when X"03a", -- M + X"4e" when X"031", -- N + X"4f" when X"044", -- O + X"50" when X"04d", -- P + X"51" when X"015", -- Q + X"52" when X"02d", -- R + X"53" when X"01b", -- S + X"54" when X"02c", -- T + X"55" when X"03c", -- U + X"56" when X"02a", -- V + X"57" when X"01d", -- W + X"58" when X"022", -- X + X"59" when X"035", -- Y + X"5a" when X"01a", -- Z + X"7b" when X"154", -- { + X"7c" when X"15d", -- | + X"7d" when X"15b", -- } + X"7e" when X"10e", -- ~ + X"7f" when X"071", -- (Delete OR DEL on numeric keypad) + X"15" when X"074", -- right arrow (cntrl U) + X"08" when X"06b", -- left arrow (BS) + X"0B" when X"075", -- (up arrow) + X"0A" when X"072", -- (down arrow, ^J, LF) + X"7f" when X"171", -- (Delete OR DEL on numeric keypad) + X"00" when others; + end generate EN_us; + + FR_fr: if KEYMAP = "FR-fr" generate + with shifted_code select + ascii <= + X"08" when X"066", -- Backspace ("backspace" key) + X"08" when X"166", -- Backspace ("backspace" key) + X"09" when X"00d", -- Horizontal Tab + X"09" when X"10d", -- Horizontal Tab + X"0d" when X"05a", -- Carriage return ("enter" key) + X"0d" when X"15a", -- Carriage return ("enter" key) + X"1b" when X"076", -- Escape ("esc" key) + X"1b" when X"176", -- Escape ("esc" key) + X"20" when X"029", -- Space + X"20" when X"129", -- Space + X"21" when X"04a", -- ! + X"22" when X"026", -- " + X"23" when X"226", -- # + X"24" when X"05b", -- $ + X"25" when X"152", -- % + X"26" when X"016", -- & + X"27" when X"025", -- ' + X"28" when X"02e", -- ( + X"29" when X"04e", -- ) + X"2a" when X"05d", -- * + X"2b" when X"155", -- + + X"2c" when X"03a", -- , + X"2d" when X"036", -- - + X"2e" when X"141", -- . + X"2f" when X"149", -- / + X"30" when X"145", -- 0 + X"31" when X"116", -- 1 + X"32" when X"11e", -- 2 + X"33" when X"126", -- 3 + X"34" when X"125", -- 4 + X"35" when X"12e", -- 5 + X"36" when X"136", -- 6 + X"37" when X"13d", -- 7 + X"38" when X"13e", -- 8 + X"39" when X"146", -- 9 + X"3a" when X"049", -- : + X"3b" when X"041", -- ; + X"3c" when X"061", -- < + X"3d" when X"055", -- = + X"3e" when X"161", -- > + X"3f" when X"13a", -- ? + X"40" when X"245", -- @ + X"41" when X"115", -- A + X"42" when X"132", -- B + X"43" when X"121", -- C + X"44" when X"123", -- D + X"45" when X"124", -- E + X"46" when X"12b", -- F + X"47" when X"134", -- G + X"48" when X"133", -- H + X"49" when X"143", -- I + X"4a" when X"13b", -- J + X"4b" when X"142", -- K + X"4c" when X"14b", -- L + X"4d" when X"14c", -- M + X"4e" when X"131", -- N + X"4f" when X"144", -- O + X"50" when X"14d", -- P + X"51" when X"11c", -- Q + X"52" when X"12d", -- R + X"53" when X"11b", -- S + X"54" when X"12c", -- T + X"55" when X"13c", -- U + X"56" when X"12a", -- V + X"57" when X"11a", -- W + X"58" when X"122", -- X + X"59" when X"135", -- Y + X"5a" when X"11d", -- Z + X"5b" when X"22e", -- [ + X"5c" when X"23e", -- \ + X"5d" when X"24e", -- ] + X"5e" when X"054", -- ^ + X"5f" when X"03e", -- _ + X"60" when X"23d", -- ` + X"41" when X"015", -- A + X"42" when X"032", -- B + X"43" when X"021", -- C + X"44" when X"023", -- D + X"45" when X"024", -- E + X"46" when X"02b", -- F + X"47" when X"034", -- G + X"48" when X"033", -- H + X"49" when X"043", -- I + X"4a" when X"03b", -- J + X"4b" when X"042", -- K + X"4c" when X"04b", -- L + X"4d" when X"04c", -- M + X"4e" when X"031", -- N + X"4f" when X"044", -- O + X"50" when X"04d", -- P + X"51" when X"01c", -- Q + X"52" when X"02d", -- R + X"53" when X"01b", -- S + X"54" when X"02c", -- T + X"55" when X"03c", -- U + X"56" when X"02a", -- V + X"57" when X"01a", -- W + X"58" when X"022", -- X + X"59" when X"035", -- Y + X"5a" when X"01d", -- Z + X"7b" when X"225", -- { + X"7c" when X"236", -- | + X"7d" when X"255", -- } + X"7e" when X"21e", -- ~ + X"7f" when X"071", -- (Delete OR DEL on numeric keypad) + X"15" when X"074", -- right arrow (cntrl U) + X"08" when X"06b", -- left arrow (BS) + X"0B" when X"075", -- (up arrow) + X"0A" when X"072", -- (down arrow, ^J, LF) + X"7f" when X"171", -- (Delete OR DEL on numeric keypad) + X"00" when others; + end generate FR_fr; + +end rtl; diff --git a/Apple - 2_MiST/rtl/main_roms.vhd b/Apple - 2_MiST/rtl/main_roms.vhd new file mode 100644 index 00000000..8dc346d1 --- /dev/null +++ b/Apple - 2_MiST/rtl/main_roms.vhd @@ -0,0 +1,2075 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity main_roms is + port ( + addr : in unsigned(13 downto 0); + clk : in std_logic; + dout : out unsigned(7 downto 0)); +end main_roms; + +-- Hack: In Quartus II 9.1, memory blocks must be a power of 2 +-- in order to be inferred as altsyncram blocks +architecture rtl of main_roms is + type rom_array is array(0 to 16383) of unsigned(7 downto 0); + + constant ROM : rom_array := ( + X"6f", X"d8", X"65", X"d7", X"f8", X"dc", X"94", X"d9", + X"b1", X"db", X"30", X"f3", X"d8", X"df", X"e1", X"db", + X"8f", X"f3", X"98", X"f3", X"e4", X"f1", X"dd", X"f1", + X"d4", X"f1", X"24", X"f2", X"31", X"f2", X"40", X"f2", + X"d7", X"f3", X"e1", X"f3", X"e8", X"f6", X"fd", X"f6", + X"68", X"f7", X"6e", X"f7", X"e6", X"f7", X"57", X"fc", + X"20", X"f7", X"26", X"f7", X"74", X"f7", X"6c", X"f2", + X"6e", X"f2", X"72", X"f2", X"76", X"f2", X"7f", X"f2", + X"4e", X"f2", X"6a", X"d9", X"55", X"f2", X"85", X"f2", + X"a5", X"f2", X"ca", X"f2", X"17", X"f3", X"bb", X"f3", + X"9e", X"f3", X"61", X"f2", X"45", X"da", X"3d", X"d9", + X"11", X"d9", X"c8", X"d9", X"48", X"d8", X"f4", X"03", + X"20", X"d9", X"6a", X"d9", X"db", X"d9", X"6d", X"d8", + X"eb", X"d9", X"83", X"e7", X"c8", X"d8", X"af", X"d8", + X"12", X"e3", X"7a", X"e7", X"d4", X"da", X"95", X"d8", + X"a4", X"d6", X"69", X"d6", X"9f", X"db", X"48", X"d6", + X"90", X"eb", X"23", X"ec", X"af", X"eb", X"0a", X"00", + X"de", X"e2", X"12", X"d4", X"cd", X"df", X"ff", X"e2", + X"8d", X"ee", X"ae", X"ef", X"41", X"e9", X"09", X"ef", + X"ea", X"ef", X"f1", X"ef", X"3a", X"f0", X"9e", X"f0", + X"64", X"e7", X"d6", X"e6", X"c5", X"e3", X"07", X"e7", + X"e5", X"e6", X"46", X"e6", X"5a", X"e6", X"86", X"e6", + X"91", X"e6", X"79", X"c0", X"e7", X"79", X"a9", X"e7", + X"7b", X"81", X"e9", X"7b", X"68", X"ea", X"7d", X"96", + X"ee", X"50", X"54", X"df", X"46", X"4e", X"df", X"7f", + X"cf", X"ee", X"7f", X"97", X"de", X"64", X"64", X"df", + X"45", X"4e", X"c4", X"46", X"4f", X"d2", X"4e", X"45", + X"58", X"d4", X"44", X"41", X"54", X"c1", X"49", X"4e", + X"50", X"55", X"d4", X"44", X"45", X"cc", X"44", X"49", + X"cd", X"52", X"45", X"41", X"c4", X"47", X"d2", X"54", + X"45", X"58", X"d4", X"50", X"52", X"a3", X"49", X"4e", + X"a3", X"43", X"41", X"4c", X"cc", X"50", X"4c", X"4f", + X"d4", X"48", X"4c", X"49", X"ce", X"56", X"4c", X"49", + X"ce", X"48", X"47", X"52", X"b2", X"48", X"47", X"d2", + X"48", X"43", X"4f", X"4c", X"4f", X"52", X"bd", X"48", + X"50", X"4c", X"4f", X"d4", X"44", X"52", X"41", X"d7", + X"58", X"44", X"52", X"41", X"d7", X"48", X"54", X"41", + X"c2", X"48", X"4f", X"4d", X"c5", X"52", X"4f", X"54", + X"bd", X"53", X"43", X"41", X"4c", X"45", X"bd", X"53", + X"48", X"4c", X"4f", X"41", X"c4", X"54", X"52", X"41", + X"43", X"c5", X"4e", X"4f", X"54", X"52", X"41", X"43", + X"c5", X"4e", X"4f", X"52", X"4d", X"41", X"cc", X"49", + X"4e", X"56", X"45", X"52", X"53", X"c5", X"46", X"4c", + X"41", X"53", X"c8", X"43", X"4f", X"4c", X"4f", X"52", + X"bd", X"50", X"4f", X"d0", X"56", X"54", X"41", X"c2", + X"48", X"49", X"4d", X"45", X"4d", X"ba", X"4c", X"4f", + X"4d", X"45", X"4d", X"ba", X"4f", X"4e", X"45", X"52", + X"d2", X"52", X"45", X"53", X"55", X"4d", X"c5", X"52", + X"45", X"43", X"41", X"4c", X"cc", X"53", X"54", X"4f", + X"52", X"c5", X"53", X"50", X"45", X"45", X"44", X"bd", + X"4c", X"45", X"d4", X"47", X"4f", X"54", X"cf", X"52", + X"55", X"ce", X"49", X"c6", X"52", X"45", X"53", X"54", + X"4f", X"52", X"c5", X"a6", X"47", X"4f", X"53", X"55", + X"c2", X"52", X"45", X"54", X"55", X"52", X"ce", X"52", + X"45", X"cd", X"53", X"54", X"4f", X"d0", X"4f", X"ce", + X"57", X"41", X"49", X"d4", X"4c", X"4f", X"41", X"c4", + X"53", X"41", X"56", X"c5", X"44", X"45", X"c6", X"50", + X"4f", X"4b", X"c5", X"50", X"52", X"49", X"4e", X"d4", + X"43", X"4f", X"4e", X"d4", X"4c", X"49", X"53", X"d4", + X"43", X"4c", X"45", X"41", X"d2", X"47", X"45", X"d4", + X"4e", X"45", X"d7", X"54", X"41", X"42", X"a8", X"54", + X"cf", X"46", X"ce", X"53", X"50", X"43", X"a8", X"54", + X"48", X"45", X"ce", X"41", X"d4", X"4e", X"4f", X"d4", + X"53", X"54", X"45", X"d0", X"ab", X"ad", X"aa", X"af", + X"de", X"41", X"4e", X"c4", X"4f", X"d2", X"be", X"bd", + X"bc", X"53", X"47", X"ce", X"49", X"4e", X"d4", X"41", + X"42", X"d3", X"55", X"53", X"d2", X"46", X"52", X"c5", + X"53", X"43", X"52", X"4e", X"a8", X"50", X"44", X"cc", + X"50", X"4f", X"d3", X"53", X"51", X"d2", X"52", X"4e", + X"c4", X"4c", X"4f", X"c7", X"45", X"58", X"d0", X"43", + X"4f", X"d3", X"53", X"49", X"ce", X"54", X"41", X"ce", + X"41", X"54", X"ce", X"50", X"45", X"45", X"cb", X"4c", + X"45", X"ce", X"53", X"54", X"52", X"a4", X"56", X"41", + X"cc", X"41", X"53", X"c3", X"43", X"48", X"52", X"a4", + X"4c", X"45", X"46", X"54", X"a4", X"52", X"49", X"47", + X"48", X"54", X"a4", X"4d", X"49", X"44", X"a4", X"00", + X"4e", X"45", X"58", X"54", X"20", X"57", X"49", X"54", + X"48", X"4f", X"55", X"54", X"20", X"46", X"4f", X"d2", + X"53", X"59", X"4e", X"54", X"41", X"d8", X"52", X"45", + X"54", X"55", X"52", X"4e", X"20", X"57", X"49", X"54", + X"48", X"4f", X"55", X"54", X"20", X"47", X"4f", X"53", + X"55", X"c2", X"4f", X"55", X"54", X"20", X"4f", X"46", + X"20", X"44", X"41", X"54", X"c1", X"49", X"4c", X"4c", + X"45", X"47", X"41", X"4c", X"20", X"51", X"55", X"41", + X"4e", X"54", X"49", X"54", X"d9", X"4f", X"56", X"45", + X"52", X"46", X"4c", X"4f", X"d7", X"4f", X"55", X"54", + X"20", X"4f", X"46", X"20", X"4d", X"45", X"4d", X"4f", + X"52", X"d9", X"55", X"4e", X"44", X"45", X"46", X"27", + X"44", X"20", X"53", X"54", X"41", X"54", X"45", X"4d", + X"45", X"4e", X"d4", X"42", X"41", X"44", X"20", X"53", + X"55", X"42", X"53", X"43", X"52", X"49", X"50", X"d4", + X"52", X"45", X"44", X"49", X"4d", X"27", X"44", X"20", + X"41", X"52", X"52", X"41", X"d9", X"44", X"49", X"56", + X"49", X"53", X"49", X"4f", X"4e", X"20", X"42", X"59", + X"20", X"5a", X"45", X"52", X"cf", X"49", X"4c", X"4c", + X"45", X"47", X"41", X"4c", X"20", X"44", X"49", X"52", + X"45", X"43", X"d4", X"54", X"59", X"50", X"45", X"20", + X"4d", X"49", X"53", X"4d", X"41", X"54", X"43", X"c8", + X"53", X"54", X"52", X"49", X"4e", X"47", X"20", X"54", + X"4f", X"4f", X"20", X"4c", X"4f", X"4e", X"c7", X"46", + X"4f", X"52", X"4d", X"55", X"4c", X"41", X"20", X"54", + X"4f", X"4f", X"20", X"43", X"4f", X"4d", X"50", X"4c", + X"45", X"d8", X"43", X"41", X"4e", X"27", X"54", X"20", + X"43", X"4f", X"4e", X"54", X"49", X"4e", X"55", X"c5", + X"55", X"4e", X"44", X"45", X"46", X"27", X"44", X"20", + X"46", X"55", X"4e", X"43", X"54", X"49", X"4f", X"ce", + X"20", X"45", X"52", X"52", X"4f", X"52", X"07", X"00", + X"20", X"49", X"4e", X"20", X"00", X"0d", X"42", X"52", + X"45", X"41", X"4b", X"07", X"00", X"ba", X"e8", X"e8", + X"e8", X"e8", X"bd", X"01", X"01", X"c9", X"81", X"d0", + X"21", X"a5", X"86", X"d0", X"0a", X"bd", X"02", X"01", + X"85", X"85", X"bd", X"03", X"01", X"85", X"86", X"dd", + X"03", X"01", X"d0", X"07", X"a5", X"85", X"dd", X"02", + X"01", X"f0", X"07", X"8a", X"18", X"69", X"12", X"aa", + X"d0", X"d8", X"60", X"20", X"e3", X"d3", X"85", X"6d", + X"84", X"6e", X"38", X"a5", X"96", X"e5", X"9b", X"85", + X"5e", X"a8", X"a5", X"97", X"e5", X"9c", X"aa", X"e8", + X"98", X"f0", X"23", X"a5", X"96", X"38", X"e5", X"5e", + X"85", X"96", X"b0", X"03", X"c6", X"97", X"38", X"a5", + X"94", X"e5", X"5e", X"85", X"94", X"b0", X"08", X"c6", + X"95", X"90", X"04", X"b1", X"96", X"91", X"94", X"88", + X"d0", X"f9", X"b1", X"96", X"91", X"94", X"c6", X"97", + X"c6", X"95", X"ca", X"d0", X"f2", X"60", X"0a", X"69", + X"36", X"b0", X"35", X"85", X"5e", X"ba", X"e4", X"5e", + X"90", X"2e", X"60", X"c4", X"70", X"90", X"28", X"d0", + X"04", X"c5", X"6f", X"90", X"22", X"48", X"a2", X"09", + X"98", X"48", X"b5", X"93", X"ca", X"10", X"fa", X"20", + X"84", X"e4", X"a2", X"f7", X"68", X"95", X"9d", X"e8", + X"30", X"fa", X"68", X"a8", X"68", X"c4", X"70", X"90", + X"06", X"d0", X"05", X"c5", X"6f", X"b0", X"01", X"60", + X"a2", X"4d", X"24", X"d8", X"10", X"03", X"4c", X"e9", + X"f2", X"20", X"fb", X"da", X"20", X"5a", X"db", X"bd", + X"60", X"d2", X"48", X"20", X"5c", X"db", X"e8", X"68", + X"10", X"f5", X"20", X"83", X"d6", X"a9", X"50", X"a0", + X"d3", X"20", X"3a", X"db", X"a4", X"76", X"c8", X"f0", + X"03", X"20", X"19", X"ed", X"20", X"fb", X"da", X"a2", + X"dd", X"20", X"2e", X"d5", X"86", X"b8", X"84", X"b9", + X"46", X"d8", X"20", X"b1", X"00", X"aa", X"f0", X"ec", + X"a2", X"ff", X"86", X"76", X"90", X"06", X"20", X"59", + X"d5", X"4c", X"05", X"d8", X"a6", X"af", X"86", X"69", + X"a6", X"b0", X"86", X"6a", X"20", X"0c", X"da", X"20", + X"59", X"d5", X"84", X"0f", X"20", X"1a", X"d6", X"90", + X"44", X"a0", X"01", X"b1", X"9b", X"85", X"5f", X"a5", + X"69", X"85", X"5e", X"a5", X"9c", X"85", X"61", X"a5", + X"9b", X"88", X"f1", X"9b", X"18", X"65", X"69", X"85", + X"69", X"85", X"60", X"a5", X"6a", X"69", X"ff", X"85", + X"6a", X"e5", X"9c", X"aa", X"38", X"a5", X"9b", X"e5", + X"69", X"a8", X"b0", X"03", X"e8", X"c6", X"61", X"18", + X"65", X"5e", X"90", X"03", X"c6", X"5f", X"18", X"b1", + X"5e", X"91", X"60", X"c8", X"d0", X"f9", X"e6", X"5f", + X"e6", X"61", X"ca", X"d0", X"f2", X"ad", X"00", X"02", + X"f0", X"38", X"a5", X"73", X"a4", X"74", X"85", X"6f", + X"84", X"70", X"a5", X"69", X"85", X"96", X"65", X"0f", + X"85", X"94", X"a4", X"6a", X"84", X"97", X"90", X"01", + X"c8", X"84", X"95", X"20", X"93", X"d3", X"a5", X"50", + X"a4", X"51", X"8d", X"fe", X"01", X"8c", X"ff", X"01", + X"a5", X"6d", X"a4", X"6e", X"85", X"69", X"84", X"6a", + X"a4", X"0f", X"b9", X"fb", X"01", X"88", X"91", X"9b", + X"d0", X"f8", X"20", X"65", X"d6", X"a5", X"67", X"a4", + X"68", X"85", X"5e", X"84", X"5f", X"18", X"a0", X"01", + X"b1", X"5e", X"d0", X"0b", X"a5", X"69", X"85", X"af", + X"a5", X"6a", X"85", X"b0", X"4c", X"3c", X"d4", X"a0", + X"04", X"c8", X"b1", X"5e", X"d0", X"fb", X"c8", X"98", + X"65", X"5e", X"aa", X"a0", X"00", X"91", X"5e", X"a5", + X"5f", X"69", X"00", X"c8", X"91", X"5e", X"86", X"5e", + X"85", X"5f", X"90", X"d2", X"a2", X"80", X"86", X"33", + X"20", X"6a", X"fd", X"e0", X"ef", X"90", X"02", X"a2", + X"ef", X"a9", X"00", X"9d", X"00", X"02", X"8a", X"f0", + X"0b", X"bd", X"ff", X"01", X"29", X"7f", X"9d", X"ff", + X"01", X"ca", X"d0", X"f5", X"a9", X"00", X"a2", X"ff", + X"a0", X"01", X"60", X"20", X"0c", X"fd", X"29", X"7f", + X"60", X"a6", X"b8", X"ca", X"a0", X"04", X"84", X"13", + X"24", X"d6", X"10", X"08", X"68", X"68", X"20", X"65", + X"d6", X"4c", X"d2", X"d7", X"e8", X"bd", X"00", X"02", + X"24", X"13", X"70", X"04", X"c9", X"20", X"f0", X"f4", + X"85", X"0e", X"c9", X"22", X"f0", X"74", X"70", X"4d", + X"c9", X"3f", X"d0", X"04", X"a9", X"ba", X"d0", X"45", + X"c9", X"30", X"90", X"04", X"c9", X"3c", X"90", X"3d", + X"84", X"ad", X"a9", X"d0", X"85", X"9d", X"a9", X"cf", + X"85", X"9e", X"a0", X"00", X"84", X"0f", X"88", X"86", + X"b8", X"ca", X"c8", X"d0", X"02", X"e6", X"9e", X"e8", + X"bd", X"00", X"02", X"c9", X"20", X"f0", X"f8", X"38", + X"f1", X"9d", X"f0", X"ee", X"c9", X"80", X"d0", X"41", + X"05", X"0f", X"c9", X"c5", X"d0", X"0d", X"bd", X"01", + X"02", X"c9", X"4e", X"f0", X"34", X"c9", X"4f", X"f0", + X"30", X"a9", X"c5", X"a4", X"ad", X"e8", X"c8", X"99", + X"fb", X"01", X"b9", X"fb", X"01", X"f0", X"39", X"38", + X"e9", X"3a", X"f0", X"04", X"c9", X"49", X"d0", X"02", + X"85", X"13", X"38", X"e9", X"78", X"d0", X"86", X"85", + X"0e", X"bd", X"00", X"02", X"f0", X"df", X"c5", X"0e", + X"f0", X"db", X"c8", X"99", X"fb", X"01", X"e8", X"d0", + X"f0", X"a6", X"b8", X"e6", X"0f", X"b1", X"9d", X"c8", + X"d0", X"02", X"e6", X"9e", X"0a", X"90", X"f6", X"b1", + X"9d", X"d0", X"9d", X"bd", X"00", X"02", X"10", X"bb", + X"99", X"fd", X"01", X"c6", X"b9", X"a9", X"ff", X"85", + X"b8", X"60", X"a5", X"67", X"a6", X"68", X"a0", X"01", + X"85", X"9b", X"86", X"9c", X"b1", X"9b", X"f0", X"1f", + X"c8", X"c8", X"a5", X"51", X"d1", X"9b", X"90", X"18", + X"f0", X"03", X"88", X"d0", X"09", X"a5", X"50", X"88", + X"d1", X"9b", X"90", X"0c", X"f0", X"0a", X"88", X"b1", + X"9b", X"aa", X"88", X"b1", X"9b", X"b0", X"d7", X"18", + X"60", X"d0", X"fd", X"a9", X"00", X"85", X"d6", X"a8", + X"91", X"67", X"c8", X"91", X"67", X"a5", X"67", X"69", + X"02", X"85", X"69", X"85", X"af", X"a5", X"68", X"69", + X"00", X"85", X"6a", X"85", X"b0", X"20", X"97", X"d6", + X"a9", X"00", X"d0", X"2a", X"a5", X"73", X"a4", X"74", + X"85", X"6f", X"84", X"70", X"a5", X"69", X"a4", X"6a", + X"85", X"6b", X"84", X"6c", X"85", X"6d", X"84", X"6e", + X"20", X"49", X"d8", X"a2", X"55", X"86", X"52", X"68", + X"a8", X"68", X"a2", X"f8", X"9a", X"48", X"98", X"48", + X"a9", X"00", X"85", X"7a", X"85", X"14", X"60", X"18", + X"a5", X"67", X"69", X"ff", X"85", X"b8", X"a5", X"68", + X"69", X"ff", X"85", X"b9", X"60", X"90", X"0a", X"f0", + X"08", X"c9", X"c9", X"f0", X"04", X"c9", X"2c", X"d0", + X"e5", X"20", X"0c", X"da", X"20", X"1a", X"d6", X"20", + X"b7", X"00", X"f0", X"10", X"c9", X"c9", X"f0", X"04", + X"c9", X"2c", X"d0", X"84", X"20", X"b1", X"00", X"20", + X"0c", X"da", X"d0", X"ca", X"68", X"68", X"a5", X"50", + X"05", X"51", X"d0", X"06", X"a9", X"ff", X"85", X"50", + X"85", X"51", X"a0", X"01", X"b1", X"9b", X"f0", X"44", + X"20", X"58", X"d8", X"20", X"fb", X"da", X"c8", X"b1", + X"9b", X"aa", X"c8", X"b1", X"9b", X"c5", X"51", X"d0", + X"04", X"e4", X"50", X"f0", X"02", X"b0", X"2d", X"84", + X"85", X"20", X"24", X"ed", X"a9", X"20", X"a4", X"85", + X"29", X"7f", X"20", X"5c", X"db", X"a5", X"24", X"c9", + X"21", X"90", X"07", X"20", X"fb", X"da", X"a9", X"05", + X"85", X"24", X"c8", X"b1", X"9b", X"d0", X"1d", X"a8", + X"b1", X"9b", X"aa", X"c8", X"b1", X"9b", X"86", X"9b", + X"85", X"9c", X"d0", X"b6", X"a9", X"0d", X"20", X"5c", + X"db", X"4c", X"d2", X"d7", X"c8", X"d0", X"02", X"e6", + X"9e", X"b1", X"9d", X"60", X"10", X"cc", X"38", X"e9", + X"7f", X"aa", X"84", X"85", X"a0", X"d0", X"84", X"9d", + X"a0", X"cf", X"84", X"9e", X"a0", X"ff", X"ca", X"f0", + X"07", X"20", X"2c", X"d7", X"10", X"fb", X"30", X"f6", + X"a9", X"20", X"20", X"5c", X"db", X"20", X"2c", X"d7", + X"30", X"05", X"20", X"5c", X"db", X"d0", X"f6", X"20", + X"5c", X"db", X"a9", X"20", X"d0", X"98", X"a9", X"80", + X"85", X"14", X"20", X"46", X"da", X"20", X"65", X"d3", + X"d0", X"05", X"8a", X"69", X"0f", X"aa", X"9a", X"68", + X"68", X"a9", X"09", X"20", X"d6", X"d3", X"20", X"a3", + X"d9", X"18", X"98", X"65", X"b8", X"48", X"a5", X"b9", + X"69", X"00", X"48", X"a5", X"76", X"48", X"a5", X"75", + X"48", X"a9", X"c1", X"20", X"c0", X"de", X"20", X"6a", + X"dd", X"20", X"67", X"dd", X"a5", X"a2", X"09", X"7f", + X"25", X"9e", X"85", X"9e", X"a9", X"af", X"a0", X"d7", + X"85", X"5e", X"84", X"5f", X"4c", X"20", X"de", X"a9", + X"13", X"a0", X"e9", X"20", X"f9", X"ea", X"20", X"b7", + X"00", X"c9", X"c7", X"d0", X"06", X"20", X"b1", X"00", + X"20", X"67", X"dd", X"20", X"82", X"eb", X"20", X"15", + X"de", X"a5", X"86", X"48", X"a5", X"85", X"48", X"a9", + X"81", X"48", X"ba", X"86", X"f8", X"20", X"58", X"d8", + X"a5", X"b8", X"a4", X"b9", X"a6", X"76", X"e8", X"f0", + X"04", X"85", X"79", X"84", X"7a", X"a0", X"00", X"b1", + X"b8", X"d0", X"57", X"a0", X"02", X"b1", X"b8", X"18", + X"f0", X"34", X"c8", X"b1", X"b8", X"85", X"75", X"c8", + X"b1", X"b8", X"85", X"76", X"98", X"65", X"b8", X"85", + X"b8", X"90", X"02", X"e6", X"b9", X"24", X"f2", X"10", + X"14", X"a6", X"76", X"e8", X"f0", X"0f", X"a9", X"23", + X"20", X"5c", X"db", X"a6", X"75", X"a5", X"76", X"20", + X"24", X"ed", X"20", X"57", X"db", X"20", X"b1", X"00", + X"20", X"28", X"d8", X"4c", X"d2", X"d7", X"f0", X"62", + X"f0", X"2d", X"e9", X"80", X"90", X"11", X"c9", X"40", + X"b0", X"14", X"0a", X"a8", X"b9", X"01", X"d0", X"48", + X"b9", X"00", X"d0", X"48", X"4c", X"b1", X"00", X"4c", + X"46", X"da", X"c9", X"3a", X"f0", X"bf", X"4c", X"c9", + X"de", X"38", X"a5", X"67", X"e9", X"01", X"a4", X"68", + X"b0", X"01", X"88", X"85", X"7d", X"84", X"7e", X"60", + X"ad", X"00", X"c0", X"c9", X"83", X"f0", X"01", X"60", + X"20", X"53", X"d5", X"a2", X"ff", X"24", X"d8", X"10", + X"03", X"4c", X"e9", X"f2", X"c9", X"03", X"b0", X"01", + X"18", X"d0", X"3c", X"a5", X"b8", X"a4", X"b9", X"a6", + X"76", X"e8", X"f0", X"0c", X"85", X"79", X"84", X"7a", + X"a5", X"75", X"a4", X"76", X"85", X"77", X"84", X"78", + X"68", X"68", X"a9", X"5d", X"a0", X"d3", X"90", X"03", + X"4c", X"31", X"d4", X"4c", X"3c", X"d4", X"d0", X"17", + X"a2", X"d2", X"a4", X"7a", X"d0", X"03", X"4c", X"12", + X"d4", X"a5", X"79", X"85", X"b8", X"84", X"b9", X"a5", + X"77", X"a4", X"78", X"85", X"75", X"84", X"76", X"60", + X"38", X"a5", X"af", X"e5", X"67", X"85", X"50", X"a5", + X"b0", X"e5", X"68", X"85", X"51", X"20", X"f0", X"d8", + X"20", X"cd", X"fe", X"20", X"01", X"d9", X"4c", X"cd", + X"fe", X"20", X"f0", X"d8", X"20", X"fd", X"fe", X"18", + X"a5", X"67", X"65", X"50", X"85", X"69", X"a5", X"68", + X"65", X"51", X"85", X"6a", X"a5", X"52", X"85", X"d6", + X"20", X"01", X"d9", X"20", X"fd", X"fe", X"24", X"d6", + X"10", X"03", X"4c", X"65", X"d6", X"4c", X"f2", X"d4", + X"a9", X"50", X"a0", X"00", X"85", X"3c", X"84", X"3d", + X"a9", X"52", X"85", X"3e", X"84", X"3f", X"84", X"d6", + X"60", X"a5", X"67", X"a4", X"68", X"85", X"3c", X"84", + X"3d", X"a5", X"69", X"a4", X"6a", X"85", X"3e", X"84", + X"3f", X"60", X"08", X"c6", X"76", X"28", X"d0", X"03", + X"4c", X"65", X"d6", X"20", X"6c", X"d6", X"4c", X"35", + X"d9", X"a9", X"03", X"20", X"d6", X"d3", X"a5", X"b9", + X"48", X"a5", X"b8", X"48", X"a5", X"76", X"48", X"a5", + X"75", X"48", X"a9", X"b0", X"48", X"20", X"b7", X"00", + X"20", X"3e", X"d9", X"4c", X"d2", X"d7", X"20", X"0c", + X"da", X"20", X"a6", X"d9", X"a5", X"76", X"c5", X"51", + X"b0", X"0b", X"98", X"38", X"65", X"b8", X"a6", X"b9", + X"90", X"07", X"e8", X"b0", X"04", X"a5", X"67", X"a6", + X"68", X"20", X"1e", X"d6", X"90", X"1e", X"a5", X"9b", + X"e9", X"01", X"85", X"b8", X"a5", X"9c", X"e9", X"00", + X"85", X"b9", X"60", X"d0", X"fd", X"a9", X"ff", X"85", + X"85", X"20", X"65", X"d3", X"9a", X"c9", X"b0", X"f0", + X"0b", X"a2", X"16", X"2c", X"a2", X"5a", X"4c", X"12", + X"d4", X"4c", X"c9", X"de", X"68", X"68", X"c0", X"42", + X"f0", X"3b", X"85", X"75", X"68", X"85", X"76", X"68", + X"85", X"b8", X"68", X"85", X"b9", X"20", X"a3", X"d9", + X"98", X"18", X"65", X"b8", X"85", X"b8", X"90", X"02", + X"e6", X"b9", X"60", X"a2", X"3a", X"2c", X"a2", X"00", + X"86", X"0d", X"a0", X"00", X"84", X"0e", X"a5", X"0e", + X"a6", X"0d", X"85", X"0d", X"86", X"0e", X"b1", X"b8", + X"f0", X"e8", X"c5", X"0e", X"f0", X"e4", X"c8", X"c9", + X"22", X"d0", X"f3", X"f0", X"e9", X"68", X"68", X"68", + X"60", X"20", X"7b", X"dd", X"20", X"b7", X"00", X"c9", + X"ab", X"f0", X"05", X"a9", X"c4", X"20", X"c0", X"de", + X"a5", X"9d", X"d0", X"05", X"20", X"a6", X"d9", X"f0", + X"b7", X"20", X"b7", X"00", X"b0", X"03", X"4c", X"3e", + X"d9", X"4c", X"28", X"d8", X"20", X"f8", X"e6", X"48", + X"c9", X"b0", X"f0", X"04", X"c9", X"ab", X"d0", X"89", + X"c6", X"a1", X"d0", X"04", X"68", X"4c", X"2a", X"d8", + X"20", X"b1", X"00", X"20", X"0c", X"da", X"c9", X"2c", + X"f0", X"ee", X"68", X"60", X"a2", X"00", X"86", X"50", + X"86", X"51", X"b0", X"f7", X"e9", X"2f", X"85", X"0d", + X"a5", X"51", X"85", X"5e", X"c9", X"19", X"b0", X"d4", + X"a5", X"50", X"0a", X"26", X"5e", X"0a", X"26", X"5e", + X"65", X"50", X"85", X"50", X"a5", X"5e", X"65", X"51", + X"85", X"51", X"06", X"50", X"26", X"51", X"a5", X"50", + X"65", X"0d", X"85", X"50", X"90", X"02", X"e6", X"51", + X"20", X"b1", X"00", X"4c", X"12", X"da", X"20", X"e3", + X"df", X"85", X"85", X"84", X"86", X"a9", X"d0", X"20", + X"c0", X"de", X"a5", X"12", X"48", X"a5", X"11", X"48", + X"20", X"7b", X"dd", X"68", X"2a", X"20", X"6d", X"dd", + X"d0", X"18", X"68", X"10", X"12", X"20", X"72", X"eb", + X"20", X"0c", X"e1", X"a0", X"00", X"a5", X"a0", X"91", + X"85", X"c8", X"a5", X"a1", X"91", X"85", X"60", X"4c", + X"27", X"eb", X"68", X"a0", X"02", X"b1", X"a0", X"c5", + X"70", X"90", X"17", X"d0", X"07", X"88", X"b1", X"a0", + X"c5", X"6f", X"90", X"0e", X"a4", X"a1", X"c4", X"6a", + X"90", X"08", X"d0", X"0d", X"a5", X"a0", X"c5", X"69", + X"b0", X"07", X"a5", X"a0", X"a4", X"a1", X"4c", X"b7", + X"da", X"a0", X"00", X"b1", X"a0", X"20", X"d5", X"e3", + X"a5", X"8c", X"a4", X"8d", X"85", X"ab", X"84", X"ac", + X"20", X"d4", X"e5", X"a9", X"9d", X"a0", X"00", X"85", + X"8c", X"84", X"8d", X"20", X"35", X"e6", X"a0", X"00", + X"b1", X"8c", X"91", X"85", X"c8", X"b1", X"8c", X"91", + X"85", X"c8", X"b1", X"8c", X"91", X"85", X"60", X"20", + X"3d", X"db", X"20", X"b7", X"00", X"f0", X"24", X"f0", + X"29", X"c9", X"c0", X"f0", X"39", X"c9", X"c3", X"18", + X"f0", X"34", X"c9", X"2c", X"18", X"f0", X"1c", X"c9", + X"3b", X"f0", X"44", X"20", X"7b", X"dd", X"24", X"11", + X"30", X"dd", X"20", X"34", X"ed", X"20", X"e7", X"e3", + X"4c", X"cf", X"da", X"a9", X"0d", X"20", X"5c", X"db", + X"49", X"ff", X"60", X"a5", X"24", X"c9", X"18", X"90", + X"05", X"20", X"fb", X"da", X"d0", X"21", X"69", X"10", + X"29", X"f0", X"85", X"24", X"90", X"19", X"08", X"20", + X"f5", X"e6", X"c9", X"29", X"f0", X"03", X"4c", X"c9", + X"de", X"28", X"90", X"07", X"ca", X"8a", X"e5", X"24", + X"90", X"05", X"aa", X"e8", X"ca", X"d0", X"06", X"20", + X"b1", X"00", X"4c", X"d7", X"da", X"20", X"57", X"db", + X"d0", X"f2", X"20", X"e7", X"e3", X"20", X"00", X"e6", + X"aa", X"a0", X"00", X"e8", X"ca", X"f0", X"bb", X"b1", + X"5e", X"20", X"5c", X"db", X"c8", X"c9", X"0d", X"d0", + X"f3", X"20", X"00", X"db", X"4c", X"44", X"db", X"a9", + X"20", X"2c", X"a9", X"3f", X"09", X"80", X"c9", X"a0", + X"90", X"02", X"05", X"f3", X"20", X"ed", X"fd", X"29", + X"7f", X"48", X"a5", X"f1", X"20", X"a8", X"fc", X"68", + X"60", X"a5", X"15", X"f0", X"12", X"30", X"04", X"a0", + X"ff", X"d0", X"04", X"a5", X"7b", X"a4", X"7c", X"85", + X"75", X"84", X"76", X"4c", X"c9", X"de", X"68", X"24", + X"d8", X"10", X"05", X"a2", X"fe", X"4c", X"e9", X"f2", + X"a9", X"ef", X"a0", X"dc", X"20", X"3a", X"db", X"a5", + X"79", X"a4", X"7a", X"85", X"b8", X"84", X"b9", X"60", + X"20", X"06", X"e3", X"a2", X"01", X"a0", X"02", X"a9", + X"00", X"8d", X"01", X"02", X"a9", X"40", X"20", X"eb", + X"db", X"60", X"c9", X"22", X"d0", X"0e", X"20", X"81", + X"de", X"a9", X"3b", X"20", X"c0", X"de", X"20", X"3d", + X"db", X"4c", X"c7", X"db", X"20", X"5a", X"db", X"20", + X"06", X"e3", X"a9", X"2c", X"8d", X"ff", X"01", X"20", + X"2c", X"d5", X"ad", X"00", X"02", X"c9", X"03", X"d0", + X"10", X"4c", X"63", X"d8", X"20", X"5a", X"db", X"4c", + X"2c", X"d5", X"a6", X"7d", X"a4", X"7e", X"a9", X"98", + X"2c", X"a9", X"00", X"85", X"15", X"86", X"7f", X"84", + X"80", X"20", X"e3", X"df", X"85", X"85", X"84", X"86", + X"a5", X"b8", X"a4", X"b9", X"85", X"87", X"84", X"88", + X"a6", X"7f", X"a4", X"80", X"86", X"b8", X"84", X"b9", + X"20", X"b7", X"00", X"d0", X"1e", X"24", X"15", X"50", + X"0e", X"20", X"0c", X"fd", X"29", X"7f", X"8d", X"00", + X"02", X"a2", X"ff", X"a0", X"01", X"d0", X"08", X"30", + X"7f", X"20", X"5a", X"db", X"20", X"dc", X"db", X"86", + X"b8", X"84", X"b9", X"20", X"b1", X"00", X"24", X"11", + X"10", X"31", X"24", X"15", X"50", X"09", X"e8", X"86", + X"b8", X"a9", X"00", X"85", X"0d", X"f0", X"0c", X"85", + X"0d", X"c9", X"22", X"f0", X"07", X"a9", X"3a", X"85", + X"0d", X"a9", X"2c", X"18", X"85", X"0e", X"a5", X"b8", + X"a4", X"b9", X"69", X"00", X"90", X"01", X"c8", X"20", + X"ed", X"e3", X"20", X"3d", X"e7", X"20", X"7b", X"da", + X"4c", X"72", X"dc", X"48", X"ad", X"00", X"02", X"f0", + X"30", X"68", X"20", X"4a", X"ec", X"a5", X"12", X"20", + X"63", X"da", X"20", X"b7", X"00", X"f0", X"07", X"c9", + X"2c", X"f0", X"03", X"4c", X"71", X"db", X"a5", X"b8", + X"a4", X"b9", X"85", X"7f", X"84", X"80", X"a5", X"87", + X"a4", X"88", X"85", X"b8", X"84", X"b9", X"20", X"b7", + X"00", X"f0", X"33", X"20", X"be", X"de", X"4c", X"f1", + X"db", X"a5", X"15", X"d0", X"cc", X"4c", X"86", X"db", + X"20", X"a3", X"d9", X"c8", X"aa", X"d0", X"12", X"a2", + X"2a", X"c8", X"b1", X"b8", X"f0", X"5f", X"c8", X"b1", + X"b8", X"85", X"7b", X"c8", X"b1", X"b8", X"c8", X"85", + X"7c", X"b1", X"b8", X"aa", X"20", X"98", X"d9", X"e0", + X"83", X"d0", X"dd", X"4c", X"2b", X"dc", X"a5", X"7f", + X"a4", X"80", X"a6", X"15", X"10", X"03", X"4c", X"53", + X"d8", X"a0", X"00", X"b1", X"7f", X"f0", X"07", X"a9", + X"df", X"a0", X"dc", X"4c", X"3a", X"db", X"60", X"3f", + X"45", X"58", X"54", X"52", X"41", X"20", X"49", X"47", + X"4e", X"4f", X"52", X"45", X"44", X"0d", X"00", X"3f", + X"52", X"45", X"45", X"4e", X"54", X"45", X"52", X"0d", + X"00", X"d0", X"04", X"a0", X"00", X"f0", X"03", X"20", + X"e3", X"df", X"85", X"85", X"84", X"86", X"20", X"65", + X"d3", X"f0", X"04", X"a2", X"00", X"f0", X"69", X"9a", + X"e8", X"e8", X"e8", X"e8", X"8a", X"e8", X"e8", X"e8", + X"e8", X"e8", X"e8", X"86", X"60", X"a0", X"01", X"20", + X"f9", X"ea", X"ba", X"bd", X"09", X"01", X"85", X"a2", + X"a5", X"85", X"a4", X"86", X"20", X"be", X"e7", X"20", + X"27", X"eb", X"a0", X"01", X"20", X"b4", X"eb", X"ba", + X"38", X"fd", X"09", X"01", X"f0", X"17", X"bd", X"0f", + X"01", X"85", X"75", X"bd", X"10", X"01", X"85", X"76", + X"bd", X"12", X"01", X"85", X"b8", X"bd", X"11", X"01", + X"85", X"b9", X"4c", X"d2", X"d7", X"8a", X"69", X"11", + X"aa", X"9a", X"20", X"b7", X"00", X"c9", X"2c", X"d0", + X"f1", X"20", X"b1", X"00", X"20", X"ff", X"dc", X"20", + X"7b", X"dd", X"18", X"24", X"38", X"24", X"11", X"30", + X"03", X"b0", X"03", X"60", X"b0", X"fd", X"a2", X"a3", + X"4c", X"12", X"d4", X"a6", X"b8", X"d0", X"02", X"c6", + X"b9", X"c6", X"b8", X"a2", X"00", X"24", X"48", X"8a", + X"48", X"a9", X"01", X"20", X"d6", X"d3", X"20", X"60", + X"de", X"a9", X"00", X"85", X"89", X"20", X"b7", X"00", + X"38", X"e9", X"cf", X"90", X"17", X"c9", X"03", X"b0", + X"13", X"c9", X"01", X"2a", X"49", X"01", X"45", X"89", + X"c5", X"89", X"90", X"61", X"85", X"89", X"20", X"b1", + X"00", X"4c", X"98", X"dd", X"a6", X"89", X"d0", X"2c", + X"b0", X"7b", X"69", X"07", X"90", X"77", X"65", X"11", + X"d0", X"03", X"4c", X"97", X"e5", X"69", X"ff", X"85", + X"5e", X"0a", X"65", X"5e", X"a8", X"68", X"d9", X"b2", + X"d0", X"b0", X"67", X"20", X"6a", X"dd", X"48", X"20", + X"fd", X"dd", X"68", X"a4", X"87", X"10", X"17", X"aa", + X"f0", X"56", X"d0", X"5f", X"46", X"11", X"8a", X"2a", + X"a6", X"b8", X"d0", X"02", X"c6", X"b9", X"c6", X"b8", + X"a0", X"1b", X"85", X"89", X"d0", X"d7", X"d9", X"b2", + X"d0", X"b0", X"48", X"90", X"d9", X"b9", X"b4", X"d0", + X"48", X"b9", X"b3", X"d0", X"48", X"20", X"10", X"de", + X"a5", X"89", X"4c", X"86", X"dd", X"4c", X"c9", X"de", + X"a5", X"a2", X"be", X"b2", X"d0", X"a8", X"68", X"85", + X"5e", X"e6", X"5e", X"68", X"85", X"5f", X"98", X"48", + X"20", X"72", X"eb", X"a5", X"a1", X"48", X"a5", X"a0", + X"48", X"a5", X"9f", X"48", X"a5", X"9e", X"48", X"a5", + X"9d", X"48", X"6c", X"5e", X"00", X"a0", X"ff", X"68", + X"f0", X"23", X"c9", X"64", X"f0", X"03", X"20", X"6a", + X"dd", X"84", X"87", X"68", X"4a", X"85", X"16", X"68", + X"85", X"a5", X"68", X"85", X"a6", X"68", X"85", X"a7", + X"68", X"85", X"a8", X"68", X"85", X"a9", X"68", X"85", + X"aa", X"45", X"a2", X"85", X"ab", X"a5", X"9d", X"60", + X"a9", X"00", X"85", X"11", X"20", X"b1", X"00", X"b0", + X"03", X"4c", X"4a", X"ec", X"20", X"7d", X"e0", X"b0", + X"64", X"c9", X"2e", X"f0", X"f4", X"c9", X"c9", X"f0", + X"55", X"c9", X"c8", X"f0", X"e7", X"c9", X"22", X"d0", + X"0f", X"a5", X"b8", X"a4", X"b9", X"69", X"00", X"90", + X"01", X"c8", X"20", X"e7", X"e3", X"4c", X"3d", X"e7", + X"c9", X"c6", X"d0", X"10", X"a0", X"18", X"d0", X"38", + X"a5", X"9d", X"d0", X"03", X"a0", X"01", X"2c", X"a0", + X"00", X"4c", X"01", X"e3", X"c9", X"c2", X"d0", X"03", + X"4c", X"54", X"e3", X"c9", X"d2", X"90", X"03", X"4c", + X"0c", X"df", X"20", X"bb", X"de", X"20", X"7b", X"dd", + X"a9", X"29", X"2c", X"a9", X"28", X"2c", X"a9", X"2c", + X"a0", X"00", X"d1", X"b8", X"d0", X"03", X"4c", X"b1", + X"00", X"a2", X"10", X"4c", X"12", X"d4", X"a0", X"15", + X"68", X"68", X"4c", X"d7", X"dd", X"20", X"e3", X"df", + X"85", X"a0", X"84", X"a1", X"a6", X"11", X"f0", X"05", + X"a2", X"00", X"86", X"ac", X"60", X"a6", X"12", X"10", + X"0d", X"a0", X"00", X"b1", X"a0", X"aa", X"c8", X"b1", + X"a0", X"a8", X"8a", X"4c", X"f2", X"e2", X"4c", X"f9", + X"ea", X"20", X"b1", X"00", X"20", X"ec", X"f1", X"8a", + X"a4", X"f0", X"20", X"71", X"f8", X"a8", X"20", X"01", + X"e3", X"4c", X"b8", X"de", X"c9", X"d7", X"f0", X"e9", + X"0a", X"48", X"aa", X"20", X"b1", X"00", X"e0", X"cf", + X"90", X"20", X"20", X"bb", X"de", X"20", X"7b", X"dd", + X"20", X"be", X"de", X"20", X"6c", X"dd", X"68", X"aa", + X"a5", X"a1", X"48", X"a5", X"a0", X"48", X"8a", X"48", + X"20", X"f8", X"e6", X"68", X"a8", X"8a", X"48", X"4c", + X"3f", X"df", X"20", X"b2", X"de", X"68", X"a8", X"b9", + X"dc", X"cf", X"85", X"91", X"b9", X"dd", X"cf", X"85", + X"92", X"20", X"90", X"00", X"4c", X"6a", X"dd", X"a5", + X"a5", X"05", X"9d", X"d0", X"0b", X"a5", X"a5", X"f0", + X"04", X"a5", X"9d", X"d0", X"03", X"a0", X"00", X"2c", + X"a0", X"01", X"4c", X"01", X"e3", X"20", X"6d", X"dd", + X"b0", X"13", X"a5", X"aa", X"09", X"7f", X"25", X"a6", + X"85", X"a6", X"a9", X"a5", X"a0", X"00", X"20", X"b2", + X"eb", X"aa", X"4c", X"b0", X"df", X"a9", X"00", X"85", + X"11", X"c6", X"89", X"20", X"00", X"e6", X"85", X"9d", + X"86", X"9e", X"84", X"9f", X"a5", X"a8", X"a4", X"a9", + X"20", X"04", X"e6", X"86", X"a8", X"84", X"a9", X"aa", + X"38", X"e5", X"9d", X"f0", X"08", X"a9", X"01", X"90", + X"04", X"a6", X"9d", X"a9", X"ff", X"85", X"a2", X"a0", + X"ff", X"e8", X"c8", X"ca", X"d0", X"07", X"a6", X"a2", + X"30", X"0f", X"18", X"90", X"0c", X"b1", X"a8", X"d1", + X"9e", X"f0", X"ef", X"a2", X"ff", X"b0", X"02", X"a2", + X"01", X"e8", X"8a", X"2a", X"25", X"16", X"f0", X"02", + X"a9", X"01", X"4c", X"93", X"eb", X"20", X"fb", X"e6", + X"20", X"1e", X"fb", X"4c", X"01", X"e3", X"20", X"be", + X"de", X"aa", X"20", X"e8", X"df", X"20", X"b7", X"00", + X"d0", X"f4", X"60", X"a2", X"00", X"20", X"b7", X"00", + X"86", X"10", X"85", X"81", X"20", X"b7", X"00", X"20", + X"7d", X"e0", X"b0", X"03", X"4c", X"c9", X"de", X"a2", + X"00", X"86", X"11", X"86", X"12", X"4c", X"07", X"e0", + X"4c", X"28", X"f1", X"4c", X"3c", X"d4", X"00", X"20", + X"b1", X"00", X"90", X"05", X"20", X"7d", X"e0", X"90", + X"0b", X"aa", X"20", X"b1", X"00", X"90", X"fb", X"20", + X"7d", X"e0", X"b0", X"f6", X"c9", X"24", X"d0", X"06", + X"a9", X"ff", X"85", X"11", X"d0", X"10", X"c9", X"25", + X"d0", X"13", X"a5", X"14", X"30", X"c6", X"a9", X"80", + X"85", X"12", X"05", X"81", X"85", X"81", X"8a", X"09", + X"80", X"aa", X"20", X"b1", X"00", X"86", X"82", X"38", + X"05", X"14", X"e9", X"28", X"d0", X"03", X"4c", X"1e", + X"e1", X"24", X"14", X"30", X"02", X"70", X"f7", X"a9", + X"00", X"85", X"14", X"a5", X"69", X"a6", X"6a", X"a0", + X"00", X"86", X"9c", X"85", X"9b", X"e4", X"6c", X"d0", + X"04", X"c5", X"6b", X"f0", X"22", X"a5", X"81", X"d1", + X"9b", X"d0", X"08", X"a5", X"82", X"c8", X"d1", X"9b", + X"f0", X"6c", X"88", X"18", X"a5", X"9b", X"69", X"07", + X"90", X"e1", X"e8", X"d0", X"dc", X"c9", X"41", X"90", + X"05", X"e9", X"5b", X"38", X"e9", X"a5", X"60", X"68", + X"48", X"c9", X"d7", X"d0", X"0f", X"ba", X"bd", X"02", + X"01", X"c9", X"de", X"d0", X"07", X"a9", X"9a", X"a0", + X"e0", X"60", X"00", X"00", X"a5", X"6b", X"a4", X"6c", + X"85", X"9b", X"84", X"9c", X"a5", X"6d", X"a4", X"6e", + X"85", X"96", X"84", X"97", X"18", X"69", X"07", X"90", + X"01", X"c8", X"85", X"94", X"84", X"95", X"20", X"93", + X"d3", X"a5", X"94", X"a4", X"95", X"c8", X"85", X"6b", + X"84", X"6c", X"a0", X"00", X"a5", X"81", X"91", X"9b", + X"c8", X"a5", X"82", X"91", X"9b", X"a9", X"00", X"c8", + X"91", X"9b", X"c8", X"91", X"9b", X"c8", X"91", X"9b", + X"c8", X"91", X"9b", X"c8", X"91", X"9b", X"a5", X"9b", + X"18", X"69", X"02", X"a4", X"9c", X"90", X"01", X"c8", + X"85", X"83", X"84", X"84", X"60", X"a5", X"0f", X"0a", + X"69", X"05", X"65", X"9b", X"a4", X"9c", X"90", X"01", + X"c8", X"85", X"94", X"84", X"95", X"60", X"90", X"80", + X"00", X"00", X"20", X"b1", X"00", X"20", X"67", X"dd", + X"a5", X"a2", X"30", X"0d", X"a5", X"9d", X"c9", X"90", + X"90", X"09", X"a9", X"fe", X"a0", X"e0", X"20", X"b2", + X"eb", X"d0", X"7e", X"4c", X"f2", X"eb", X"a5", X"14", + X"d0", X"47", X"a5", X"10", X"05", X"12", X"48", X"a5", + X"11", X"48", X"a0", X"00", X"98", X"48", X"a5", X"82", + X"48", X"a5", X"81", X"48", X"20", X"02", X"e1", X"68", + X"85", X"81", X"68", X"85", X"82", X"68", X"a8", X"ba", + X"bd", X"02", X"01", X"48", X"bd", X"01", X"01", X"48", + X"a5", X"a0", X"9d", X"02", X"01", X"a5", X"a1", X"9d", + X"01", X"01", X"c8", X"20", X"b7", X"00", X"c9", X"2c", + X"f0", X"d2", X"84", X"0f", X"20", X"b8", X"de", X"68", + X"85", X"11", X"68", X"85", X"12", X"29", X"7f", X"85", + X"10", X"a6", X"6b", X"a5", X"6c", X"86", X"9b", X"85", + X"9c", X"c5", X"6e", X"d0", X"04", X"e4", X"6d", X"f0", + X"3f", X"a0", X"00", X"b1", X"9b", X"c8", X"c5", X"81", + X"d0", X"06", X"a5", X"82", X"d1", X"9b", X"f0", X"16", + X"c8", X"b1", X"9b", X"18", X"65", X"9b", X"aa", X"c8", + X"b1", X"9b", X"65", X"9c", X"90", X"d7", X"a2", X"6b", + X"2c", X"a2", X"35", X"4c", X"12", X"d4", X"a2", X"78", + X"a5", X"10", X"d0", X"f7", X"a5", X"14", X"f0", X"02", + X"38", X"60", X"20", X"ed", X"e0", X"a5", X"0f", X"a0", + X"04", X"d1", X"9b", X"d0", X"e1", X"4c", X"4b", X"e2", + X"a5", X"14", X"f0", X"05", X"a2", X"2a", X"4c", X"12", + X"d4", X"20", X"ed", X"e0", X"20", X"e3", X"d3", X"a9", + X"00", X"a8", X"85", X"ae", X"a2", X"05", X"a5", X"81", + X"91", X"9b", X"10", X"01", X"ca", X"c8", X"a5", X"82", + X"91", X"9b", X"10", X"02", X"ca", X"ca", X"86", X"ad", + X"a5", X"0f", X"c8", X"c8", X"c8", X"91", X"9b", X"a2", + X"0b", X"a9", X"00", X"24", X"10", X"50", X"08", X"68", + X"18", X"69", X"01", X"aa", X"68", X"69", X"00", X"c8", + X"91", X"9b", X"c8", X"8a", X"91", X"9b", X"20", X"ad", + X"e2", X"86", X"ad", X"85", X"ae", X"a4", X"5e", X"c6", + X"0f", X"d0", X"dc", X"65", X"95", X"b0", X"5d", X"85", + X"95", X"a8", X"8a", X"65", X"94", X"90", X"03", X"c8", + X"f0", X"52", X"20", X"e3", X"d3", X"85", X"6d", X"84", + X"6e", X"a9", X"00", X"e6", X"ae", X"a4", X"ad", X"f0", + X"05", X"88", X"91", X"94", X"d0", X"fb", X"c6", X"95", + X"c6", X"ae", X"d0", X"f5", X"e6", X"95", X"38", X"a5", + X"6d", X"e5", X"9b", X"a0", X"02", X"91", X"9b", X"a5", + X"6e", X"c8", X"e5", X"9c", X"91", X"9b", X"a5", X"10", + X"d0", X"62", X"c8", X"b1", X"9b", X"85", X"0f", X"a9", + X"00", X"85", X"ad", X"85", X"ae", X"c8", X"68", X"aa", + X"85", X"a0", X"68", X"85", X"a1", X"d1", X"9b", X"90", + X"0e", X"d0", X"06", X"c8", X"8a", X"d1", X"9b", X"90", + X"07", X"4c", X"96", X"e1", X"4c", X"10", X"d4", X"c8", + X"a5", X"ae", X"05", X"ad", X"18", X"f0", X"0a", X"20", + X"ad", X"e2", X"8a", X"65", X"a0", X"aa", X"98", X"a4", + X"5e", X"65", X"a1", X"86", X"ad", X"c6", X"0f", X"d0", + X"ca", X"85", X"ae", X"a2", X"05", X"a5", X"81", X"10", + X"01", X"ca", X"a5", X"82", X"10", X"02", X"ca", X"ca", + X"86", X"64", X"a9", X"00", X"20", X"b6", X"e2", X"8a", + X"65", X"94", X"85", X"83", X"98", X"65", X"95", X"85", + X"84", X"a8", X"a5", X"83", X"60", X"84", X"5e", X"b1", + X"9b", X"85", X"64", X"88", X"b1", X"9b", X"85", X"65", + X"a9", X"10", X"85", X"99", X"a2", X"00", X"a0", X"00", + X"8a", X"0a", X"aa", X"98", X"2a", X"a8", X"b0", X"a4", + X"06", X"ad", X"26", X"ae", X"90", X"0b", X"18", X"8a", + X"65", X"64", X"aa", X"98", X"65", X"65", X"a8", X"b0", + X"93", X"c6", X"99", X"d0", X"e3", X"60", X"a5", X"11", + X"f0", X"03", X"20", X"00", X"e6", X"20", X"84", X"e4", + X"38", X"a5", X"6f", X"e5", X"6d", X"a8", X"a5", X"70", + X"e5", X"6e", X"a2", X"00", X"86", X"11", X"85", X"9e", + X"84", X"9f", X"a2", X"90", X"4c", X"9b", X"eb", X"a4", + X"24", X"a9", X"00", X"38", X"f0", X"ec", X"a6", X"76", + X"e8", X"d0", X"a1", X"a2", X"95", X"2c", X"a2", X"e0", + X"4c", X"12", X"d4", X"20", X"41", X"e3", X"20", X"06", + X"e3", X"20", X"bb", X"de", X"a9", X"80", X"85", X"14", + X"20", X"e3", X"df", X"20", X"6a", X"dd", X"20", X"b8", + X"de", X"a9", X"d0", X"20", X"c0", X"de", X"48", X"a5", + X"84", X"48", X"a5", X"83", X"48", X"a5", X"b9", X"48", + X"a5", X"b8", X"48", X"20", X"95", X"d9", X"4c", X"af", + X"e3", X"a9", X"c2", X"20", X"c0", X"de", X"09", X"80", + X"85", X"14", X"20", X"ea", X"df", X"85", X"8a", X"84", + X"8b", X"4c", X"6a", X"dd", X"20", X"41", X"e3", X"a5", + X"8b", X"48", X"a5", X"8a", X"48", X"20", X"b2", X"de", + X"20", X"6a", X"dd", X"68", X"85", X"8a", X"68", X"85", + X"8b", X"a0", X"02", X"b1", X"8a", X"85", X"83", X"aa", + X"c8", X"b1", X"8a", X"f0", X"99", X"85", X"84", X"c8", + X"b1", X"83", X"48", X"88", X"10", X"fa", X"a4", X"84", + X"20", X"2b", X"eb", X"a5", X"b9", X"48", X"a5", X"b8", + X"48", X"b1", X"8a", X"85", X"b8", X"c8", X"b1", X"8a", + X"85", X"b9", X"a5", X"84", X"48", X"a5", X"83", X"48", + X"20", X"67", X"dd", X"68", X"85", X"8a", X"68", X"85", + X"8b", X"20", X"b7", X"00", X"f0", X"03", X"4c", X"c9", + X"de", X"68", X"85", X"b8", X"68", X"85", X"b9", X"a0", + X"00", X"68", X"91", X"8a", X"68", X"c8", X"91", X"8a", + X"68", X"c8", X"91", X"8a", X"68", X"c8", X"91", X"8a", + X"68", X"c8", X"91", X"8a", X"60", X"20", X"6a", X"dd", + X"a0", X"00", X"20", X"36", X"ed", X"68", X"68", X"a9", + X"ff", X"a0", X"00", X"f0", X"12", X"a6", X"a0", X"a4", + X"a1", X"86", X"8c", X"84", X"8d", X"20", X"52", X"e4", + X"86", X"9e", X"84", X"9f", X"85", X"9d", X"60", X"a2", + X"22", X"86", X"0d", X"86", X"0e", X"85", X"ab", X"84", + X"ac", X"85", X"9e", X"84", X"9f", X"a0", X"ff", X"c8", + X"b1", X"ab", X"f0", X"0c", X"c5", X"0d", X"f0", X"04", + X"c5", X"0e", X"d0", X"f3", X"c9", X"22", X"f0", X"01", + X"18", X"84", X"9d", X"98", X"65", X"ab", X"85", X"ad", + X"a6", X"ac", X"90", X"01", X"e8", X"86", X"ae", X"a5", + X"ac", X"f0", X"04", X"c9", X"02", X"d0", X"0b", X"98", + X"20", X"d5", X"e3", X"a6", X"ab", X"a4", X"ac", X"20", + X"e2", X"e5", X"a6", X"52", X"e0", X"5e", X"d0", X"05", + X"a2", X"bf", X"4c", X"12", X"d4", X"a5", X"9d", X"95", + X"00", X"a5", X"9e", X"95", X"01", X"a5", X"9f", X"95", + X"02", X"a0", X"00", X"86", X"a0", X"84", X"a1", X"88", + X"84", X"11", X"86", X"53", X"e8", X"e8", X"e8", X"86", + X"52", X"60", X"46", X"13", X"48", X"49", X"ff", X"38", + X"65", X"6f", X"a4", X"70", X"b0", X"01", X"88", X"c4", + X"6e", X"90", X"11", X"d0", X"04", X"c5", X"6d", X"90", + X"0b", X"85", X"6f", X"84", X"70", X"85", X"71", X"84", + X"72", X"aa", X"68", X"60", X"a2", X"4d", X"a5", X"13", + X"30", X"b8", X"20", X"84", X"e4", X"a9", X"80", X"85", + X"13", X"68", X"d0", X"d0", X"a6", X"73", X"a5", X"74", + X"86", X"6f", X"85", X"70", X"a0", X"00", X"84", X"8b", + X"a5", X"6d", X"a6", X"6e", X"85", X"9b", X"86", X"9c", + X"a9", X"55", X"a2", X"00", X"85", X"5e", X"86", X"5f", + X"c5", X"52", X"f0", X"05", X"20", X"23", X"e5", X"f0", + X"f7", X"a9", X"07", X"85", X"8f", X"a5", X"69", X"a6", + X"6a", X"85", X"5e", X"86", X"5f", X"e4", X"6c", X"d0", + X"04", X"c5", X"6b", X"f0", X"05", X"20", X"19", X"e5", + X"f0", X"f3", X"85", X"94", X"86", X"95", X"a9", X"03", + X"85", X"8f", X"a5", X"94", X"a6", X"95", X"e4", X"6e", + X"d0", X"07", X"c5", X"6d", X"d0", X"03", X"4c", X"62", + X"e5", X"85", X"5e", X"86", X"5f", X"a0", X"00", X"b1", + X"5e", X"aa", X"c8", X"b1", X"5e", X"08", X"c8", X"b1", + X"5e", X"65", X"94", X"85", X"94", X"c8", X"b1", X"5e", + X"65", X"95", X"85", X"95", X"28", X"10", X"d3", X"8a", + X"30", X"d0", X"c8", X"b1", X"5e", X"a0", X"00", X"0a", + X"69", X"05", X"65", X"5e", X"85", X"5e", X"90", X"02", + X"e6", X"5f", X"a6", X"5f", X"e4", X"95", X"d0", X"04", + X"c5", X"94", X"f0", X"ba", X"20", X"23", X"e5", X"f0", + X"f3", X"b1", X"5e", X"30", X"35", X"c8", X"b1", X"5e", + X"10", X"30", X"c8", X"b1", X"5e", X"f0", X"2b", X"c8", + X"b1", X"5e", X"aa", X"c8", X"b1", X"5e", X"c5", X"70", + X"90", X"06", X"d0", X"1e", X"e4", X"6f", X"b0", X"1a", + X"c5", X"9c", X"90", X"16", X"d0", X"04", X"e4", X"9b", + X"90", X"10", X"86", X"9b", X"85", X"9c", X"a5", X"5e", + X"a6", X"5f", X"85", X"8a", X"86", X"8b", X"a5", X"8f", + X"85", X"91", X"a5", X"8f", X"18", X"65", X"5e", X"85", + X"5e", X"90", X"02", X"e6", X"5f", X"a6", X"5f", X"a0", + X"00", X"60", X"a6", X"8b", X"f0", X"f7", X"a5", X"91", + X"29", X"04", X"4a", X"a8", X"85", X"91", X"b1", X"8a", + X"65", X"9b", X"85", X"96", X"a5", X"9c", X"69", X"00", + X"85", X"97", X"a5", X"6f", X"a6", X"70", X"85", X"94", + X"86", X"95", X"20", X"9a", X"d3", X"a4", X"91", X"c8", + X"a5", X"94", X"91", X"8a", X"aa", X"e6", X"95", X"a5", + X"95", X"c8", X"91", X"8a", X"4c", X"88", X"e4", X"a5", + X"a1", X"48", X"a5", X"a0", X"48", X"20", X"60", X"de", + X"20", X"6c", X"dd", X"68", X"85", X"ab", X"68", X"85", + X"ac", X"a0", X"00", X"b1", X"ab", X"18", X"71", X"a0", + X"90", X"05", X"a2", X"b0", X"4c", X"12", X"d4", X"20", + X"d5", X"e3", X"20", X"d4", X"e5", X"a5", X"8c", X"a4", + X"8d", X"20", X"04", X"e6", X"20", X"e6", X"e5", X"a5", + X"ab", X"a4", X"ac", X"20", X"04", X"e6", X"20", X"2a", + X"e4", X"4c", X"95", X"dd", X"a0", X"00", X"b1", X"ab", + X"48", X"c8", X"b1", X"ab", X"aa", X"c8", X"b1", X"ab", + X"a8", X"68", X"86", X"5e", X"84", X"5f", X"a8", X"f0", + X"0a", X"48", X"88", X"b1", X"5e", X"91", X"71", X"98", + X"d0", X"f8", X"68", X"18", X"65", X"71", X"85", X"71", + X"90", X"02", X"e6", X"72", X"60", X"20", X"6c", X"dd", + X"a5", X"a0", X"a4", X"a1", X"85", X"5e", X"84", X"5f", + X"20", X"35", X"e6", X"08", X"a0", X"00", X"b1", X"5e", + X"48", X"c8", X"b1", X"5e", X"aa", X"c8", X"b1", X"5e", + X"a8", X"68", X"28", X"d0", X"13", X"c4", X"70", X"d0", + X"0f", X"e4", X"6f", X"d0", X"0b", X"48", X"18", X"65", + X"6f", X"85", X"6f", X"90", X"02", X"e6", X"70", X"68", + X"86", X"5e", X"84", X"5f", X"60", X"c4", X"54", X"d0", + X"0c", X"c5", X"53", X"d0", X"08", X"85", X"52", X"e9", + X"03", X"85", X"53", X"a0", X"00", X"60", X"20", X"fb", + X"e6", X"8a", X"48", X"a9", X"01", X"20", X"dd", X"e3", + X"68", X"a0", X"00", X"91", X"9e", X"68", X"68", X"4c", + X"2a", X"e4", X"20", X"b9", X"e6", X"d1", X"8c", X"98", + X"90", X"04", X"b1", X"8c", X"aa", X"98", X"48", X"8a", + X"48", X"20", X"dd", X"e3", X"a5", X"8c", X"a4", X"8d", + X"20", X"04", X"e6", X"68", X"a8", X"68", X"18", X"65", + X"5e", X"85", X"5e", X"90", X"02", X"e6", X"5f", X"98", + X"20", X"e6", X"e5", X"4c", X"2a", X"e4", X"20", X"b9", + X"e6", X"18", X"f1", X"8c", X"49", X"ff", X"4c", X"60", + X"e6", X"a9", X"ff", X"85", X"a1", X"20", X"b7", X"00", + X"c9", X"29", X"f0", X"06", X"20", X"be", X"de", X"20", + X"f8", X"e6", X"20", X"b9", X"e6", X"ca", X"8a", X"48", + X"18", X"a2", X"00", X"f1", X"8c", X"b0", X"b8", X"49", + X"ff", X"c5", X"a1", X"90", X"b3", X"a5", X"a1", X"b0", + X"af", X"20", X"b8", X"de", X"68", X"a8", X"68", X"85", + X"91", X"68", X"68", X"68", X"aa", X"68", X"85", X"8c", + X"68", X"85", X"8d", X"a5", X"91", X"48", X"98", X"48", + X"a0", X"00", X"8a", X"f0", X"1d", X"60", X"20", X"dc", + X"e6", X"4c", X"01", X"e3", X"20", X"fd", X"e5", X"a2", + X"00", X"86", X"11", X"a8", X"60", X"20", X"dc", X"e6", + X"f0", X"08", X"a0", X"00", X"b1", X"5e", X"a8", X"4c", + X"01", X"e3", X"4c", X"99", X"e1", X"20", X"b1", X"00", + X"20", X"67", X"dd", X"20", X"08", X"e1", X"a6", X"a0", + X"d0", X"f0", X"a6", X"a1", X"4c", X"b7", X"00", X"20", + X"dc", X"e6", X"d0", X"03", X"4c", X"4e", X"e8", X"a6", + X"b8", X"a4", X"b9", X"86", X"ad", X"84", X"ae", X"a6", + X"5e", X"86", X"b8", X"18", X"65", X"5e", X"85", X"60", + X"a6", X"5f", X"86", X"b9", X"90", X"01", X"e8", X"86", + X"61", X"a0", X"00", X"b1", X"60", X"48", X"a9", X"00", + X"91", X"60", X"20", X"b7", X"00", X"20", X"4a", X"ec", + X"68", X"a0", X"00", X"91", X"60", X"a6", X"ad", X"a4", + X"ae", X"86", X"b8", X"84", X"b9", X"60", X"20", X"67", + X"dd", X"20", X"52", X"e7", X"20", X"be", X"de", X"4c", + X"f8", X"e6", X"a5", X"9d", X"c9", X"91", X"b0", X"9a", + X"20", X"f2", X"eb", X"a5", X"a0", X"a4", X"a1", X"84", + X"50", X"85", X"51", X"60", X"a5", X"50", X"48", X"a5", + X"51", X"48", X"20", X"52", X"e7", X"a0", X"00", X"b1", + X"50", X"a8", X"68", X"85", X"51", X"68", X"85", X"50", + X"4c", X"01", X"e3", X"20", X"46", X"e7", X"8a", X"a0", + X"00", X"91", X"50", X"60", X"20", X"46", X"e7", X"86", + X"85", X"a2", X"00", X"20", X"b7", X"00", X"f0", X"03", + X"20", X"4c", X"e7", X"86", X"86", X"a0", X"00", X"b1", + X"50", X"45", X"86", X"25", X"85", X"f0", X"f8", X"60", + X"a9", X"64", X"a0", X"ee", X"4c", X"be", X"e7", X"20", + X"e3", X"e9", X"a5", X"a2", X"49", X"ff", X"85", X"a2", + X"45", X"aa", X"85", X"ab", X"a5", X"9d", X"4c", X"c1", + X"e7", X"20", X"f0", X"e8", X"90", X"3c", X"20", X"e3", + X"e9", X"d0", X"03", X"4c", X"53", X"eb", X"a6", X"ac", + X"86", X"92", X"a2", X"a5", X"a5", X"a5", X"a8", X"f0", + X"ce", X"38", X"e5", X"9d", X"f0", X"24", X"90", X"12", + X"84", X"9d", X"a4", X"aa", X"84", X"a2", X"49", X"ff", + X"69", X"00", X"a0", X"00", X"84", X"92", X"a2", X"9d", + X"d0", X"04", X"a0", X"00", X"84", X"ac", X"c9", X"f9", + X"30", X"c7", X"a8", X"a5", X"ac", X"56", X"01", X"20", + X"07", X"e9", X"24", X"ab", X"10", X"57", X"a0", X"9d", + X"e0", X"a5", X"f0", X"02", X"a0", X"a5", X"38", X"49", + X"ff", X"65", X"92", X"85", X"ac", X"b9", X"04", X"00", + X"f5", X"04", X"85", X"a1", X"b9", X"03", X"00", X"f5", + X"03", X"85", X"a0", X"b9", X"02", X"00", X"f5", X"02", + X"85", X"9f", X"b9", X"01", X"00", X"f5", X"01", X"85", + X"9e", X"b0", X"03", X"20", X"9e", X"e8", X"a0", X"00", + X"98", X"18", X"a6", X"9e", X"d0", X"4a", X"a6", X"9f", + X"86", X"9e", X"a6", X"a0", X"86", X"9f", X"a6", X"a1", + X"86", X"a0", X"a6", X"ac", X"86", X"a1", X"84", X"ac", + X"69", X"08", X"c9", X"20", X"d0", X"e4", X"a9", X"00", + X"85", X"9d", X"85", X"a2", X"60", X"65", X"92", X"85", + X"ac", X"a5", X"a1", X"65", X"a9", X"85", X"a1", X"a5", + X"a0", X"65", X"a8", X"85", X"a0", X"a5", X"9f", X"65", + X"a7", X"85", X"9f", X"a5", X"9e", X"65", X"a6", X"85", + X"9e", X"4c", X"8d", X"e8", X"69", X"01", X"06", X"ac", + X"26", X"a1", X"26", X"a0", X"26", X"9f", X"26", X"9e", + X"10", X"f2", X"38", X"e5", X"9d", X"b0", X"c7", X"49", + X"ff", X"69", X"01", X"85", X"9d", X"90", X"0e", X"e6", + X"9d", X"f0", X"42", X"66", X"9e", X"66", X"9f", X"66", + X"a0", X"66", X"a1", X"66", X"ac", X"60", X"a5", X"a2", + X"49", X"ff", X"85", X"a2", X"a5", X"9e", X"49", X"ff", + X"85", X"9e", X"a5", X"9f", X"49", X"ff", X"85", X"9f", + X"a5", X"a0", X"49", X"ff", X"85", X"a0", X"a5", X"a1", + X"49", X"ff", X"85", X"a1", X"a5", X"ac", X"49", X"ff", + X"85", X"ac", X"e6", X"ac", X"d0", X"0e", X"e6", X"a1", + X"d0", X"0a", X"e6", X"a0", X"d0", X"06", X"e6", X"9f", + X"d0", X"02", X"e6", X"9e", X"60", X"a2", X"45", X"4c", + X"12", X"d4", X"a2", X"61", X"b4", X"04", X"84", X"ac", + X"b4", X"03", X"94", X"04", X"b4", X"02", X"94", X"03", + X"b4", X"01", X"94", X"02", X"a4", X"a4", X"94", X"01", + X"69", X"08", X"30", X"e8", X"f0", X"e6", X"e9", X"08", + X"a8", X"a5", X"ac", X"b0", X"14", X"16", X"01", X"90", + X"02", X"f6", X"01", X"76", X"01", X"76", X"01", X"76", + X"02", X"76", X"03", X"76", X"04", X"6a", X"c8", X"d0", + X"ec", X"18", X"60", X"81", X"00", X"00", X"00", X"00", + X"03", X"7f", X"5e", X"56", X"cb", X"79", X"80", X"13", + X"9b", X"0b", X"64", X"80", X"76", X"38", X"93", X"16", + X"82", X"38", X"aa", X"3b", X"20", X"80", X"35", X"04", + X"f3", X"34", X"81", X"35", X"04", X"f3", X"34", X"80", + X"80", X"00", X"00", X"00", X"80", X"31", X"72", X"17", + X"f8", X"20", X"82", X"eb", X"f0", X"02", X"10", X"03", + X"4c", X"99", X"e1", X"a5", X"9d", X"e9", X"7f", X"48", + X"a9", X"80", X"85", X"9d", X"a9", X"2d", X"a0", X"e9", + X"20", X"be", X"e7", X"a9", X"32", X"a0", X"e9", X"20", + X"66", X"ea", X"a9", X"13", X"a0", X"e9", X"20", X"a7", + X"e7", X"a9", X"18", X"a0", X"e9", X"20", X"5c", X"ef", + X"a9", X"37", X"a0", X"e9", X"20", X"be", X"e7", X"68", + X"20", X"d5", X"ec", X"a9", X"3c", X"a0", X"e9", X"20", + X"e3", X"e9", X"d0", X"03", X"4c", X"e2", X"e9", X"20", + X"0e", X"ea", X"a9", X"00", X"85", X"62", X"85", X"63", + X"85", X"64", X"85", X"65", X"a5", X"ac", X"20", X"b0", + X"e9", X"a5", X"a1", X"20", X"b0", X"e9", X"a5", X"a0", + X"20", X"b0", X"e9", X"a5", X"9f", X"20", X"b0", X"e9", + X"a5", X"9e", X"20", X"b5", X"e9", X"4c", X"e6", X"ea", + X"d0", X"03", X"4c", X"da", X"e8", X"4a", X"09", X"80", + X"a8", X"90", X"19", X"18", X"a5", X"65", X"65", X"a9", + X"85", X"65", X"a5", X"64", X"65", X"a8", X"85", X"64", + X"a5", X"63", X"65", X"a7", X"85", X"63", X"a5", X"62", + X"65", X"a6", X"85", X"62", X"66", X"62", X"66", X"63", + X"66", X"64", X"66", X"65", X"66", X"ac", X"98", X"4a", + X"d0", X"d6", X"60", X"85", X"5e", X"84", X"5f", X"a0", + X"04", X"b1", X"5e", X"85", X"a9", X"88", X"b1", X"5e", + X"85", X"a8", X"88", X"b1", X"5e", X"85", X"a7", X"88", + X"b1", X"5e", X"85", X"aa", X"45", X"a2", X"85", X"ab", + X"a5", X"aa", X"09", X"80", X"85", X"a6", X"88", X"b1", + X"5e", X"85", X"a5", X"a5", X"9d", X"60", X"a5", X"a5", + X"f0", X"1f", X"18", X"65", X"9d", X"90", X"04", X"30", + X"1d", X"18", X"2c", X"10", X"14", X"69", X"80", X"85", + X"9d", X"d0", X"03", X"4c", X"52", X"e8", X"a5", X"ab", + X"85", X"a2", X"60", X"a5", X"a2", X"49", X"ff", X"30", + X"05", X"68", X"68", X"4c", X"4e", X"e8", X"4c", X"d5", + X"e8", X"20", X"63", X"eb", X"aa", X"f0", X"10", X"18", + X"69", X"02", X"b0", X"f2", X"a2", X"00", X"86", X"ab", + X"20", X"ce", X"e7", X"e6", X"9d", X"f0", X"e7", X"60", + X"84", X"20", X"00", X"00", X"00", X"20", X"63", X"eb", + X"a9", X"50", X"a0", X"ea", X"a2", X"00", X"86", X"ab", + X"20", X"f9", X"ea", X"4c", X"69", X"ea", X"20", X"e3", + X"e9", X"f0", X"76", X"20", X"72", X"eb", X"a9", X"00", + X"38", X"e5", X"9d", X"85", X"9d", X"20", X"0e", X"ea", + X"e6", X"9d", X"f0", X"ba", X"a2", X"fc", X"a9", X"01", + X"a4", X"a6", X"c4", X"9e", X"d0", X"10", X"a4", X"a7", + X"c4", X"9f", X"d0", X"0a", X"a4", X"a8", X"c4", X"a0", + X"d0", X"04", X"a4", X"a9", X"c4", X"a1", X"08", X"2a", + X"90", X"09", X"e8", X"95", X"65", X"f0", X"32", X"10", + X"34", X"a9", X"01", X"28", X"b0", X"0e", X"06", X"a9", + X"26", X"a8", X"26", X"a7", X"26", X"a6", X"b0", X"e6", + X"30", X"ce", X"10", X"e2", X"a8", X"a5", X"a9", X"e5", + X"a1", X"85", X"a9", X"a5", X"a8", X"e5", X"a0", X"85", + X"a8", X"a5", X"a7", X"e5", X"9f", X"85", X"a7", X"a5", + X"a6", X"e5", X"9e", X"85", X"a6", X"98", X"4c", X"a6", + X"ea", X"a9", X"40", X"d0", X"ce", X"0a", X"0a", X"0a", + X"0a", X"0a", X"0a", X"85", X"ac", X"28", X"4c", X"e6", + X"ea", X"a2", X"85", X"4c", X"12", X"d4", X"a5", X"62", + X"85", X"9e", X"a5", X"63", X"85", X"9f", X"a5", X"64", + X"85", X"a0", X"a5", X"65", X"85", X"a1", X"4c", X"2e", + X"e8", X"85", X"5e", X"84", X"5f", X"a0", X"04", X"b1", + X"5e", X"85", X"a1", X"88", X"b1", X"5e", X"85", X"a0", + X"88", X"b1", X"5e", X"85", X"9f", X"88", X"b1", X"5e", + X"85", X"a2", X"09", X"80", X"85", X"9e", X"88", X"b1", + X"5e", X"85", X"9d", X"84", X"ac", X"60", X"a2", X"98", + X"2c", X"a2", X"93", X"a0", X"00", X"f0", X"04", X"a6", + X"85", X"a4", X"86", X"20", X"72", X"eb", X"86", X"5e", + X"84", X"5f", X"a0", X"04", X"a5", X"a1", X"91", X"5e", + X"88", X"a5", X"a0", X"91", X"5e", X"88", X"a5", X"9f", + X"91", X"5e", X"88", X"a5", X"a2", X"09", X"7f", X"25", + X"9e", X"91", X"5e", X"88", X"a5", X"9d", X"91", X"5e", + X"84", X"ac", X"60", X"a5", X"aa", X"85", X"a2", X"a2", + X"05", X"b5", X"a4", X"95", X"9c", X"ca", X"d0", X"f9", + X"86", X"ac", X"60", X"20", X"72", X"eb", X"a2", X"06", + X"b5", X"9c", X"95", X"a4", X"ca", X"d0", X"f9", X"86", + X"ac", X"60", X"a5", X"9d", X"f0", X"fb", X"06", X"ac", + X"90", X"f7", X"20", X"c6", X"e8", X"d0", X"f2", X"4c", + X"8f", X"e8", X"a5", X"9d", X"f0", X"09", X"a5", X"a2", + X"2a", X"a9", X"ff", X"b0", X"02", X"a9", X"01", X"60", + X"20", X"82", X"eb", X"85", X"9e", X"a9", X"00", X"85", + X"9f", X"a2", X"88", X"a5", X"9e", X"49", X"ff", X"2a", + X"a9", X"00", X"85", X"a1", X"85", X"a0", X"86", X"9d", + X"85", X"ac", X"85", X"a2", X"4c", X"29", X"e8", X"46", + X"a2", X"60", X"85", X"60", X"84", X"61", X"a0", X"00", + X"b1", X"60", X"c8", X"aa", X"f0", X"c4", X"b1", X"60", + X"45", X"a2", X"30", X"c2", X"e4", X"9d", X"d0", X"21", + X"b1", X"60", X"09", X"80", X"c5", X"9e", X"d0", X"19", + X"c8", X"b1", X"60", X"c5", X"9f", X"d0", X"12", X"c8", + X"b1", X"60", X"c5", X"a0", X"d0", X"0b", X"c8", X"a9", + X"7f", X"c5", X"ac", X"b1", X"60", X"e5", X"a1", X"f0", + X"28", X"a5", X"a2", X"90", X"02", X"49", X"ff", X"4c", + X"88", X"eb", X"a5", X"9d", X"f0", X"4a", X"38", X"e9", + X"a0", X"24", X"a2", X"10", X"09", X"aa", X"a9", X"ff", + X"85", X"a4", X"20", X"a4", X"e8", X"8a", X"a2", X"9d", + X"c9", X"f9", X"10", X"06", X"20", X"f0", X"e8", X"84", + X"a4", X"60", X"a8", X"a5", X"a2", X"29", X"80", X"46", + X"9e", X"05", X"9e", X"85", X"9e", X"20", X"07", X"e9", + X"84", X"a4", X"60", X"a5", X"9d", X"c9", X"a0", X"b0", + X"20", X"20", X"f2", X"eb", X"84", X"ac", X"a5", X"a2", + X"84", X"a2", X"49", X"80", X"2a", X"a9", X"a0", X"85", + X"9d", X"a5", X"a1", X"85", X"0d", X"4c", X"29", X"e8", + X"85", X"9e", X"85", X"9f", X"85", X"a0", X"85", X"a1", + X"a8", X"60", X"a0", X"00", X"a2", X"0a", X"94", X"99", + X"ca", X"10", X"fb", X"90", X"0f", X"c9", X"2d", X"d0", + X"04", X"86", X"a3", X"f0", X"04", X"c9", X"2b", X"d0", + X"05", X"20", X"b1", X"00", X"90", X"5b", X"c9", X"2e", + X"f0", X"2e", X"c9", X"45", X"d0", X"30", X"20", X"b1", + X"00", X"90", X"17", X"c9", X"c9", X"f0", X"0e", X"c9", + X"2d", X"f0", X"0a", X"c9", X"c8", X"f0", X"08", X"c9", + X"2b", X"f0", X"04", X"d0", X"07", X"66", X"9c", X"20", + X"b1", X"00", X"90", X"5c", X"24", X"9c", X"10", X"0e", + X"a9", X"00", X"38", X"e5", X"9a", X"4c", X"a0", X"ec", + X"66", X"9b", X"24", X"9b", X"50", X"c3", X"a5", X"9a", + X"38", X"e5", X"99", X"85", X"9a", X"f0", X"12", X"10", + X"09", X"20", X"55", X"ea", X"e6", X"9a", X"d0", X"f9", + X"f0", X"07", X"20", X"39", X"ea", X"c6", X"9a", X"d0", + X"f9", X"a5", X"a3", X"30", X"01", X"60", X"4c", X"d0", + X"ee", X"48", X"24", X"9b", X"10", X"02", X"e6", X"99", + X"20", X"39", X"ea", X"68", X"38", X"e9", X"30", X"20", + X"d5", X"ec", X"4c", X"61", X"ec", X"48", X"20", X"63", + X"eb", X"68", X"20", X"93", X"eb", X"a5", X"aa", X"45", + X"a2", X"85", X"ab", X"a6", X"9d", X"4c", X"c1", X"e7", + X"a5", X"9a", X"c9", X"0a", X"90", X"09", X"a9", X"64", + X"24", X"9c", X"30", X"11", X"4c", X"d5", X"e8", X"0a", + X"0a", X"18", X"65", X"9a", X"0a", X"18", X"a0", X"00", + X"71", X"b8", X"38", X"e9", X"30", X"85", X"9a", X"4c", + X"87", X"ec", X"9b", X"3e", X"bc", X"1f", X"fd", X"9e", + X"6e", X"6b", X"27", X"fd", X"9e", X"6e", X"6b", X"28", + X"00", X"a9", X"58", X"a0", X"d3", X"20", X"31", X"ed", + X"a5", X"76", X"a6", X"75", X"85", X"9e", X"86", X"9f", + X"a2", X"90", X"38", X"20", X"a0", X"eb", X"20", X"34", + X"ed", X"4c", X"3a", X"db", X"a0", X"01", X"a9", X"2d", + X"88", X"24", X"a2", X"10", X"04", X"c8", X"99", X"ff", + X"00", X"85", X"a2", X"84", X"ad", X"c8", X"a9", X"30", + X"a6", X"9d", X"d0", X"03", X"4c", X"57", X"ee", X"a9", + X"00", X"e0", X"80", X"f0", X"02", X"b0", X"09", X"a9", + X"14", X"a0", X"ed", X"20", X"7f", X"e9", X"a9", X"f7", + X"85", X"99", X"a9", X"0f", X"a0", X"ed", X"20", X"b2", + X"eb", X"f0", X"1e", X"10", X"12", X"a9", X"0a", X"a0", + X"ed", X"20", X"b2", X"eb", X"f0", X"02", X"10", X"0e", + X"20", X"39", X"ea", X"c6", X"99", X"d0", X"ee", X"20", + X"55", X"ea", X"e6", X"99", X"d0", X"dc", X"20", X"a0", + X"e7", X"20", X"f2", X"eb", X"a2", X"01", X"a5", X"99", + X"18", X"69", X"0a", X"30", X"09", X"c9", X"0b", X"b0", + X"06", X"69", X"ff", X"aa", X"a9", X"02", X"38", X"e9", + X"02", X"85", X"9a", X"86", X"99", X"8a", X"f0", X"02", + X"10", X"13", X"a4", X"ad", X"a9", X"2e", X"c8", X"99", + X"ff", X"00", X"8a", X"f0", X"06", X"a9", X"30", X"c8", + X"99", X"ff", X"00", X"84", X"ad", X"a0", X"00", X"a2", + X"80", X"a5", X"a1", X"18", X"79", X"6c", X"ee", X"85", + X"a1", X"a5", X"a0", X"79", X"6b", X"ee", X"85", X"a0", + X"a5", X"9f", X"79", X"6a", X"ee", X"85", X"9f", X"a5", + X"9e", X"79", X"69", X"ee", X"85", X"9e", X"e8", X"b0", + X"04", X"10", X"de", X"30", X"02", X"30", X"da", X"8a", + X"90", X"04", X"49", X"ff", X"69", X"0a", X"69", X"2f", + X"c8", X"c8", X"c8", X"c8", X"84", X"83", X"a4", X"ad", + X"c8", X"aa", X"29", X"7f", X"99", X"ff", X"00", X"c6", + X"99", X"d0", X"06", X"a9", X"2e", X"c8", X"99", X"ff", + X"00", X"84", X"ad", X"a4", X"83", X"8a", X"49", X"ff", + X"29", X"80", X"aa", X"c0", X"24", X"d0", X"aa", X"a4", + X"ad", X"b9", X"ff", X"00", X"88", X"c9", X"30", X"f0", + X"f8", X"c9", X"2e", X"f0", X"01", X"c8", X"a9", X"2b", + X"a6", X"9a", X"f0", X"2e", X"10", X"08", X"a9", X"00", + X"38", X"e5", X"9a", X"aa", X"a9", X"2d", X"99", X"01", + X"01", X"a9", X"45", X"99", X"00", X"01", X"8a", X"a2", + X"2f", X"38", X"e8", X"e9", X"0a", X"b0", X"fb", X"69", + X"3a", X"99", X"03", X"01", X"8a", X"99", X"02", X"01", + X"a9", X"00", X"99", X"04", X"01", X"f0", X"08", X"99", + X"ff", X"00", X"a9", X"00", X"99", X"00", X"01", X"a9", + X"00", X"a0", X"01", X"60", X"80", X"00", X"00", X"00", + X"00", X"fa", X"0a", X"1f", X"00", X"00", X"98", X"96", + X"80", X"ff", X"f0", X"bd", X"c0", X"00", X"01", X"86", + X"a0", X"ff", X"ff", X"d8", X"f0", X"00", X"00", X"03", + X"e8", X"ff", X"ff", X"ff", X"9c", X"00", X"00", X"00", + X"0a", X"ff", X"ff", X"ff", X"ff", X"20", X"63", X"eb", + X"a9", X"64", X"a0", X"ee", X"20", X"f9", X"ea", X"f0", + X"70", X"a5", X"a5", X"d0", X"03", X"4c", X"50", X"e8", + X"a2", X"8a", X"a0", X"00", X"20", X"2b", X"eb", X"a5", + X"aa", X"10", X"0f", X"20", X"23", X"ec", X"a9", X"8a", + X"a0", X"00", X"20", X"b2", X"eb", X"d0", X"03", X"98", + X"a4", X"0d", X"20", X"55", X"eb", X"98", X"48", X"20", + X"41", X"e9", X"a9", X"8a", X"a0", X"00", X"20", X"7f", + X"e9", X"20", X"09", X"ef", X"68", X"4a", X"90", X"0a", + X"a5", X"9d", X"f0", X"06", X"a5", X"a2", X"49", X"ff", + X"85", X"a2", X"60", X"81", X"38", X"aa", X"3b", X"29", + X"07", X"71", X"34", X"58", X"3e", X"56", X"74", X"16", + X"7e", X"b3", X"1b", X"77", X"2f", X"ee", X"e3", X"85", + X"7a", X"1d", X"84", X"1c", X"2a", X"7c", X"63", X"59", + X"58", X"0a", X"7e", X"75", X"fd", X"e7", X"c6", X"80", + X"31", X"72", X"18", X"10", X"81", X"00", X"00", X"00", + X"00", X"a9", X"db", X"a0", X"ee", X"20", X"7f", X"e9", + X"a5", X"ac", X"69", X"50", X"90", X"03", X"20", X"7a", + X"eb", X"85", X"92", X"20", X"66", X"eb", X"a5", X"9d", + X"c9", X"88", X"90", X"03", X"20", X"2b", X"ea", X"20", + X"23", X"ec", X"a5", X"0d", X"18", X"69", X"81", X"f0", + X"f3", X"38", X"e9", X"01", X"48", X"a2", X"05", X"b5", + X"a5", X"b4", X"9d", X"95", X"9d", X"94", X"a5", X"ca", + X"10", X"f5", X"a5", X"92", X"85", X"ac", X"20", X"aa", + X"e7", X"20", X"d0", X"ee", X"a9", X"e0", X"a0", X"ee", + X"20", X"72", X"ef", X"a9", X"00", X"85", X"ab", X"68", + X"20", X"10", X"ea", X"60", X"85", X"ad", X"84", X"ae", + X"20", X"21", X"eb", X"a9", X"93", X"20", X"7f", X"e9", + X"20", X"76", X"ef", X"a9", X"93", X"a0", X"00", X"4c", + X"7f", X"e9", X"85", X"ad", X"84", X"ae", X"20", X"1e", + X"eb", X"b1", X"ad", X"85", X"a3", X"a4", X"ad", X"c8", + X"98", X"d0", X"02", X"e6", X"ae", X"85", X"ad", X"a4", + X"ae", X"20", X"7f", X"e9", X"a5", X"ad", X"a4", X"ae", + X"18", X"69", X"05", X"90", X"01", X"c8", X"85", X"ad", + X"84", X"ae", X"20", X"be", X"e7", X"a9", X"98", X"a0", + X"00", X"c6", X"a3", X"d0", X"e4", X"60", X"98", X"35", + X"44", X"7a", X"68", X"28", X"b1", X"46", X"20", X"82", + X"eb", X"aa", X"30", X"18", X"a9", X"c9", X"a0", X"00", + X"20", X"f9", X"ea", X"8a", X"f0", X"e7", X"a9", X"a6", + X"a0", X"ef", X"20", X"7f", X"e9", X"a9", X"aa", X"a0", + X"ef", X"20", X"be", X"e7", X"a6", X"a1", X"a5", X"9e", + X"85", X"a1", X"86", X"9e", X"a9", X"00", X"85", X"a2", + X"a5", X"9d", X"85", X"ac", X"a9", X"80", X"85", X"9d", + X"20", X"2e", X"e8", X"a2", X"c9", X"a0", X"00", X"4c", + X"2b", X"eb", X"a9", X"66", X"a0", X"f0", X"20", X"be", + X"e7", X"20", X"63", X"eb", X"a9", X"6b", X"a0", X"f0", + X"a6", X"aa", X"20", X"5e", X"ea", X"20", X"63", X"eb", + X"20", X"23", X"ec", X"a9", X"00", X"85", X"ab", X"20", + X"aa", X"e7", X"a9", X"70", X"a0", X"f0", X"20", X"a7", + X"e7", X"a5", X"a2", X"48", X"10", X"0d", X"20", X"a0", + X"e7", X"a5", X"a2", X"30", X"09", X"a5", X"16", X"49", + X"ff", X"85", X"16", X"20", X"d0", X"ee", X"a9", X"70", + X"a0", X"f0", X"20", X"be", X"e7", X"68", X"10", X"03", + X"20", X"d0", X"ee", X"a9", X"75", X"a0", X"f0", X"4c", + X"5c", X"ef", X"20", X"21", X"eb", X"a9", X"00", X"85", + X"16", X"20", X"f1", X"ef", X"a2", X"8a", X"a0", X"00", + X"20", X"e7", X"ef", X"a9", X"93", X"a0", X"00", X"20", + X"f9", X"ea", X"a9", X"00", X"85", X"a2", X"a5", X"16", + X"20", X"62", X"f0", X"a9", X"8a", X"a0", X"00", X"4c", + X"66", X"ea", X"48", X"4c", X"23", X"f0", X"81", X"49", + X"0f", X"da", X"a2", X"83", X"49", X"0f", X"da", X"a2", + X"7f", X"00", X"00", X"00", X"00", X"05", X"84", X"e6", + X"1a", X"2d", X"1b", X"86", X"28", X"07", X"fb", X"f8", + X"87", X"99", X"68", X"89", X"01", X"87", X"23", X"35", + X"df", X"e1", X"86", X"a5", X"5d", X"e7", X"28", X"83", + X"49", X"0f", X"da", X"a2", X"a6", X"d3", X"c1", X"c8", + X"d4", X"c8", X"d5", X"c4", X"ce", X"ca", X"a5", X"a2", + X"48", X"10", X"03", X"20", X"d0", X"ee", X"a5", X"9d", + X"48", X"c9", X"81", X"90", X"07", X"a9", X"13", X"a0", + X"e9", X"20", X"66", X"ea", X"a9", X"ce", X"a0", X"f0", + X"20", X"5c", X"ef", X"68", X"c9", X"81", X"90", X"07", + X"a9", X"66", X"a0", X"f0", X"20", X"a7", X"e7", X"68", + X"10", X"03", X"4c", X"d0", X"ee", X"60", X"0b", X"76", + X"b3", X"83", X"bd", X"d3", X"79", X"1e", X"f4", X"a6", + X"f5", X"7b", X"83", X"fc", X"b0", X"10", X"7c", X"0c", + X"1f", X"67", X"ca", X"7c", X"de", X"53", X"cb", X"c1", + X"7d", X"14", X"64", X"70", X"4c", X"7d", X"b7", X"ea", + X"51", X"7a", X"7d", X"63", X"30", X"88", X"7e", X"7e", + X"92", X"44", X"99", X"3a", X"7e", X"4c", X"cc", X"91", + X"c7", X"7f", X"aa", X"aa", X"aa", X"13", X"81", X"00", + X"00", X"00", X"00", X"e6", X"b8", X"d0", X"02", X"e6", + X"b9", X"ad", X"60", X"ea", X"c9", X"3a", X"b0", X"0a", + X"c9", X"20", X"f0", X"ef", X"38", X"e9", X"30", X"38", + X"e9", X"d0", X"60", X"80", X"4f", X"c7", X"52", X"58", + X"a2", X"ff", X"86", X"76", X"a2", X"fb", X"9a", X"a9", + X"28", X"a0", X"f1", X"85", X"01", X"84", X"02", X"85", + X"04", X"84", X"05", X"20", X"73", X"f2", X"a9", X"4c", + X"85", X"00", X"85", X"03", X"85", X"90", X"85", X"0a", + X"a9", X"99", X"a0", X"e1", X"85", X"0b", X"84", X"0c", + X"a2", X"1c", X"bd", X"0a", X"f1", X"95", X"b0", X"86", + X"f1", X"ca", X"d0", X"f6", X"86", X"f2", X"8a", X"85", + X"a4", X"85", X"54", X"48", X"a9", X"03", X"85", X"8f", + X"20", X"fb", X"da", X"a9", X"01", X"8d", X"fd", X"01", + X"8d", X"fc", X"01", X"a2", X"55", X"86", X"52", X"a9", + X"00", X"a0", X"08", X"85", X"50", X"84", X"51", X"a0", + X"00", X"e6", X"51", X"b1", X"50", X"49", X"ff", X"91", + X"50", X"d1", X"50", X"d0", X"08", X"49", X"ff", X"91", + X"50", X"d1", X"50", X"f0", X"ec", X"a4", X"50", X"a5", + X"51", X"29", X"f0", X"84", X"73", X"85", X"74", X"84", + X"6f", X"85", X"70", X"a2", X"00", X"a0", X"08", X"86", + X"67", X"84", X"68", X"a0", X"00", X"84", X"d6", X"98", + X"91", X"67", X"e6", X"67", X"d0", X"02", X"e6", X"68", + X"a5", X"67", X"a4", X"68", X"20", X"e3", X"d3", X"20", + X"4b", X"d6", X"a9", X"3a", X"a0", X"db", X"85", X"04", + X"84", X"05", X"a9", X"3c", X"a0", X"d4", X"85", X"01", + X"84", X"02", X"6c", X"01", X"00", X"20", X"67", X"dd", + X"20", X"52", X"e7", X"6c", X"50", X"00", X"20", X"f8", + X"e6", X"8a", X"4c", X"8b", X"fe", X"20", X"f8", X"e6", + X"8a", X"4c", X"95", X"fe", X"20", X"f8", X"e6", X"e0", + X"30", X"b0", X"13", X"86", X"f0", X"a9", X"2c", X"20", + X"c0", X"de", X"20", X"f8", X"e6", X"e0", X"30", X"b0", + X"05", X"86", X"2c", X"86", X"2d", X"60", X"4c", X"99", + X"e1", X"20", X"ec", X"f1", X"e4", X"f0", X"b0", X"08", + X"a5", X"f0", X"85", X"2c", X"85", X"2d", X"86", X"f0", + X"a9", X"c5", X"20", X"c0", X"de", X"20", X"f8", X"e6", + X"e0", X"30", X"b0", X"e2", X"60", X"20", X"ec", X"f1", + X"8a", X"a4", X"f0", X"c0", X"28", X"b0", X"d7", X"4c", + X"00", X"f8", X"20", X"09", X"f2", X"8a", X"a4", X"2c", + X"c0", X"28", X"b0", X"ca", X"a4", X"f0", X"4c", X"19", + X"f8", X"20", X"09", X"f2", X"8a", X"a8", X"c0", X"28", + X"b0", X"bc", X"a5", X"f0", X"4c", X"28", X"f8", X"20", + X"f8", X"e6", X"8a", X"4c", X"64", X"f8", X"20", X"f8", + X"e6", X"ca", X"8a", X"c9", X"18", X"b0", X"a7", X"4c", + X"5b", X"fb", X"20", X"f8", X"e6", X"8a", X"49", X"ff", + X"aa", X"e8", X"86", X"f1", X"60", X"38", X"90", X"18", + X"66", X"f2", X"60", X"a9", X"ff", X"d0", X"02", X"a9", + X"3f", X"a2", X"00", X"85", X"32", X"86", X"f3", X"60", + X"a9", X"7f", X"a2", X"40", X"d0", X"f5", X"20", X"67", + X"dd", X"20", X"52", X"e7", X"a5", X"50", X"c5", X"6d", + X"a5", X"51", X"e5", X"6e", X"b0", X"03", X"4c", X"10", + X"d4", X"a5", X"50", X"85", X"73", X"85", X"6f", X"a5", + X"51", X"85", X"74", X"85", X"70", X"60", X"20", X"67", + X"dd", X"20", X"52", X"e7", X"a5", X"50", X"c5", X"73", + X"a5", X"51", X"e5", X"74", X"b0", X"e0", X"a5", X"50", + X"c5", X"69", X"a5", X"51", X"e5", X"6a", X"90", X"d6", + X"a5", X"50", X"85", X"69", X"a5", X"51", X"85", X"6a", + X"4c", X"6c", X"d6", X"a9", X"ab", X"20", X"c0", X"de", + X"a5", X"b8", X"85", X"f4", X"a5", X"b9", X"85", X"f5", + X"38", X"66", X"d8", X"a5", X"75", X"85", X"f6", X"a5", + X"76", X"85", X"f7", X"20", X"a6", X"d9", X"4c", X"98", + X"d9", X"86", X"de", X"a6", X"f8", X"86", X"df", X"a5", + X"75", X"85", X"da", X"a5", X"76", X"85", X"db", X"a5", + X"79", X"85", X"dc", X"a5", X"7a", X"85", X"dd", X"a5", + X"f4", X"85", X"b8", X"a5", X"f5", X"85", X"b9", X"a5", + X"f6", X"85", X"75", X"a5", X"f7", X"85", X"76", X"20", + X"b7", X"00", X"20", X"3e", X"d9", X"4c", X"d2", X"d7", + X"a5", X"da", X"85", X"75", X"a5", X"db", X"85", X"76", + X"a5", X"dc", X"85", X"b8", X"a5", X"dd", X"85", X"b9", + X"a6", X"df", X"9a", X"4c", X"d2", X"d7", X"4c", X"c9", + X"de", X"b0", X"fb", X"a6", X"af", X"86", X"69", X"a6", + X"b0", X"86", X"6a", X"20", X"0c", X"da", X"20", X"1a", + X"d6", X"a5", X"9b", X"85", X"60", X"a5", X"9c", X"85", + X"61", X"a9", X"2c", X"20", X"c0", X"de", X"20", X"0c", + X"da", X"e6", X"50", X"d0", X"02", X"e6", X"51", X"20", + X"1a", X"d6", X"a5", X"9b", X"c5", X"60", X"a5", X"9c", + X"e5", X"61", X"b0", X"01", X"60", X"a0", X"00", X"b1", + X"9b", X"91", X"60", X"e6", X"9b", X"d0", X"02", X"e6", + X"9c", X"e6", X"60", X"d0", X"02", X"e6", X"61", X"a5", + X"69", X"c5", X"9b", X"a5", X"6a", X"e5", X"9c", X"b0", + X"e6", X"a6", X"61", X"a4", X"60", X"d0", X"01", X"ca", + X"88", X"86", X"6a", X"84", X"69", X"4c", X"f2", X"d4", + X"ad", X"56", X"c0", X"ad", X"53", X"c0", X"4c", X"40", + X"fb", X"ad", X"54", X"c0", X"4c", X"39", X"fb", X"20", + X"d9", X"f7", X"a0", X"03", X"b1", X"9b", X"aa", X"88", + X"b1", X"9b", X"e9", X"01", X"b0", X"01", X"ca", X"85", + X"50", X"86", X"51", X"20", X"cd", X"fe", X"20", X"bc", + X"f7", X"4c", X"cd", X"fe", X"20", X"d9", X"f7", X"20", + X"fd", X"fe", X"a0", X"02", X"b1", X"9b", X"c5", X"50", + X"c8", X"b1", X"9b", X"e5", X"51", X"b0", X"03", X"4c", + X"10", X"d4", X"20", X"bc", X"f7", X"4c", X"fd", X"fe", + X"2c", X"55", X"c0", X"2c", X"52", X"c0", X"a9", X"40", + X"d0", X"08", X"a9", X"20", X"2c", X"54", X"c0", X"2c", + X"53", X"c0", X"85", X"e6", X"ad", X"57", X"c0", X"ad", + X"50", X"c0", X"a9", X"00", X"85", X"1c", X"a5", X"e6", + X"85", X"1b", X"a0", X"00", X"84", X"1a", X"a5", X"1c", + X"91", X"1a", X"20", X"7e", X"f4", X"c8", X"d0", X"f6", + X"e6", X"1b", X"a5", X"1b", X"29", X"1f", X"d0", X"ee", + X"60", X"85", X"e2", X"86", X"e0", X"84", X"e1", X"48", + X"29", X"c0", X"85", X"26", X"4a", X"4a", X"05", X"26", + X"85", X"26", X"68", X"85", X"27", X"0a", X"0a", X"0a", + X"26", X"27", X"0a", X"26", X"27", X"0a", X"66", X"26", + X"a5", X"27", X"29", X"1f", X"05", X"e6", X"85", X"27", + X"8a", X"c0", X"00", X"f0", X"05", X"a0", X"23", X"69", + X"04", X"c8", X"e9", X"07", X"b0", X"fb", X"84", X"e5", + X"aa", X"bd", X"b9", X"f4", X"85", X"30", X"98", X"4a", + X"a5", X"e4", X"85", X"1c", X"b0", X"28", X"60", X"20", + X"11", X"f4", X"a5", X"1c", X"51", X"26", X"25", X"30", + X"51", X"26", X"91", X"26", X"60", X"10", X"23", X"a5", + X"30", X"4a", X"b0", X"05", X"49", X"c0", X"85", X"30", + X"60", X"88", X"10", X"02", X"a0", X"27", X"a9", X"c0", + X"85", X"30", X"84", X"e5", X"a5", X"1c", X"0a", X"c9", + X"c0", X"10", X"06", X"a5", X"1c", X"49", X"7f", X"85", + X"1c", X"60", X"a5", X"30", X"0a", X"49", X"80", X"30", + X"dd", X"a9", X"81", X"c8", X"c0", X"28", X"90", X"e0", + X"a0", X"00", X"b0", X"dc", X"18", X"a5", X"d1", X"29", + X"04", X"f0", X"25", X"a9", X"7f", X"25", X"30", X"31", + X"26", X"d0", X"19", X"e6", X"ea", X"a9", X"7f", X"25", + X"30", X"10", X"11", X"18", X"a5", X"d1", X"29", X"04", + X"f0", X"0e", X"b1", X"26", X"45", X"1c", X"25", X"30", + X"d0", X"02", X"e6", X"ea", X"51", X"26", X"91", X"26", + X"a5", X"d1", X"65", X"d3", X"29", X"03", X"c9", X"02", + X"6a", X"b0", X"92", X"30", X"30", X"18", X"a5", X"27", + X"2c", X"b9", X"f5", X"d0", X"22", X"06", X"26", X"b0", + X"1a", X"2c", X"cd", X"f4", X"f0", X"05", X"69", X"1f", + X"38", X"b0", X"12", X"69", X"23", X"48", X"a5", X"26", + X"69", X"b0", X"b0", X"02", X"69", X"f0", X"85", X"26", + X"68", X"b0", X"02", X"69", X"1f", X"66", X"26", X"69", + X"fc", X"85", X"27", X"60", X"18", X"a5", X"27", X"69", + X"04", X"2c", X"b9", X"f5", X"d0", X"f3", X"06", X"26", + X"90", X"18", X"69", X"e0", X"18", X"2c", X"08", X"f5", + X"f0", X"12", X"a5", X"26", X"69", X"50", X"49", X"f0", + X"f0", X"02", X"49", X"f0", X"85", X"26", X"a5", X"e6", + X"90", X"02", X"69", X"e0", X"66", X"26", X"90", X"d1", + X"48", X"a9", X"00", X"85", X"e0", X"85", X"e1", X"85", + X"e2", X"68", X"48", X"38", X"e5", X"e0", X"48", X"8a", + X"e5", X"e1", X"85", X"d3", X"b0", X"0a", X"68", X"49", + X"ff", X"69", X"01", X"48", X"a9", X"00", X"e5", X"d3", + X"85", X"d1", X"85", X"d5", X"68", X"85", X"d0", X"85", + X"d4", X"68", X"85", X"e0", X"86", X"e1", X"98", X"18", + X"e5", X"e2", X"90", X"04", X"49", X"ff", X"69", X"fe", + X"85", X"d2", X"84", X"e2", X"66", X"d3", X"38", X"e5", + X"d0", X"aa", X"a9", X"ff", X"e5", X"d1", X"85", X"1d", + X"a4", X"e5", X"b0", X"05", X"0a", X"20", X"65", X"f4", + X"38", X"a5", X"d4", X"65", X"d2", X"85", X"d4", X"a5", + X"d5", X"e9", X"00", X"85", X"d5", X"b1", X"26", X"45", + X"1c", X"25", X"30", X"51", X"26", X"91", X"26", X"e8", + X"d0", X"04", X"e6", X"1d", X"f0", X"62", X"a5", X"d3", + X"b0", X"da", X"20", X"d3", X"f4", X"18", X"a5", X"d4", + X"65", X"d0", X"85", X"d4", X"a5", X"d5", X"65", X"d1", + X"50", X"d9", X"81", X"82", X"84", X"88", X"90", X"a0", + X"c0", X"1c", X"ff", X"fe", X"fa", X"f4", X"ec", X"e1", + X"d4", X"c5", X"b4", X"a1", X"8d", X"78", X"61", X"49", + X"31", X"18", X"ff", X"a5", X"26", X"0a", X"a5", X"27", + X"29", X"03", X"2a", X"05", X"26", X"0a", X"0a", X"0a", + X"85", X"e2", X"a5", X"27", X"4a", X"4a", X"29", X"07", + X"05", X"e2", X"85", X"e2", X"a5", X"e5", X"0a", X"65", + X"e5", X"0a", X"aa", X"ca", X"a5", X"30", X"29", X"7f", + X"e8", X"4a", X"d0", X"fc", X"85", X"e1", X"8a", X"18", + X"65", X"e5", X"90", X"02", X"e6", X"e1", X"85", X"e0", + X"60", X"86", X"1a", X"84", X"1b", X"aa", X"4a", X"4a", + X"4a", X"4a", X"85", X"d3", X"8a", X"29", X"0f", X"aa", + X"bc", X"ba", X"f5", X"84", X"d0", X"49", X"0f", X"aa", + X"bc", X"bb", X"f5", X"c8", X"84", X"d2", X"a4", X"e5", + X"a2", X"00", X"86", X"ea", X"a1", X"1a", X"85", X"d1", + X"a2", X"80", X"86", X"d4", X"86", X"d5", X"a6", X"e7", + X"a5", X"d4", X"38", X"65", X"d0", X"85", X"d4", X"90", + X"04", X"20", X"b3", X"f4", X"18", X"a5", X"d5", X"65", + X"d2", X"85", X"d5", X"90", X"03", X"20", X"b4", X"f4", + X"ca", X"d0", X"e5", X"a5", X"d1", X"4a", X"4a", X"4a", + X"d0", X"d4", X"e6", X"1a", X"d0", X"02", X"e6", X"1b", + X"a1", X"1a", X"d0", X"ca", X"60", X"86", X"1a", X"84", + X"1b", X"aa", X"4a", X"4a", X"4a", X"4a", X"85", X"d3", + X"8a", X"29", X"0f", X"aa", X"bc", X"ba", X"f5", X"84", + X"d0", X"49", X"0f", X"aa", X"bc", X"bb", X"f5", X"c8", + X"84", X"d2", X"a4", X"e5", X"a2", X"00", X"86", X"ea", + X"a1", X"1a", X"85", X"d1", X"a2", X"80", X"86", X"d4", + X"86", X"d5", X"a6", X"e7", X"a5", X"d4", X"38", X"65", + X"d0", X"85", X"d4", X"90", X"04", X"20", X"9c", X"f4", + X"18", X"a5", X"d5", X"65", X"d2", X"85", X"d5", X"90", + X"03", X"20", X"9d", X"f4", X"ca", X"d0", X"e5", X"a5", + X"d1", X"4a", X"4a", X"4a", X"d0", X"d4", X"e6", X"1a", + X"d0", X"02", X"e6", X"1b", X"a1", X"1a", X"d0", X"ca", + X"60", X"20", X"67", X"dd", X"20", X"52", X"e7", X"a4", + X"51", X"a6", X"50", X"c0", X"01", X"90", X"06", X"d0", + X"1d", X"e0", X"18", X"b0", X"19", X"8a", X"48", X"98", + X"48", X"a9", X"2c", X"20", X"c0", X"de", X"20", X"f8", + X"e6", X"e0", X"c0", X"b0", X"09", X"86", X"9d", X"68", + X"a8", X"68", X"aa", X"a5", X"9d", X"60", X"4c", X"06", + X"f2", X"20", X"f8", X"e6", X"e0", X"08", X"b0", X"f6", + X"bd", X"f6", X"f6", X"85", X"e4", X"60", X"00", X"2a", + X"55", X"7f", X"80", X"aa", X"d5", X"ff", X"c9", X"c1", + X"f0", X"0d", X"20", X"b9", X"f6", X"20", X"57", X"f4", + X"20", X"b7", X"00", X"c9", X"c1", X"d0", X"e6", X"20", + X"c0", X"de", X"20", X"b9", X"f6", X"84", X"9d", X"a8", + X"8a", X"a6", X"9d", X"20", X"3a", X"f5", X"4c", X"08", + X"f7", X"20", X"f8", X"e6", X"86", X"f9", X"60", X"20", + X"f8", X"e6", X"86", X"e7", X"60", X"20", X"f8", X"e6", + X"a5", X"e8", X"85", X"1a", X"a5", X"e9", X"85", X"1b", + X"8a", X"a2", X"00", X"c1", X"1a", X"f0", X"02", X"b0", + X"a5", X"0a", X"90", X"03", X"e6", X"1b", X"18", X"a8", + X"b1", X"1a", X"65", X"1a", X"aa", X"c8", X"b1", X"1a", + X"65", X"e9", X"85", X"1b", X"86", X"1a", X"20", X"b7", + X"00", X"c9", X"c5", X"d0", X"09", X"20", X"c0", X"de", + X"20", X"b9", X"f6", X"20", X"11", X"f4", X"a5", X"f9", + X"60", X"20", X"2d", X"f7", X"4c", X"05", X"f6", X"20", + X"2d", X"f7", X"4c", X"61", X"f6", X"a9", X"00", X"85", + X"3d", X"85", X"3f", X"a0", X"50", X"84", X"3c", X"c8", + X"84", X"3e", X"20", X"fd", X"fe", X"18", X"a5", X"73", + X"aa", X"ca", X"86", X"3e", X"e5", X"50", X"48", X"a5", + X"74", X"a8", X"e8", X"d0", X"01", X"88", X"84", X"3f", + X"e5", X"51", X"c5", X"6e", X"90", X"02", X"d0", X"03", + X"4c", X"10", X"d4", X"85", X"74", X"85", X"70", X"85", + X"3d", X"85", X"e9", X"68", X"85", X"e8", X"85", X"73", + X"85", X"6f", X"85", X"3c", X"20", X"fa", X"fc", X"a9", + X"03", X"4c", X"02", X"ff", X"18", X"a5", X"9b", X"65", + X"50", X"85", X"3e", X"a5", X"9c", X"65", X"51", X"85", + X"3f", X"a0", X"04", X"b1", X"9b", X"20", X"ef", X"e0", + X"a5", X"94", X"85", X"3c", X"a5", X"95", X"85", X"3d", + X"60", X"a9", X"40", X"85", X"14", X"20", X"e3", X"df", + X"a9", X"00", X"85", X"14", X"4c", X"f0", X"d8", X"20", + X"f8", X"e6", X"ca", X"8a", X"c9", X"28", X"90", X"0a", + X"e9", X"28", X"48", X"20", X"fb", X"da", X"68", X"4c", + X"ec", X"f7", X"85", X"24", X"60", X"cb", X"d2", X"d7", + X"4a", X"08", X"20", X"47", X"f8", X"28", X"a9", X"0f", + X"90", X"02", X"69", X"e0", X"85", X"2e", X"b1", X"26", + X"45", X"30", X"25", X"2e", X"51", X"26", X"91", X"26", + X"60", X"20", X"00", X"f8", X"c4", X"2c", X"b0", X"11", + X"c8", X"20", X"0e", X"f8", X"90", X"f6", X"69", X"01", + X"48", X"20", X"00", X"f8", X"68", X"c5", X"2d", X"90", + X"f5", X"60", X"a0", X"2f", X"d0", X"02", X"a0", X"27", + X"84", X"2d", X"a0", X"27", X"a9", X"00", X"85", X"30", + X"20", X"28", X"f8", X"88", X"10", X"f6", X"60", X"48", + X"4a", X"29", X"03", X"09", X"04", X"85", X"27", X"68", + X"29", X"18", X"90", X"02", X"69", X"7f", X"85", X"26", + X"0a", X"0a", X"05", X"26", X"85", X"26", X"60", X"a5", + X"30", X"18", X"69", X"03", X"29", X"0f", X"85", X"30", + X"0a", X"0a", X"0a", X"0a", X"05", X"30", X"85", X"30", + X"60", X"4a", X"08", X"20", X"47", X"f8", X"b1", X"26", + X"28", X"90", X"04", X"4a", X"4a", X"4a", X"4a", X"29", + X"0f", X"60", X"a6", X"3a", X"a4", X"3b", X"20", X"96", + X"fd", X"20", X"48", X"f9", X"a1", X"3a", X"a8", X"4a", + X"90", X"09", X"6a", X"b0", X"10", X"c9", X"a2", X"f0", + X"0c", X"29", X"87", X"4a", X"aa", X"bd", X"62", X"f9", + X"20", X"79", X"f8", X"d0", X"04", X"a0", X"80", X"a9", + X"00", X"aa", X"bd", X"a6", X"f9", X"85", X"2e", X"29", + X"03", X"85", X"2f", X"98", X"29", X"8f", X"aa", X"98", + X"a0", X"03", X"e0", X"8a", X"f0", X"0b", X"4a", X"90", + X"08", X"4a", X"4a", X"09", X"20", X"88", X"d0", X"fa", + X"c8", X"88", X"d0", X"f2", X"60", X"ff", X"ff", X"ff", + X"20", X"82", X"f8", X"48", X"b1", X"3a", X"20", X"da", + X"fd", X"a2", X"01", X"20", X"4a", X"f9", X"c4", X"2f", + X"c8", X"90", X"f1", X"a2", X"03", X"c0", X"04", X"90", + X"f2", X"68", X"a8", X"b9", X"c0", X"f9", X"85", X"2c", + X"b9", X"00", X"fa", X"85", X"2d", X"a9", X"00", X"a0", + X"05", X"06", X"2d", X"26", X"2c", X"2a", X"88", X"d0", + X"f8", X"69", X"bf", X"20", X"ed", X"fd", X"ca", X"d0", + X"ec", X"20", X"48", X"f9", X"a4", X"2f", X"a2", X"06", + X"e0", X"03", X"f0", X"1c", X"06", X"2e", X"90", X"0e", + X"bd", X"b3", X"f9", X"20", X"ed", X"fd", X"bd", X"b9", + X"f9", X"f0", X"03", X"20", X"ed", X"fd", X"ca", X"d0", + X"e7", X"60", X"88", X"30", X"e7", X"20", X"da", X"fd", + X"a5", X"2e", X"c9", X"e8", X"b1", X"3a", X"90", X"f2", + X"20", X"56", X"f9", X"aa", X"e8", X"d0", X"01", X"c8", + X"98", X"20", X"da", X"fd", X"8a", X"4c", X"da", X"fd", + X"a2", X"03", X"a9", X"a0", X"20", X"ed", X"fd", X"ca", + X"d0", X"f8", X"60", X"38", X"a5", X"2f", X"a4", X"3b", + X"aa", X"10", X"01", X"88", X"65", X"3a", X"90", X"01", + X"c8", X"60", X"04", X"20", X"54", X"30", X"0d", X"80", + X"04", X"90", X"03", X"22", X"54", X"33", X"0d", X"80", + X"04", X"90", X"04", X"20", X"54", X"33", X"0d", X"80", + X"04", X"90", X"04", X"20", X"54", X"3b", X"0d", X"80", + X"04", X"90", X"00", X"22", X"44", X"33", X"0d", X"c8", + X"44", X"00", X"11", X"22", X"44", X"33", X"0d", X"c8", + X"44", X"a9", X"01", X"22", X"44", X"33", X"0d", X"80", + X"04", X"90", X"01", X"22", X"44", X"33", X"0d", X"80", + X"04", X"90", X"26", X"31", X"87", X"9a", X"00", X"21", + X"81", X"82", X"00", X"00", X"59", X"4d", X"91", X"92", + X"86", X"4a", X"85", X"9d", X"ac", X"a9", X"ac", X"a3", + X"a8", X"a4", X"d9", X"00", X"d8", X"a4", X"a4", X"00", + X"1c", X"8a", X"1c", X"23", X"5d", X"8b", X"1b", X"a1", + X"9d", X"8a", X"1d", X"23", X"9d", X"8b", X"1d", X"a1", + X"00", X"29", X"19", X"ae", X"69", X"a8", X"19", X"23", + X"24", X"53", X"1b", X"23", X"24", X"53", X"19", X"a1", + X"00", X"1a", X"5b", X"5b", X"a5", X"69", X"24", X"24", + X"ae", X"ae", X"a8", X"ad", X"29", X"00", X"7c", X"00", + X"15", X"9c", X"6d", X"9c", X"a5", X"69", X"29", X"53", + X"84", X"13", X"34", X"11", X"a5", X"69", X"23", X"a0", + X"d8", X"62", X"5a", X"48", X"26", X"62", X"94", X"88", + X"54", X"44", X"c8", X"54", X"68", X"44", X"e8", X"94", + X"00", X"b4", X"08", X"84", X"74", X"b4", X"28", X"6e", + X"74", X"f4", X"cc", X"4a", X"72", X"f2", X"a4", X"8a", + X"00", X"aa", X"a2", X"a2", X"74", X"74", X"74", X"72", + X"44", X"68", X"b2", X"32", X"b2", X"00", X"22", X"00", + X"1a", X"1a", X"26", X"26", X"72", X"72", X"88", X"c8", + X"c4", X"ca", X"26", X"48", X"44", X"44", X"a2", X"c8", + X"85", X"45", X"68", X"48", X"0a", X"0a", X"0a", X"30", + X"03", X"6c", X"fe", X"03", X"28", X"20", X"4c", X"ff", + X"68", X"85", X"3a", X"68", X"85", X"3b", X"6c", X"f0", + X"03", X"20", X"82", X"f8", X"20", X"da", X"fa", X"4c", + X"65", X"ff", X"d8", X"20", X"84", X"fe", X"20", X"2f", + X"fb", X"20", X"93", X"fe", X"20", X"89", X"fe", X"ad", + X"58", X"c0", X"ad", X"5a", X"c0", X"ad", X"5d", X"c0", + X"ad", X"5f", X"c0", X"ad", X"ff", X"cf", X"2c", X"10", + X"c0", X"d8", X"20", X"3a", X"ff", X"ad", X"f3", X"03", + X"49", X"a5", X"cd", X"f4", X"03", X"d0", X"17", X"ad", + X"f2", X"03", X"d0", X"0f", X"a9", X"e0", X"cd", X"f3", + X"03", X"d0", X"08", X"a0", X"03", X"8c", X"f2", X"03", + X"4c", X"00", X"e0", X"6c", X"f2", X"03", X"20", X"60", + X"fb", X"a2", X"05", X"bd", X"fc", X"fa", X"9d", X"ef", + X"03", X"ca", X"d0", X"f7", X"a9", X"c8", X"86", X"00", + X"85", X"01", X"a0", X"07", X"c6", X"01", X"a5", X"01", + X"c9", X"c0", X"f0", X"d7", X"8d", X"f8", X"07", X"b1", + X"00", X"d9", X"01", X"fb", X"d0", X"ec", X"88", X"88", + X"10", X"f5", X"6c", X"00", X"00", X"ea", X"ea", X"20", + X"8e", X"fd", X"a9", X"45", X"85", X"40", X"a9", X"00", + X"85", X"41", X"a2", X"fb", X"a9", X"a0", X"20", X"ed", + X"fd", X"bd", X"1e", X"fa", X"20", X"ed", X"fd", X"a9", + X"bd", X"20", X"ed", X"fd", X"b5", X"4a", X"20", X"da", + X"fd", X"e8", X"30", X"e8", X"60", X"59", X"fa", X"00", + X"e0", X"45", X"20", X"ff", X"00", X"ff", X"03", X"ff", + X"3c", X"c1", X"d0", X"d0", X"cc", X"c5", X"a0", X"dd", + X"db", X"c4", X"c2", X"c1", X"ff", X"c3", X"ff", X"ff", + X"ff", X"c1", X"d8", X"d9", X"d0", X"d3", X"ad", X"70", + X"c0", X"a0", X"00", X"ea", X"ea", X"bd", X"64", X"c0", + X"10", X"04", X"c8", X"d0", X"f8", X"88", X"60", X"a9", + X"00", X"85", X"48", X"ad", X"56", X"c0", X"ad", X"54", + X"c0", X"ad", X"51", X"c0", X"a9", X"00", X"f0", X"0b", + X"ad", X"50", X"c0", X"ad", X"53", X"c0", X"20", X"36", + X"f8", X"a9", X"14", X"85", X"22", X"a9", X"00", X"85", + X"20", X"a9", X"28", X"85", X"21", X"a9", X"18", X"85", + X"23", X"a9", X"17", X"85", X"25", X"4c", X"22", X"fc", + X"20", X"58", X"fc", X"a0", X"08", X"b9", X"08", X"fb", + X"99", X"0e", X"04", X"88", X"d0", X"f7", X"60", X"ad", + X"f3", X"03", X"49", X"a5", X"8d", X"f4", X"03", X"60", + X"c9", X"8d", X"d0", X"18", X"ac", X"00", X"c0", X"10", + X"13", X"c0", X"93", X"d0", X"0f", X"2c", X"10", X"c0", + X"ac", X"00", X"c0", X"10", X"fb", X"c0", X"83", X"f0", + X"03", X"2c", X"10", X"c0", X"4c", X"fd", X"fb", X"38", + X"4c", X"2c", X"fc", X"a8", X"b9", X"48", X"fa", X"20", + X"97", X"fb", X"20", X"0c", X"fd", X"c9", X"ce", X"b0", + X"ee", X"c9", X"c9", X"90", X"ea", X"c9", X"cc", X"f0", + X"e6", X"d0", X"e8", X"ea", X"ea", X"ea", X"ea", X"ea", + X"ea", X"ea", X"ea", X"ea", X"ea", X"ea", X"ea", X"ea", + X"ea", X"48", X"4a", X"29", X"03", X"09", X"04", X"85", + X"29", X"68", X"29", X"18", X"90", X"02", X"69", X"7f", + X"85", X"28", X"0a", X"0a", X"05", X"28", X"85", X"28", + X"60", X"c9", X"87", X"d0", X"12", X"a9", X"40", X"20", + X"a8", X"fc", X"a0", X"c0", X"a9", X"0c", X"20", X"a8", + X"fc", X"ad", X"30", X"c0", X"88", X"d0", X"f5", X"60", + X"a4", X"24", X"91", X"28", X"e6", X"24", X"a5", X"24", + X"c5", X"21", X"b0", X"66", X"60", X"c9", X"a0", X"b0", + X"ef", X"a8", X"10", X"ec", X"c9", X"8d", X"f0", X"5a", + X"c9", X"8a", X"f0", X"5a", X"c9", X"88", X"d0", X"c9", + X"c6", X"24", X"10", X"e8", X"a5", X"21", X"85", X"24", + X"c6", X"24", X"a5", X"22", X"c5", X"25", X"b0", X"0b", + X"c6", X"25", X"a5", X"25", X"20", X"c1", X"fb", X"65", + X"20", X"85", X"28", X"60", X"49", X"c0", X"f0", X"28", + X"69", X"fd", X"90", X"c0", X"f0", X"da", X"69", X"fd", + X"90", X"2c", X"f0", X"de", X"69", X"fd", X"90", X"5c", + X"d0", X"e9", X"a4", X"24", X"a5", X"25", X"48", X"20", + X"24", X"fc", X"20", X"9e", X"fc", X"a0", X"00", X"68", + X"69", X"00", X"c5", X"23", X"90", X"f0", X"b0", X"ca", + X"a5", X"22", X"85", X"25", X"a0", X"00", X"84", X"24", + X"f0", X"e4", X"a9", X"00", X"85", X"24", X"e6", X"25", + X"a5", X"25", X"c5", X"23", X"90", X"b6", X"c6", X"25", + X"a5", X"22", X"48", X"20", X"24", X"fc", X"a5", X"28", + X"85", X"2a", X"a5", X"29", X"85", X"2b", X"a4", X"21", + X"88", X"68", X"69", X"01", X"c5", X"23", X"b0", X"0d", + X"48", X"20", X"24", X"fc", X"b1", X"28", X"91", X"2a", + X"88", X"10", X"f9", X"30", X"e1", X"a0", X"00", X"20", + X"9e", X"fc", X"b0", X"86", X"a4", X"24", X"a9", X"a0", + X"91", X"28", X"c8", X"c4", X"21", X"90", X"f9", X"60", + X"38", X"48", X"e9", X"01", X"d0", X"fc", X"68", X"e9", + X"01", X"d0", X"f6", X"60", X"e6", X"42", X"d0", X"02", + X"e6", X"43", X"a5", X"3c", X"c5", X"3e", X"a5", X"3d", + X"e5", X"3f", X"e6", X"3c", X"d0", X"02", X"e6", X"3d", + X"60", X"a0", X"4b", X"20", X"db", X"fc", X"d0", X"f9", + X"69", X"fe", X"b0", X"f5", X"a0", X"21", X"20", X"db", + X"fc", X"c8", X"c8", X"88", X"d0", X"fd", X"90", X"05", + X"a0", X"32", X"88", X"d0", X"fd", X"ac", X"20", X"c0", + X"a0", X"2c", X"ca", X"60", X"a2", X"08", X"48", X"20", + X"fa", X"fc", X"68", X"2a", X"a0", X"3a", X"ca", X"d0", + X"f5", X"60", X"20", X"fd", X"fc", X"88", X"ad", X"60", + X"c0", X"45", X"2f", X"10", X"f8", X"45", X"2f", X"85", + X"2f", X"c0", X"80", X"60", X"a4", X"24", X"b1", X"28", + X"48", X"29", X"3f", X"09", X"40", X"91", X"28", X"68", + X"6c", X"38", X"00", X"e6", X"4e", X"d0", X"02", X"e6", + X"4f", X"2c", X"00", X"c0", X"10", X"f5", X"91", X"28", + X"ad", X"00", X"c0", X"2c", X"10", X"c0", X"60", X"20", + X"0c", X"fd", X"20", X"a5", X"fb", X"20", X"0c", X"fd", + X"c9", X"9b", X"f0", X"f3", X"60", X"a5", X"32", X"48", + X"a9", X"ff", X"85", X"32", X"bd", X"00", X"02", X"20", + X"ed", X"fd", X"68", X"85", X"32", X"bd", X"00", X"02", + X"c9", X"88", X"f0", X"1d", X"c9", X"98", X"f0", X"0a", + X"e0", X"f8", X"90", X"03", X"20", X"3a", X"ff", X"e8", + X"d0", X"13", X"a9", X"dc", X"20", X"ed", X"fd", X"20", + X"8e", X"fd", X"a5", X"33", X"20", X"ed", X"fd", X"a2", + X"01", X"8a", X"f0", X"f3", X"ca", X"20", X"35", X"fd", + X"c9", X"95", X"d0", X"02", X"b1", X"28", X"c9", X"e0", + X"90", X"02", X"29", X"df", X"9d", X"00", X"02", X"c9", + X"8d", X"d0", X"b2", X"20", X"9c", X"fc", X"a9", X"8d", + X"d0", X"5b", X"a4", X"3d", X"a6", X"3c", X"20", X"8e", + X"fd", X"20", X"40", X"f9", X"a0", X"00", X"a9", X"ad", + X"4c", X"ed", X"fd", X"a5", X"3c", X"09", X"07", X"85", + X"3e", X"a5", X"3d", X"85", X"3f", X"a5", X"3c", X"29", + X"07", X"d0", X"03", X"20", X"92", X"fd", X"a9", X"a0", + X"20", X"ed", X"fd", X"b1", X"3c", X"20", X"da", X"fd", + X"20", X"ba", X"fc", X"90", X"e8", X"60", X"4a", X"90", + X"ea", X"4a", X"4a", X"a5", X"3e", X"90", X"02", X"49", + X"ff", X"65", X"3c", X"48", X"a9", X"bd", X"20", X"ed", + X"fd", X"68", X"48", X"4a", X"4a", X"4a", X"4a", X"20", + X"e5", X"fd", X"68", X"29", X"0f", X"09", X"b0", X"c9", + X"ba", X"90", X"02", X"69", X"06", X"6c", X"36", X"00", + X"c9", X"a0", X"90", X"02", X"25", X"32", X"84", X"35", + X"48", X"20", X"78", X"fb", X"68", X"a4", X"35", X"60", + X"c6", X"34", X"f0", X"9f", X"ca", X"d0", X"16", X"c9", + X"ba", X"d0", X"bb", X"85", X"31", X"a5", X"3e", X"91", + X"40", X"e6", X"40", X"d0", X"02", X"e6", X"41", X"60", + X"a4", X"34", X"b9", X"ff", X"01", X"85", X"31", X"60", + X"a2", X"01", X"b5", X"3e", X"95", X"42", X"95", X"44", + X"ca", X"10", X"f7", X"60", X"b1", X"3c", X"91", X"42", + X"20", X"b4", X"fc", X"90", X"f7", X"60", X"b1", X"3c", + X"d1", X"42", X"f0", X"1c", X"20", X"92", X"fd", X"b1", + X"3c", X"20", X"da", X"fd", X"a9", X"a0", X"20", X"ed", + X"fd", X"a9", X"a8", X"20", X"ed", X"fd", X"b1", X"42", + X"20", X"da", X"fd", X"a9", X"a9", X"20", X"ed", X"fd", + X"20", X"b4", X"fc", X"90", X"d9", X"60", X"20", X"75", + X"fe", X"a9", X"14", X"48", X"20", X"d0", X"f8", X"20", + X"53", X"f9", X"85", X"3a", X"84", X"3b", X"68", X"38", + X"e9", X"01", X"d0", X"ef", X"60", X"8a", X"f0", X"07", + X"b5", X"3c", X"95", X"3a", X"ca", X"10", X"f9", X"60", + X"a0", X"3f", X"d0", X"02", X"a0", X"ff", X"84", X"32", + X"60", X"a9", X"00", X"85", X"3e", X"a2", X"38", X"a0", + X"1b", X"d0", X"08", X"a9", X"00", X"85", X"3e", X"a2", + X"36", X"a0", X"f0", X"a5", X"3e", X"29", X"0f", X"f0", + X"06", X"09", X"c0", X"a0", X"00", X"f0", X"02", X"a9", + X"fd", X"94", X"00", X"95", X"01", X"60", X"ea", X"ea", + X"4c", X"00", X"e0", X"4c", X"03", X"e0", X"20", X"75", + X"fe", X"20", X"3f", X"ff", X"6c", X"3a", X"00", X"4c", + X"d7", X"fa", X"60", X"ea", X"60", X"ea", X"ea", X"ea", + X"ea", X"ea", X"4c", X"f8", X"03", X"a9", X"40", X"20", + X"c9", X"fc", X"a0", X"27", X"a2", X"00", X"41", X"3c", + X"48", X"a1", X"3c", X"20", X"ed", X"fe", X"20", X"ba", + X"fc", X"a0", X"1d", X"68", X"90", X"ee", X"a0", X"22", + X"20", X"ed", X"fe", X"f0", X"4d", X"a2", X"10", X"0a", + X"20", X"d6", X"fc", X"d0", X"fa", X"60", X"20", X"00", + X"fe", X"68", X"68", X"d0", X"6c", X"20", X"fa", X"fc", + X"a9", X"16", X"20", X"c9", X"fc", X"85", X"2e", X"20", + X"fa", X"fc", X"a0", X"24", X"20", X"fd", X"fc", X"b0", + X"f9", X"20", X"fd", X"fc", X"a0", X"3b", X"20", X"ec", + X"fc", X"81", X"3c", X"45", X"2e", X"85", X"2e", X"20", + X"ba", X"fc", X"a0", X"35", X"90", X"f0", X"20", X"ec", + X"fc", X"c5", X"2e", X"f0", X"0d", X"a9", X"c5", X"20", + X"ed", X"fd", X"a9", X"d2", X"20", X"ed", X"fd", X"20", + X"ed", X"fd", X"a9", X"87", X"4c", X"ed", X"fd", X"a5", + X"48", X"48", X"a5", X"45", X"a6", X"46", X"a4", X"47", + X"28", X"60", X"85", X"45", X"86", X"46", X"84", X"47", + X"08", X"68", X"85", X"48", X"ba", X"86", X"49", X"d8", + X"60", X"20", X"84", X"fe", X"20", X"2f", X"fb", X"20", + X"93", X"fe", X"20", X"89", X"fe", X"d8", X"20", X"3a", + X"ff", X"a9", X"aa", X"85", X"33", X"20", X"67", X"fd", + X"20", X"c7", X"ff", X"20", X"a7", X"ff", X"84", X"34", + X"a0", X"17", X"88", X"30", X"e8", X"d9", X"cc", X"ff", + X"d0", X"f8", X"20", X"be", X"ff", X"a4", X"34", X"4c", + X"73", X"ff", X"a2", X"03", X"0a", X"0a", X"0a", X"0a", + X"0a", X"26", X"3e", X"26", X"3f", X"ca", X"10", X"f8", + X"a5", X"31", X"d0", X"06", X"b5", X"3f", X"95", X"3d", + X"95", X"41", X"e8", X"f0", X"f3", X"d0", X"06", X"a2", + X"00", X"86", X"3e", X"86", X"3f", X"b9", X"00", X"02", + X"c8", X"49", X"b0", X"c9", X"0a", X"90", X"d3", X"69", + X"88", X"c9", X"fa", X"b0", X"cd", X"60", X"a9", X"fe", + X"48", X"b9", X"e3", X"ff", X"48", X"a5", X"31", X"a0", + X"00", X"84", X"31", X"60", X"bc", X"b2", X"be", X"b2", + X"ef", X"c4", X"b2", X"a9", X"bb", X"a6", X"a4", X"06", + X"95", X"07", X"02", X"05", X"f0", X"00", X"eb", X"93", + X"a7", X"c6", X"99", X"b2", X"c9", X"be", X"c1", X"35", + X"8c", X"c4", X"96", X"af", X"17", X"17", X"2b", X"1f", + X"83", X"7f", X"5d", X"cc", X"b5", X"fc", X"17", X"17", + X"f5", X"03", X"fb", X"03", X"62", X"fa", X"59", 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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"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"); +begin + +process (clk) + begin + if rising_edge(clk) then + dout <= ROM(TO_INTEGER(addr)); + end if; + end process; + +end rtl; diff --git a/Apple - 2_MiST/rtl/mist_io.v b/Apple - 2_MiST/rtl/mist_io.v new file mode 100644 index 00000000..ad233a3b --- /dev/null +++ b/Apple - 2_MiST/rtl/mist_io.v @@ -0,0 +1,491 @@ +// +// mist_io.v +// +// mist_io for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// 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 . +// +/////////////////////////////////////////////////////////////////////// + +// +// Use buffer to access SD card. It's time-critical part. +// Made module synchroneous with 2 clock domains: clk_sys and SPI_SCK +// (Sorgelig) +// +// for synchronous projects default value for PS2DIV is fine for any frequency of system clock. +// clk_ps2 = clk_sys/(PS2DIV*2) +// + +module mist_io #(parameter STRLEN=0, parameter PS2DIV=100) +( + + // parameter STRLEN and the actual length of conf_str have to match + input [(8*STRLEN)-1:0] conf_str, + + // Global clock. It should be around 100MHz (higher is better). + input clk_sys, + + // Global SPI clock from ARM. 24MHz + input SPI_SCK, + + input CONF_DATA0, + input SPI_SS2, + output SPI_DO, + input SPI_DI, + + output reg [7:0] joystick_0, + output reg [7:0] joystick_1, + output reg [15:0] joystick_analog_0, + output reg [15:0] joystick_analog_1, + output [1:0] buttons, + output [1:0] switches, + output scandoubler_disable, + output ypbpr, + + output reg [31:0] status, + + // SD config + input sd_conf, + input sd_sdhc, + output img_mounted, // signaling that new image has been mounted + output reg [31:0] img_size, // size of image in bytes + + // SD block level access + input [31:0] sd_lba, + input sd_rd, + input sd_wr, + output reg sd_ack, + output reg sd_ack_conf, + + // SD byte level access. Signals for 2-PORT altsyncram. + output reg [8:0] sd_buff_addr, + output reg [7:0] sd_buff_dout, + input [7:0] sd_buff_din, + output reg sd_buff_wr, + + // ps2 keyboard emulation + output ps2_kbd_clk, + output reg ps2_kbd_data, + output ps2_mouse_clk, + output reg ps2_mouse_data, + input ps2_caps_led, + + // ARM -> FPGA download + output reg ioctl_download = 0, // signal indicating an active download + output reg [7:0] ioctl_index, // menu index used to upload the file + output ioctl_wr, + output reg [24:0] ioctl_addr, + output reg [7:0] ioctl_dout +); + +reg [7:0] b_data; +reg [6:0] sbuf; +reg [7:0] cmd; +reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... +reg [9:0] byte_cnt; // counts bytes +reg [7:0] but_sw; +reg [2:0] stick_idx; + +reg mount_strobe = 0; +assign img_mounted = mount_strobe; + +assign buttons = but_sw[1:0]; +assign switches = but_sw[3:2]; +assign scandoubler_disable = but_sw[4]; +assign ypbpr = but_sw[5]; + +wire [7:0] spi_dout = { sbuf, SPI_DI}; + +// this variant of user_io is for 8 bit cores (type == a4) only +wire [7:0] core_type = 8'ha4; + +// command byte read by the io controller +wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd }; + +reg spi_do; +assign SPI_DO = CONF_DATA0 ? 1'bZ : spi_do; + +wire [7:0] kbd_led = { 2'b01, 4'b0000, ps2_caps_led, 1'b1}; + +// drive MISO only when transmitting core id +always@(negedge SPI_SCK) begin + if(!CONF_DATA0) begin + // first byte returned is always core type, further bytes are + // command dependent + if(byte_cnt == 0) begin + spi_do <= core_type[~bit_cnt]; + + end else begin + case(cmd) + // reading config string + 8'h14: begin + // returning a byte from string + if(byte_cnt < STRLEN + 1) spi_do <= conf_str[{STRLEN - byte_cnt,~bit_cnt}]; + else spi_do <= 0; + end + + // reading sd card status + 8'h16: begin + if(byte_cnt == 1) spi_do <= sd_cmd[~bit_cnt]; + else if((byte_cnt >= 2) && (byte_cnt < 6)) spi_do <= sd_lba[{5-byte_cnt, ~bit_cnt}]; + else spi_do <= 0; + end + + // reading sd card write data + 8'h18: + spi_do <= b_data[~bit_cnt]; + + // reading keyboard LED status + 8'h1f: + spi_do <= kbd_led[~bit_cnt]; + + default: + spi_do <= 0; + endcase + end + end +end + +reg b_wr2,b_wr3; +always @(negedge clk_sys) begin + b_wr3 <= b_wr2; + sd_buff_wr <= b_wr3; +end + +// SPI receiver +always@(posedge SPI_SCK or posedge CONF_DATA0) begin + + if(CONF_DATA0) begin + b_wr2 <= 0; + bit_cnt <= 0; + byte_cnt <= 0; + sd_ack <= 0; + sd_ack_conf <= 0; + end else begin + b_wr2 <= 0; + + sbuf <= spi_dout[6:0]; + bit_cnt <= bit_cnt + 1'd1; + if(bit_cnt == 5) begin + if (byte_cnt == 0) sd_buff_addr <= 0; + if((byte_cnt != 0) & (sd_buff_addr != 511)) sd_buff_addr <= sd_buff_addr + 1'b1; + if((byte_cnt == 1) & ((cmd == 8'h17) | (cmd == 8'h19))) sd_buff_addr <= 0; + end + + // finished reading command byte + if(bit_cnt == 7) begin + if(~&byte_cnt) byte_cnt <= byte_cnt + 8'd1; + if(byte_cnt == 0) begin + cmd <= spi_dout; + + if(spi_dout == 8'h19) begin + sd_ack_conf <= 1; + sd_buff_addr <= 0; + end + if((spi_dout == 8'h17) || (spi_dout == 8'h18)) begin + sd_ack <= 1; + sd_buff_addr <= 0; + end + if(spi_dout == 8'h18) b_data <= sd_buff_din; + + mount_strobe <= 0; + + end else begin + + case(cmd) + // buttons and switches + 8'h01: but_sw <= spi_dout; + 8'h02: joystick_0 <= spi_dout; + 8'h03: joystick_1 <= spi_dout; + + // store incoming ps2 mouse bytes + 8'h04: begin + ps2_mouse_fifo[ps2_mouse_wptr] <= spi_dout; + ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; + end + + // store incoming ps2 keyboard bytes + 8'h05: begin + ps2_kbd_fifo[ps2_kbd_wptr] <= spi_dout; + ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; + end + + 8'h15: status[7:0] <= spi_dout; + + // send SD config IO -> FPGA + // flag that download begins + // sd card knows data is config if sd_dout_strobe is asserted + // with sd_ack still being inactive (low) + 8'h19, + // send sector IO -> FPGA + // flag that download begins + 8'h17: begin + sd_buff_dout <= spi_dout; + b_wr2 <= 1; + end + + 8'h18: b_data <= sd_buff_din; + + // joystick analog + 8'h1a: begin + // first byte is joystick index + if(byte_cnt == 1) stick_idx <= spi_dout[2:0]; + else if(byte_cnt == 2) begin + // second byte is x axis + if(stick_idx == 0) joystick_analog_0[15:8] <= spi_dout; + else if(stick_idx == 1) joystick_analog_1[15:8] <= spi_dout; + end else if(byte_cnt == 3) begin + // third byte is y axis + if(stick_idx == 0) joystick_analog_0[7:0] <= spi_dout; + else if(stick_idx == 1) joystick_analog_1[7:0] <= spi_dout; + end + end + + // notify image selection + 8'h1c: mount_strobe <= 1; + + // send image info + 8'h1d: if(byte_cnt<5) img_size[(byte_cnt-1)<<3 +:8] <= spi_dout; + + // status, 32bit version + 8'h1e: if(byte_cnt<5) status[(byte_cnt-1)<<3 +:8] <= spi_dout; + default: ; + endcase + end + end + end +end + + +/////////////////////////////// PS2 /////////////////////////////// +// 8 byte fifos to store ps2 bytes +localparam PS2_FIFO_BITS = 3; + +reg clk_ps2; +always @(negedge clk_sys) begin + integer cnt; + cnt <= cnt + 1'd1; + if(cnt == PS2DIV) begin + clk_ps2 <= ~clk_ps2; + cnt <= 0; + end +end + +// keyboard +reg [7:0] ps2_kbd_fifo[1<= 1)&&(ps2_kbd_tx_state < 9)) begin + ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits + ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down + if(ps2_kbd_tx_byte[0]) + ps2_kbd_parity <= !ps2_kbd_parity; + end + + // transmission of parity + if(ps2_kbd_tx_state == 9) ps2_kbd_data <= ps2_kbd_parity; + + // transmission of stop bit + if(ps2_kbd_tx_state == 10) ps2_kbd_data <= 1; // stop bit is 1 + + // advance state machine + if(ps2_kbd_tx_state < 11) ps2_kbd_tx_state <= ps2_kbd_tx_state + 1'd1; + else ps2_kbd_tx_state <= 0; + end + end +end + +// mouse +reg [7:0] ps2_mouse_fifo[1<= 1)&&(ps2_mouse_tx_state < 9)) begin + ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits + ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down + if(ps2_mouse_tx_byte[0]) + ps2_mouse_parity <= !ps2_mouse_parity; + end + + // transmission of parity + if(ps2_mouse_tx_state == 9) ps2_mouse_data <= ps2_mouse_parity; + + // transmission of stop bit + if(ps2_mouse_tx_state == 10) ps2_mouse_data <= 1; // stop bit is 1 + + // advance state machine + if(ps2_mouse_tx_state < 11) ps2_mouse_tx_state <= ps2_mouse_tx_state + 1'd1; + else ps2_mouse_tx_state <= 0; + end + end +end + + +/////////////////////////////// DOWNLOADING /////////////////////////////// + +reg [7:0] data_w; +reg [24:0] addr_w; +reg rclk = 0; + +localparam UIO_FILE_TX = 8'h53; +localparam UIO_FILE_TX_DAT = 8'h54; +localparam UIO_FILE_INDEX = 8'h55; + +// data_io has its own SPI interface to the io controller +always@(posedge SPI_SCK, posedge SPI_SS2) begin + reg [6:0] sbuf; + reg [7:0] cmd; + reg [4:0] cnt; + reg [24:0] addr; + + if(SPI_SS2) cnt <= 0; + else begin + rclk <= 0; + + // don't shift in last bit. It is evaluated directly + // when writing to ram + if(cnt != 15) sbuf <= { sbuf[5:0], SPI_DI}; + + // increase target address after write + if(rclk) addr <= addr + 1'd1; + + // count 0-7 8-15 8-15 ... + if(cnt < 15) cnt <= cnt + 1'd1; + else cnt <= 8; + + // finished command byte + if(cnt == 7) cmd <= {sbuf, SPI_DI}; + + // prepare/end transmission + if((cmd == UIO_FILE_TX) && (cnt == 15)) begin + // prepare + if(SPI_DI) begin + addr <= 0; + ioctl_download <= 1; + end else begin + addr_w <= addr; + ioctl_download <= 0; + end + end + + // command 0x54: UIO_FILE_TX + if((cmd == UIO_FILE_TX_DAT) && (cnt == 15)) begin + addr_w <= addr; + data_w <= {sbuf, SPI_DI}; + rclk <= 1; + end + + // expose file (menu) index + if((cmd == UIO_FILE_INDEX) && (cnt == 15)) ioctl_index <= {sbuf, SPI_DI}; + end +end + +assign ioctl_wr = |ioctl_wrd; +reg [1:0] ioctl_wrd; + +always@(negedge clk_sys) begin + reg rclkD, rclkD2; + + rclkD <= rclk; + rclkD2 <= rclkD; + ioctl_wrd<= {ioctl_wrd[0],1'b0}; + + if(rclkD & ~rclkD2) begin + ioctl_dout <= data_w; + ioctl_addr <= addr_w; + ioctl_wrd <= 2'b11; + end +end + +endmodule diff --git a/Apple - 2_MiST/rtl/osd.v b/Apple - 2_MiST/rtl/osd.v new file mode 100644 index 00000000..c62c10af --- /dev/null +++ b/Apple - 2_MiST/rtl/osd.v @@ -0,0 +1,179 @@ +// A simple OSD implementation. Can be hooked up between a cores +// VGA output and the physical VGA pins + +module osd ( + // OSDs pixel clock, should be synchronous to cores pixel clock to + // avoid jitter. + input clk_sys, + + // SPI interface + input SPI_SCK, + input SPI_SS3, + input SPI_DI, + + // VGA signals coming from core + input [5:0] R_in, + input [5:0] G_in, + input [5:0] B_in, + input HSync, + input VSync, + + // VGA signals going to video connector + output [5:0] R_out, + output [5:0] G_out, + output [5:0] B_out +); + +parameter OSD_X_OFFSET = 10'd0; +parameter OSD_Y_OFFSET = 10'd0; +parameter OSD_COLOR = 3'd0; + +localparam OSD_WIDTH = 10'd256; +localparam OSD_HEIGHT = 10'd128; + +// ********************************************************************************* +// spi client +// ********************************************************************************* + +// this core supports only the display related OSD commands +// of the minimig +reg osd_enable; +(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[2047:0]; // the OSD buffer itself + +// the OSD has its own SPI interface to the io controller +always@(posedge SPI_SCK, posedge SPI_SS3) begin + reg [4:0] cnt; + reg [10:0] bcnt; + reg [7:0] sbuf; + reg [7:0] cmd; + + if(SPI_SS3) begin + cnt <= 0; + bcnt <= 0; + end else begin + sbuf <= {sbuf[6:0], SPI_DI}; + + // 0:7 is command, rest payload + if(cnt < 15) cnt <= cnt + 1'd1; + else cnt <= 8; + + if(cnt == 7) begin + cmd <= {sbuf[6:0], SPI_DI}; + + // lower three command bits are line address + bcnt <= {sbuf[1:0], SPI_DI, 8'h00}; + + // command 0x40: OSDCMDENABLE, OSDCMDDISABLE + if(sbuf[6:3] == 4'b0100) osd_enable <= SPI_DI; + end + + // command 0x20: OSDCMDWRITE + if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin + osd_buffer[bcnt] <= {sbuf[6:0], SPI_DI}; + bcnt <= bcnt + 1'd1; + end + end +end + +// ********************************************************************************* +// video timing and sync polarity anaylsis +// ********************************************************************************* + +// horizontal counter +reg [9:0] h_cnt; +reg [9:0] hs_low, hs_high; +wire hs_pol = hs_high < hs_low; +wire [9:0] dsp_width = hs_pol ? hs_low : hs_high; + +// vertical counter +reg [9:0] v_cnt; +reg [9:0] vs_low, vs_high; +wire vs_pol = vs_high < vs_low; +wire [9:0] dsp_height = vs_pol ? vs_low : vs_high; + +wire doublescan = (dsp_height>350); + +reg ce_pix; +always @(negedge clk_sys) begin + integer cnt = 0; + integer pixsz, pixcnt; + reg hs; + + cnt <= cnt + 1; + hs <= HSync; + + pixcnt <= pixcnt + 1; + if(pixcnt == pixsz) pixcnt <= 0; + ce_pix <= !pixcnt; + + if(hs && ~HSync) begin + cnt <= 0; + pixsz <= (cnt >> 9) - 1; + pixcnt <= 0; + ce_pix <= 1; + end +end + +always @(posedge clk_sys) begin + reg hsD, hsD2; + reg vsD, vsD2; + + if(ce_pix) begin + // bring hsync into local clock domain + hsD <= HSync; + hsD2 <= hsD; + + // falling edge of HSync + if(!hsD && hsD2) begin + h_cnt <= 0; + hs_high <= h_cnt; + end + + // rising edge of HSync + else if(hsD && !hsD2) begin + h_cnt <= 0; + hs_low <= h_cnt; + v_cnt <= v_cnt + 1'd1; + end else begin + h_cnt <= h_cnt + 1'd1; + end + + vsD <= VSync; + vsD2 <= vsD; + + // falling edge of VSync + if(!vsD && vsD2) begin + v_cnt <= 0; + vs_high <= v_cnt; + end + + // rising edge of VSync + else if(vsD && !vsD2) begin + v_cnt <= 0; + vs_low <= v_cnt; + end + end +end + +// area in which OSD is being displayed +wire [9:0] h_osd_start = ((dsp_width - OSD_WIDTH)>> 1) + OSD_X_OFFSET; +wire [9:0] h_osd_end = h_osd_start + OSD_WIDTH; +wire [9:0] v_osd_start = ((dsp_height- (OSD_HEIGHT<> 1) + OSD_Y_OFFSET; +wire [9:0] v_osd_end = v_osd_start + (OSD_HEIGHT<= h_osd_start) && (h_cnt < h_osd_end) && + (VSync != vs_pol) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end); + +reg [7:0] osd_byte; +always @(posedge clk_sys) if(ce_pix) osd_byte <= osd_buffer[{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt[7:0]}]; + +wire osd_pixel = osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]]; + +assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[5:3]}; +assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[5:3]}; +assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[5:3]}; + +endmodule diff --git a/Apple - 2_MiST/rtl/pll.qip b/Apple - 2_MiST/rtl/pll.qip new file mode 100644 index 00000000..afd958be --- /dev/null +++ b/Apple - 2_MiST/rtl/pll.qip @@ -0,0 +1,4 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "13.1" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"] diff --git a/Apple - 2_MiST/rtl/pll.v b/Apple - 2_MiST/rtl/pll.v new file mode 100644 index 00000000..077dd7c1 --- /dev/null +++ b/Apple - 2_MiST/rtl/pll.v @@ -0,0 +1,376 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll.v +// 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. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll ( + areset, + inclk0, + c0, + c1, + c2, + locked); + + input areset; + input inclk0; + output c0; + output c1; + output c2; + output locked; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 areset; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [4:0] sub_wire0; + wire sub_wire2; + wire [0:0] sub_wire7 = 1'h0; + wire [2:2] sub_wire4 = sub_wire0[2:2]; + wire [0:0] sub_wire3 = sub_wire0[0:0]; + wire [1:1] sub_wire1 = sub_wire0[1:1]; + wire c1 = sub_wire1; + wire locked = sub_wire2; + wire c0 = sub_wire3; + wire c2 = sub_wire4; + wire sub_wire5 = inclk0; + wire [1:0] sub_wire6 = {sub_wire7, sub_wire5}; + + altpll altpll_component ( + .areset (areset), + .inclk (sub_wire6), + .clk (sub_wire0), + .locked (sub_wire2), + .activeclock (), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 33, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 35, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 66, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 35, + altpll_component.clk1_phase_shift = "0", + altpll_component.clk2_divide_by = 132, + altpll_component.clk2_duty_cycle = 50, + altpll_component.clk2_multiply_by = 35, + altpll_component.clk2_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 37037, + altpll_component.intended_device_family = "Cyclone III", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_USED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_USED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// 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 "33" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "66" +// Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "132" +// 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: EFF_OUTPUT_FREQ_VALUE0 STRING "28.636364" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "14.318182" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "7.159091" +// 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 "ps" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 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: MULT_FACTOR0 NUMERIC "35" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "35" +// Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "35" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "28.63636000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "14.31818000" +// Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "7.15909000" +// 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_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 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_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "ps" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps" +// 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.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: 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_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA2 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 "33" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "35" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "66" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "35" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "132" +// Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "35" +// Retrieval info: CONSTANT: CLK2_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_UNUSED" +// 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: 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: 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: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Apple - 2_MiST/rtl/ram.qip b/Apple - 2_MiST/rtl/ram.qip new file mode 100644 index 00000000..b96c7229 --- /dev/null +++ b/Apple - 2_MiST/rtl/ram.qip @@ -0,0 +1,3 @@ +set_global_assignment -name IP_TOOL_NAME "RAM: 1-PORT" +set_global_assignment -name IP_TOOL_VERSION "13.1" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "ram.v"] diff --git a/Apple - 2_MiST/rtl/ram.v b/Apple - 2_MiST/rtl/ram.v new file mode 100644 index 00000000..5c37f64f --- /dev/null +++ b/Apple - 2_MiST/rtl/ram.v @@ -0,0 +1,172 @@ +// megafunction wizard: %RAM: 1-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: ram.v +// Megafunction Name(s): +// altsyncram +// +// 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. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module ram ( + address, + clock, + data, + wren, + q); + + input [13:0] address; + input clock; + input [15:0] data; + input wren; + output [15:0] q; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clock; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [15:0] sub_wire0; + wire [15:0] q = sub_wire0[15:0]; + + altsyncram altsyncram_component ( + .address_a (address), + .clock0 (clock), + .data_a (data), + .wren_a (wren), + .q_a (sub_wire0), + .aclr0 (1'b0), + .aclr1 (1'b0), + .address_b (1'b1), + .addressstall_a (1'b0), + .addressstall_b (1'b0), + .byteena_a (1'b1), + .byteena_b (1'b1), + .clock1 (1'b1), + .clocken0 (1'b1), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .data_b (1'b1), + .eccstatus (), + .q_b (), + .rden_a (1'b1), + .rden_b (1'b1), + .wren_b (1'b0)); + defparam + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_output_a = "BYPASS", + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 16384, + altsyncram_component.operation_mode = "SINGLE_PORT", + altsyncram_component.outdata_aclr_a = "NONE", + altsyncram_component.outdata_reg_a = "CLOCK0", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", + altsyncram_component.widthad_a = 14, + altsyncram_component.width_a = 16, + altsyncram_component.width_byteena_a = 1; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" +// Retrieval info: PRIVATE: AclrAddr NUMERIC "0" +// Retrieval info: PRIVATE: AclrByte NUMERIC "0" +// Retrieval info: PRIVATE: AclrData NUMERIC "0" +// Retrieval info: PRIVATE: AclrOutput NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +// Retrieval info: PRIVATE: BlankMemory NUMERIC "1" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: Clken NUMERIC "0" +// Retrieval info: PRIVATE: DataBusSeparated NUMERIC "1" +// Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" +// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" +// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" +// Retrieval info: PRIVATE: JTAG_ID STRING "NONE" +// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" +// Retrieval info: PRIVATE: MIFfilename STRING "" +// Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "16384" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" +// Retrieval info: PRIVATE: RegAddr NUMERIC "1" +// Retrieval info: PRIVATE: RegData NUMERIC "1" +// Retrieval info: PRIVATE: RegOutput NUMERIC "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: SingleClock NUMERIC "1" +// Retrieval info: PRIVATE: UseDQRAM NUMERIC "1" +// Retrieval info: PRIVATE: WRCONTROL_ACLR_A NUMERIC "0" +// Retrieval info: PRIVATE: WidthAddr NUMERIC "14" +// Retrieval info: PRIVATE: WidthData NUMERIC "16" +// Retrieval info: PRIVATE: rden NUMERIC "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" +// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "16384" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "SINGLE_PORT" +// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0" +// Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_NO_NBE_READ" +// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "14" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "16" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: USED_PORT: address 0 0 14 0 INPUT NODEFVAL "address[13..0]" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +// Retrieval info: USED_PORT: data 0 0 16 0 INPUT NODEFVAL "data[15..0]" +// Retrieval info: USED_PORT: q 0 0 16 0 OUTPUT NODEFVAL "q[15..0]" +// Retrieval info: USED_PORT: wren 0 0 0 0 INPUT NODEFVAL "wren" +// Retrieval info: CONNECT: @address_a 0 0 14 0 address 0 0 14 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: @data_a 0 0 16 0 data 0 0 16 0 +// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 16 0 @q_a 0 0 16 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL ram.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf diff --git a/Apple - 2_MiST/rtl/roms/apple_II.rom b/Apple - 2_MiST/rtl/roms/apple_II.rom new file mode 100644 index 0000000000000000000000000000000000000000..cb94b9f045b776a6529567d5178c3c8d26c4641f GIT binary patch literal 12288 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 Q-H8)#Xa+UQ@4OKHKm2p-{r~^~ literal 0 HcmV?d00001 diff --git a/Apple - 2_MiST/rtl/roms/bios.a65 b/Apple - 2_MiST/rtl/roms/bios.a65 new file mode 100644 index 00000000..393d28db --- /dev/null +++ b/Apple - 2_MiST/rtl/roms/bios.a65 @@ -0,0 +1,255 @@ +; Trivial BIOS for an Apple II+ -- just enough to show the hardware works +; +; Stephen A. Edwards +; +; Assemble with "xa -A 53248 -bt 53248 ..." to start the code at $D000 + +gbasl = $26 +gbash = $27 +basl = $28 +bash = $29 + +text = $400 ; start of text/lores screen memory +bhires = $2000 ; start of hires screen memory +line8 = $428 +line9 = $4A8 +line10 = $528 +line11 = $5A8 + +line23 = $7D0 + +keyboard = $C000 +key_strobe = $C010 + +spkr = $C030 +grset = $C050 +txtset = $C051 +nomix = $C052 +mix = $C053 +page1 = $C054 +page2 = $C055 +lores = $C056 +hires = $C057 + +nmi_vector = $FFFA +nmi = reset +irq = reset + +reset: + cld + lda txtset + lda page1 + +; Clear the text screen + + lda #text + sta gbash + ldy #0 + ldx #4 + lda #$A0 ; Normal space +l0 + sta (gbasl),y + dey + bne l0 + inc gbash + dex + bne l0 + +; Play three tones + + ldy #0 +tone1 + lda #15 + jsr wait + sta spkr + dey + bne tone1 + +tone2 + lda #12 + jsr wait + sta spkr + dey + bne tone2 + +tone3 + lda #8 + jsr wait + sta spkr + dey + bne tone3 + +; Print some messages + lda #text + sta gbash + lda #hello + sta bash + jsr write_string + + lda #roms1 + sta bash + jsr write_string + + lda #line10 + sta gbash + lda #roms2 + sta bash + jsr write_string + + lda #line11 + sta gbash + lda #roms3 + sta bash + jsr write_string + + lda #line23 + sta gbash + lda #press + sta bash + jsr write_string + +wait_for_key + bit keyboard + bpl wait_for_key + sta key_strobe + +; Set lores mode + sta lores + sta nomix + sta grset + +; Fill the screen with colors + lda #0 +fill + ldx #text + stx gbash + ldy #0 + ldx #4 +l2 + sta (gbasl),y + adc #1 + dey + bne l2 + inc gbash + dex + bne l2 + + adc #1 + + bit keyboard + bpl fill + sta key_strobe + +; Wait for another keypress + +wait_key1 + bit keyboard + bpl wait_key1 + sta key_strobe + +; Set hires mode + sta hires + +; Fill the screen with colors + lda #0 +fillh + ldx #bhires + stx gbash + ldy #0 + ldx #$20 +l3 + sta (gbasl),y + adc #1 + dey + bne l3 + inc gbash + dex + bne l3 + + adc #1 + + bit keyboard + bpl fillh + sta key_strobe + +; Wait for another keypress + +wait_key2 + bit keyboard + bpl wait_key2 + sta key_strobe + + jmp reset + +done + rts +write_string + ldy #0 +l1 + lda (basl),y + beq done + ora #$80 + sta (gbasl),y + iny + bne l1 + rts + +; A quadratic delay + +wait sec +wait2 pha +wait3 sbc #1 + bne wait3 + pla + sbc #1 + bne wait2 + rts + + +hello .asc "APPLE2FPGA" + .byt 0 + +roms1 .asc "THIS IS NOT APPLE'S BIOS" + .byt 0 + +roms2 .asc "TO RUN APPLE PROGRAMS, GET A COPY OF THE" + .byt 0 + +roms3 .asc "ACTUAL APPLE II ROMS (D000-FFFF)" + .byt 0 + +press .asc "PRESS ANY KEY TO ADVANCE" + .byt 0 + +; Pad to the start of the NMI vector +here .dsb (nmi_vector - here) + + .word nmi + .word reset + .word irq diff --git a/Apple - 2_MiST/rtl/roms/bios.rom b/Apple - 2_MiST/rtl/roms/bios.rom new file mode 100644 index 0000000000000000000000000000000000000000..2fefadd0eb0a9571066ba7585832bd052a9ee6d7 GIT binary patch literal 12288 zcmeIuKTpCy7zXeo!KjG_c9(Z*OM*$myn`vF`^SUNDcH%#8Z;5X=K zoQ}=a#l+1)NC*xdf3%xlz~|aDcTb*c-uzx>SLrNF1&cJ1kMx91^CFpOW4V6QpXD-P zqCjW!*i6TAAx^UGQMN7Yt_nRe#5^j|>0Fp9s$@q)9SF^zj^?5DA(#+|S& zpLc>XH7wPms_XU1ty9>v7_Ww1-rg5&n|!wukWn*D^SrKBiFv*i1jL;_wX8m=|MFUo zJ5`HeK>z{}fB*y_009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;| WfB*y_009U<00Izzz&{j_Og-NcCaTc@ literal 0 HcmV?d00001 diff --git a/Apple - 2_MiST/rtl/roms/slot6.rom b/Apple - 2_MiST/rtl/roms/slot6.rom new file mode 100644 index 0000000000000000000000000000000000000000..56698b0f8879c56af152fc0cbff4230ba53592b0 GIT binary patch literal 256 zcmZ3auz+C^bDK>Umx|2?0ahE&|C)6hIJ_?Wo-sF!`NRu>rwS4OckN|hn4!tc#R?Q}Jg_oMVa1;gf!D2St+uU>D>+)#B{+a;1%7*8 zz3?5(IJxS==T{Kcv=5vb6YhJi{h)f`<^twc2e7DCs|}b|wduI '0'); + + -- + -- output timing + -- + signal hpos_o : std_logic_vector(9 downto 0) := (others => '0'); + + signal vcnt : integer range 0 to 1023 := 0; + signal hcnt : integer range 0 to 1023 := 0; + signal hcnti : integer range 0 to 1023 := 0; + + signal CLK_x2_n : std_logic := '1'; + +begin + -- dual port line buffer, max line of 1024 pixels + u_ram : entity work.RAMB16_S18_S18 +-- generic map (INIT_A => X"00000", INIT_B => X"00000", SIM_COLLISION_CHECK => "ALL") -- "NONE", "WARNING", "GENERATE_X_ONLY", "ALL" + port map ( + -- input + q_a => open, + data_a => I_VIDEO, + + + address_a => hpos_i, + wren_a => '1', + rden_a => CLK, + + clock_a => CLK_x2, + + -- output + q_b => O_VIDEO, + data_b => x"0000", + + + address_b => hpos_o, + wren_b => '0', + rden_b => '1', + + clock_b => CLK_x2_n + ); + + CLK_x2_n <= not CLK_x2; + + -- horizontal counter for input video + p_hcounter : process + begin + wait until rising_edge(CLK_x2); + if CLK = '0' then + ihsync_last <= I_HSYNC; + + -- trigger off rising hsync + if I_HSYNC = '1' and ihsync_last = '0' then + hcnti <= 0; + else + hcnti <= hcnti + 1; + end if; + end if; + end process; + + -- increment write position during active video + p_ram_in : process + begin + wait until rising_edge(CLK_x2); + if CLK = '0' then + if (hcnti < cstart) or (hcnti >= (cstart + clength)) then + hpos_i <= (others => '0'); + else + hpos_i <= hpos_i + 1; + end if; + end if; + end process; + + -- VGA H and V counters, synchronized to input frame V sync, then H sync + p_out_ctrs : process + variable trigger : boolean; + begin + wait until rising_edge(CLK_x2); + ivsync_last_x2 <= I_VSYNC; + + if (I_VSYNC = '0') and (ivsync_last_x2 = '1') then + trigger := true; + elsif trigger and I_HSYNC = '0' then + trigger := false; + hcnt <= 0; + vcnt <= 0; + else + hcnt <= hcnt + 1; + if hcnt = (hA+hB+hC+hD+hpad+hpad-1) then + hcnt <= 0; + vcnt <= vcnt + 1; + end if; + end if; + end process; + + -- generate hsync + p_gen_hsync : process + begin + wait until rising_edge(CLK_x2); + -- H sync timing + if (hcnt < hB) then + O_HSYNC <= '0'; + else + O_HSYNC <= '1'; + end if; + end process; + + -- generate vsync + p_gen_vsync : process + begin + wait until rising_edge(CLK_x2); + -- V sync timing + if (vcnt < vB) then + O_VSYNC <= '0'; + else + O_VSYNC <= '1'; + end if; + end process; + + -- generate active output video + p_gen_active_vid : process + begin + wait until rising_edge(CLK_x2); + -- visible video area doubled from the original game + if ((hcnt >= (hB + hC + hpad)) and (hcnt < (hB + hC + hD + hpad))) and ((vcnt > 2*(vB + vC + vpad)) and (vcnt <= 2*(vB + vC + vD + vpad))) then + hpos_o <= hpos_o + 1; + else + hpos_o <= (others => '0'); + end if; + end process; + + -- generate blanking signal including additional borders to pad the input signal to standard VGA resolution + p_gen_blank : process + begin + wait until rising_edge(CLK_X2); + -- active video area 640x480 (VGA) after padding with blank borders + if ((hcnt >= (hB + hC)) and (hcnt < (hB + hC + hD + 2*hpad))) and ((vcnt > 2*(vB + vC)) and (vcnt <= 2*(vB + vC + vD + 2*vpad))) then + O_CMPBLK_N <= '1'; + else + O_CMPBLK_N <= '0'; + end if; + end process; + +end architecture RTL; diff --git a/Apple - 2_MiST/rtl/scandoubler.v b/Apple - 2_MiST/rtl/scandoubler.v new file mode 100644 index 00000000..0213d20c --- /dev/null +++ b/Apple - 2_MiST/rtl/scandoubler.v @@ -0,0 +1,195 @@ +// +// scandoubler.v +// +// Copyright (c) 2015 Till Harbaum +// Copyright (c) 2017 Sorgelig +// +// 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 . + +// TODO: Delay vsync one line + +module scandoubler #(parameter LENGTH, parameter HALF_DEPTH) +( + // system interface + input clk_sys, + input ce_pix, + input ce_pix_actual, + + input hq2x, + + // shifter video interface + input hs_in, + input vs_in, + input line_start, + + input [DWIDTH:0] r_in, + input [DWIDTH:0] g_in, + input [DWIDTH:0] b_in, + input mono, + + // output interface + output reg hs_out, + output vs_out, + output [DWIDTH:0] r_out, + output [DWIDTH:0] g_out, + output [DWIDTH:0] b_out +); + + +localparam DWIDTH = HALF_DEPTH ? 2 : 5; + +assign vs_out = vs_in; + +reg [2:0] phase; +reg [2:0] ce_div; +reg [7:0] pix_len = 0; +wire [7:0] pl = pix_len + 1'b1; + +reg ce_x1, ce_x4; +reg req_line_reset; +wire ls_in = hs_in | line_start; +always @(negedge clk_sys) begin + reg old_ce; + reg [2:0] ce_cnt; + + reg [7:0] pixsz2, pixsz4 = 0; + + old_ce <= ce_pix; + if(~&pix_len) pix_len <= pix_len + 1'd1; + + ce_x4 <= 0; + ce_x1 <= 0; + + // use such odd comparison to place c_x4 evenly if master clock isn't multiple 4. + if((pl == pixsz4) || (pl == pixsz2) || (pl == (pixsz2+pixsz4))) begin + phase <= phase + 1'd1; + ce_x4 <= 1; + end + + if(~old_ce & ce_pix) begin + pixsz2 <= {1'b0, pl[7:1]}; + pixsz4 <= {2'b00, pl[7:2]}; + ce_x1 <= 1; + ce_x4 <= 1; + pix_len <= 0; + phase <= phase + 1'd1; + + ce_cnt <= ce_cnt + 1'd1; + if(ce_pix_actual) begin + phase <= 0; + ce_div <= ce_cnt + 1'd1; + ce_cnt <= 0; + req_line_reset <= 0; + end + + if(ls_in) req_line_reset <= 1; + end +end + +reg ce_sd; +always @(*) begin + case(ce_div) + 2: ce_sd = !phase[0]; + 4: ce_sd = !phase[1:0]; + default: ce_sd <= 1; + endcase +end + +`define BITS_TO_FIT(N) ( \ + N <= 2 ? 0 : \ + N <= 4 ? 1 : \ + N <= 8 ? 2 : \ + N <= 16 ? 3 : \ + N <= 32 ? 4 : \ + N <= 64 ? 5 : \ + N <= 128 ? 6 : \ + N <= 256 ? 7 : \ + N <= 512 ? 8 : \ + N <=1024 ? 9 : 10 ) + +localparam AWIDTH = `BITS_TO_FIT(LENGTH); +Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x +( + .clk(clk_sys), + .ce_x4(ce_x4 & ce_sd), + .inputpixel({b_in,g_in,r_in}), + .mono(mono), + .disable_hq2x(~hq2x), + .reset_frame(vs_in), + .reset_line(req_line_reset), + .read_y(sd_line), + .read_x(sd_h_actual), + .outpixel({b_out,g_out,r_out}) +); + +reg [10:0] sd_h_actual; +always @(*) begin + case(ce_div) + 2: sd_h_actual = sd_h[10:1]; + 4: sd_h_actual = sd_h[10:2]; + default: sd_h_actual = sd_h; + endcase +end + +reg [10:0] sd_h; +reg [1:0] sd_line; +always @(posedge clk_sys) begin + + reg [11:0] hs_max,hs_rise,hs_ls; + reg [10:0] hcnt; + reg [11:0] sd_hcnt; + + reg hs, hs2, vs, ls; + + if(ce_x1) begin + hs <= hs_in; + ls <= ls_in; + + if(ls && !ls_in) hs_ls <= {hcnt,1'b1}; + + // falling edge of hsync indicates start of line + if(hs && !hs_in) begin + hs_max <= {hcnt,1'b1}; + hcnt <= 0; + if(ls && !ls_in) hs_ls <= {10'd0,1'b1}; + end else begin + hcnt <= hcnt + 1'd1; + end + + // save position of rising edge + if(!hs && hs_in) hs_rise <= {hcnt,1'b1}; + + vs <= vs_in; + if(vs && ~vs_in) sd_line <= 0; + end + + if(ce_x4) begin + hs2 <= hs_in; + + // output counter synchronous to input and at twice the rate + sd_hcnt <= sd_hcnt + 1'd1; + sd_h <= sd_h + 1'd1; + if(hs2 && !hs_in) sd_hcnt <= hs_max; + if(sd_hcnt == hs_max) sd_hcnt <= 0; + + // replicate horizontal sync at twice the speed + if(sd_hcnt == hs_max) hs_out <= 0; + if(sd_hcnt == hs_rise) hs_out <= 1; + + if(sd_hcnt == hs_ls) sd_h <= 0; + if(sd_hcnt == hs_ls) sd_line <= sd_line + 1'd1; + end +end + +endmodule diff --git a/Apple - 2_MiST/rtl/spi_controller.vhd b/Apple - 2_MiST/rtl/spi_controller.vhd new file mode 100644 index 00000000..24a6489b --- /dev/null +++ b/Apple - 2_MiST/rtl/spi_controller.vhd @@ -0,0 +1,471 @@ +------------------------------------------------------------------------------- +-- +-- SD/MMC interface (SPI-style) for the Apple ][ Emulator +-- +-- Michel Stempin (michel.stempin@wanadoo.fr) +-- Working with MMC/SD/SDHC cards +-- +-- From previous work by: +-- Stephen A. Edwards (sedwards@cs.columbia.edu) +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity spi_controller is + generic ( + BLOCK_SIZE : natural := 512; + BLOCK_BITS : natural := 9; + TRACK_SIZE : natural := 16#1A00# + ); + + port ( + -- Card Interface --------------------------------------------------------- + CS_N : out std_logic; -- MMC chip select + MOSI : out std_logic; -- Data to card (master out slave in) + MISO : in std_logic; -- Data from card (master in slave out) + SCLK : out std_logic; -- Card clock + -- Track buffer Interface ------------------------------------------------- + ram_write_addr : out unsigned(13 downto 0); + ram_di : out unsigned(7 downto 0); + ram_we : out std_logic; + track : in unsigned(5 downto 0); -- Track number (0-34) + image : in unsigned(9 downto 0); -- Which disk image to read + -- System Interface ------------------------------------------------------- + CLK_14M : in std_logic; -- System clock + reset : in std_logic + ); + +end spi_controller; + +architecture rtl of spi_controller is + + ----------------------------------------------------------------------------- + -- States of the combined MMC/SD/SDHC reset, track and command FSM + -- + type states is ( + -- Reset FSM + POWER_UP, + RAMP_UP, + CHECK_CMD0, + CHECK_CMD8, + CHECK_CMD55, + CHECK_ACMD41, + CHECK_CMD1, + CHECK_CMD58, + CHECK_SET_BLOCKLEN, + ERROR, + -- Track read FSM + IDLE, + READ_TRACK, + READ_BLOCK_WAIT, + READ_BLOCK_DATA, + READ_BLOCK_CRC, + -- SD command embedded FSM + WAIT_NRC, + SEND_CMD, + RECEIVE_BYTE_WAIT, + RECEIVE_BYTE); + -- + signal state, return_state : states; + -- + ----------------------------------------------------------------------------- + + signal slow_clk : boolean := true; + signal spi_clk : std_logic; + signal sclk_sig : std_logic; + + signal current_track : unsigned(5 downto 0); + signal current_image : unsigned(9 downto 0); + signal write_addr : unsigned(13 downto 0); + + signal command : std_logic_vector(5 downto 0); + signal argument : std_logic_vector(31 downto 0); + signal crc7 : std_logic_vector(6 downto 0); + signal command_out : std_logic_vector(55 downto 0); + signal recv_bytes : unsigned(39 downto 0); + type versions is (MMC, SD1x, SD2x); + signal version : versions; + signal high_capacity : boolean; + +begin + + ram_write_addr <= write_addr; + + ----------------------------------------------------------------------------- + -- Process var_clkgen + -- + -- Purpose: + -- Implements the variable speed clock for MMC compatibility. + -- If slow_clk is false, spi_clk == CLK_14M, thus SCLK = 7M + -- If slow_clk is true, spi_clk = CLK_14M / 32 and SCLK = 223.214kHz, which + -- is between 100kHz and 400kHz, as required for MMC compatibility. + -- + var_clkgen : process (CLK_14M, slow_clk) + variable var_clk : unsigned(4 downto 0) := (others => '0'); + begin + if slow_clk then + spi_clk <= var_clk(4); + if rising_edge(CLK_14M) then + var_clk := var_clk + 1; + end if; + else + spi_clk <= CLK_14M; + end if; + end process; + + SCLK <= sclk_sig; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process sd_fsm + -- + -- Purpose: + -- Implements the combined "SD Card init", "track read" and "command" FSMs. + -- + sd_fsm : process(spi_clk) + subtype cmd_t is std_logic_vector(5 downto 0); + constant CMD0 : cmd_t := std_logic_vector(to_unsigned(0, 6)); + constant CMD1 : cmd_t := std_logic_vector(to_unsigned(1, 6)); + constant CMD8 : cmd_t := std_logic_vector(to_unsigned(8, 6)); + constant CMD16 : cmd_t := std_logic_vector(to_unsigned(16, 6)); + constant CMD17 : cmd_t := std_logic_vector(to_unsigned(17, 6)); + constant CMD55 : cmd_t := std_logic_vector(to_unsigned(55, 6)); + constant CMD58 : cmd_t := std_logic_vector(to_unsigned(58, 6)); + constant ACMD41 : cmd_t := std_logic_vector(to_unsigned(41, 6)); + variable counter : unsigned(7 downto 0); + variable byte_counter : unsigned(BLOCK_BITS - 1 downto 0); + variable lba : unsigned(31 downto 0); + + begin + if rising_edge(spi_clk) then + ram_we <= '0'; + if reset = '1' then + state <= POWER_UP; + -- Deliberately out of range + current_track <= (others => '1'); + current_image <= (others => '1'); + sclk_sig <= '0'; + slow_clk <= true; + CS_N <= '1'; + command <= (others => '0'); + argument <= (others => '0'); + crc7 <= (others => '0'); + command_out <= (others => '1'); + counter := TO_UNSIGNED(0, 8); + byte_counter := TO_UNSIGNED(0, BLOCK_BITS); + write_addr <= (others => '0'); + high_capacity <= false; + version <= MMC; + lba := (others => '0'); + else + case state is + + --------------------------------------------------------------------- + -- SD Card init FSM + --------------------------------------------------------------------- + when POWER_UP => + counter := TO_UNSIGNED(224, 8); + state <= RAMP_UP; + + -- Output a series of 74 clock signals (or 1ms delay, whichever is + -- greater) to wake up the card + when RAMP_UP => + if counter = 0 then + CS_N <= '0'; + command <= CMD0; + argument <= (others => '0'); + crc7 <= "1001010"; + return_state <= CHECK_CMD0; + state <= WAIT_NRC; + else + counter := counter - 1; + sclk_sig <= not sclk_sig; + end if; + + -- CMD0: GO_IDLE_STATE ---------------------------------------------- + when CHECK_CMD0 => + if recv_bytes(7 downto 0) = x"01" then + command <= CMD8; + -- Propose 2.7-3.6V operating voltage and a "10101010" test pattern + argument <= x"000001aa"; + crc7 <= "1000011"; + return_state <= CHECK_CMD8; + state <= WAIT_NRC; + else + state <= ERROR; + end if; + + -- CMD8: SEND_IF_COND ----------------------------------------------- + when CHECK_CMD8 => + argument <= (others => '0'); + crc7 <= (others => '0'); + if recv_bytes(39 downto 32) <= x"01" then + -- This is an SD 2.x/3.x Card + version <= SD2x; + if recv_bytes(11 downto 8) /= "0001" or recv_bytes(7 downto 0) /= x"aa" then + -- Operating voltage or pattern check failure + state <= ERROR; + else + command <= CMD55; + high_capacity <= true; + return_state <= CHECK_CMD55; + state <= WAIT_NRC; + end if; + else + -- This is an MMC Card or an SD 1.x Card + version <= SD1x; + high_capacity <= false; + command <= CMD55; + return_state <= CHECK_CMD55; + state <= WAIT_NRC; + end if; + + -- CMD55: APP_CMD --------------------------------------------------- + when CHECK_CMD55 => + if recv_bytes(7 downto 0) = x"01" then + -- This is an SD Card + command <= ACMD41; + if high_capacity then + -- Ask for HCS (High Capacity Support) + argument <= x"40000000"; + end if; + return_state <= CHECK_ACMD41; + state <= WAIT_NRC; + else + -- This is an MMC Card + version <= MMC; + command <= CMD1; + return_state <= CHECK_CMD1; + state <= WAIT_NRC; + end if; + + -- ACMD41: SEND_OP_CMD (SD Card) ------------------------------------ + when CHECK_ACMD41 => + if recv_bytes(7 downto 0) = x"00" then + if version = SD2x then + -- This is an SD 2.x/3.x Card, read OCR + command <= CMD58; + argument <= (others => '0'); + return_state <= CHECK_CMD58; + state <= WAIT_NRC; + else + -- This is an SD 1.x Card, no HCS + command <= CMD16; + argument <= std_logic_vector(to_unsigned(BLOCK_SIZE, 32)); + return_state <= CHECK_SET_BLOCKLEN; + state <= WAIT_NRC; + end if; + elsif recv_bytes(7 downto 0) = x"01" then + -- Wait until the card goes out of idle state + command <= CMD55; + argument <= (others => '0'); + return_state <= CHECK_CMD55; + state <= WAIT_NRC; + else + -- Found an MMC card that understands CMD55, but not ACMD41 + command <= CMD1; + return_state <= CHECK_CMD1; + state <= WAIT_NRC; + end if; + + -- CMD1: SEND_OP_CMD (MMC Card) ------------------------------------- + when CHECK_CMD1 => + if recv_bytes(7 downto 0) <= x"01" then + command <= CMD16; + argument <= std_logic_vector(to_unsigned(BLOCK_SIZE, 32)); + return_state <= CHECK_SET_BLOCKLEN; + state <= WAIT_NRC; + else + -- Wait until the card goes out of idle state + command <= CMD1; + return_state <= CHECK_CMD1; + state <= WAIT_NRC; + end if; + + -- CMD58: READ_OCR -------------------------------------------------- + when CHECK_CMD58 => + if recv_bytes(7 downto 0) = x"00" then + if recv_bytes(30) = '1' then + high_capacity <= true; + else + high_capacity <= false; + end if; + command <= CMD16; + argument <= std_logic_vector(to_unsigned(BLOCK_SIZE, 32)); + return_state <= CHECK_SET_BLOCKLEN; + state <= WAIT_NRC; + else + state <= ERROR; + end if; + + -- CMD16: SET_BLOCKLEN (BLOCK_SIZE) --------------------------------- + when CHECK_SET_BLOCKLEN => + if recv_bytes(7 downto 0) = x"00" then + slow_clk <= false; + state <= IDLE; + else + state <= ERROR; + end if; + + -- Error state ------------------------------------------------------ + when ERROR => + sclk_sig <= '0'; + slow_clk <= true; + CS_N <= '1'; + + --------------------------------------------------------------------- + -- Embedded "read track" FSM + --------------------------------------------------------------------- + -- Idle state where we sit waiting for user image/track requests ---- + when IDLE => + if track /= current_track or image /= current_image then + -- Compute the LBA (Logical Block Address) from the given + -- image/track numbers. + -- Each Apple ][ floppy image contains 35 tracks, each consisting of + -- 16 x 256-byte sectors. + -- However, because of inter-sector gaps and address fields in + -- raw mode, the actual length is set to 0x1A00, so each image is + -- actually $1A00 bytes * 0x23 tracks = 0x38E00 bytes. + -- So: lba = image * 0x38E00 + track * 0x1A00 + -- In order to avoid multiplications by constants, we replace + -- them by direct add/sub of shifted image/track values: + -- 0x38E00 = 0011 1000 1110 0000 0000 + -- = 0x40000 - 0x8000 + 0x1000 - 0x200 + -- 0x01A00 = 0000 0001 1010 0000 0000 + -- = 0x1000 + 0x800 + 0x200 + lba := ("0000" & image & "000000000000000000") - + ( image & "000000000000000") + + ( image & "000000000000") - + ( image & "000000000") + + ( track & "000000000") + + ( track & "00000000000") + + ( track & "000000000000"); + if high_capacity then + -- For SDHC, blocks are addressed by blocks, not bytes + lba := lba srl BLOCK_BITS; + end if; + write_addr <= (others => '0'); + CS_N <= '0'; + state <= READ_TRACK; + current_track <= track; + current_image <= image; + else + CS_N <= '1'; + sclk_sig <= '1'; + end if; + + -- Read in a whole track into buffer memory ------------------------- + when READ_TRACK => + if write_addr = TRACK_SIZE then + state <= IDLE; + else + command <= CMD17; + argument <= std_logic_vector(lba); + return_state <= READ_BLOCK_WAIT; + state <= WAIT_NRC; + end if; + + -- Wait for a 0 bit to signal the start of the block ---------------- + when READ_BLOCK_WAIT => + if sclk_sig = '1' and MISO = '0' then + state <= READ_BLOCK_DATA; + byte_counter := TO_UNSIGNED(BLOCK_SIZE - 1, BLOCK_BITS); + counter := TO_UNSIGNED(7, 8); + return_state <= READ_BLOCK_DATA; + state <= RECEIVE_BYTE; + end if; + sclk_sig <= not sclk_sig; + + -- Read a block of data --------------------------------------------- + when READ_BLOCK_DATA => + ram_we <= '1'; + write_addr <= write_addr + 1; + if byte_counter = 0 then + counter := TO_UNSIGNED(7, 8); + return_state <= READ_BLOCK_CRC; + state <= RECEIVE_BYTE; + else + byte_counter := byte_counter - 1; + counter := TO_UNSIGNED(7, 8); + return_state <= READ_BLOCK_DATA; + state <= RECEIVE_BYTE; + end if; + + -- Read the block CRC ----------------------------------------------- + when READ_BLOCK_CRC => + counter := TO_UNSIGNED(7, 8); + return_state <= READ_TRACK; + if high_capacity then + lba := lba + 1; + else + lba := lba + BLOCK_SIZE; + end if; + state <= RECEIVE_BYTE; + + --------------------------------------------------------------------- + -- Embedded "command" FSM + --------------------------------------------------------------------- + -- Wait for card response in front of host command ------------------ + when WAIT_NRC => + counter := TO_UNSIGNED(63, 8); + command_out <= "11111111" & "01" & command & argument & crc7 & "1"; + sclk_sig <= not sclk_sig; + state <= SEND_CMD; + + -- Send a command to the card --------------------------------------- + when SEND_CMD => + if sclk_sig = '1' then + if counter = 0 then + state <= RECEIVE_BYTE_WAIT; + else + counter := counter - 1; + command_out <= command_out(54 downto 0) & "1"; + end if; + end if; + sclk_sig <= not sclk_sig; + + -- Wait for a "0", indicating the first bit of a response ----------- + when RECEIVE_BYTE_WAIT => + if sclk_sig = '1' then + if MISO = '0' then + recv_bytes <= (others => '0'); + if command = CMD8 or command = CMD58 then + -- This is an R7 response, but we already have read bit 39 + counter := TO_UNSIGNED(38,8); + else + -- This is a data byte or an r1 response, but we already read + -- bit 7 + counter := TO_UNSIGNED(6, 8); + end if; + state <= RECEIVE_BYTE; + end if; + end if; + sclk_sig <= not sclk_sig; + + -- Receive a byte --------------------------------------------------- + when RECEIVE_BYTE => + if sclk_sig = '1' then + recv_bytes <= recv_bytes(38 downto 0) & MISO; + if counter = 0 then + state <= return_state; + ram_di <= recv_bytes(6 downto 0) & MISO; + else + counter := counter - 1; + end if; + end if; + sclk_sig <= not sclk_sig; + + when others => null; + end case; + end if; + end if; + end process sd_fsm; + + MOSI <= command_out(55); + +end rtl; diff --git a/Apple - 2_MiST/rtl/timing_generator.vhd b/Apple - 2_MiST/rtl/timing_generator.vhd new file mode 100644 index 00000000..2612b89b --- /dev/null +++ b/Apple - 2_MiST/rtl/timing_generator.vhd @@ -0,0 +1,150 @@ +------------------------------------------------------------------------------- +-- +-- Apple ][ Timing logic +-- +-- Stephen A. Edwards, sedwards@cs.columbia.edu +-- +-- Taken more-or-less verbatim from the schematics in the +-- Apple ][ reference manual +-- +-- This takes a 14.31818 MHz master clock and divides it down to generate +-- the various lower-frequency signals (e.g., 7M, phase 0, colorburst) +-- as well as horizontal and vertical blanking and sync signals for the video +-- and the video addresses. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity timing_generator is + + port ( + CLK_14M : in std_logic; -- 14.31818 MHz master clock + CLK_7M : buffer std_logic := '0'; + Q3 : buffer std_logic := '0'; -- 2 MHz signal in phase with PHI0 + RAS_N : buffer std_logic := '0'; + CAS_N : buffer std_logic := '0'; + AX : buffer std_logic := '0'; + PHI0 : buffer std_logic := '0'; -- 1.0 MHz processor clock + PRE_PHI0 : buffer std_logic := '0'; -- One 14M cycle before + COLOR_REF : buffer std_logic := '0'; -- 3.579545 MHz colorburst + + TEXT_MODE : in std_logic; + PAGE2 : in std_logic; + HIRES : in std_logic; + + VIDEO_ADDRESS : out unsigned(15 downto 0); + H0 : out std_logic; + VA : out std_logic; -- Character row address + VB : out std_logic; + VC : out std_logic; + V2 : out std_logic; + V4 : out std_logic; + HBL : buffer std_logic; -- Horizontal blanking + VBL : buffer std_logic; -- Vertical blanking + BLANK : out std_logic; -- Composite blanking + LDPS_N : out std_logic; + LD194 : out std_logic + ); + +end timing_generator; + +architecture rtl of timing_generator is + + signal H : unsigned(6 downto 0) := "0000000"; + signal V : unsigned(8 downto 0) := "011111010"; + signal COLOR_DELAY_N : std_logic; + +begin + + -- To generate the once-a-line hiccup: D1 pin 6 + COLOR_DELAY_N <= + not (not COLOR_REF and (not AX and not CAS_N) and PHI0 and not H(6)); + + -- The DRAM signal generator + C2_74S195: process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if Q3 = '1' then -- shift + (Q3, CAS_N, AX, RAS_N) <= + unsigned'(CAS_N, AX, RAS_N, '0'); + else -- load + (Q3, CAS_N, AX, RAS_N) <= + unsigned'(RAS_N, AX, COLOR_DELAY_N, AX); + end if; + end if; + end process; + + -- The main clock signal generator + B1_74S175 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + COLOR_REF <= CLK_7M xor COLOR_REF; + CLK_7M <= not CLK_7M; + PHI0 <= PRE_PHI0; + if AX = '1' then + PRE_PHI0 <= not (Q3 xor PHI0); -- B1 pin 10 + end if; + end if; + end process; + + LDPS_N <= not (PHI0 and not AX and not CAS_N); + LD194 <= not (PHI0 and not AX and not CAS_N and not CLK_7M); + + -- Four four-bit presettable binary counters + -- Seven-bit horizontal counter counts 0, 40, 41, ..., 7F (65 states) + -- Nine-bit vertical counter counts $FA .. $1FF (262 states) + D11D12D13D14_74LS161 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + -- True the cycle before the rising edge of LDPS_N: emulates + -- the effects of using LDPS_N as the clock for the video counters + if (PHI0 and not AX and ((Q3 and RAS_N) or + (not Q3 and COLOR_DELAY_N))) = '1' then + if H(6) = '0' then H <= "1000000"; + else + H <= H + 1; + if H = "1111111" then + V <= V + 1; + if V = "111111111" then V <= "011111010"; end if; + end if; + end if; + end if; + end if; + + end process; + + H0 <= H(0); + VA <= V(0); + VB <= V(1); + VC <= V(2); + V2 <= V(5); + V4 <= V(7); + + HBL <= not (H(5) or (H(3) and H(4))); + VBL <= V(6) and V(7); + + BLANK <= HBL or VBL; + + -- V_SYNC <= VBL and V(5) and not V(4) and not V(3) and + -- not V(2) and (H(4) or H(3) or H(5)); + -- H_SYNC <= HBL and H(3) and not H(2); + + -- SYNC <= not (V_SYNC or H_SYNC); + -- COLOR_BURST <= HBL and H(2) and H(3) and (COLOR_REF or TEXT_MODE); + + -- Video address calculation + VIDEO_ADDRESS(2 downto 0) <= H(2 downto 0); + VIDEO_ADDRESS(6 downto 3) <= (not H(5) & V(6) & H(4) & H(3)) + + ( V(7) & not H(5) & V(7) & '1') + + ( "000" & V(6)); + VIDEO_ADDRESS(9 downto 7) <= V(5 downto 3); + VIDEO_ADDRESS(14 downto 10) <= + ( "00" & HBL & PAGE2 & not PAGE2) when HIRES = '0' else + (PAGE2 & not PAGE2 & V(2 downto 0)); + + VIDEO_ADDRESS(15) <= '0'; + +end rtl; diff --git a/Apple - 2_MiST/rtl/vga_controller.vhd b/Apple - 2_MiST/rtl/vga_controller.vhd new file mode 100644 index 00000000..674b7e8a --- /dev/null +++ b/Apple - 2_MiST/rtl/vga_controller.vhd @@ -0,0 +1,291 @@ +------------------------------------------------------------------------------- +-- +-- A VGA line-doubler for an Apple ][ +-- +-- Stephen A. Edwards, sedwards@cs.columbia.edu +-- +-- +-- FIXME: This is all wrong +-- +-- The Apple ][ uses a 14.31818 MHz master clock. It outputs a new +-- horizontal line every 65 * 14 + 2 = 912 14M cycles. The extra two +-- are from the "extended cycle" used to keep the 3.579545 MHz +-- colorburst signal in sync. Of these, 40 * 14 = 560 are active video. +-- +-- In graphics mode, the Apple effectively generates 140 four-bit pixels +-- output serially (i.e., with 3.579545 MHz pixel clock). In text mode, +-- it generates 280 one-bit pixels (i.e., with a 7.15909 MHz pixel clock). +-- +-- We capture 140 four-bit nibbles for each line and interpret them in +-- one of the two modes. In graphics mode, each is displayed as a +-- single pixel of one of 16 colors. In text mode, each is displayed +-- as two black or white pixels. +-- +-- The VGA display is nominally 640 X 480, but we use a 14.31818 MHz +-- dot clock. To stay in sync with the Apple, we generate a new line +-- every 912 / 2 = 456 14M cycles= 31.8 us, a 31.4 kHz horizontal +-- refresh rate. Of these, 280 will be active video. +-- +-- One set of suggested VGA timings: +-- +-- ______________________ ________ +-- ________| VIDEO |________| VIDEO +-- |-C-|----------D-----------|-E-| +-- __ ______________________________ ___________ +-- |_| |_| +-- |B| +-- |---------------A----------------| +-- +-- A = 31.77 us Scanline time +-- B = 3.77 us Horizontal sync time +-- C = 1.89 us Back porch +-- D = 25.17 us Active video +-- E = 0.94 us Front porch +-- +-- We use A = 456 / 14.31818 MHz = 31.84 us +-- B = 54 / 14.31818 MHz = 3.77 us +-- C = 106 / 14.31818 MHz = 7.40 us +-- D = 280 / 14.31818 MHz = 19.56 us +-- E = 16 / 14.31818 MHz = 1.12 us +------------------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity vga_controller is + + port ( + CLK_28M : in std_logic; -- 14.31818 MHz master clock + + VIDEO : in std_logic; -- from the Apple video generator + COLOR_LINE : in std_logic; + COLOR : in std_logic; + HBL : in std_logic; + VBL : in std_logic; + LD194 : in std_logic; + + VGA_CLK : out std_logic; + VGA_HS : out std_logic; -- Active low + VGA_VS : out std_logic; -- Active low + VGA_BLANK : out std_logic; + VGA_R : out unsigned(9 downto 0); + VGA_G : out unsigned(9 downto 0); + VGA_B : out unsigned(9 downto 0) + ); + +end vga_controller; + +architecture rtl of vga_controller is + + -- Double-ported RAM (one read port, one write port) + -- that holds two lines of 560 pixels + type line_memory_t is array (0 to 2047) of std_logic; + signal line_memory : line_memory_t; + + -- RGB values from Linards Ticmanis, + -- http://newsgroups.derkeiler.com/Archive/Comp/comp.sys.apple2/2005-09/msg00534.html + + type basis_color is array(0 to 3) of unsigned(7 downto 0); + constant basis_r : basis_color := ( X"88", X"38", X"07", X"38" ); + constant basis_g : basis_color := ( X"22", X"24", X"67", X"52" ); + constant basis_b : basis_color := ( X"2C", X"A0", X"2C", X"07" ); + + signal ram_write_addr : unsigned(10 downto 0); + signal ram_we : std_logic; + signal ram_read_addr : unsigned(10 downto 0); + signal ram_data_out : std_logic; + + signal shift_reg : unsigned(5 downto 0); -- Last six pixels + + signal last_hbl : std_logic; + signal hcount : unsigned(10 downto 0); + signal hcount2 : unsigned(10 downto 0); + signal vcount : unsigned(5 downto 0); + signal even_line : std_logic; + signal hactive, hactive_early2, hactive_early1 : std_logic; + + constant VGA_SCANLINE : integer := 456*2; -- Must be 456*2 (set by the Apple) + + constant VGA_HSYNC : integer := 54 * 2; + constant VGA_BACK_PORCH : integer := 66 * 2; + constant VGA_ACTIVE : integer := 282 * 2; + constant VGA_FRONT_PORCH : integer := 54 * 2; + + -- VGA_HSYNC + VGA_BACK_PORCH + VGA_ACTIVE + VGA_FRONT_PORCH = VGA_SCANLINE + + constant VBL_TO_VSYNC : integer := 33; + constant VGA_VSYNC_LINES : integer := 3; + + signal VGA_VS_I, VGA_HS_I : std_logic; + + signal video_active : std_logic; + signal vbl_delayed, vbl_delayed2 : std_logic; + signal hbl_delayed : std_logic; + signal color_line_delayed_1, color_line_delayed_2 : std_logic; + +begin + + delay_hbl : process (CLK_28M) + begin + if rising_edge(CLK_28M) then + if LD194 = '0' then + hbl_delayed <= HBL; + end if; + end if; + end process; + + hcount_vcount_control : process (CLK_28M) + begin + if rising_edge(CLK_28M) then + if last_hbl = '1' and hbl_delayed = '0' then -- Falling edge + color_line_delayed_2 <= color_line_delayed_1; + color_line_delayed_1 <= COLOR; + hcount <= (others => '0'); + vbl_delayed2 <= vbl_delayed; + vbl_delayed <= VBL; + if vbl_delayed = '1' then + even_line <= '0'; + vcount <= vcount + 1; + else + vcount <= (others => '0'); + even_line <= not even_line; + end if; + else + hcount <= hcount + 1; + end if; + last_hbl <= hbl_delayed; + end if; + end process hcount_vcount_control; + + hsync_gen : process (CLK_28M) + begin + if rising_edge(CLK_28M) then + if hcount = VGA_ACTIVE + VGA_FRONT_PORCH or + hcount = VGA_SCANLINE + VGA_ACTIVE + VGA_FRONT_PORCH then + VGA_HS_I <= '0'; + elsif hcount = VGA_ACTIVE + VGA_FRONT_PORCH + VGA_HSYNC or + hcount = VGA_SCANLINE + VGA_ACTIVE + VGA_FRONT_PORCH + VGA_HSYNC then + VGA_HS_I <= '1'; + end if; + + hactive <= hactive_early1; + hactive_early1 <= hactive_early2; + + if hcount = VGA_SCANLINE - 1 or + hcount = VGA_SCANLINE + VGA_SCANLINE - 1 then + hactive_early2 <= '1'; + elsif hcount = VGA_ACTIVE or + hcount = VGA_ACTIVE + VGA_SCANLINE then + hactive_early2 <= '0'; + end if; + end if; + end process hsync_gen; + + VGA_HS <= VGA_HS_I; + + vsync_gen : process (CLK_28M) + begin + if rising_edge(CLK_28M) then + if vcount = VBL_TO_VSYNC then + VGA_VS_I <= '0'; + elsif vcount = VBL_TO_VSYNC + VGA_VSYNC_LINES then + VGA_VS_I <= '1'; + end if; + end if; + end process vsync_gen; + + VGA_VS <= VGA_VS_I; + + hcount2 <= hcount - VGA_SCANLINE; + + ram_read_addr <= + even_line & hcount(9 downto 0) when hcount < VGA_SCANLINE else + even_line & hcount2(9 downto 0); + + shifter: process (CLK_28M) + begin + if rising_edge(CLK_28M) then + shift_reg <= ram_data_out & shift_reg(5 downto 1); + end if; + end process; + + ram_write_addr <= (not even_line) & hcount(10 downto 1); + ram_we <= '1' when hcount(0) = '1' else '0'; + + video_active <= hactive and not vbl_delayed2; + + pixel_generator: process (CLK_28M) + variable r, g, b : unsigned(7 downto 0); + begin + if rising_edge(CLK_28M) then + r := X"00"; + g := X"00"; + b := X"00"; + if video_active = '1' then + + if color_line_delayed_2 = '0' then -- Monochrome mode + + if shift_reg(2) = '1' then + r := X"FF"; g := X"FF"; b := X"FF"; + end if; + + elsif shift_reg(0) = shift_reg(4) and shift_reg(5) = shift_reg(1) then + + -- Tint of adjacent pixels is consistent : display the color + + if shift_reg(1) = '1' then + r := r + basis_r(to_integer(hcount + 1)); + g := g + basis_g(to_integer(hcount + 1)); + b := b + basis_b(to_integer(hcount + 1)); + end if; + if shift_reg(2) = '1' then + r := r + basis_r(to_integer(hcount + 2)); + g := g + basis_g(to_integer(hcount + 2)); + b := b + basis_b(to_integer(hcount + 2)); + end if; + if shift_reg(3) = '1' then + r := r + basis_r(to_integer(hcount + 3)); + g := g + basis_g(to_integer(hcount + 3)); + b := b + basis_b(to_integer(hcount + 3)); + end if; + if shift_reg(4) = '1' then + r := r + basis_r(to_integer(hcount)); + g := g + basis_g(to_integer(hcount)); + b := b + basis_b(to_integer(hcount)); + end if; + else + + -- Tint is changing: display only black, gray, or white + + case shift_reg(3 downto 2) is + when "11" => r := X"FF"; g := X"FF"; b := X"FF"; + when "01" | "10" => r := X"80"; g := X"80"; b := X"80"; + when others => r := X"00"; g := X"00"; b := X"00"; + end case; + end if; + + end if; + + VGA_R <= r & r(7 downto 6); + VGA_G <= g & g(7 downto 6); + VGA_B <= b & b(7 downto 6); + + end if; + end process pixel_generator; + + -- The two-port RAM that stores the line data + line_storage : process (CLK_28M) + begin + if rising_edge(CLK_28M) then + if ram_we = '1' then + line_memory(to_integer(ram_write_addr)) <= VIDEO; + end if; + ram_data_out <= line_memory(to_integer(ram_read_addr)); + end if; + end process line_storage; + + VGA_CLK <= CLK_28M; + + VGA_BLANK <= video_active; + +end rtl; diff --git a/Apple - 2_MiST/rtl/video_generator.vhd b/Apple - 2_MiST/rtl/video_generator.vhd new file mode 100644 index 00000000..e24819f0 --- /dev/null +++ b/Apple - 2_MiST/rtl/video_generator.vhd @@ -0,0 +1,221 @@ +------------------------------------------------------------------------------- +-- +-- Apple ][ Video Generation Logic +-- +-- Stephen A. Edwards, sedwards@cs.columbia.edu +-- +-- This takes data from memory and various mode switches to produce the +-- serial one-bit video data stream. +-- +------------------------------------------------------------------------------- +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity video_generator is + + port ( + CLK_14M : in std_logic; -- 14.31818 MHz master clock + CLK_7M : in std_logic; + AX : in std_logic; + CAS_N : in std_logic; + TEXT_MODE : in std_logic; + PAGE2 : in std_logic; + HIRES_MODE : in std_logic; + MIXED_MODE : in std_logic; + H0 : in std_logic; + VA : in std_logic; + VB : in std_logic; + VC : in std_logic; + V2 : in std_logic; + V4 : in std_logic; + BLANK : in std_logic; + DL : in unsigned(7 downto 0); -- Data from RAM + LDPS_N : in std_logic; + LD194 : in std_logic; + FLASH_CLK : in std_logic; -- Low-frequency flashing text clock + HIRES : out std_logic; + VIDEO : out std_logic; + COLOR_LINE : out std_logic + ); + +end video_generator; + +architecture rtl of video_generator is + + signal char_rom_addr : unsigned(8 downto 0); + signal char_rom_out : unsigned(4 downto 0); + signal text_shiftreg : unsigned(5 downto 0); + signal invert_character : std_logic; + signal text_pixel : std_logic; -- B2 p11 + signal blank_delayed : std_logic; + signal video_sig : std_logic; -- output of B10 p5 + signal graph_shiftreg : unsigned(7 downto 0); + signal graphics_time_1, graphics_time_2, + graphics_time_3 : std_logic; -- B5 p2, B8 p15, B8 p2 + signal lores_time : std_logic; -- A11 p6 + signal pixel_select : std_logic_vector(1 downto 0); -- A10 p14, A10 p15 + signal hires_delayed : std_logic; -- A11 p9 + +begin + + ----------------------------------------------------------------------------- + -- + -- Text Mode Circuitry + -- + -- The character ROM drives a parallel-to-serial shift register + -- whose output is selectively inverted by inverted or flashing text + -- + ----------------------------------------------------------------------------- + + char_rom_addr <= DL(5 downto 0) & VC & VB & VA; + + thecharrom : entity work.character_rom + port map( + addr => char_rom_addr, + clk => CLK_14M, -- FIXME: a lower frequency? + dout => char_rom_out + ); + + -- Parallel-to-serial shifter for text mode + -- The Apple actually used LDPS_N as the clock, not 14M; this is equivalent + A3_74166: process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if CLK_7M = '0' then + if LDPS_N = '0' then -- load + text_shiftreg <= char_rom_out & "0"; + else -- shift + text_shiftreg <= '0' & text_shiftreg(5 downto 1); + end if; + end if; + end if; + end process; + + -- Latch and decoder for flashing/inverted text + -- Comprises part of B11, B13, and A10 + flash_invert : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + invert_character <= not (DL(7) or (DL(6) and FLASH_CLK)); + end if; + end if; + end process; + + text_pixel <= text_shiftreg(0) xor invert_character; + + ----------------------------------------------------------------------------- + -- + -- Lores and Hires Mode Circuitry + -- + -- An eight-bit shift register that either shifts (hires mode) or rotates + -- the two nibbles (lores) followed by a mux that selects the video + -- data from the text mode display, the hires shift register (possibly + -- delayed by a 14M clock pulse), or one of the bits in the lores shift + -- register. + -- + ----------------------------------------------------------------------------- + + -- Original Apple clocked this shift register on the rising edge of RAS_N + B5B8_74LS174 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if AX = '1' and CAS_N = '0' then + graphics_time_3 <= graphics_time_2; + graphics_time_2 <= graphics_time_1; + graphics_time_1 <= not (TEXT_MODE or (V2 and V4 and MIXED_MODE)); + end if; + end if; + end process; + + COLOR_LINE <= graphics_time_1; + + HIRES <= HIRES_MODE and graphics_time_3; -- to address generator + + lores_time <= not HIRES_MODE and graphics_time_3; + + A8A10_74LS194 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + if lores_time = '1' then -- LORES mode + pixel_select <= VC & H0; + else -- HIRES mode + pixel_select <= graphics_time_1 & DL(7); + end if; + end if; + end if; + end process; + + -- Shift hires pixels by one 14M cycle to get orange and blue + A11_74LS74 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + hires_delayed <= graph_shiftreg(0); + end if; + end process; + + -- A pair of four-bit universal shift registers that either + -- shift the whole byte (hires mode) or rotate the two nibbles (lores mode) + B4B9_74LS194 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + graph_shiftreg <= DL; + else + if lores_time = '1' then -- LORES configuration + graph_shiftreg <= graph_shiftreg(4) & graph_shiftreg(7 downto 5) & + graph_shiftreg(0) & graph_shiftreg(3 downto 1); + else -- HIRES configuration + if CLK_7M = '0' then + graph_shiftreg <= graph_shiftreg(4) & graph_shiftreg(7 downto 1); + end if; + end if; + end if; + end if; + end process; + + -- Synchronize BLANK to LD194 + A10_74LS194: process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if LD194 = '0' then + blank_delayed <= BLANK; + end if; + end if; + end process; + + -- Video output mux and flip-flop + A9B10_74LS151 : process (CLK_14M) + begin + if rising_edge(CLK_14M) then + if blank_delayed = '0' then + if lores_time = '1' then -- LORES mode + case pixel_select is + when "00" => video_sig <= graph_shiftreg(0); + when "01" => video_sig <= graph_shiftreg(2); + when "10" => video_sig <= graph_shiftreg(4); + when "11" => video_sig <= graph_shiftreg(6); + when others => video_sig <= 'X'; + end case; + else + if pixel_select(1) = '0' then -- TEXT mode + video_sig <= text_pixel; + else -- HIRES mode + if pixel_select(0) = '1' then + video_sig <= hires_delayed; + else + video_sig <= graph_shiftreg(0); + end if; + end if; + end if; + else + video_sig <= '0'; + end if; + end if; + end process; + + VIDEO <= video_sig; + +end rtl; diff --git a/Apple - 2_MiST/rtl/video_mixer.sv b/Apple - 2_MiST/rtl/video_mixer.sv new file mode 100644 index 00000000..04cfd4ba --- /dev/null +++ b/Apple - 2_MiST/rtl/video_mixer.sv @@ -0,0 +1,242 @@ +// +// +// Copyright (c) 2017 Sorgelig +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +`timescale 1ns / 1ps + +// +// LINE_LENGTH: Length of display line in pixels +// Usually it's length from HSync to HSync. +// May be less if line_start is used. +// +// HALF_DEPTH: If =1 then color dept is 3 bits per component +// For half depth 6 bits monochrome is available with +// mono signal enabled and color = {G, R} + +module video_mixer +#( + parameter LINE_LENGTH = 768, + parameter HALF_DEPTH = 0, + + parameter OSD_COLOR = 3'd4, + parameter OSD_X_OFFSET = 10'd0, + parameter OSD_Y_OFFSET = 10'd0 +) +( + // master clock + // it should be multiple by (ce_pix*4). + input clk_sys, + + // Pixel clock or clock_enable (both are accepted). + input ce_pix, + + // Some systems have multiple resolutions. + // ce_pix_actual should match ce_pix where every second or fourth pulse is enabled, + // thus half or qurter resolutions can be used without brake video sync while switching resolutions. + // For fixed single resolution (or when video sync stability isn't required) ce_pix_actual = ce_pix. + input ce_pix_actual, + + // OSD SPI interface + input SPI_SCK, + input SPI_SS3, + input SPI_DI, + + // scanlines (00-none 01-25% 10-50% 11-75%) + input [1:0] scanlines, + + // 0 = HVSync 31KHz, 1 = CSync 15KHz + input scandoubler_disable, + + // High quality 2x scaling + input hq2x, + + // YPbPr always uses composite sync + input ypbpr, + + // 0 = 16-240 range. 1 = 0-255 range. (only for YPbPr color space) + input ypbpr_full, + + // color + input [DWIDTH:0] R, + input [DWIDTH:0] G, + input [DWIDTH:0] B, + + // Monochrome mode (for HALF_DEPTH only) + input mono, + + // interlace sync. Positive pulses. + input HSync, + input VSync, + + // Falling of this signal means start of informative part of line. + // It can be horizontal blank signal. + // This signal can be used to reduce amount of required FPGA RAM for HQ2x scan doubler + // If FPGA RAM is not an issue, then simply set it to 0 for whole line processing. + // Keep in mind: due to algo first and last pixels of line should be black to avoid side artefacts. + // Thus, if blank signal is used to reduce the line, make sure to feed at least one black (or paper) pixel + // before first informative pixel. + input line_start, + + // MiST video output signals + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + output VGA_VS, + output VGA_HS +); + +localparam DWIDTH = HALF_DEPTH ? 2 : 5; + +wire [DWIDTH:0] R_sd; +wire [DWIDTH:0] G_sd; +wire [DWIDTH:0] B_sd; +wire hs_sd, vs_sd; + +scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH)) scandoubler +( + .*, + .hs_in(HSync), + .vs_in(VSync), + .r_in(R), + .g_in(G), + .b_in(B), + + .hs_out(hs_sd), + .vs_out(vs_sd), + .r_out(R_sd), + .g_out(G_sd), + .b_out(B_sd) +); + +wire [DWIDTH:0] rt = (scandoubler_disable ? R : R_sd); +wire [DWIDTH:0] gt = (scandoubler_disable ? G : G_sd); +wire [DWIDTH:0] bt = (scandoubler_disable ? B : B_sd); + +generate + if(HALF_DEPTH) begin + wire [5:0] r = mono ? {gt,rt} : {rt,rt}; + wire [5:0] g = mono ? {gt,rt} : {gt,gt}; + wire [5:0] b = mono ? {gt,rt} : {bt,bt}; + end else begin + wire [5:0] r = rt; + wire [5:0] g = gt; + wire [5:0] b = bt; + end +endgenerate + +wire hs = (scandoubler_disable ? HSync : hs_sd); +wire vs = (scandoubler_disable ? VSync : vs_sd); + +reg scanline = 0; +always @(posedge clk_sys) begin + reg old_hs, old_vs; + + old_hs <= hs; + old_vs <= vs; + + if(old_hs && ~hs) scanline <= ~scanline; + if(old_vs && ~vs) scanline <= 0; +end + +wire [5:0] r_out, g_out, b_out; +always @(*) begin + case(scanlines & {scanline, scanline}) + 1: begin // reduce 25% = 1/2 + 1/4 + r_out = {1'b0, r[5:1]} + {2'b00, r[5:2]}; + g_out = {1'b0, g[5:1]} + {2'b00, g[5:2]}; + b_out = {1'b0, b[5:1]} + {2'b00, b[5:2]}; + end + + 2: begin // reduce 50% = 1/2 + r_out = {1'b0, r[5:1]}; + g_out = {1'b0, g[5:1]}; + b_out = {1'b0, b[5:1]}; + end + + 3: begin // reduce 75% = 1/4 + r_out = {2'b00, r[5:2]}; + g_out = {2'b00, g[5:2]}; + b_out = {2'b00, b[5:2]}; + end + + default: begin + r_out = r; + g_out = g; + b_out = b; + end + endcase +end + +wire [5:0] red, green, blue; +osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR) osd +( + .*, + + .R_in(r_out), + .G_in(g_out), + .B_in(b_out), + .HSync(hs), + .VSync(vs), + + .R_out(red), + .G_out(green), + .B_out(blue) +); + +wire [5:0] yuv_full[225] = '{ + 6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1, + 6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4, + 6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6, + 6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8, + 6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11, + 6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13, + 6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15, + 6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17, + 6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20, + 6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22, + 6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24, + 6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27, + 6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29, + 6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31, + 6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33, + 6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36, + 6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38, + 6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40, + 6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42, + 6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45, + 6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47, + 6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49, + 6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52, + 6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54, + 6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56, + 6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58, + 6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61, + 6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63, + 6'd63 +}; + +// http://marsee101.blog19.fc2.com/blog-entry-2311.html +// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B) +// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) +// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) + +wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); +wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); +wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); + +wire [7:0] y = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8]; +wire [7:0] pb = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8]; +wire [7:0] pr = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8]; + +assign VGA_R = ypbpr ? (ypbpr_full ? yuv_full[pr-8'd16] : pr[7:2]) : red; +assign VGA_G = ypbpr ? (ypbpr_full ? yuv_full[y -8'd16] : y[7:2]) : green; +assign VGA_B = ypbpr ? (ypbpr_full ? yuv_full[pb-8'd16] : pb[7:2]) : blue; +assign VGA_VS = (scandoubler_disable | ypbpr) ? 1'b1 : ~vs_sd; +assign VGA_HS = scandoubler_disable ? ~(HSync ^ VSync) : ypbpr ? ~(hs_sd ^ vs_sd) : ~hs_sd; + +endmodule diff --git a/Apple - 2_MiST/snapshot/AppleII_MiST.rbf b/Apple - 2_MiST/snapshot/AppleII_MiST.rbf new file mode 100644 index 0000000000000000000000000000000000000000..e25000fc59d77c24c248df28b626e1b555fb1d18 GIT binary patch literal 280752 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 OpX;PfUORd-Sokjp^1(9z literal 0 HcmV?d00001