diff --git a/Atari - 7800_TeST/Atari7800.qpf b/Atari - 7800_TeST/Atari7800.qpf new file mode 100644 index 00000000..086d0dc1 --- /dev/null +++ b/Atari - 7800_TeST/Atari7800.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 = 23:59:05 March 16, 2017 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "13.1" +DATE = "23:59:05 March 16, 2017" + +# Revisions + +PROJECT_REVISION = "Atari7800" diff --git a/Atari - 7800_TeST/Atari7800.qsf b/Atari - 7800_TeST/Atari7800.qsf new file mode 100644 index 00000000..679890ef --- /dev/null +++ b/Atari - 7800_TeST/Atari7800.qsf @@ -0,0 +1,231 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2014 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.4 Build 182 03/12/2014 SJ Web Edition +# Date created = 14:33:15 July 17, 2018 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# Atari7800_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 "23:59:05 MARCH 16, 2017" +set_global_assignment -name LAST_QUARTUS_VERSION 13.1 +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY Output_Files +set_global_assignment -name VERILOG_INCLUDE_FILE rtl/atari7800.vh +set_global_assignment -name VERILOG_INCLUDE_FILE rtl/tia.vh +set_global_assignment -name VERILOG_INCLUDE_FILE rtl/riot.vh +set_global_assignment -name SYSTEMVERILOG_FILE rtl/cart_top.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/Atari7800.sv +set_global_assignment -name VERILOG_FILE rtl/BIOS_ROM.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/uv_to_vga.sv +set_global_assignment -name VERILOG_FILE rtl/ram2k.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/maria.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/TIA.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/RIOT.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu_wrapper.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/line_ram.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/timing_ctrl.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/memory_map.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/dma_ctrl.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/audio.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/audio_xformer.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/cpu.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/ALU.sv +set_global_assignment -name VERILOG_FILE rtl/pll.v +set_global_assignment -name VERILOG_FILE rtl/defender_rom.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/sigma_delta_dac.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/video_mixer.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/osd.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/mist_io.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/scandoubler.sv +set_global_assignment -name SYSTEMVERILOG_FILE rtl/hq2x.sv + +# Pin & Location Assignments +# ========================== +set_location_assignment PIN_54 -to CLOCK_27 +set_location_assignment PIN_7 -to LED +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_90 -to SPI_SS4 +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 PIN_31 -to UART_RX +set_location_assignment PIN_46 -to UART_TX + +# 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_DO_CCPP_REMOVAL ON + +# Analysis & Synthesis Assignments +# ================================ +set_global_assignment -name FAMILY "Cyclone III" +set_global_assignment -name VERILOG_INPUT_VERSION SYSTEMVERILOG_2005 +set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144 +set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 8 +set_global_assignment -name DEVICE_FILTER_PACKAGE TQFP +set_global_assignment -name TOP_LEVEL_ENTITY cart_top + +# Fitter Assignments +# ================== +set_global_assignment -name DEVICE EP3C25E144C8 +set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1 +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" +set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF +set_global_assignment -name ENABLE_NCE_PIN OFF +set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF +set_global_assignment -name CYCLONEIII_CONFIGURATION_SCHEME "PASSIVE SERIAL" +set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF +set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON +set_global_assignment -name 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" + +# EDA Netlist Writer Assignments +# ============================== +set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (VHDL)" + +# 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 EDA_TOOL_SETTINGS(eda_simulation) +# --------------------------------------- + + # EDA Netlist Writer Assignments + # ============================== + set_global_assignment -name EDA_OUTPUT_DATA_FORMAT VHDL -section_id eda_simulation + +# end EDA_TOOL_SETTINGS(eda_simulation) +# ------------------------------------- + +# ---------------------- +# start ENTITY(cart_top) + + # 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(cart_top) +# -------------------- +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Atari - 7800_TeST/Atari7800.qws b/Atari - 7800_TeST/Atari7800.qws new file mode 100644 index 00000000..f178369c Binary files /dev/null and b/Atari - 7800_TeST/Atari7800.qws differ diff --git a/Atari - 7800_TeST/Atari7800.srf b/Atari - 7800_TeST/Atari7800.srf new file mode 100644 index 00000000..91697a7c --- /dev/null +++ b/Atari - 7800_TeST/Atari7800.srf @@ -0,0 +1,2 @@ +{ "" "" "" "*" { } { } 0 10230 "" 0 0 "Quartus II" 0 -1 0 ""} +{ "" "" "" "*" { } { } 0 10036 "" 0 0 "Quartus II" 0 -1 0 ""} diff --git a/Atari - 7800_TeST/Snapshot/Atari7800.rbf b/Atari - 7800_TeST/Snapshot/Atari7800.rbf new file mode 100644 index 00000000..1fb8029e Binary files /dev/null and b/Atari - 7800_TeST/Snapshot/Atari7800.rbf differ diff --git a/Atari - 7800_TeST/clean.bat b/Atari - 7800_TeST/clean.bat new file mode 100644 index 00000000..b3b7c3b5 --- /dev/null +++ b/Atari - 7800_TeST/clean.bat @@ -0,0 +1,37 @@ +@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 /s new_rtl_netlist +del /s old_rtl_netlist + +pause diff --git a/Atari - 7800_TeST/rtl/ALU.sv b/Atari - 7800_TeST/rtl/ALU.sv new file mode 100644 index 00000000..0a5abe18 --- /dev/null +++ b/Atari - 7800_TeST/rtl/ALU.sv @@ -0,0 +1,110 @@ +/* + * ALU. + * + * AI and BI are 8 bit inputs. Result in OUT. + * CI is Carry In. + * CO is Carry Out. + * + * op[3:0] is defined as follows: + * + * 0011 AI + BI + * 0111 AI - BI + * 1011 AI + AI + * 1100 AI | BI + * 1101 AI & BI + * 1110 AI ^ BI + * 1111 AI + * + */ + `timescale 1ns / 1ps + + +module ALU( clk, op, right, AI, BI, CI, CO, BCD, OUT, V, Z, N, HC, RDY ); + input clk; + input right; + input [3:0] op; // operation + input [7:0] AI; + input [7:0] BI; + input CI; + input BCD; // BCD style carry + output [7:0] OUT; + output CO; + output V; + output Z; + output N; + output HC; + input RDY; + +reg [7:0] OUT; +reg CO; +wire V; +wire Z; +reg N; +reg HC; + +reg AI7; +reg BI7; +reg [8:0] temp_logic; +reg [7:0] temp_BI; +reg [4:0] temp_l; +reg [4:0] temp_h; +wire [8:0] temp = { temp_h, temp_l[3:0] }; +wire adder_CI = (right | (op[3:2] == 2'b11)) ? 0 : CI; + +// calculate the logic operations. The 'case' can be done in 1 LUT per +// bit. The 'right' shift is a simple mux that can be implemented by +// F5MUX. +always @* begin + case( op[1:0] ) + 2'b00: temp_logic = AI | BI; + 2'b01: temp_logic = AI & BI; + 2'b10: temp_logic = AI ^ BI; + 2'b11: temp_logic = AI; + endcase + + if( right ) + temp_logic = { AI[0], CI, AI[7:1] }; +end + +// Add logic result to BI input. This only makes sense when logic = AI. +// This stage can be done in 1 LUT per bit, using carry chain logic. +always @* begin + case( op[3:2] ) + 2'b00: temp_BI = BI; // A+B + 2'b01: temp_BI = ~BI; // A-B + 2'b10: temp_BI = temp_logic; // A+A + 2'b11: temp_BI = 0; // A+0 + endcase +end + +// HC9 is the half carry bit when doing BCD add +wire HC9 = BCD & (temp_l[3:1] >= 3'd5); + +// CO9 is the carry-out bit when doing BCD add +wire CO9 = BCD & (temp_h[3:1] >= 3'd5); + +// combined half carry bit +wire temp_HC = temp_l[4] | HC9; + +// perform the addition as 2 separate nibble, so we get +// access to the half carry flag +always @* begin + temp_l = temp_logic[3:0] + temp_BI[3:0] + adder_CI; + temp_h = temp_logic[8:4] + temp_BI[7:4] + temp_HC; +end + +// calculate the flags +always @(posedge clk) + if( RDY ) begin + AI7 <= AI[7]; + BI7 <= temp_BI[7]; + OUT <= temp[7:0]; + CO <= temp[8] | CO9; + N <= temp[7]; + HC <= temp_HC; + end + +assign V = AI7 ^ BI7 ^ CO ^ N; +assign Z = ~|OUT; + +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/Atari7800.sv b/Atari - 7800_TeST/rtl/Atari7800.sv new file mode 100644 index 00000000..a7e9036c --- /dev/null +++ b/Atari - 7800_TeST/rtl/Atari7800.sv @@ -0,0 +1,444 @@ +`timescale 1ns / 1ps +`include "atari7800.vh" + + + +module Atari7800( + input logic clock_25, + input logic sysclk_7_143, + input logic clock_divider_locked, + + input logic reset, + output logic [3:0] RED, GREEN, BLUE, + output logic HSync, VSync, + + output logic [15:0] aud_signal_out, + + input logic [7:0] cart_DB_out, + output logic [15:0] AB, + output logic RW, + output logic pclk_0, + + output logic [7:0] ld, + + // Tia inputs + input logic [3:0] idump, + input logic [1:0] ilatch, + + output logic tia_en, + + // Riot inputs + input logic [7:0] PAin, PBin, + output logic [7:0] PAout, PBout +); + + assign ld[0] = lock_ctrl; + + ////////////// + // Signals // + //////////// + + // Clock Signals + + logic pclk_2, tia_clk, sel_slow_clock; + + + // VGA Signals + logic [9:0] vga_row, vga_col; + logic tia_hsync, tia_vsync, vga_hsync, vga_vsync; + + (* keep = "true" *) logic tia_hsync_kept; + (* keep = "true" *) logic tia_vsync_kept; + (* keep = "true" *) logic vga_hsync_kept; + (* keep = "true" *) logic vga_vsync_kept; + + assign tia_hsync_kept = ~tia_hsync; + assign tia_vsync_kept = ~tia_vsync; + assign vga_hsync_kept = vga_hsync; + assign vga_vsync_kept = vga_vsync; + + // MARIA Signals + logic m_int_b, maria_RDY; + logic maria_rw; + logic halt_b, maria_drive_AB; + logic [7:0] uv_display, uv_maria, uv_tia; + logic [15:0] maria_AB_out; + + + + // TIA Signals + logic hblank_tia, vblank_tia, aud0, aud1, tia_RDY; + logic [3:0] audv0, audv1; + logic [7:0] tia_db_out; + + // RIOT Signals + logic riot_RS_b; + + // 6502 Signals + logic RDY, IRQ_n, CPU_NMI; + logic [7:0] core_DB_out; + logic [15:0] core_AB_out; + + logic cpu_reset, core_halt_b, core_latch_data; + logic [2:0] cpu_reset_counter; + + assign IRQ_n = 1'b1; + + //ctrl Signals + logic maria_en, lock_ctrl, bios_en_b; + logic [1:0] ctrl_writes; + + // Buses + // AB and RW defined in port declaration + logic [7:0] read_DB, write_DB; + + logic [7:0] tia_DB_out, riot_DB_out, maria_DB_out, + ram0_DB_out, ram1_DB_out, bios_DB_out; + + `chipselect CS_maria_buf, CS_core_buf, CS_buf, CS; + + logic memclk; + assign memclk = (~halt_b & maria_drive_AB) ? sysclk_7_143 : pclk_0; + + /*always_ff @(posedge sysclk_7_143, posedge reset) begin + if (reset) begin + CS_maria_buf <= `CS_NONE; + CS_core_buf <= `CS_NONE; + end else begin + CS_maria_buf <= CS; + CS_core_buf <= CS; + end + end + + assign CS_buf = maria_drive_AB ? CS_maria_buf : CS_core_buf;*/ + + always_ff @(posedge memclk, posedge reset) + if (reset) + CS_buf <= `CS_NONE; + else + CS_buf <= CS; + + + //CS LOGIC + logic ram0_cs, ram1_cs, bios_cs, tia_cs, riot_cs, riot_ram_cs; + + always_comb begin + ram0_cs = 1'b0; + ram1_cs = 1'b0; + bios_cs = 1'b0; + tia_cs = 1'b0; + riot_cs = 1'b0; + riot_ram_cs = 1'b0; + casex (CS) + `CS_RAM0: ram0_cs = 1'b1; + `CS_RAM1: ram1_cs = 1'b1; + `CS_BIOS: bios_cs = 1'b1; + `CS_TIA: tia_cs = 1'b1; + `CS_RIOT_IO: riot_cs = 1'b1; + `CS_RIOT_RAM: begin riot_cs = 1'b1; riot_ram_cs = 1'b1; end + endcase + end + + + always_comb begin + casex (CS_buf) + `CS_RAM0: read_DB = ram0_DB_out; + `CS_RAM1: read_DB = ram1_DB_out; + `CS_RIOT_IO, + `CS_RIOT_RAM: read_DB = riot_DB_out; + `CS_TIA: read_DB = tia_DB_out; + `CS_BIOS: read_DB = bios_DB_out; + `CS_MARIA: read_DB = maria_DB_out; + `CS_CART: read_DB = cart_DB_out; + // Otherwise, nothing is driving the data bus. THIS SHOULD NEVER HAPPEN + default: read_DB = 8'h46; + endcase + + write_DB = core_DB_out; + + AB = (maria_drive_AB) ? maria_AB_out : core_AB_out; + end + /* + (* ram_style = "distributed" *) + reg [7:0] ram0 [2047:0]; + (* ram_style = "distributed" *) + reg [7:0] ram1 [2047:0]; + integer cnt; + always_ff @(posedge memclk) begin + if (reset) begin + for (cnt = 0; cnt < 2048;cnt = cnt + 1) begin + ram0[cnt] <= 8'b0; + ram1[cnt] <= 8'b0; + end + end + else if(ram0_cs) + if (RW) + ram0_DB_out <= ram0[AB[10:0]]; + else + ram0[AB[10:0]] <= write_DB; + else if (ram1_cs) + if (RW) + ram1_DB_out <= ram1[AB[10:0]]; + else + ram1[AB[10:0]] <= write_DB; + end */ + + ram2k ram0_inst( + .clock(memclk), + //.ena(~ram0_cs_b), + .clken(ram0_cs), + .wren(~RW), + .address(AB[10:0]), + .data(write_DB), + .q(ram0_DB_out) + ); + + ram2k ram1_inst( + .clock(memclk), + //.ena(~ram1_cs_b), + .clken(ram1_cs), + .wren(~RW), + .address(AB[10:0]), + .data(write_DB), + .q(ram1_DB_out) + ); + + //assign bios_cs_b = ~(AB[15] & ~bios_en_b); + + + BIOS_ROM BIOS_ROM( + .clock(memclk), + .clken(bios_cs), + .address(AB[11:0]), + .q(bios_DB_out) + ); + + assign pclk_2 = ~pclk_0; +// console_pll console_pll ( +// .inclk0(CLOCK_PLL), +// .c0(clock_100), +// .c1(clock_25), // 25 MHz +// .c2(sysclk_7_143), // 7.143 MHz. Divide to 1.79 MHz +// .locked(clock_divider_locked) +// ); + + assign VSync = vga_vsync; + assign HSync = vga_hsync; + + // VGA + uv_to_vga vga_out( + .clk(clock_25), .reset(reset), + .uv_in(uv_display), + .row(vga_row), .col(vga_col), + .RED(RED), .GREEN(GREEN), .BLUE(BLUE), + .HSync(vga_hsync), .VSync(vga_vsync), + .tia_en(tia_en), + .tia_hblank(hblank_tia), + .tia_vblank(vblank_tia), + .tia_clk(tia_clk) + ); + + // VIDEO + always_comb case ({maria_en, tia_en}) + 2'b00: uv_display = uv_maria; + 2'b01: uv_display = uv_tia; + 2'b10: uv_display = uv_maria; + 2'b11: uv_display = uv_tia; + default: uv_display = uv_maria; + endcase + + // MARIA + maria maria_inst( + .AB_in(AB), + .AB_out(maria_AB_out), + .drive_AB(maria_drive_AB), + .read_DB_in(read_DB), + .write_DB_in(write_DB), + .DB_out(maria_DB_out), + .bios_en(~bios_en_b), + .reset(reset), + .sysclk(sysclk_7_143), + .pclk_2(pclk_2), + .sel_slow_clock(sel_slow_clock), + .core_latch_data(core_latch_data), + .tia_en(tia_en), + .tia_clk(tia_clk), + .pclk_0(pclk_0), + .CS(CS), + //.ram0_b(ram0_cs_b), + //.ram1_b(ram1_cs_b), + //.p6532_b(riot_cs_b), + //.tia_b(tia_cs_b), + //.riot_ram_b(riot_RS_b), + .RW(RW), + .enable(maria_en), + .vga_row(vga_row), + .vga_col(vga_col), + .UV_out(uv_maria), + .int_b(m_int_b), + .halt_b(halt_b), + .ready(maria_RDY) + ); + + // TIA + TIA tia_inst(.A({(AB[5] & tia_en), AB[4:0]}), // Address bus input + .Din(write_DB), // Data bus input + .Dout(tia_DB_out), // Data bus output + .CS_n({2'b0,~tia_cs}), // Active low chip select input + .CS(tia_cs), // Chip select input + .R_W_n(RW), // Active low read/write input + .RDY(tia_RDY), // CPU ready output + .MASTERCLK(tia_clk), // 3.58 Mhz pixel clock input + .CLK2(pclk_0), // 1.19 Mhz bus clock input + .idump_in(idump), // Dumped I/O + .Ilatch(ilatch), // Latched I/O + .HSYNC(tia_hsync), // Video horizontal sync output + .HBLANK(hblank_tia), // Video horizontal blank output + .VSYNC(tia_vsync), // Video vertical sync output + .VBLANK(vblank_tia), // Video vertical sync output + .COLOROUT(uv_tia), // Indexed color output + .RES_n(~reset), // Active low reset input + .AUD0(aud0), //audio pin 0 + .AUD1(aud1), //audio pin 1 + .audv0(audv0), //audio volume for use with external xformer module + .audv1(audv1) //audio volume for use with external xformer module + ); + + audio_xformer audio_xform(.AUD0(aud0), .AUD1(aud1), .AUDV0(audv0), + .AUDV1(audv1), .AUD_SIGNAL(aud_signal_out)); + + //RIOT + RIOT riot_inst(.A(AB[6:0]), // Address bus input + .Din(write_DB), // Data bus input + .Dout(riot_DB_out), // Data bus output + .CS(riot_cs), // Chip select input + .CS_n(~riot_cs), // Active low chip select input + .R_W_n(RW), // Active high read, active low write input + .RS_n(~riot_ram_cs), // Active low rom select input + .RES_n(~reset), // Active low reset input + .IRQ_n(), // Active low interrupt output + .CLK(pclk_0), // Clock input + .PAin(PAin), // 8 bit port A input + .PAout(PAout), // 8 bit port A output + .PBin(PBin), // 8 bit port B input + .PBout(PBout)); // 8 bit port B output + + //6502 + assign cpu_reset = cpu_reset_counter != 3'b111; + + always_ff @(posedge pclk_0, posedge reset) begin + if (reset) begin + cpu_reset_counter <= 3'b0; + end else begin + if (cpu_reset_counter != 3'b111) + cpu_reset_counter <= cpu_reset_counter + 3'b001; + end + end + + + assign RDY = maria_en ? maria_RDY : ((tia_en) ? tia_RDY : clock_divider_locked); + + assign core_halt_b = (ctrl_writes == 2'd2) ? halt_b : 1'b1; + + /// DEBUG /////////////////////////////////////////// + `ifndef SIM + + (* keep = "true" *) + logic [15:0] pc_temp; + + assign ld[1] = pc_reached_230a; + assign ld[2] = pc_reached_26bc; + //assign ld[3] = pc_reached_fbad; + assign ld[4] = pc_reached_fbbd; + assign ld[5] = pc_reached_faaf; + + + assign ld[6] = tia_en; + assign ld[7] = maria_en; + + logic pc_reached_230a; // Beginning of RAM code + logic pc_reached_26bc; // Exit BIOS + logic pc_reached_fbad; // waiting for VSYNC + logic pc_reached_fbbd; // done waiting for VSYNC + logic pc_reached_faaf; // NMI handler + + always_ff @(posedge sysclk_7_143, posedge reset) begin + if (reset) begin + pc_reached_230a <= 1'b0; + pc_reached_26bc <= 1'b0; + pc_reached_fbad <= 1'b0; + pc_reached_fbbd <= 1'b0; + pc_reached_faaf <= 1'b0; + end else begin + if (pc_temp == 16'h230a) + pc_reached_230a <= 1'b1; + if (pc_temp == 16'h23ee) + pc_reached_26bc <= 1'b1; + if (pc_temp == 16'hfbad) + pc_reached_fbad <= 1'b1; + if (pc_temp == 16'hfbbd) + pc_reached_fbbd <= 1'b1; + if (pc_temp == 16'hfaaf) + pc_reached_faaf <= 1'b1; + end + end + `endif + ////////////////////////////////////////////////////// + + assign CPU_NMI = (lock_ctrl) ? (~m_int_b) : (~m_int_b & ~bios_en_b); + + cpu_wrapper cpu_inst(.clk(pclk_0), + .core_latch_data(core_latch_data), + .sysclk(sysclk_7_143), + .reset(cpu_reset), + .AB(core_AB_out), + .DB_IN(read_DB), + .DB_OUT(core_DB_out), + .RD(RW), + .IRQ(~IRQ_n), + .NMI(CPU_NMI), + .RDY(RDY), + .halt_b(core_halt_b), + .pc_temp(pc_temp)); + + + + ctrl_reg ctrl(.clk(pclk_0), + .lock_in(write_DB[0]), + .maria_en_in(write_DB[1]), + .bios_en_in(write_DB[2]), + .tia_en_in(write_DB[3]), + .latch_b(RW | ~tia_cs | lock_ctrl), + .rst(reset), + .lock_out(lock_ctrl), + .maria_en_out(maria_en), + .bios_en_out(bios_en_b), + .tia_en_out(tia_en), + .writes(ctrl_writes)); + + +endmodule + +module ctrl_reg(input logic clk, lock_in, maria_en_in, bios_en_in, tia_en_in, latch_b, rst, + output logic lock_out, maria_en_out, bios_en_out, tia_en_out, + output logic [1:0] writes); + + + always_ff @(posedge clk, posedge rst) begin + if (rst) begin + lock_out <= 0; + maria_en_out <= 0; + bios_en_out <= 0; + tia_en_out <= 0; + writes <= 0; + end + else if (~latch_b) begin + lock_out <= lock_in; + maria_en_out <= maria_en_in; + bios_en_out <= bios_en_in; + tia_en_out <= tia_en_in; + if (writes < 2'd2) + writes <= writes + 1; + end + end +endmodule diff --git a/Atari - 7800_TeST/rtl/BIOS_ROM.v b/Atari - 7800_TeST/rtl/BIOS_ROM.v new file mode 100644 index 00000000..197fe978 --- /dev/null +++ b/Atari - 7800_TeST/rtl/BIOS_ROM.v @@ -0,0 +1,169 @@ +// megafunction wizard: %ROM: 1-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: BIOS_ROM.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 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 BIOS_ROM ( + address, + clken, + clock, + q); + + input [11:0] address; + input clken; + input clock; + output [7:0] q; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clken; + tri1 clock; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [7:0] sub_wire0; + wire [7:0] q = sub_wire0[7:0]; + + altsyncram altsyncram_component ( + .address_a (address), + .clock0 (clock), + .clocken0 (clken), + .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), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .data_a ({8{1'b1}}), + .data_b (1'b1), + .eccstatus (), + .q_b (), + .rden_a (1'b1), + .rden_b (1'b1), + .wren_a (1'b0), + .wren_b (1'b0)); + defparam + altsyncram_component.address_aclr_a = "NONE", + altsyncram_component.clock_enable_input_a = "NORMAL", + altsyncram_component.clock_enable_output_a = "NORMAL", +`ifdef NO_PLI + altsyncram_component.init_file = "../rtl/rom/7800ntsc.rif" +`else + altsyncram_component.init_file = "../rtl/rom/7800ntsc.hex" +`endif +, + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 4096, + altsyncram_component.operation_mode = "ROM", + altsyncram_component.outdata_aclr_a = "NONE", + altsyncram_component.outdata_reg_a = "CLOCK0", + altsyncram_component.widthad_a = 12, + altsyncram_component.width_a = 8, + 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: AclrOutput NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +// Retrieval info: PRIVATE: BlankMemory NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "1" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "1" +// Retrieval info: PRIVATE: Clken 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 "../rtl/rom/7800ntsc.hex" +// Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "4096" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: RegAddr 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 "0" +// Retrieval info: PRIVATE: WidthAddr NUMERIC "12" +// Retrieval info: PRIVATE: WidthData NUMERIC "8" +// Retrieval info: PRIVATE: rden NUMERIC "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: ADDRESS_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "NORMAL" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "NORMAL" +// Retrieval info: CONSTANT: INIT_FILE STRING "../rtl/rom/7800ntsc.hex" +// 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 "4096" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM" +// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0" +// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "12" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: USED_PORT: address 0 0 12 0 INPUT NODEFVAL "address[11..0]" +// Retrieval info: USED_PORT: clken 0 0 0 0 INPUT VCC "clken" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +// Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +// Retrieval info: CONNECT: @address_a 0 0 12 0 address 0 0 12 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: @clocken0 0 0 0 0 clken 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL BIOS_ROM.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL BIOS_ROM.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL BIOS_ROM.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL BIOS_ROM.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL BIOS_ROM_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL BIOS_ROM_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf diff --git a/Atari - 7800_TeST/rtl/RIOT.sv b/Atari - 7800_TeST/rtl/RIOT.sv new file mode 100644 index 00000000..917c7079 --- /dev/null +++ b/Atari - 7800_TeST/rtl/RIOT.sv @@ -0,0 +1,174 @@ +/* Atari on an FPGA +Masters of Engineering Project +Cornell University, 2007 +Daniel Beer + RIOT.v +Redesign of the MOS 6532 chip. Provides RAM, I/O and timers to the Atari. +*/ +`timescale 1ns / 1ps + +`include "riot.vh" +module RIOT(A, // Address bus input + Din, // Data bus input + Dout, // Data bus output + CS, // Chip select input + CS_n, // Active low chip select input + R_W_n, // Active low read/write input + RS_n, // Active low rom select input + RES_n, // Active low reset input + IRQ_n, // Active low interrupt output + CLK, // Clock input + PAin, // 8 bit port A input + PAout, // 8 bit port A output + PBin, // 8 bit port B input + PBout);// 8 bit port B output + input [6:0] A; + input [7:0] Din; + output [7:0] Dout; + input CS, CS_n, R_W_n, RS_n, RES_n, CLK; + output IRQ_n; + input [7:0] PAin, PBin; + output [7:0] PAout, PBout; // Output register + reg [7:0] Dout; // RAM allocation + reg [7:0] RAM[127:0]; // I/O registers + reg [7:0] DRA, DRB; // Data registers + reg [7:0] DDRA, DDRB; // Data direction registers + wire PA7; + reg R_PA7; + assign PA7 = (PAin[7] & ~DDRA[7]) | (DRA[7] & DDRA[7]); + assign PAout = DRA & DDRA; + assign PBout = DRB & DDRB; + // Timer registers + reg [8:0] Timer; + reg [9:0] Prescaler; + reg [1:0] Timer_Mode; + reg Timer_Int_Flag, PA7_Int_Flag, Timer_Int_Enable, PA7_Int_Enable, PA7_Int_Mode; // Timer prescaler constants + wire [9:0] PRESCALER_VALS[3:0]; + assign PRESCALER_VALS[0] = 10'd0; + assign PRESCALER_VALS[1] = 10'd7; + assign PRESCALER_VALS[2] = 10'd63; + assign PRESCALER_VALS[3] = 10'd1023; + // Interrupt + assign IRQ_n = ~(Timer_Int_Flag & Timer_Int_Enable | PA7_Int_Flag & PA7_Int_Enable); + // Operation decoding + wire [6:0] op; + reg [6:0] R_op; + assign op = {RS_n, R_W_n, A[4:0]}; + // Registered data in + reg [7:0] R_Din; + integer cnt; + // Software operations + always @(posedge CLK) + begin + // Reset operation + if (~RES_n) begin + DRA <= 8'b0; + DDRA <= 8'b0; + DRB <= 8'b00010100; + DDRB <= 8'b00010100; + Timer_Int_Flag <= 1'b0; + PA7_Int_Flag <= 1'b0; + PA7_Int_Enable <= 1'b0; + PA7_Int_Mode <= 1'b0; + // Fill RAM with 0s + for (cnt = 0; cnt < 128; cnt = cnt + 1) + RAM[cnt] <= 8'b0; + R_PA7 <= 1'b0; + R_op <= `NOP; + R_Din <= 8'b0; + end + // If the chip is enabled, execute an operation + else if (CS & ~CS_n) begin + // Register inputs for use later + R_PA7 <= PA7; + R_op <= op; + R_Din <= Din; + // Update the timer interrupt flag + casex (op) + `WRITE_TIMER: Timer_Int_Flag <= 1'b0; + `READ_TIMER: Timer_Int_Flag <= 1'b0; + default: if (Timer == 9'b111111111) Timer_Int_Flag <= 1'b1; + endcase + // Update the port A interrupt flag + casex (op) + `READ_INT_FLAG: PA7_Int_Flag <= 1'b0; + default: PA7_Int_Flag <= PA7_Int_Flag | (PA7 != R_PA7 & PA7 == PA7_Int_Mode); + endcase + // Process the current operation + casex(op) // RAM access + `READ_RAM: Dout <= RAM[A]; + `WRITE_RAM: RAM[A] <= Din; + // Port A data access + `READ_DRA : Dout <= (PAin & ~DDRA) | (DRA & DDRA); + `WRITE_DRA: DRA <= Din; + // Port A direction register access + `READ_DDRA: Dout <= DDRA; + `WRITE_DDRA: DDRA <= Din; + // Port B data access + `READ_DRB: Dout <= (PBin & ~DDRB) | (DRB & DDRB); + `WRITE_DRB: DRB <= Din; + // Port B direction register access + `READ_DDRB: Dout <= DDRB; + `WRITE_DDRB: DDRB <= Din; + // Timer access + `READ_TIMER: Dout <= Timer[7:0]; + // Status register access + `READ_INT_FLAG: Dout <= {Timer_Int_Flag, PA7_Int_Flag, 6'b0}; + // Enable the port A interrupt + `WRITE_EDGE_DETECT: begin + PA7_Int_Mode <= A[0]; PA7_Int_Enable <= A[1]; + end + endcase + end + // Even if the chip is not enabled, update background functions + else begin + // Update the timer interrupt + if (Timer == 9'b111111111) + Timer_Int_Flag <= 1'b1; + // Update the port A interrupt + R_PA7 <= PA7; + PA7_Int_Flag <= PA7_Int_Flag | (PA7 != R_PA7 & PA7 == PA7_Int_Mode); + // Set the operation to a NOP + R_op <=`NOP; + end + end + // Update the timer at the negative edge of the clock + always @(negedge CLK)begin + // Reset operation + if (~RES_n) begin + Timer <= 9'b0; + Timer_Mode <= 2'b0; + Prescaler <= 10'b0; + Timer_Int_Enable <= 1'b0; + end + // Otherwise, process timer operations + else + casex + (R_op) + // Write value to the timer and update the prescaler based on the address + `WRITE_TIMER:begin + Timer <= {1'b0, R_Din}; + Timer_Mode <= R_op[1:0]; + Prescaler <= PRESCALER_VALS[R_op[1:0]]; + Timer_Int_Enable <= R_op[3]; + end + // Otherwise decrement the prescaler and if necessary the timer. + // The prescaler holds a variable number of counts that must be + // run before the timer is decremented + default:if (Timer != 9'b100000000) begin + if (Prescaler != 10'b0) + Prescaler <= Prescaler - 10'b1; + else begin + if (Timer == 9'b0) + begin + Prescaler <= 10'b0; + Timer_Mode <= 2'b0; + end + else + Prescaler <= PRESCALER_VALS[Timer_Mode]; + Timer <= Timer - 9'b1; + end + end + endcase + end +endmodule diff --git a/Atari - 7800_TeST/rtl/TIA.sv b/Atari - 7800_TeST/rtl/TIA.sv new file mode 100644 index 00000000..61852f62 --- /dev/null +++ b/Atari - 7800_TeST/rtl/TIA.sv @@ -0,0 +1,477 @@ +/* Atari on an FPGA + Masters of Engineering Project + Cornell University, 2007 + Daniel Beer + TIA.v + Redesign of the Atari TIA chip. Provides the Atari with video generation, + sound generation and I/O. + */ + `timescale 1ns / 1ps + +`include "tia.vh" +module TIA(A, // Address bus input + Din, // Data bus input + Dout, // Data bus output + CS_n, // Active low chip select input + CS, // Chip select input + R_W_n, // Active low read/write input + RDY, // CPU ready output + MASTERCLK, // 3.58 Mhz pixel clock input + CLK2, // 1.19 Mhz bus clock input + idump_in, // Dumped I/O + Ilatch, // Latched I/O + HSYNC, // Video horizontal sync output + HBLANK, // Video horizontal blank output + VSYNC, // Video vertical sync output + VBLANK, // Video vertical sync output + COLOROUT, // Indexed color output + RES_n, // Active low reset input + AUD0, //audio pin 0 + AUD1, //audio pin 1 + audv0, //audio volume for use with external xformer module + audv1); //audio volume for use with external xformer module + input [5:0] A; + input [7:0] Din; + output [7:0] Dout; + input [2:0] CS_n; + input CS; + input R_W_n; + output RDY; + input MASTERCLK; + input CLK2; + input [1:0] Ilatch; + input [3:0] idump_in; + output HSYNC, HBLANK; + output VSYNC, VBLANK; + output [7:0] COLOROUT; + input RES_n; + output AUD0, AUD1; + output reg [3:0] audv0, audv1; + // Data output register + reg [7:0] Dout; + // Video control signal registers + wire HSYNC; + reg VSYNC, VBLANK; + // Horizontal pixel counter + reg [7:0] hCount; + reg [3:0] hCountReset; + reg clk_30; + reg [7:0] clk_30_count; + + wire [3:0] Idump; + + // Pixel counter update + always @(posedge MASTERCLK) + begin + // Reset operation + if (~RES_n) begin + hCount <= 8'd0; + hCountReset[3:1] <= 3'd0; + clk_30 <= 0; + clk_30_count <= 0; + latchedInputs <= 2'b11; + end + else begin + if (inputLatchReset) + latchedInputs <= 2'b11; + else + latchedInputs <= latchedInputs & Ilatch; + + if (clk_30_count == 57) begin + clk_30 <= ~clk_30; + clk_30_count <= 0; + end else begin + clk_30_count <= clk_30_count + 1; + end + // Increment the count and reset if necessary + if ((hCountReset[3]) ||(hCount == 8'd227)) + hCount <= 8'd0; + else + hCount <= hCount + 8'd1; + // Software resets are delayed by three cycles + hCountReset[3:1] <= hCountReset[2:0]; + end + end + assign HSYNC = (hCount >= 8'd20) && (hCount < 8'd36); + assign HBLANK = (hCount < 8'd68); + // Screen object registers + // These registers are set by the software and used to generate pixels + reg [7:0] player0Pos, player1Pos, missile0Pos, missile1Pos, ballPos; + reg [4:0] player0Size, player1Size; + reg [7:0] player0Color, player1Color, ballColor, pfColor, bgColor; + reg [3:0] player0Motion, player1Motion, missile0Motion, missile1Motion, + ballMotion; + reg missile0Enable, missile1Enable, ballEnable, R_ballEnable; + reg [1:0] ballSize; + reg [19:0] pfGraphic; + reg [7:0] player0Graphic, player1Graphic; + reg [7:0] R_player0Graphic, R_player1Graphic; + reg pfReflect, player0Reflect, player1Reflect; + reg prioCtrl; + reg pfColorCtrl; + reg [14:0] collisionLatch; + reg missile0Lock, missile1Lock; + reg player0VertDelay, player1VertDelay, ballVertDelay; + reg [3:0] audc0, audc1; + reg [4:0] audf0, audf1; + // Pixel number calculation + wire [7:0] pixelNum; + + + //audio control + audio audio_ctrl(.AUDC0(audc0), + .AUDC1(audc1), + .AUDF0(audf0), + .AUDF1(audf1), + .CLK_30(clk_30), //30khz clock + .AUD0(AUD0), + .AUD1(AUD1)); + + assign pixelNum = (hCount >= 8'd68) ? (hCount - 8'd68) : 8'd227; + + // Pixel tests. For each pixel and screen object, a test is done based on the + // screen objects register to determine if the screen object should show on that + // pixel. The results of all the tests are fed into logic to pick which displayed + // object has priority and color the pixel the color of that object. + // Playfield pixel test + wire [5:0] pfPixelNum; + wire pfPixelOn, pfLeftPixelVal, pfRightPixelVal; + assign pfPixelNum = pixelNum[7:2]; + assign pfLeftPixelVal = pfGraphic[pfPixelNum]; + assign pfRightPixelVal = (pfReflect == 1'b0)? pfGraphic[pfPixelNum - 6'd20]: + pfGraphic[6'd39 - pfPixelNum]; + assign pfPixelOn = (pfPixelNum < 6'd20)? pfLeftPixelVal : pfRightPixelVal; + // Player 0 sprite pixel test + wire pl0PixelOn; + wire [7:0] pl0Mask, pl0MaskDel; + assign pl0MaskDel = (player0VertDelay)? R_player0Graphic : player0Graphic; + assign pl0Mask = (!player0Reflect)? pl0MaskDel : {pl0MaskDel[0], pl0MaskDel[1], + pl0MaskDel[2], pl0MaskDel[3], + pl0MaskDel[4], pl0MaskDel[5], + pl0MaskDel[6], pl0MaskDel[7]}; + objPixelOn player0_test(pixelNum, player0Pos, player0Size[2:0], pl0Mask, pl0PixelOn); + // Player 1 sprite pixel test + wire pl1PixelOn; + wire [7:0] pl1Mask, pl1MaskDel; + assign pl1MaskDel = (player1VertDelay)? R_player1Graphic : player1Graphic; + assign pl1Mask = (!player1Reflect)? pl1MaskDel : {pl1MaskDel[0], pl1MaskDel[1], + pl1MaskDel[2], pl1MaskDel[3], + pl1MaskDel[4], pl1MaskDel[5], + pl1MaskDel[6], pl1MaskDel[7]}; + objPixelOn player1_test(pixelNum, player1Pos, player1Size[2:0], pl1Mask, pl1PixelOn); + // Missile 0 pixel test + wire mis0PixelOn, mis0PixelOut; + wire [7:0] mis0ActualPos; + reg [7:0] mis0Mask; + always @(player0Size) + begin + case(player0Size[4:3]) + 2'd0: mis0Mask <= 8'h01; + 2'd1: mis0Mask <= 8'h03; + 2'd2: mis0Mask <= 8'h0F; + 2'd3: mis0Mask <= 8'hFF; + endcase + end + assign mis0ActualPos = (missile0Lock)? player0Pos : missile0Pos; + objPixelOn missile0_test(pixelNum, mis0ActualPos, player0Size[2:0], mis0Mask, mis0PixelOut); + assign mis0PixelOn = mis0PixelOut && missile0Enable; + // Missile 1 pixel test + wire mis1PixelOn, mis1PixelOut; + wire [7:0] mis1ActualPos; + reg [7:0] mis1Mask; + always @(player1Size) + begin + case(player1Size[4:3]) + 2'd0: mis1Mask <= 8'h01; + 2'd1: mis1Mask <= 8'h03; + 2'd2: mis1Mask <= 8'h0F; + 2'd3: mis1Mask <= 8'hFF; + endcase + end + assign mis1ActualPos = (missile1Lock)? player1Pos : missile1Pos; + objPixelOn missile1_test(pixelNum, mis1ActualPos, player1Size[2:0], mis1Mask, mis1PixelOut); + assign mis1PixelOn = mis1PixelOut && missile1Enable; + // Ball pixel test + wire ballPixelOut, ballPixelOn, ballEnableDel; + reg [7:0] ballMask; + always @(ballSize) + begin + case(ballSize) + 2'd0: ballMask <= 8'h01; + 2'd1: ballMask <= 8'h03; + 2'd2: ballMask <= 8'h0F; + 2'd3: ballMask <= 8'hFF; + endcase + end + objPixelOn ball_test(pixelNum, ballPos, 3'd0, ballMask, ballPixelOut); + assign ballEnableDel = ((ballVertDelay)? R_ballEnable : ballEnable); + assign ballPixelOn = ballPixelOut && ballEnableDel; + // Playfield color selection + // The programmer can select a unique color for the playfield or have it match + // the player's sprites colors + reg [7:0] pfActualColor; + always @(pfColorCtrl, pfColor, player0Color, player1Color, pfPixelNum) + begin + if (pfColorCtrl) + begin + if (pfPixelNum < 6'd20) + pfActualColor <= player0Color; + else + pfActualColor <= player1Color; + end + else + pfActualColor <= pfColor; + end + // Final pixel color selection + reg [7:0] pixelColor; + assign COLOROUT = (HBLANK)? 8'b0 : pixelColor; + // This combinational logic uses a priority encoder like structure to select + // the highest priority screen object and color the pixel. + always @(prioCtrl, pfPixelOn, pl0PixelOn, pl1PixelOn, mis0PixelOn, mis1PixelOn, + ballPixelOn, pfActualColor, player0Color, player1Color, bgColor) + begin + // Show the playfield behind the players + if (!prioCtrl) + begin + if (pl0PixelOn || mis0PixelOn) + pixelColor <= player0Color; + else if (pl1PixelOn || mis1PixelOn) + pixelColor <= player1Color; + else if (pfPixelOn) + pixelColor <= pfActualColor; + else + pixelColor <= bgColor; + end + // Otherwise, show the playfield in front of the players + else begin + if (pfPixelOn) + pixelColor <= pfActualColor; + else if (pl0PixelOn || mis0PixelOn) + pixelColor <= player0Color; + else if (pl1PixelOn || mis1PixelOn) + pixelColor <= player1Color; + else + pixelColor <= bgColor; + end + end + // Collision register and latching update + wire [14:0] collisions; + reg collisionLatchReset; + assign collisions = {pl0PixelOn && pl1PixelOn, mis0PixelOn && mis1PixelOn, + ballPixelOn && pfPixelOn, + mis1PixelOn && pfPixelOn, mis1PixelOn && ballPixelOn, + mis0PixelOn && pfPixelOn, mis0PixelOn && ballPixelOn, + pl1PixelOn && pfPixelOn, pl1PixelOn && ballPixelOn, + pl0PixelOn && pfPixelOn, pl0PixelOn && ballPixelOn, + mis1PixelOn && pl0PixelOn, mis1PixelOn && pl1PixelOn, + mis0PixelOn && pl1PixelOn, mis0PixelOn && pl0PixelOn}; + always @(posedge MASTERCLK, posedge collisionLatchReset) + begin + if (collisionLatchReset) + collisionLatch <= 15'b000000000000000; + else + collisionLatch <= collisionLatch | collisions; + end + // WSYNC logic + // When a WSYNC is signalled by the programmer, the CPU ready line is lowered + // until the end of a scanline + reg wSync, wSyncReset; + always @(hCount, wSyncReset) + begin + if (hCount == 8'd0) + wSync <= 1'b0; + else if (wSyncReset && hCount > 8'd2) + wSync <= 1'b1; + end + assign RDY = ~wSync; + // Latched input registers and update + wire [1:0] latchedInputsValue; + reg inputLatchEnabled; + reg inputLatchReset; + reg [1:0] latchedInputs; + + /*always_ff @(Ilatch, inputLatchReset) + begin + if (inputLatchReset) + latchedInputs <= 2'b11; + else + latchedInputs <= latchedInputs & Ilatch; + end*/ + + assign latchedInputsValue = (inputLatchEnabled)? latchedInputs : Ilatch; + // Dumped input registers update + reg inputDumpEnabled; + assign Idump = (inputDumpEnabled)? 4'b0000 : idump_in; + // Software operations + always @(posedge CLK2) + begin + // Reset operation + if (~RES_n) begin + inputLatchReset <= 1'b0; + collisionLatchReset <= 1'b0; + hCountReset[0] <= 1'b0; + wSyncReset <= 1'b0; + Dout <= 8'b00000000; + end + // If the chip is enabled, execute an operation + else if (CS) begin + // Software reset signals + inputLatchReset <= ({R_W_n, A[5:0]} == `VBLANK && Din[6] && !inputLatchEnabled); + collisionLatchReset <= ({R_W_n, A[5:0]} == `CXCLR); + hCountReset[0] <= ({R_W_n, A[5:0]} == `RSYNC); + wSyncReset <= ({R_W_n, A[5:0]} == `WSYNC) && !wSync; + case({R_W_n, A[5:0]}) + // Collision latch reads + `CXM0P, `CXM0P_7800: Dout <= {collisionLatch[1:0],6'b000000}; + `CXM1P, `CXM1P_7800: Dout <= {collisionLatch[3:2],6'b000000}; + `CXP0FB, `CXP0FB_7800: Dout <= {collisionLatch[5:4],6'b000000}; + `CXP1FB, `CXP1FB_7800: Dout <= {collisionLatch[7:6],6'b000000}; + `CXM0FB, `CXM0FB_7800: Dout <= {collisionLatch[9:8],6'b000000}; + `CXM1FB, `CXM1FB_7800: Dout <= {collisionLatch[11:10],6'b000000}; + `CXBLPF, `CXBLPF_7800: Dout <= {collisionLatch[12],7'b0000000}; + `CXPPMM, `CXPPMM_7800: Dout <= {collisionLatch[14:13],6'b000000}; + // I/O reads + `INPT0, `INPT0_7800: Dout <= {Idump[0], 7'b0000000}; + `INPT1, `INPT1_7800: Dout <= {Idump[1], 7'b0000000}; + `INPT2, `INPT2_7800: Dout <= {Idump[2], 7'b0000000}; + `INPT3, `INPT3_7800: Dout <= {Idump[3], 7'b0000000}; + `INPT4, `INPT4_7800: Dout <= {latchedInputsValue[0], 7'b0000000}; + `INPT5, `INPT5_7800: Dout <= {latchedInputsValue[1], 7'b0000000}; + // Video signals + `VSYNC: VSYNC <= Din[1]; + `VBLANK: begin + inputLatchEnabled <= Din[6]; + inputDumpEnabled <= Din[7]; + VBLANK <= Din[1]; + end + `WSYNC:; + `RSYNC:; + // Screen object register access + `NUSIZ0: player0Size <= {Din[5:4],Din[2:0]}; + `NUSIZ1: player1Size <= {Din[5:4],Din[2:0]}; + `COLUP0: player0Color <= Din; + `COLUP1: player1Color <= Din; + `COLUPF: pfColor <= Din; + `COLUBK: bgColor <= Din; + `CTRLPF: begin + pfReflect <= Din[0]; + pfColorCtrl <= Din[1]; + prioCtrl <= Din[2]; + ballSize <= Din[5:4]; + end + `REFP0: player0Reflect <= Din[3]; + `REFP1: player1Reflect <= Din[3]; + `PF0: pfGraphic[3:0] <= Din[7:4]; + `PF1: pfGraphic[11:4] <= {Din[0], Din[1], Din[2], Din[3], + Din[4], Din[5], Din[6], Din[7]}; + `PF2: pfGraphic[19:12] <= Din[7:0]; + `RESP0: player0Pos <= pixelNum; + `RESP1: player1Pos <= pixelNum; + `RESM0: missile0Pos <= pixelNum; + `RESM1: missile1Pos <= pixelNum; + `RESBL: ballPos <= pixelNum; + // Audio controls + `AUDC0: audc0 <= Din[3:0]; + `AUDC1: audc1 <= Din[3:0]; + `AUDF0: audf0 <= Din[4:0]; + `AUDF1: audf1 <= Din[4:0]; + `AUDV0: audv0 <= Din[3:0]; + `AUDV1: audv1 <= Din[3:0]; + // Screen object register access + `GRP0: begin + player0Graphic <= {Din[0], Din[1], Din[2], Din[3], + Din[4], Din[5], Din[6], Din[7]}; + R_player1Graphic <= player1Graphic; + end + `GRP1: begin + player1Graphic <= {Din[0], Din[1], Din[2], Din[3], + Din[4], Din[5], Din[6], Din[7]}; + R_player0Graphic <= player0Graphic; + R_ballEnable <= ballEnable; + end + `ENAM0: missile0Enable <= Din[1]; + `ENAM1: missile1Enable <= Din[1]; + `ENABL: ballEnable <= Din[1]; + `HMP0: player0Motion <= Din[7:4]; + `HMP1: player1Motion <= Din[7:4]; + `HMM0: missile0Motion <= Din[7:4]; + `HMM1: missile1Motion <= Din[7:4]; + `HMBL: ballMotion <= Din[7:4]; + `VDELP0: player0VertDelay <= Din[0]; + `VDELP1: player1VertDelay <= Din[0]; + `VDELBL: ballVertDelay <= Din[0]; + `RESMP0: missile0Lock <= Din[1]; + `RESMP1: missile1Lock <= Din[1]; + // Strobed line that initiates an object move + `HMOVE: begin + player0Pos <= player0Pos - {{4{player0Motion[3]}}, + player0Motion[3:0]}; + player1Pos <= player1Pos - {{4{player1Motion[3]}}, + player1Motion[3:0]}; + missile0Pos <= missile0Pos - {{4{missile0Motion[3]}}, + missile0Motion[3:0]}; + missile1Pos <= missile1Pos - {{4{missile1Motion[3]}}, + missile1Motion[3:0]}; + ballPos <= ballPos - {{4{ballMotion[3]}},ballMotion[3:0]}; + end + // Motion register clear + `HMCLR: begin + player0Motion <= Din[7:4]; + player1Motion <= Din[7:4]; + missile0Motion <= Din[7:4]; + missile1Motion <= Din[7:4]; + ballMotion <= Din[7:4]; + end + `CXCLR:; + default: Dout <= 8'b00000000; + endcase + end + // If the chip is not enabled, do nothing + else begin + inputLatchReset <= 1'b0; + collisionLatchReset <= 1'b0; + hCountReset[0] <= 1'b0; + wSyncReset <= 1'b0; + Dout <= 8'b00000000; + end + end +endmodule +// objPixelOn module +// Checks the pixel number against a stretched and possibly duplicated version of the +// object. +module objPixelOn(pixelNum, objPos, objSize, objMask, pixelOn); + input [7:0] pixelNum, objPos, objMask; + input [2:0] objSize; + output pixelOn; + wire [7:0] objIndex; + wire [8:0] objByteIndex; + wire objMaskOn, objPosOn; + reg objSizeOn; + reg [2:0] objMaskSel; + assign objIndex = pixelNum - objPos - 8'd1; + assign objByteIndex = 9'b1 << (objIndex[7:3]); + always @(objSize, objByteIndex) + begin + case (objSize) + 3'd0: objSizeOn <= (objByteIndex & 9'b00000001) != 0; + 3'd1: objSizeOn <= (objByteIndex & 9'b00000101) != 0; + 3'd2: objSizeOn <= (objByteIndex & 9'b00010001) != 0; + 3'd3: objSizeOn <= (objByteIndex & 9'b00010101) != 0; + 3'd4: objSizeOn <= (objByteIndex & 9'b10000001) != 0; + 3'd5: objSizeOn <= (objByteIndex & 9'b00000011) != 0; + 3'd6: objSizeOn <= (objByteIndex & 9'b10010001) != 0; + 3'd7: objSizeOn <= (objByteIndex & 9'b00001111) != 0; + endcase + end + always @(objSize, objIndex) + begin + case (objSize) + 3'd5: objMaskSel <= objIndex[3:1]; + 3'd7: objMaskSel <= objIndex[4:2]; + default: objMaskSel <= objIndex[2:0]; + endcase + end + assign objMaskOn = objMask[objMaskSel]; + assign objPosOn = (pixelNum > objPos) && ({1'b0, pixelNum} <= {1'b0, objPos} + 9'd72); + assign pixelOn = objSizeOn && objMaskOn && objPosOn; +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/atari7800.vh b/Atari - 7800_TeST/rtl/atari7800.vh new file mode 100644 index 00000000..d1d73a75 --- /dev/null +++ b/Atari - 7800_TeST/rtl/atari7800.vh @@ -0,0 +1,11 @@ +`define CS_NONE 'h0 +`define CS_RAM0 'h1 +`define CS_RAM1 'h2 +`define CS_RIOT_IO 'h3 +`define CS_RIOT_RAM 'h4 +`define CS_TIA 'h5 +`define CS_BIOS 'h6 +`define CS_MARIA 'h7 +`define CS_CART 'h8 + +`define chipselect logic[3:0] \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/audio.sv b/Atari - 7800_TeST/rtl/audio.sv new file mode 100644 index 00000000..e0786a27 --- /dev/null +++ b/Atari - 7800_TeST/rtl/audio.sv @@ -0,0 +1,93 @@ +`timescale 1ns / 1ps + +module audio(input logic [3:0] AUDC0, AUDC1, + input logic [4:0] AUDF0, AUDF1, + input logic CLK_30, //30khz clock + output logic AUD0,AUD1 + ); + + logic [4:0] counter0, counter1 = 5'b0; + integer rep0,rep1,ind0,ind1 = 0; + logic [1:0] pattern45 = 2'b10; + logic pattern0b = 1'b1; + logic [14:0] pattern1 = 15'b111100010011010; + logic [30:0] pattern6a = 31'b1111111111111111110000000000000; + logic [30:0] pattern79 = 31'b1111100011011101010000100101100; + logic [5:0] patterncd = 6'b111000; + logic [92:0] patterne = 93'b111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000; + logic [92:0] patternf = 93'b111111111100000111000000011110000000000111111000111111000011111111100000011111000000111100000; + logic [464:0] pattern2 = 465'b111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000111111111111100000000000000000000000000000001111111111111111111111111111111000000000000000000111111111111100000000000000000011111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000001111111111111111110000000000000000000000000000000111111111111111111111111111111100000000000001111111111111111110000000000000; + logic [464:0] pattern3 = 465'b111111000000100011100111110001111111000111100011001100000111111111000100000111011001111111111100000100000111010011111111111100000100111110010111111111111000000100111110110111111111100000011100110000100111111000000000010000110111101111110000000000110000110100001111100000000011100011110101111111100000111110000011110101111111100001100000000111000101111111000011000000011111011101111111000010000111111110010001111000000010001111111000110111111000000110011110000011100; + logic [510:0] pattern8 = 511'b1111111110000011110111110001011100110010000010010100111011010001111001111100110110001010100100011100011011010101110001001100010001000000001000010001100001001110010101011000011011110100110111001000101000010101101001111110110010010010110111111001001101010011001100000001100011001010001101001011111110100010110001110101100101100111100011111011101000001101011011011101100000101101011111010101010000001010010101111001011101110000001110011101001001111010111010100010010000110011100001011110110110011010000111011110000; + + always_comb begin + case (AUDC0) + 4'h0,4'hb: rep0 = 1; + 4'h1: rep0 = 15; + 4'h2,4'h3: rep0 = 465; + 4'h4,4'h5: rep0 = 2; + 4'h6,4'h7,4'h9,4'ha: rep0 = 31; + 4'h8: rep0 = 511; + 4'hc,4'hd: rep0 = 6; + 4'he,4'hf: rep0 = 93; + default: rep0 = 1; + endcase + case (AUDC1) + 4'h0,4'hb: rep1 = 1; + 4'h1: rep1 = 15; + 4'h2,4'h3: rep1 = 465; + 4'h4,4'h5: rep1 = 2; + 4'h6,4'h7,4'h9,4'ha: rep1 = 31; + 4'h8: rep1 = 511; + 4'hc,4'hd: rep1 = 6; + 4'he,4'hf: rep1 = 93; + default: rep0 = 1; + endcase + end + + always_ff @(posedge CLK_30) begin //divide the clk by the frequency value + if (counter0 == AUDF0) begin + case (AUDC0) + 4'h0,4'hb: AUD0 <= pattern0b; + 4'h1: AUD0 <= pattern1[ind0]; + 4'h2: AUD0 <= pattern2[ind0]; + 4'h3: AUD0 <= pattern3[ind0]; + 4'h4,4'h5: AUD0 <= pattern45[ind0]; + 4'h6,4'ha: AUD0 <= pattern6a[ind0]; + 4'h7,4'h9: AUD0 <= pattern79[ind0]; + 4'h8: AUD0 <= pattern8[ind0]; + 4'hc,4'hd: AUD0 <= patterncd[ind0]; + 4'he: AUD0 <= patterne[ind0]; + 4'hf: AUD0 <= patternf[ind0]; + default: AUD0 <= 1'bx; + endcase + ind0 <= (ind0 + 1) % rep0; + counter0 <= 0; + end + else + counter0 <= counter0 + 1; + + if (counter1 == AUDF1) begin + case (AUDC1) + 4'h0,4'hb: AUD1 <= pattern0b; + 4'h1: AUD1 <= pattern1[ind1]; + 4'h2: AUD1 <= pattern2[ind1]; + 4'h3: AUD1 <= pattern3[ind1]; + 4'h4,4'h5: AUD1 <= pattern45[ind1]; + 4'h6,4'ha: AUD1 <= pattern6a[ind1]; + 4'h7,4'h9: AUD1 <= pattern79[ind1]; + 4'h8: AUD1 <= pattern8[ind1]; + 4'hc,4'hd: AUD1 <= patterncd[ind1]; + 4'he: AUD1 <= patterne[ind1]; + 4'hf: AUD1 <= patternf[ind1]; + default: AUD1 <= 1'bx; + endcase + ind1 <= (ind1 + 1) % rep1; + counter1 <= 0; + end + else + counter1 <= counter1 + 1; + end + + +endmodule diff --git a/Atari - 7800_TeST/rtl/audio_xformer.sv b/Atari - 7800_TeST/rtl/audio_xformer.sv new file mode 100644 index 00000000..2ccac83a --- /dev/null +++ b/Atari - 7800_TeST/rtl/audio_xformer.sv @@ -0,0 +1,24 @@ +`timescale 1ns / 1ps + +module audio_xformer(input logic AUD0, AUD1, + input logic [3:0] AUDV0, AUDV1, + output logic [15:0] AUD_SIGNAL); + + logic [15:0] audio0,audio1; + + + assign AUD_SIGNAL = audio0 + audio1; + + always_comb begin + case (AUD0) + 1: audio0 = 16'h3FF * AUDV0; + 0: audio0 = 16'hFC00 * AUDV0; + endcase + case (AUD1) + 1: audio1 = 16'h3FF * AUDV1; + 0: audio1 = 16'hFC00 * AUDV1; + endcase + end + + +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/build_id.tcl b/Atari - 7800_TeST/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Atari - 7800_TeST/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/Atari - 7800_TeST/rtl/build_id.v b/Atari - 7800_TeST/rtl/build_id.v new file mode 100644 index 00000000..3192af89 --- /dev/null +++ b/Atari - 7800_TeST/rtl/build_id.v @@ -0,0 +1,2 @@ +`define BUILD_DATE "180630" +`define BUILD_TIME "212824" diff --git a/Atari - 7800_TeST/rtl/cart_top.sv b/Atari - 7800_TeST/rtl/cart_top.sv new file mode 100644 index 00000000..222f220f --- /dev/null +++ b/Atari - 7800_TeST/rtl/cart_top.sv @@ -0,0 +1,257 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 11/02/2015 11:36:06 AM +// Design Name: +// Module Name: cart_top +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + +`include "atari7800.vh" + +`define INPUT_CYCLES 256 +`define INPUT_CYCLES_NBITS 9 + +module cart_top( + input CLOCK_27, + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + output VGA_HS, + output VGA_VS, + output LED, + output AUDIO_L, + output AUDIO_R, +// output UART_TX,//uses for Tape Record +// input UART_RX,//uses for Tape Play + input SPI_SCK, + output SPI_DO, + input SPI_DI, + input SPI_SS2, + input SPI_SS3, + input SPI_SS4, + input CONF_DATA0, + + output logic [7:0] ld, + + input logic [7:0] sw, + input logic PB_UP,PB_DOWN,PB_LEFT,PB_RIGHT,PB_CENTER, + + + inout logic [6:0] ctrl_0_fmc, ctrl_1_fmc + ); + +`include "rtl\build_id.v" +assign LED = 1; +localparam CONF_STR = { + "ATARI7800;;", + "O34,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;", + "T6,Reset;", + "V,v0.0.",`BUILD_DATE + }; + + + + wire clk25, clk7p143, clk6p25; + wire locked; + + pll pll ( + .inclk0(CLOCK_27), + .c0(clk25), + .c1(clk7p143), + .c2(clk6p25), + .locked(locked) + ); + wire scandoubler_disable; + wire ypbpr; + wire ps2_kbd_clk, ps2_kbd_data; + wire [31:0] status; + wire [1:0] buttons; + wire [1:0] switches; + wire [3:0] r, g, b; + wire hs, vs, hb, vb; + wire blankn = ~(hb | vb); + + + logic [7:0] cart_data_out; + logic [15:0] AB; + logic RW; + logic pclk_0; + reg [`INPUT_CYCLES_NBITS-1:0] paddleA0_ctr = {`INPUT_CYCLES_NBITS{1'b0}}; + reg [`INPUT_CYCLES_NBITS-1:0] paddleB0_ctr = {`INPUT_CYCLES_NBITS{1'b0}}; + reg [`INPUT_CYCLES_NBITS-1:0] paddleA1_ctr = {`INPUT_CYCLES_NBITS{1'b0}}; + reg [`INPUT_CYCLES_NBITS-1:0] paddleB1_ctr = {`INPUT_CYCLES_NBITS{1'b0}}; + + always_ff @(posedge pclk_0) begin + if (~ctrl_0_fmc[6]) + paddleA0_ctr <= 0; + else if (paddleA0_ctr < `INPUT_CYCLES) + paddleA0_ctr <= paddleA0_ctr + 1; + + if (~ctrl_0_fmc[4]) + paddleB0_ctr <= 0; + else if (paddleB0_ctr < `INPUT_CYCLES) + paddleB0_ctr <= paddleB0_ctr + 1; + + if (~ctrl_1_fmc[6]) + paddleA1_ctr <= 0; + else if (paddleA1_ctr < `INPUT_CYCLES) + paddleA1_ctr <= paddleA1_ctr + 1; + + if (~ctrl_1_fmc[4]) + paddleB1_ctr <= 0; + else if (paddleB1_ctr < `INPUT_CYCLES) + paddleB1_ctr <= paddleB1_ctr + 1; + end + + + logic [3:0] idump; + logic [1:0] ilatch; + logic [7:0] PAin, PBin, PAout, PBout; + logic [15:0] audio; + + + logic right_0_b, left_0_b, down_0_b, up_0_b, fire_0_b, paddle_A_0, paddle_B_0; + logic right_1_b, left_1_b, down_1_b, up_1_b, fire_1_b, paddle_A_1, paddle_B_1; + logic player1_2bmode, player2_2bmode; + + assign player1_2bmode = ~PBout[2] & ~tia_en; + assign player2_2bmode = ~PBout[4] & ~tia_en; + + assign {right_0_b, left_0_b, down_0_b, up_0_b} = ctrl_0_fmc[3:0]; + assign {right_1_b, left_1_b, down_1_b, up_1_b} = ctrl_1_fmc[3:0]; + + assign paddle_B_0 = paddleB0_ctr == `INPUT_CYCLES; + assign paddle_B_1 = paddleB1_ctr == `INPUT_CYCLES; + assign paddle_A_0 = paddleA0_ctr == `INPUT_CYCLES; + assign paddle_A_1 = paddleA1_ctr == `INPUT_CYCLES; + + assign fire_0_b = (~paddle_A_0 & ~paddle_B_0); + assign fire_1_b = (~paddle_A_1 & ~paddle_B_1); + logic tia_en; + + assign PAin[7:4] = {right_0_b, left_0_b, down_0_b, up_0_b}; + assign PAin[3:0] = {right_1_b, left_1_b, down_1_b, up_1_b}; + + assign PBin[7] = sw[1]; // RDiff + assign PBin[6] = sw[0]; // LDiff + assign PBin[5] = 1'b0; // Unused + assign PBin[4] = 1'b0; + assign PBin[3] = ~PB_DOWN; // Pause + assign PBin[2] = 1'b0; // 2 Button mode + assign PBin[1] = ~PB_LEFT; // Select + assign PBin[0] = ~PB_UP; // Reset + + + assign ilatch[0] = fire_0_b; + assign ilatch[1] = fire_1_b; + + assign idump = {paddle_A_0, paddle_B_0, paddle_A_1, paddle_B_1}; + + logic [7:0] def_dout; + assign cart_data_out = def_dout; + + defender_rom defender_rom ( + .clock(pclk_0), + .address(AB[11:0]), + .q(def_dout) + ); + + Atari7800 console( + .clock_25(clk25), + .sysclk_7_143(clk7p143), + .clock_divider_locked(locked), + .reset((buttons[1] || status[0] || status[6])), + .RED(r), + .GREEN(g), + .BLUE(b), + .HSync(hs), + .VSync(vs), + .aud_signal_out(audio), + + .cart_DB_out(cart_data_out), + .AB(AB), + .RW(RW), + .pclk_0(pclk_0), + .ld(ld), + .tia_en(tia_en), + + .idump(idump), + .ilatch(ilatch), + .PAin(PAin), + .PBin(PBin), + .PAout(PAout), + .PBout(PBout) + ); + +sigma_delta_dac #(.MSBI(15)) sigma_delta_dac ( + .DACout(AUDIO_L), + .DACin(audio), + .CLK(clk25), + .RESET() +); + +mist_io #(.STRLEN(($size(CONF_STR)>>3))) mist_io +( + .conf_str(CONF_STR), + .clk_sys(clk25), + .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), + .status(status), + .ps2_kbd_clk(ps2_kbd_clk), + .ps2_kbd_data(ps2_kbd_data) +); + +video_mixer #(.LINE_LENGTH(480), .HALF_DEPTH(0)) video_mixer +( + .clk_sys(clk25), + .ce_pix(clk6p25), + .ce_pix_actual(clk6p25), + .SPI_SCK(SPI_SCK), + .SPI_SS3(SPI_SS3), + .SPI_DI(SPI_DI), + .scanlines(scandoubler_disable ? 2'b00 : {status[4:3] == 3, status[4:3] == 2}), + .scandoubler_disable(1),//scandoubler_disable), + .hq2x(status[4:3]==1), + .ypbpr(ypbpr), + .ypbpr_full(1), + .R({r,r[1:0]}), + .G({g,g[1:0]}), + .B({b,b[1:0]}), +// .R(blankn ? {r,r[1:0]} : "000000"), +// .G(blankn ? {g,g[1:0]} : "000000"), +// .B(blankn ? {b,b[1:0]} : "000000"), + .mono(0), + .HSync(hs), + .VSync(vs), + .line_start(0), + .VGA_R(VGA_R), + .VGA_G(VGA_G), + .VGA_B(VGA_B), + .VGA_VS(VGA_VS), + .VGA_HS(VGA_HS) +); + + +assign AUDIO_R = AUDIO_L; + +endmodule diff --git a/Atari - 7800_TeST/rtl/cpu.sv b/Atari - 7800_TeST/rtl/cpu.sv new file mode 100644 index 00000000..64ff3cd8 --- /dev/null +++ b/Atari - 7800_TeST/rtl/cpu.sv @@ -0,0 +1,1250 @@ +/* + * verilog model of 6502 CPU. + * + * (C) Arlet Ottens, + * + * Feel free to use this code in any project (commercial or not), as long as you + * keep this message, and the copyright notice. This code is provided "as is", + * without any warranties of any kind. + * + */ + +/* + * Note that not all 6502 interface signals are supported (yet). The goal + * is to create an Acorn Atom model, and the Atom didn't use all signals on + * the main board. + * + * The data bus is implemented as separate read/write buses. Combine them + * on the output pads if external memory is required. + */ + `timescale 1ns / 1ps +`include "atari7800.vh" + + + + + +module cpu( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY, pc_temp, res); + +input clk; // CPU clock +input reset; // reset signal +output reg [15:0] AB; // address bus +input [7:0] DI; // data in, read bus +output [7:0] DO; // data out, write bus +output WE; // write enable +input IRQ; // interrupt request +input NMI; // non-maskable interrupt request +input RDY; // Ready signal. Pauses CPU when RDY=0 + +output [15:0] pc_temp; +output reg res; + +assign pc_temp = PC_temp; + +/* + * internal signals + */ + +reg [15:0] PC; // Program Counter +reg [7:0] ABL; // Address Bus Register LSB +reg [7:0] ABH; // Address Bus Register MSB +wire [7:0] ADD; // Adder Hold Register (registered in ALU) + +reg [7:0] DIHOLD; // Hold for Data In +reg DIHOLD_valid; // +wire [7:0] DIMUX; // + +reg [7:0] IRHOLD; // Hold for Instruction register +reg IRHOLD_valid; // Valid instruction in IRHOLD + +reg [7:0] AXYS[3:0]; // A, X, Y and S register file + +wire [7:0] AA; +wire [7:0] XX; +wire [7:0] YY; +wire [7:0] SS; +assign YY = AXYS[3]; +assign XX = AXYS[2]; +assign SS = AXYS[1]; +assign AA = AXYS[0]; + +(* keep = "true" *) +wire [15:0] pc_temp_kept; + +assign pc_temp_kept = PC_temp; + +reg C = 0; // carry flag (init at zero to avoid X's in ALU sim) +reg Z = 0; // zero flag +reg I = 0; // interrupt flag +reg D = 0; // decimal flag +reg V = 0; // overflow flag +reg N = 0; // negative flag +wire AZ; // ALU Zero flag +wire AV; // ALU overflow flag +wire AN; // ALU negative flag +wire HC; // ALU half carry + +reg [7:0] AI; // ALU Input A +reg [7:0] BI; // ALU Input B +wire [7:0] DI; // Data In +wire [7:0] IR; // Instruction register +reg [7:0] DO; // Data Out +reg WE; // Write Enable +reg CI; // Carry In +wire CO; // Carry Out +wire [7:0] PCH = PC[15:8]; +wire [7:0] PCL = PC[7:0]; + +reg NMI_edge = 0; // captured NMI edge + +reg [1:0] regsel; // Select A, X, Y or S register +wire [7:0] regfile = AXYS[regsel]; // Selected register output + +parameter + SEL_A = 2'd0, + SEL_S = 2'd1, + SEL_X = 2'd2, + SEL_Y = 2'd3; + +/* + * define some signals for watching in simulator output + */ + + +`ifdef SIM +wire [7:0] A = AXYS[SEL_A]; // Accumulator +wire [7:0] X = AXYS[SEL_X]; // X register +wire [7:0] Y = AXYS[SEL_Y]; // Y register +wire [7:0] S = AXYS[SEL_S]; // Stack pointer +`endif + +wire [7:0] P = { N, V, 2'b11, D, I, Z, C }; + +/* + * instruction decoder/sequencer + */ + +reg [5:0] state; + +/* + * control signals + */ + +reg PC_inc; // Increment PC +reg [15:0] PC_temp; // intermediate value of PC + +reg [1:0] src_reg; // source register index +reg [1:0] dst_reg; // destination register index + +reg index_y; // if set, then Y is index reg rather than X +reg load_reg; // loading a register (A, X, Y, S) in this instruction +reg inc; // increment +reg write_back; // set if memory is read/modified/written +reg load_only; // LDA/LDX/LDY instruction +reg store; // doing store (STA/STX/STY) +reg adc_sbc; // doing ADC/SBC +reg compare; // doing CMP/CPY/CPX +reg shift; // doing shift/rotate instruction +reg rotate; // doing rotate (no shift) +reg backwards; // backwards branch +reg cond_true; // branch condition is true +reg [2:0] cond_code; // condition code bits from instruction +reg shift_right; // Instruction ALU shift/rotate right +reg alu_shift_right; // Current cycle shift right enable +reg [3:0] op; // Main ALU operation for instruction +reg [3:0] alu_op; // Current cycle ALU operation +reg adc_bcd; // ALU should do BCD style carry +reg adj_bcd; // results should be BCD adjusted + +/* + * some flip flops to remember we're doing special instructions. These + * get loaded at the DECODE state, and used later + */ +reg bit_ins; // doing BIT instruction +reg plp; // doing PLP instruction +reg php; // doing PHP instruction +reg clc; // clear carry +reg sec; // set carry +reg cld; // clear decimal +reg sed; // set decimal +reg cli; // clear interrupt +reg sei; // set interrupt +reg clv; // clear overflow +reg brk; // doing BRK + +//reg res; // in reset + +/* + * ALU operations + */ + +parameter + OP_OR = 4'b1100, + OP_AND = 4'b1101, + OP_EOR = 4'b1110, + OP_ADD = 4'b0011, + OP_SUB = 4'b0111, + OP_ROL = 4'b1011, + OP_A = 4'b1111; + +/* + * Microcode state machine. Basically, every addressing mode has its own + * path through the state machine. Additional information, such as the + * operation, source and destination registers are decoded in parallel, and + * kept in separate flops. + */ + +parameter + ABS0 = 6'd0, // ABS - fetch LSB + ABS1 = 6'd1, // ABS - fetch MSB + ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X) + ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry) + ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed) + BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0]) + BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU + BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed) + BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1) + BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1) + BRK2 = 6'd10, // BRK/IRQ - push P, send S to ALU (-1) + BRK3 = 6'd11, // BRK/IRQ - write S, and fetch @ fffe + DECODE = 6'd12, // IR is valid, decode instruction, and write prev reg + FETCH = 6'd13, // fetch next opcode, and perform prev ALU op + INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X) + INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 + INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1 + INDX3 = 6'd17, // (ZP,X) - fetch data + INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) + INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) + INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) + INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed) + JMP0 = 6'd22, // JMP - fetch PCL and hold + JMP1 = 6'd23, // JMP - fetch PCH + JMPI0 = 6'd24, // JMP IND - fetch LSB and send to ALU for delay (+0) + JMPI1 = 6'd25, // JMP IND - fetch MSB, proceed with JMP0 state + JSR0 = 6'd26, // JSR - push PCH, save LSB, send S to ALU (-1) + JSR1 = 6'd27, // JSR - push PCL, send S to ALU (-1) + JSR2 = 6'd28, // JSR - write S + JSR3 = 6'd29, // JSR - fetch MSB + PULL0 = 6'd30, // PLP/PLA - save next op in IRHOLD, send S to ALU (+1) + PULL1 = 6'd31, // PLP/PLA - fetch data from stack, write S + PULL2 = 6'd32, // PLP/PLA - prefetch op, but don't increment PC + PUSH0 = 6'd33, // PHP/PHA - send A to ALU (+0) + PUSH1 = 6'd34, // PHP/PHA - write A/P, send S to ALU (-1) + READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift) + REG = 6'd36, // Read register for reg-reg transfers + RTI0 = 6'd37, // RTI - send S to ALU (+1) + RTI1 = 6'd38, // RTI - read P from stack + RTI2 = 6'd39, // RTI - read PCL from stack + RTI3 = 6'd40, // RTI - read PCH from stack + RTI4 = 6'd41, // RTI - read PCH from stack + RTS0 = 6'd42, // RTS - send S to ALU (+1) + RTS1 = 6'd43, // RTS - read PCL from stack + RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH + RTS3 = 6'd45, // RTS - load PC and increment + WRITE = 6'd46, // Write memory for read/modify/write + ZP0 = 6'd47, // Z-page - fetch ZP address + ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X) + ZPX1 = 6'd49; // ZP, X - load from memory + +`ifdef SIM + +/* + * easy to read names in simulator output + */ +reg [8*6-1:0] statename; + +always @* + case( state ) + DECODE: statename = "DECODE"; + REG: statename = "REG"; + ZP0: statename = "ZP0"; + ZPX0: statename = "ZPX0"; + ZPX1: statename = "ZPX1"; + ABS0: statename = "ABS0"; + ABS1: statename = "ABS1"; + ABSX0: statename = "ABSX0"; + ABSX1: statename = "ABSX1"; + ABSX2: statename = "ABSX2"; + INDX0: statename = "INDX0"; + INDX1: statename = "INDX1"; + INDX2: statename = "INDX2"; + INDX3: statename = "INDX3"; + INDY0: statename = "INDY0"; + INDY1: statename = "INDY1"; + INDY2: statename = "INDY2"; + INDY3: statename = "INDY3"; + READ: statename = "READ"; + WRITE: statename = "WRITE"; + FETCH: statename = "FETCH"; + PUSH0: statename = "PUSH0"; + PUSH1: statename = "PUSH1"; + PULL0: statename = "PULL0"; + PULL1: statename = "PULL1"; + PULL2: statename = "PULL2"; + JSR0: statename = "JSR0"; + JSR1: statename = "JSR1"; + JSR2: statename = "JSR2"; + JSR3: statename = "JSR3"; + RTI0: statename = "RTI0"; + RTI1: statename = "RTI1"; + RTI2: statename = "RTI2"; + RTI3: statename = "RTI3"; + RTI4: statename = "RTI4"; + RTS0: statename = "RTS0"; + RTS1: statename = "RTS1"; + RTS2: statename = "RTS2"; + RTS3: statename = "RTS3"; + BRK0: statename = "BRK0"; + BRK1: statename = "BRK1"; + BRK2: statename = "BRK2"; + BRK3: statename = "BRK3"; + BRA0: statename = "BRA0"; + BRA1: statename = "BRA1"; + BRA2: statename = "BRA2"; + JMP0: statename = "JMP0"; + JMP1: statename = "JMP1"; + JMPI0: statename = "JMPI0"; + JMPI1: statename = "JMPI1"; + endcase + +//always @( PC ) +// $display( "%t, PC:%04x IR:%02x A:%02x X:%02x Y:%02x S:%02x C:%d Z:%d V:%d N:%d P:%02x", $time, PC, IR, A, X, Y, S, C, Z, V, N, P ); + +`endif + + + +/* + * Program Counter Increment/Load. First calculate the base value in + * PC_temp. + */ +always @* + case( state ) + DECODE: if( (~I & IRQ) | NMI_edge ) + PC_temp = { ABH, ABL }; + else + PC_temp = PC; + + + JMP1, + JMPI1, + JSR3, + RTS3, + RTI4: PC_temp = { DIMUX, ADD }; + + BRA1: PC_temp = { ABH, ADD }; + + BRA2: PC_temp = { ADD, PCL }; + + BRK2: PC_temp = res ? 16'hfffc : + NMI_edge ? 16'hfffa : 16'hfffe; + + default: PC_temp = PC; + endcase + +/* + * Determine wether we need PC_temp, or PC_temp + 1 + */ +always @* + case( state ) + DECODE: if( (~I & IRQ) | NMI_edge ) + PC_inc = 0; + else + PC_inc = 1; + + ABS0, + ABSX0, + FETCH, + BRA0, + BRA2, + BRK3, + JMPI1, + JMP1, + RTI4, + RTS3: PC_inc = 1; + + BRA1: PC_inc = CO ^~ backwards; + + default: PC_inc = 0; + endcase + +/* + * Set new PC + */ +always @(posedge clk) + if( RDY ) + PC <= PC_temp + PC_inc; + +/* + * Address Generator + */ + +parameter + ZEROPAGE = 8'h00, + STACKPAGE = 8'h01; + +always @* + case( state ) + ABSX1, + INDX3, + INDY2, + JMP1, + JMPI1, + RTI4, + ABS1: AB = { DIMUX, ADD }; + + BRA2, + INDY3, + ABSX2: AB = { ADD, ABL }; + + BRA1: AB = { ABH, ADD }; + + JSR0, + PUSH1, + RTS0, + RTI0, + BRK0: AB = { STACKPAGE, regfile }; + + BRK1, + JSR1, + PULL1, + RTS1, + RTS2, + RTI1, + RTI2, + RTI3, + BRK2: AB = { STACKPAGE, ADD }; + + INDY1, + INDX1, + ZPX1, + INDX2: AB = { ZEROPAGE, ADD }; + + ZP0, + INDY0: AB = { ZEROPAGE, DIMUX }; + + REG, + READ, + WRITE: AB = { ABH, ABL }; + + default: AB = PC; + endcase + +/* + * ABH/ABL pair is used for registering previous address bus state. + * This can be used to keep the current address, freeing up the original + * source of the address, such as the ALU or DI. + */ +always @(posedge clk) + if( state != PUSH0 && state != PUSH1 && RDY && + state != PULL0 && state != PULL1 && state != PULL2 ) + begin + ABL <= AB[7:0]; + ABH <= AB[15:8]; + end + +/* + * Data Out MUX + */ +always @* + case( state ) + WRITE: DO = ADD; + + JSR0, + BRK0: DO = PCH; + + JSR1, + BRK1: DO = PCL; + + PUSH1: DO = php ? P : ADD; + + BRK2: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P; + + default: DO = regfile; + endcase + +/* + * Write Enable Generator + */ + +always @* + case( state ) + BRK0, // writing to stack or memory + BRK1, + BRK2, + JSR0, + JSR1, + PUSH1, + WRITE: WE = 1; + + INDX3, // only if doing a STA, STX or STY + INDY3, + ABSX2, + ABS1, + ZPX1, + ZP0: WE = store; + + default: WE = 0; + endcase + +/* + * register file, contains A, X, Y and S (stack pointer) registers. At each + * cycle only 1 of those registers needs to be accessed, so they combined + * in a small memory, saving resources. + */ + +reg write_register; // set when register file is written + +always @* + case( state ) + DECODE: write_register = load_reg & ~plp; + + PULL1, + RTS2, + RTI3, + BRK3, + JSR0, + JSR2 : write_register = 1; + + default: write_register = 0; + endcase + +/* + * BCD adjust logic + */ + +always @(posedge clk) + adj_bcd <= adc_sbc & (D | sed); // '1' when doing a BCD instruction + +reg [3:0] ADJL; +reg [3:0] ADJH; + +// adjustment term to be added to ADD[3:0] based on the following +// adj_bcd: '1' if doing ADC/SBC with D=1 +// adc_bcd: '1' if doing ADC with D=1 +// HC : half carry bit from ALU +always @* begin + casex( {adj_bcd, adc_bcd, HC} ) + 3'b0xx: ADJL = 4'd0; // no BCD instruction + 3'b100: ADJL = 4'd10; // SBC, and digital borrow + 3'b101: ADJL = 4'd0; // SBC, but no borrow + 3'b110: ADJL = 4'd0; // ADC, but no carry + 3'b111: ADJL = 4'd6; // ADC, and decimal/digital carry + endcase +end + +// adjustment term to be added to ADD[7:4] based on the following +// adj_bcd: '1' if doing ADC/SBC with D=1 +// adc_bcd: '1' if doing ADC with D=1 +// CO : carry out bit from ALU +always @* begin + casex( {adj_bcd, adc_bcd, CO} ) + 3'b0xx: ADJH = 4'd0; // no BCD instruction + 3'b100: ADJH = 4'd10; // SBC, and digital borrow + 3'b101: ADJH = 4'd0; // SBC, but no borrow + 3'b110: ADJH = 4'd0; // ADC, but no carry + 3'b111: ADJH = 4'd6; // ADC, and decimal/digital carry + endcase +end + +/* + * write to a register. Usually this is the (BCD corrected) output of the + * ALU, but in case of the JSR0 we use the S register to temporarily store + * the PCL. This is possible, because the S register itself is stored in + * the ALU during those cycles. + */ +always @(posedge clk) + if( write_register & RDY ) + AXYS[regsel] <= (state == JSR0) ? DIMUX : { ADD[7:4] + ADJH, ADD[3:0] + ADJL }; + +/* + * register select logic. This determines which of the A, X, Y or + * S registers will be accessed. + */ + +always @* + case( state ) + INDY1, + INDX0, + ZPX0, + ABSX0 : regsel = index_y ? SEL_Y : SEL_X; + + + DECODE : regsel = dst_reg; + + BRK0, + BRK3, + JSR0, + JSR2, + PULL0, + PULL1, + PUSH1, + RTI0, + RTI3, + RTS0, + RTS2 : regsel = SEL_S; + + default: regsel = src_reg; + endcase + +/* + * ALU + */ + +ALU ALU( .clk(clk), + .op(alu_op), + .right(alu_shift_right), + .AI(AI), + .BI(BI), + .CI(CI), + .BCD(adc_bcd & (state == FETCH)), + .CO(CO), + .OUT(ADD), + .V(AV), + .Z(AZ), + .N(AN), + .HC(HC), + .RDY(RDY) ); + +/* + * Select current ALU operation + */ + +always @* + case( state ) + READ: alu_op = op; + + BRA1: alu_op = backwards ? OP_SUB : OP_ADD; + + FETCH, + REG : alu_op = op; + + DECODE, + ABS1: alu_op = 1'bx; + + PUSH1, + BRK0, + BRK1, + BRK2, + JSR0, + JSR1: alu_op = OP_SUB; + + default: alu_op = OP_ADD; + endcase + +/* + * Determine shift right signal to ALU + */ + +always @* + if( state == FETCH || state == REG || state == READ ) + alu_shift_right = shift_right; + else + alu_shift_right = 0; + +/* + * Sign extend branch offset. + */ + +always @(posedge clk) + if( RDY ) + backwards <= DIMUX[7]; + +/* + * ALU A Input MUX + */ + +always @* + case( state ) + JSR1, + RTS1, + RTI1, + RTI2, + BRK1, + BRK2, + INDX1: AI = ADD; + + REG, + ZPX0, + INDX0, + ABSX0, + RTI0, + RTS0, + JSR0, + JSR2, + BRK0, + PULL0, + INDY1, + PUSH0, + PUSH1: AI = regfile; + + BRA0, + READ: AI = DIMUX; + + BRA1: AI = ABH; // don't use PCH in case we're + + FETCH: AI = load_only ? 0 : regfile; + + DECODE, + ABS1: AI = 8'hxx; // don't care + + default: AI = 0; + endcase + + +/* + * ALU B Input mux + */ + +always @* + case( state ) + BRA1, + RTS1, + RTI0, + RTI1, + RTI2, + INDX1, + READ, + REG, + JSR0, + JSR1, + JSR2, + BRK0, + BRK1, + BRK2, + PUSH0, + PUSH1, + PULL0, + RTS0: BI = 8'h00; + + BRA0: BI = PCL; + + DECODE, + ABS1: BI = 8'hxx; + + default: BI = DIMUX; + endcase + +/* + * ALU CI (carry in) mux + */ + +always @* + case( state ) + INDY2, + BRA1, + ABSX1: CI = CO; + + DECODE, + ABS1: CI = 1'bx; + + READ, + REG: CI = rotate ? C : + shift ? 0 : inc; + + FETCH: CI = rotate ? C : + compare ? 1 : + (shift | load_only) ? 0 : C; + + PULL0, + RTI0, + RTI1, + RTI2, + RTS0, + RTS1, + INDY0, + INDX1: CI = 1; + + default: CI = 0; + endcase + +/* + * Processor Status Register update + * + */ + +/* + * Update C flag when doing ADC/SBC, shift/rotate, compare + */ +always @(posedge clk ) + if( shift && state == WRITE ) + C <= CO; + else if( state == RTI2 ) + C <= DIMUX[0]; + else if( ~write_back && state == DECODE ) begin + if( adc_sbc | shift | compare ) + C <= CO; + else if( plp ) + C <= ADD[0]; + else begin + if( sec ) C <= 1; + if( clc ) C <= 0; + end + end + +/* + * Update Z, N flags when writing A, X, Y, Memory, or when doing compare + */ + +always @(posedge clk) + if( state == WRITE ) + Z <= AZ; + else if( state == RTI2 ) + Z <= DIMUX[1]; + else if( state == DECODE ) begin + if( plp ) + Z <= ADD[1]; + else if( (load_reg & (regsel != SEL_S)) | compare | bit_ins ) + Z <= AZ; + end + +always @(posedge clk) + if( state == WRITE ) + N <= AN; + else if( state == RTI2 ) + N <= DIMUX[7]; + else if( state == DECODE ) begin + if( plp ) + N <= ADD[7]; + else if( (load_reg & (regsel != SEL_S)) | compare ) + N <= AN; + end else if( state == FETCH && bit_ins ) + N <= DIMUX[7]; + +/* + * Update I flag + */ + +always @(posedge clk) + if( state == BRK3 ) + I <= 1; + else if( state == RTI2 ) + I <= DIMUX[2]; + else if( state == REG ) begin + if( sei ) I <= 1; + if( cli ) I <= 0; + end else if( state == DECODE ) + if( plp ) I <= ADD[2]; + +/* + * Update D flag + */ +always @(posedge clk ) + if( state == RTI2 ) + D <= DIMUX[3]; + else if( state == DECODE ) begin + if( sed ) D <= 1; + if( cld ) D <= 0; + if( plp ) D <= ADD[3]; + end + +/* + * Update V flag + */ +always @(posedge clk ) + if( state == RTI2 ) + V <= DIMUX[6]; + else if( state == DECODE ) begin + if( adc_sbc ) V <= AV; + if( clv ) V <= 0; + if( plp ) V <= ADD[6]; + end else if( state == FETCH && bit_ins ) + V <= DIMUX[6]; + +/* + * Instruction decoder + */ + +/* + * IR register/mux. Hold previous DI value in IRHOLD in PULL0 and PUSH0 + * states. In these states, the IR has been prefetched, and there is no + * time to read the IR again before the next decode. + */ + +reg RDY1 = 1; + +always @(posedge clk ) + RDY1 <= RDY; + +always @(posedge clk ) + if( ~RDY && RDY1 ) + DIHOLD <= DI; + +always @(posedge clk ) + if( reset ) + IRHOLD_valid <= 0; + else if( RDY ) begin + if( state == PULL0 || state == PUSH0 ) begin + IRHOLD <= DIMUX; + IRHOLD_valid <= 1; + end else if( state == DECODE ) + IRHOLD_valid <= 0; + end + +assign IR = (IRQ & ~I) | NMI_edge ? 8'h00 : + IRHOLD_valid ? IRHOLD : DIMUX; + +assign DIMUX = ~RDY1 ? DIHOLD : DI; + +/* + * Microcode state machine + */ +always @(posedge clk or posedge reset) + if( reset ) + state <= BRK0; + else if( RDY ) case( state ) + DECODE : + casex ( IR ) + 8'b0000_0000: state <= BRK0; + 8'b0010_0000: state <= JSR0; + 8'b0010_1100: state <= ABS0; // BIT abs + 8'b0100_0000: state <= RTI0; // + 8'b0100_1100: state <= JMP0; + 8'b0110_0000: state <= RTS0; + 8'b0110_1100: state <= JMPI0; + 8'b0x00_1000: state <= PUSH0; + 8'b0x10_1000: state <= PULL0; + 8'b0xx1_1000: state <= REG; // CLC, SEC, CLI, SEI + 8'b1xx0_00x0: state <= FETCH; // IMM + 8'b1xx0_1100: state <= ABS0; // X/Y abs + 8'b1xxx_1000: state <= REG; // DEY, TYA, ... + 8'bxxx0_0001: state <= INDX0; + 8'bxxx0_01xx: state <= ZP0; + 8'bxxx0_1001: state <= FETCH; // IMM + 8'bxxx0_1101: state <= ABS0; // even E column + 8'bxxx0_1110: state <= ABS0; // even E column + 8'bxxx1_0000: state <= BRA0; // odd 0 column + 8'bxxx1_0001: state <= INDY0; // odd 1 column + 8'bxxx1_01xx: state <= ZPX0; // odd 4,5,6,7 columns + 8'bxxx1_1001: state <= ABSX0; // odd 9 column + 8'bxxx1_11xx: state <= ABSX0; // odd C, D, E, F columns + 8'bxxxx_1010: state <= REG; // A, TXA, ... NOP + endcase + + ZP0 : state <= write_back ? READ : FETCH; + + ZPX0 : state <= ZPX1; + ZPX1 : state <= write_back ? READ : FETCH; + + ABS0 : state <= ABS1; + ABS1 : state <= write_back ? READ : FETCH; + + ABSX0 : state <= ABSX1; + ABSX1 : state <= (CO | store | write_back) ? ABSX2 : FETCH; + ABSX2 : state <= write_back ? READ : FETCH; + + INDX0 : state <= INDX1; + INDX1 : state <= INDX2; + INDX2 : state <= INDX3; + INDX3 : state <= FETCH; + + INDY0 : state <= INDY1; + INDY1 : state <= INDY2; + INDY2 : state <= (CO | store) ? INDY3 : FETCH; + INDY3 : state <= FETCH; + + READ : state <= WRITE; + WRITE : state <= FETCH; + FETCH : state <= DECODE; + + REG : state <= DECODE; + + PUSH0 : state <= PUSH1; + PUSH1 : state <= DECODE; + + PULL0 : state <= PULL1; + PULL1 : state <= PULL2; + PULL2 : state <= DECODE; + + JSR0 : state <= JSR1; + JSR1 : state <= JSR2; + JSR2 : state <= JSR3; + JSR3 : state <= FETCH; + + RTI0 : state <= RTI1; + RTI1 : state <= RTI2; + RTI2 : state <= RTI3; + RTI3 : state <= RTI4; + RTI4 : state <= DECODE; + + RTS0 : state <= RTS1; + RTS1 : state <= RTS2; + RTS2 : state <= RTS3; + RTS3 : state <= FETCH; + + BRA0 : state <= cond_true ? BRA1 : DECODE; + BRA1 : state <= (CO ^ backwards) ? BRA2 : DECODE; + BRA2 : state <= DECODE; + + JMP0 : state <= JMP1; + JMP1 : state <= DECODE; + + JMPI0 : state <= JMPI1; + JMPI1 : state <= JMP0; + + BRK0 : state <= BRK1; + BRK1 : state <= BRK2; + BRK2 : state <= BRK3; + BRK3 : state <= JMP0; + + endcase + +/* + * Additional control signals + */ + +always @(posedge clk) + if( reset ) + res <= 1; + else if( state == DECODE ) + res <= 0; + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0xx01010, // ASLA, ROLA, LSRA, RORA + 8'b0xxxxx01, // ORA, AND, EOR, ADC + 8'b100x10x0, // DEY, TYA, TXA, TXS + 8'b1010xxx0, // LDA/LDX/LDY + 8'b10111010, // TSX + 8'b1011x1x0, // LDX/LDY + 8'b11001010, // DEX + 8'b1x1xxx01, // LDA, SBC + 8'bxxx01000: // DEY, TAY, INY, INX + load_reg <= 1; + + default: load_reg <= 0; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1110_1000, // INX + 8'b1100_1010, // DEX + 8'b101x_xx10: // LDX, TAX, TSX + dst_reg <= SEL_X; + + 8'b0x00_1000, // PHP, PHA + 8'b1001_1010: // TXS + dst_reg <= SEL_S; + + 8'b1x00_1000, // DEY, DEX + 8'b101x_x100, // LDY + 8'b1010_x000: // LDY #imm, TAY + dst_reg <= SEL_Y; + + default: dst_reg <= SEL_A; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b1011_1010: // TSX + src_reg <= SEL_S; + + 8'b100x_x110, // STX + 8'b100x_1x10, // TXA, TXS + 8'b1110_xx00, // INX, CPX + 8'b1100_1010: // DEX + src_reg <= SEL_X; + + 8'b100x_x100, // STY + 8'b1001_1000, // TYA + 8'b1100_xx00, // CPY + 8'b1x00_1000: // DEY, INY + src_reg <= SEL_Y; + + default: src_reg <= SEL_A; + endcase + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'bxxx1_0001, // INDY + 8'b10x1_x110, // LDX/STX zpg/abs, Y + 8'bxxxx_1001: // abs, Y + index_y <= 1; + + default: index_y <= 0; + endcase + + +always @(posedge clk) + if( state == DECODE && RDY ) + casex( IR ) + 8'b100x_x1x0, // STX, STY + 8'b100x_xx01: // STA + store <= 1; + + default: store <= 0; + + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0xxx_x110, // ASL, ROL, LSR, ROR + 8'b11xx_x110: // DEC/INC + write_back <= 1; + + default: write_back <= 0; + endcase + + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b101x_xxxx: // LDA, LDX, LDY + load_only <= 1; + default: load_only <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b111x_x110, // INC + 8'b11x0_1000: // INX, INY + inc <= 1; + + default: inc <= 0; + endcase + +always @(posedge clk ) + if( (state == DECODE || state == BRK0) && RDY ) + casex( IR ) + 8'bx11x_xx01: // SBC, ADC + adc_sbc <= 1; + + default: adc_sbc <= 0; + endcase + +always @(posedge clk ) + if( (state == DECODE || state == BRK0) && RDY ) + casex( IR ) + 8'b011x_xx01: // ADC + adc_bcd <= (D | sed); + + default: adc_bcd <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0xxx_x110, // ASL, ROL, LSR, ROR (abs, absx, zpg, zpgx) + 8'b0xxx_1010: // ASL, ROL, LSR, ROR (acc) + shift <= 1; + + default: shift <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b11x0_0x00, // CPX, CPY (imm/zp) + 8'b11x0_1100, // CPX, CPY (abs) + 8'b110x_xx01: // CMP + compare <= 1; + + default: compare <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b01xx_xx10: // ROR, LSR + shift_right <= 1; + + default: shift_right <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0x1x_1010, // ROL A, ROR A + 8'b0x1x_x110: // ROR, ROL + rotate <= 1; + + default: rotate <= 0; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b00xx_xx10: // ROL, ASL + op <= OP_ROL; + + 8'b0010_x100: // BIT zp/abs + op <= OP_AND; + + 8'b01xx_xx10: // ROR, LSR + op <= OP_A; + + 8'b1000_1000, // DEY + 8'b1100_1010, // DEX + 8'b110x_x110, // DEC + 8'b11xx_xx01, // CMP, SBC + 8'b11x0_0x00, // CPX, CPY (imm, zpg) + 8'b11x0_1100: op <= OP_SUB; + + 8'b010x_xx01, // EOR + 8'b00xx_xx01: // ORA, AND + op <= { 2'b11, IR[6:5] }; + + default: op <= OP_ADD; + endcase + +always @(posedge clk ) + if( state == DECODE && RDY ) + casex( IR ) + 8'b0010_x100: // BIT zp/abs + bit_ins <= 1; + + default: bit_ins <= 0; + endcase + +/* + * special instructions + */ +always @(posedge clk ) + if( state == DECODE && RDY ) begin + php <= (IR == 8'h08); + clc <= (IR == 8'h18); + plp <= (IR == 8'h28); + sec <= (IR == 8'h38); + cli <= (IR == 8'h58); + sei <= (IR == 8'h78); + clv <= (IR == 8'hb8); + cld <= (IR == 8'hd8); + sed <= (IR == 8'hf8); + brk <= (IR == 8'h00); + end + +always @(posedge clk) + if( RDY ) + cond_code <= IR[7:5]; + +always @* + case( cond_code ) + 3'b000: cond_true = ~N; + 3'b001: cond_true = N; + 3'b010: cond_true = ~V; + 3'b011: cond_true = V; + 3'b100: cond_true = ~C; + 3'b101: cond_true = C; + 3'b110: cond_true = ~Z; + 3'b111: cond_true = Z; + endcase + + +reg NMI_1 = 0; // delayed NMI signal + +always @(posedge clk) + NMI_1 <= NMI; + +always @(posedge clk ) + if( NMI_edge && state == BRK3 ) + NMI_edge <= 0; + else if( NMI & ~NMI_1 ) + NMI_edge <= 1; + +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/cpu_wrapper.sv b/Atari - 7800_TeST/rtl/cpu_wrapper.sv new file mode 100644 index 00000000..4e1f5e7c --- /dev/null +++ b/Atari - 7800_TeST/rtl/cpu_wrapper.sv @@ -0,0 +1,65 @@ +`timescale 1ns / 1ps + + +module cpu_wrapper( clk, sysclk, reset, AB, DB_IN, DB_OUT, RD, IRQ, NMI, RDY, halt_b, pc_temp, core_latch_data); + +input clk; // CPU clock +input sysclk; // MARIA Clock +input reset; // reset signal +output [15:0] AB; // address bus +input [7:0] DB_IN; // data in, +output [7:0] DB_OUT; // data_out, +output RD; // read enable +input IRQ; // interrupt request +input NMI; // non-maskable interrupt request +input RDY; // Ready signal. Pauses CPU when RDY=0 +input halt_b; +input core_latch_data; + +output [15:0] pc_temp; + +logic res; +logic rdy_in; +logic WE_OUT; +logic WE, holding; +logic [7:0] DB_hold, DB_into_cpu; + +cpu core(.clk(clk), .reset(reset),.AB(AB),.DI(DB_hold),.DO(DB_OUT),.WE(WE_OUT),.IRQ(IRQ),.NMI(NMI),.RDY(rdy_in), .pc_temp(pc_temp), .res(res)); + +assign RD = ~(WE & ~res & ~reset); +assign WE = WE_OUT & rdy_in; //& ~core_latch_data; +//assign rdy_in = RDY & halt_b; +assign DB_hold = (holding) ? DB_hold : DB_IN; + +//assign DB_into_cpu = (core_latch_data) ? DB_IN : DB_hold; +//assign DB_into_cpu = DB_hold; + + +/*always_ff @(posedge sysclk) begin + if (core_latch_data & rdy_in) begin + DB_hold <= DB_IN; + end +end*/ + +/*always_ff @(posedge clk) begin + if (rdy_in) + DB_hold <= DB_IN; +end*/ + +/*always_ff @(posedge clk, posedge reset) + if (reset) + holding <= 1'b0; + else + holding <= ~rdy_in;*/ + +assign holding = ~rdy_in; + +always_ff @(negedge clk, posedge reset) + if (reset) + rdy_in <= 1'b1; + else if (halt_b & RDY) + rdy_in <= 1'b1; + else + rdy_in <= 1'b0; + +endmodule: cpu_wrapper \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/defender_rom.v b/Atari - 7800_TeST/rtl/defender_rom.v new file mode 100644 index 00000000..0ed1d560 --- /dev/null +++ b/Atari - 7800_TeST/rtl/defender_rom.v @@ -0,0 +1,164 @@ +// megafunction wizard: %ROM: 1-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: defender_rom.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 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 defender_rom ( + address, + clock, + q); + + input [11:0] address; + input clock; + output [7:0] q; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clock; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [7:0] sub_wire0; + wire [7:0] q = sub_wire0[7:0]; + + altsyncram altsyncram_component ( + .address_a (address), + .clock0 (clock), + .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_a ({8{1'b1}}), + .data_b (1'b1), + .eccstatus (), + .q_b (), + .rden_a (1'b1), + .rden_b (1'b1), + .wren_a (1'b0), + .wren_b (1'b0)); + defparam + altsyncram_component.address_aclr_a = "NONE", + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_output_a = "BYPASS", +`ifdef NO_PLI + altsyncram_component.init_file = "../rtl/rom/Defender.rif" +`else + altsyncram_component.init_file = "../rtl/rom/Defender.hex" +`endif +, + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 4096, + altsyncram_component.operation_mode = "ROM", + altsyncram_component.outdata_aclr_a = "NONE", + altsyncram_component.outdata_reg_a = "CLOCK0", + altsyncram_component.widthad_a = 12, + altsyncram_component.width_a = 8, + 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: AclrOutput NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +// Retrieval info: PRIVATE: BlankMemory NUMERIC "0" +// 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: 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 "../rtl/rom/Defender.hex" +// Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "4096" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: RegAddr 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 "0" +// Retrieval info: PRIVATE: WidthAddr NUMERIC "12" +// Retrieval info: PRIVATE: WidthData NUMERIC "8" +// Retrieval info: PRIVATE: rden NUMERIC "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: ADDRESS_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: INIT_FILE STRING "../rtl/rom/Defender.hex" +// 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 "4096" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM" +// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0" +// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "12" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: USED_PORT: address 0 0 12 0 INPUT NODEFVAL "address[11..0]" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +// Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +// Retrieval info: CONNECT: @address_a 0 0 12 0 address 0 0 12 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL defender_rom.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL defender_rom.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL defender_rom.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL defender_rom.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL defender_rom_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL defender_rom_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf diff --git a/Atari - 7800_TeST/rtl/dma_ctrl.sv b/Atari - 7800_TeST/rtl/dma_ctrl.sv new file mode 100644 index 00000000..18b4ff8d --- /dev/null +++ b/Atari - 7800_TeST/rtl/dma_ctrl.sv @@ -0,0 +1,403 @@ +`timescale 1ns / 1ps + +module dma_ctrl( + output logic [15:0] AddrB, + output logic drive_AB, + input logic [7:0] DataB, + // from memory map + input logic [15:0] ZP, + + output logic palette_w, input_w, pixels_w, + output logic wm_w, + + input logic zp_dma_start, dp_dma_start, dp_dma_kill, + output logic zp_dma_done, dp_dma_done, dp_dma_done_dli, + + input logic character_width, + input logic [7:0] char_base, + + input logic sysclk, reset, last_line +); + logic [15:0] DP; + logic [15:0] DP_saved; + logic [15:0] PP; + logic [15:0] ZP_saved, ZP_saved_next; + logic [15:0] CHAR_PTR; + logic [1:0] char_ptr_cycles; + logic char_bytes_fetched; + logic [4:0] WIDTH; + logic [3:0] OFFSET; + + logic INDIRECT_MODE; + + // control regs + logic DLIen, DLIen_prev, A12en, A11en; + + // states + enum logic [1:0] {waiting = 2'b00, zp_dma = 2'b01, dp_dma = 2'b10} state; + enum logic [2:0] {drive_zp_addr = 3'b000, w_offset = 3'b001, w_DPH = 3'b010 ,w_DPL = 3'b100} zp_state; + enum logic [3:0] {drive_dp_addr = 4'h00, + w_PPL = 4'h01, + w_PALETTE_WIDTH = 4'h02, + w_PPH = 4'h03, + w_PALETTE_WIDTH_2 = 4'h04, + w_INPUT = 4'h05, + drive_pp_addr = 4'h06, + w_PIXELS = 4'h07, + w_PIXELS_slow = 4'h08, + drive_char_addr = 4'h09, + w_CHAR_PTR = 4'ha, + w_CHAR_PIXELS = 4'hb, + drive_next_zp_addr = 4'hc, + w_next_offset = 4'hd, + w_next_DPL = 4'he, + w_next_DPH = 4'hf} dp_state; + + logic five_byte_mode, null_width, null_data, zero_offset; + + logic PP_in_cart; + assign PP_in_cart = |(PP_plus_offset[15:14]); + + logic [7:0] CB_plus_offset; + assign CB_plus_offset = char_base + {4'b0, OFFSET}; + + logic CB_in_cart; + assign CB_in_cart = |(CB_plus_offset[7:6]); + + assign null_width = (DataB[4:0] == 5'b0); + assign null_data = (DataB == 8'b0); + assign zero_offset = (OFFSET == 4'b0); + + assign drive_AB = (state != waiting); + + assign ZP_saved_next = ZP_saved + 1; + + logic [15:0] PP_plus_offset; + assign PP_plus_offset = PP + {4'b0, OFFSET, 8'b0}; + + always_comb begin + AddrB = 'h1234; + wm_w = 0; + palette_w = 0; + input_w = 0; + pixels_w = 0; + case (state) + zp_dma: begin + AddrB = ZP_saved; + end + dp_dma: begin + AddrB = 16'hx; + case (dp_state) + drive_dp_addr: begin + AddrB = DP_saved; + end + + w_PPL: begin + AddrB = DP_saved; + end + + w_PALETTE_WIDTH: begin + AddrB = DP_saved; + if (~null_data) begin + wm_w = null_width; + palette_w = ~null_width; + end + end + + w_PPH: begin + AddrB = DP_saved; + end + + w_PALETTE_WIDTH_2: begin + AddrB = DP_saved; + palette_w = 1; + end + + w_INPUT: begin + AddrB = DP_saved; + input_w = 1; + end + + drive_pp_addr: begin + AddrB = PP_plus_offset; + end + + w_PIXELS: begin + AddrB = PP + 1; + pixels_w = 1; + end + + w_PIXELS_slow: begin + if (char_ptr_cycles == 2'b11) begin + pixels_w = 1; + AddrB = PP + 1; + end else begin + AddrB = PP; + end + end + + drive_char_addr: begin + AddrB = PP; + end + + w_CHAR_PTR: begin + AddrB = {CB_plus_offset, DataB}; + end + + w_CHAR_PIXELS: begin + if (char_ptr_cycles == 2'b11) begin + pixels_w = 1; + if (~char_bytes_fetched & character_width) begin + AddrB = CHAR_PTR + 1; + end else begin + AddrB = PP; + end + end else begin + AddrB = CHAR_PTR; + end + end + + drive_next_zp_addr: begin + AddrB = ZP_saved; + end + w_next_offset: begin + AddrB = ZP_saved; + end + w_next_DPL: begin + AddrB = ZP_saved; + end + w_next_DPH: begin + AddrB = ZP_saved; + end + endcase + end + endcase + end + + always_ff @(posedge sysclk, posedge reset) begin + if (reset) begin + state <= waiting; + zp_state <= drive_zp_addr; + dp_state <= drive_dp_addr; + zp_dma_done <= 0; + dp_dma_done <= 0; + dp_dma_done_dli <= 0; + five_byte_mode <= 0; + INDIRECT_MODE <= 0; + end else begin + case (state) + waiting: begin + if (zp_dma_start) begin + state <= zp_dma; + ZP_saved <= ZP; + end else if (dp_dma_start) begin + state <= dp_dma; + DP_saved <= DP; + end + zp_dma_done <= 0; + dp_dma_done <= 0; + dp_dma_done_dli <= 0; + end + //////////////////////////////////////////////////////////// + zp_dma: begin + case (zp_state) + drive_zp_addr: begin // Read zp + zp_state <= w_offset; + // AddrB = ZP_saved; + ZP_saved <= ZP_saved_next; + end + w_offset: begin //write cbits and offset + zp_state <= w_DPH; + {DLIen,A12en,A11en} <= DataB[7:5]; + OFFSET <= DataB[3:0]; + // AddrB = ZP_saved_next; + ZP_saved <= ZP_saved_next; + end + w_DPH: begin //Write DPH + zp_state <= w_DPL; + DP[15:8] <= DataB; + // AddrB = ZP_saved; + ZP_saved <= ZP_saved_next; + end + w_DPL: begin //Write DPL + zp_state <= drive_zp_addr; + state <= waiting; + DP[7:0] <= DataB; + DP_saved <= {DP[15:8], DataB}; + zp_dma_done <= 1'b1; + dp_dma_done_dli <= DLIen; + end + endcase // case (zp_state) + end // case: zp_dma + + ////////////////////////////////////////////////////////////// + dp_dma: begin + if (dp_dma_kill) begin + dp_state <= drive_dp_addr; + state <= waiting; + dp_dma_done <= 1'b1; + end else case (dp_state) + drive_dp_addr: begin //read from dp + dp_state <= w_PPL; + // AddrB = DP_saved; + DP_saved <= DP_saved+1; + five_byte_mode <= 0; + INDIRECT_MODE <= 0; + end + w_PPL: begin //Write PPL + dp_state <= w_PALETTE_WIDTH; + PP[7:0] <= DataB; + // AddrB = DP_saved; + DP_saved <= DP_saved+1; + end + w_PALETTE_WIDTH: + // Write palette/width or determine 5b + // mode or find end of DP list + if (null_data) begin //Found end of DP list + if (last_line) begin // Found end of frame + dp_state <= drive_dp_addr; + state <= waiting; + dp_dma_done <= 1; + dp_dma_done_dli <= 1'b0; + end else if (zero_offset) begin // Found end of zone, but not end of frame + dp_state <= drive_next_zp_addr; + state <= dp_dma; + end else begin // Not at end of zone or frame. Get ready for next line in zone. + state <= waiting; + dp_state <= drive_dp_addr; + OFFSET <= OFFSET - 1; + dp_dma_done <= 1; + end + end else begin + // Write palette and width or determine its 5b mode + dp_state <= w_PPH; + five_byte_mode <= null_width; + INDIRECT_MODE <= null_width & DataB[5]; + // wm_w <= null_width; + // ind_w <= null_width; + // palette_w <= ~null_width; + WIDTH <= DataB[4:0]; + // AddrB <= DP; + DP_saved <= DP_saved+1; + end + w_PPH: begin //Write PPH + dp_state <= (five_byte_mode) ? w_PALETTE_WIDTH_2 : w_INPUT; + PP[15:8] <= DataB; + // AddrB <= DP; + DP_saved <= DP_saved+1; + end + w_PALETTE_WIDTH_2: begin //Write palette and width for realzies + dp_state <= w_INPUT; + // palette_w <= 1; + WIDTH <= DataB[4:0]; + // AddrB <= DP; + DP_saved <= DP_saved+1; + end + w_INPUT: begin //write INPUT + if (INDIRECT_MODE) begin + dp_state <= drive_char_addr; + end else begin + if ((A12en & PP_plus_offset[12]) | (A11en & PP_plus_offset[11])) + dp_state <= drive_dp_addr; + else + dp_state <= drive_pp_addr; + end + // palette_w <= 0; + // AddrB <= DP; + // input_w <= 1; + end + drive_pp_addr: begin //read from pp + if (PP_in_cart) begin + dp_state <= w_PIXELS_slow; + char_ptr_cycles <= 2'b00; + end else begin + dp_state <= w_PIXELS; + end + WIDTH <= WIDTH+1; + PP <= PP_plus_offset; + end + w_PIXELS: begin //Write Pixel data + PP <= PP + 1; + WIDTH <= WIDTH + 1; + dp_state <= (WIDTH == 5'b0) ? drive_dp_addr : w_PIXELS; + end + w_PIXELS_slow: begin + // Similar to w_CHAR_PIXELS in that we wait 4 cycles, + // but similar to w_PIXELS otherwise + if (char_ptr_cycles == 2'b11) begin + // Data is ready on the data bus + WIDTH <= WIDTH + 1; + PP <= PP + 1; + dp_state <= (WIDTH == 5'b0) ? drive_dp_addr: w_PIXELS_slow; + char_ptr_cycles <= 2'b00; + end else begin + char_ptr_cycles <= char_ptr_cycles + 1; + end + end + drive_char_addr: begin // read character pointer from pp + dp_state <= w_CHAR_PTR; + WIDTH <= WIDTH + 1; + PP <= PP + 1; + end + w_CHAR_PTR: begin + dp_state <= w_CHAR_PIXELS; + CHAR_PTR <= {CB_plus_offset, DataB}; + char_bytes_fetched <= 2'b0; + char_ptr_cycles <= (CB_in_cart) ? 2'b00 : 2'b11; + end + + w_CHAR_PIXELS: begin + if (char_ptr_cycles == 2'b11) begin + if (~char_bytes_fetched & character_width) begin + dp_state <= w_CHAR_PIXELS; + char_bytes_fetched <= 1'b1; + CHAR_PTR <= CHAR_PTR + 1; + end else begin + if (WIDTH == 5'b0) begin + dp_state <= drive_dp_addr; + end else begin + dp_state <= w_CHAR_PTR; + WIDTH <= WIDTH + 1; + PP <= PP + 1; + end + end + end else begin + char_ptr_cycles <= char_ptr_cycles + 1; + end + end + + ///////////////////////////////////////////////// + //Loading next zp when OFFSET has been decremented to 0 + drive_next_zp_addr: begin //Read zp + dp_state <= w_next_offset; + // AddrB <= ZP_saved; + ZP_saved <= ZP_saved_next; + end + w_next_offset: begin //write cbits and offset + dp_state <= w_next_DPH; + DLIen_prev <= DLIen; + {DLIen,A12en,A11en} <= DataB[7:5]; + OFFSET <= DataB[3:0]; + // AddrB <= ZP_saved; + ZP_saved <= ZP_saved_next; + end + w_next_DPH: begin //Write DPH + dp_state <= w_next_DPL; + DP[15:8] <= DataB; + // AddrB <= ZP_saved; + ZP_saved <= ZP_saved_next; + end + w_next_DPL: begin //Write DPH + dp_state <= drive_dp_addr; + state <= waiting; + DP[7:0] <= DataB; + DP_saved <= {DP[15:8], DataB}; + dp_dma_done <= 1; + dp_dma_done_dli <= DLIen; + end + endcase // case (dp_state) + end // case: dp_dma + endcase + end + end // always_ff @ +endmodule // dma_ctrl \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/hq2x.sv b/Atari - 7800_TeST/rtl/hq2x.sv new file mode 100644 index 00000000..f17732b6 --- /dev/null +++ b/Atari - 7800_TeST/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/Atari - 7800_TeST/rtl/line_ram.sv b/Atari - 7800_TeST/rtl/line_ram.sv new file mode 100644 index 00000000..9b9b6f88 --- /dev/null +++ b/Atari - 7800_TeST/rtl/line_ram.sv @@ -0,0 +1,261 @@ +`timescale 1ns / 1ps + +// Graphics Mode Definitions +`define GM_160A 3'b000 +`define GM_160B 3'b100 +`define GM_320A 3'b011 +`define GM_320B 3'b110 +`define GM_320C 3'b111 +`define GM_320D 3'b010 + +module line_ram( + input logic SYSCLK, RESET, + output logic [7:0] PLAYBACK, + // Databus inputs + input logic [7:0] INPUT_ADDR, + input logic [2:0] PALETTE, + input logic [7:0] PIXELS, + input logic WM, + // Write enable for databus inputs + input logic PALETTE_W, INPUT_W, PIXELS_W, WM_W, + // Memory mapped registers + input logic [24:0][7:0] COLOR_MAP, + input logic [1:0] READ_MODE, + input logic KANGAROO_MODE, BORDER_CONTROL, + input logic COLOR_KILL, + input logic LRAM_SWAP, + // VGA Control signal + input logic [8:0] LRAM_OUT_COL +); + + logic [159:0][4:0] lram_in, lram_out; + logic rm_in, rm_out; + + logic [7:0] input_addr; + logic [2:0] palette; + logic wm; + + logic [2:0] display_mode; + assign display_mode = {wm, READ_MODE}; + + logic [2:0] playback_palette; + logic [1:0] playback_color; + logic [4:0] playback_cell; + logic [8:0] playback_ix; + logic [7:0] lram_ix; + + assign playback_ix = (LRAM_OUT_COL < 9'd320) ? LRAM_OUT_COL : 9'd0; + + always_comb begin + if (playback_color == 2'b0) begin + PLAYBACK = COLOR_MAP[0]; + end else begin + PLAYBACK = COLOR_MAP[3 * playback_palette + playback_color]; + end + end + + logic [4:0] cell1, cell2, cell3, cell4; + logic [4:0] pcell1, pcell2, pcell3, pcell4; + + assign cell1 = lram_in[input_addr]; + assign cell2 = lram_in[input_addr+1]; + assign cell3 = lram_in[input_addr+2]; + assign cell4 = lram_in[input_addr+3]; + + assign pcell1 = lram_in[input_addr-4]; + assign pcell2 = lram_in[input_addr-3]; + assign pcell3 = lram_in[input_addr-2]; + assign pcell4 = lram_in[input_addr-1]; + + // Assign playback_color and playback_palette based on + // lram_in and playback_ix and display_mode + always_comb begin + lram_ix = playback_ix[8:1]; // 2 pixels per lram cell + playback_cell = lram_out[lram_ix]; + playback_palette = playback_cell[4:2]; // Default to 160A/B + playback_color = playback_cell[1:0]; + casex (rm_out) + 2'b0x: begin + // 160A is read as four double-pixels per byte: + // + // + // + // + // 160B is read as two double-pixels per byte: + // + // + // In both cases, the lineram cells are stored in + // exactly the order specified above. They can be + // read directly. + playback_palette = playback_cell[4:2]; + playback_color = playback_cell[1:0]; + end + 2'b10: begin + // 320B is read as four pixels per byte: + // + // + // + // + // 320B is stored as two cells per byte (wm=1): + // [P2 D3 D2 D7 D6] + // [P2 D1 D0 D5 D4] + // + // 320D is read as eight pixels per byte: + // + // + // + // + // + // + // + // + // 320D is stored as four cells per byte (wm=0): + // [P2 P1 P0 D7 D6] + // [P2 P1 P0 D5 D4] + // [P2 P1 P0 D3 D2] + // [P2 P1 P0 D1 D0] + // + // In both cases, the palette is always + // For a given pair of pixels, the color selectors + // are, from left to right, and + // Example: Either D7,D3:D6,D2 (320B) or D7,P1:D6,P0 (320D) + playback_palette = {playback_cell[4], 2'b0}; + if (playback_ix[0]) begin + // Right pixel + playback_color = {playback_cell[0], playback_cell[2]}; + end else begin + // Left pixel + playback_color = {playback_cell[1], playback_cell[3]}; + end + end + 2'b11: begin + // 320A is read as eight pixels per byte: + // + // + // + // + // + // + // + // + // 320A is stored as four cells per byte (wm=0): + // [P2 P1 P0 D7 D6] + // [P2 P1 P0 D5 D4] + // [P2 P1 P0 D3 D2] + // [P2 P1 P0 D1 D0] + // + // 320C is read as four pixels per byte: + // + // + // + // + // 320C is stored as two cells per byte (wm=1): + // [P2 D3 D2 D7 D6] + // [P2 D1 D0 D5 D4] + // + // In both cases, the palette is always + // For a given pair of pixels, the color selectors + // are, from left to right, and + playback_palette = playback_cell[4:2]; + if (playback_ix[0]) begin + // Right pixel + playback_color = {playback_cell[0], 1'b0}; + end else begin + // Left pixel + playback_color = {playback_cell[1], 1'b0}; + end + end + endcase + end + + always_ff @(posedge SYSCLK, posedge RESET) begin + if (RESET) begin + input_addr <= 8'b0; + palette <= 3'b0; + wm <= 1'b0; + lram_in <= 800'd0; + lram_out <= 800'd0; + end else begin + input_addr <= INPUT_W ? INPUT_ADDR : input_addr; + palette <= PALETTE_W ? PALETTE : palette; + wm <= WM_W ? WM : wm; + if (LRAM_SWAP) begin + lram_in <= 800'd0; // All background color + lram_out <= lram_in; + rm_out <= rm_in; + end + if (PIXELS_W) begin + // Load PIXELS byte into lram_in + rm_in <= READ_MODE; + case (wm) + 1'b0: begin + // "When wm = 0, each byte specifies four pixel cells + // of the lineram" + // This encompasses: + // 160A: + // [P2 P1 P0 D7 D6] + // [P2 P1 P0 D5 D4] + // [P2 P1 P0 D3 D2] + // [P2 P1 P0 D1 D0] + // 320A: + // [P2 P1 P0 D7 0] + // [P2 P1 P0 D6 0] + // [P2 P1 P0 D5 0] + // [P2 P1 P0 D4 0] + // [P2 P1 P0 D3 0] + // [P2 P1 P0 D2 0] + // [P2 P1 P0 D1 0] + // [P2 P1 P0 D0 0] + // 320D: + // [P2 0 0 D7 P1] + // [P2 0 0 D6 P0] + // [P2 0 0 D5 P1] + // [P2 0 0 D4 P0] + // [P2 0 0 D3 P1] + // [P2 0 0 D2 P0] + // [P2 0 0 D1 P1] + // [P2 0 0 D0 P0] + // These can all be written into the cells using + // the same format and read out differently. + input_addr <= input_addr + 4; + if (|PIXELS[7:6]) + lram_in[input_addr+0] <= {palette, PIXELS[7:6]}; + if (|PIXELS[5:4]) + lram_in[input_addr+1] <= {palette, PIXELS[5:4]}; + if (|PIXELS[3:2]) + lram_in[input_addr+2] <= {palette, PIXELS[3:2]}; + if (|PIXELS[1:0]) + lram_in[input_addr+3] <= {palette, PIXELS[1:0]}; + end + 1'b1: begin + // "When wm = 1, each byte specifies two cells within the lineram." + // This encompasses: + // 160B: + // [P2 D3 D2 D7 D6] + // [P2 D1 D0 D5 D4] + // 320B: + // [P2 0 0 D7 D3] + // [P2 0 0 D6 D2] + // [P2 0 0 D5 D1] + // [P2 0 0 D4 D0] + // 320C: + // [P2 D3 D2 D7 0] + // [P2 D3 D2 D6 0] + // [P2 D1 D0 D5 0] + // [P2 D1 D0 D4 0] + // Again, these can be written into the cells in + // the same format and read out differently. Note: + // transparency may not be correct in 320B mode here + // since the color bits are different than 160B and 320C. + input_addr <= input_addr + 2; + if (|PIXELS[7:6]) + lram_in[input_addr+0] <= {palette[2], PIXELS[3:2], PIXELS[7:6]}; + if (|PIXELS[5:4]) + lram_in[input_addr+1] <= {palette[2], PIXELS[1:0], PIXELS[5:4]}; + end + endcase + end + end + end + +endmodule diff --git a/Atari - 7800_TeST/rtl/maria.sv b/Atari - 7800_TeST/rtl/maria.sv new file mode 100644 index 00000000..2f30002d --- /dev/null +++ b/Atari - 7800_TeST/rtl/maria.sv @@ -0,0 +1,178 @@ +`timescale 1ns / 1ps +`include "atari7800.vh" + + +module maria( + // Busses ("tristate") + input logic [15:0] AB_in, + output logic [15:0] AB_out, + output logic drive_AB, + + input logic [7:0] read_DB_in, + input logic [7:0] write_DB_in, + output logic [7:0] DB_out, + // inout wire [15:0] AB, + // inout wire [ 7:0] DB, + //inout wire [7:0] DB, + //inout wire [15:0] AB, + + // Clocking + input logic reset, + input logic sysclk, pclk_2, + output logic tia_clk, pclk_0, sel_slow_clock, + + // Memory Map Select lines + output `chipselect CS, + input logic bios_en, + input logic tia_en, + //output logic ram0_b, ram1_b, p6532_b, tia_b, + //output logic riot_ram_b, + + // Maria configuration + input logic RW, enable, + + // VGA Interface + input logic [9:0] vga_row, vga_col, + output logic [7:0] UV_out, + + // Outputs to 6502 + output logic int_b, halt_b, ready, core_latch_data +); + + // Bus interface + // Defined as ports. + //logic drive_AB; + //logic [15:0] AB_in, AB_out; + //logic drive_DB; + //logic [7:0] DB_in, DB_out; + //assign DB = drive_DB ? DB_out : 'bz; + //assign AB = drive_AB ? AB_out : 'bz; + //assign DB_in = DB; + //assign AB_in = AB; + + // For testing DMA. + //assign DB_in = DB; + //assign AB = AB_out; + //assign AB_in = AB_out; + + //// Memory Mapped Registers + // Control register format: + // {CK, DM1, DM0, CW, BC, KM, RM1, RM0} + // CK: Color Kill + // {DM1, DM0}: DMA Control. 0: Test A. 1: Test B. + // 2: Normal DMA. 3: No DMA. + // CW: Character Width (For indirect mode). 0=>2bytes. 1=>1byte. + // BC: Border Control: 0=>Background Color. 1=>Black Border. + // KM: Kangaroo Mode: 0=>Transparency, 1=>No transparency + // {RM1, RM0}: Read mode. + logic [7:0] ctrl; + logic [24:0][7:0] color_map; + logic [7:0] char_base; + logic [15:0] ZP; + + //// Signals from memory_map to timing_ctrl + logic deassert_ready, zp_written; + + // Write enables for internal Display List registers + logic palette_w, input_w, pixels_w, wm_w; + + //// Control signals between timing_ctrl and dma_ctrl + logic zp_dma_start, dp_dma_start; + logic zp_dma_done, dp_dma_done; + // When dp_dma_done is asserted, use this signal to specify + // whether timing_ctrl needs to raise a display list interrupt + logic dp_dma_done_dli; + // If a DMA is taking too long (too many objects,) kill it + logic dp_dma_kill; + // Next-line ZP DMA not needed at end of DP DMA + logic last_line; + + //// Control signals between timing_ctrl and line_ram + logic lram_swap; + + logic VBLANK; + + line_ram line_ram_inst( + .SYSCLK(sysclk), .RESET(reset), + .PLAYBACK(UV_out), + // Databus inputs + .INPUT_ADDR(read_DB_in), .PALETTE(read_DB_in[7:5]), .PIXELS(read_DB_in), + .WM(read_DB_in[7]), + // Write enable for databus inputs + .PALETTE_W(palette_w), .INPUT_W(input_w), .PIXELS_W(pixels_w), + .WM_W(wm_w), + // Memory mapped registers + .COLOR_MAP(color_map), + .READ_MODE(ctrl[1:0]), + .KANGAROO_MODE(ctrl[2]), + .BORDER_CONTROL(ctrl[3]), + .COLOR_KILL(ctrl[7]), + // Control signals from timing_ctrl + .LRAM_SWAP(lram_swap), + .LRAM_OUT_COL(vga_col[9:1]) + ); + + timing_ctrl timing_ctrl_inst( + // Enabled only if men is asserted and display mode is 10 + .enable(enable & ctrl[6] & ~ctrl[5]), + // Clocking + .sysclk(sysclk), .reset(reset), .pclk_2(pclk_2), + .pclk_0(pclk_0), .tia_clk(tia_clk), + // Signals needed to slow pclk_0 + .sel_slow_clock(sel_slow_clock), + // Outputs to 6502 + .halt_b(halt_b), .int_b(int_b), .ready(ready), .core_latch_data(core_latch_data), + .VBLANK(VBLANK), + // Signals to/from dma_ctrl + .zp_dma_start(zp_dma_start), .dp_dma_start(dp_dma_start), + .zp_dma_done(zp_dma_done), .dp_dma_done(dp_dma_done), + .dp_dma_done_dli(dp_dma_done_dli), + .dp_dma_kill(dp_dma_kill), .last_line(last_line), + // Signals to/from line_ram + .lram_swap(lram_swap), + // Signals to/from VGA + .vga_row(vga_row), .vga_col(vga_col), + // Signals from memory map + .deassert_ready(deassert_ready), + .zp_written(zp_written) + ); + + memory_map memory_map_inst( + .maria_en(enable), + .tia_en(tia_en), + .AB(AB_in), + .DB_in(write_DB_in), .DB_out(DB_out), + //.drive_DB(drive_DB), + .halt_b(halt_b), .we_b(RW), + //.tia_b(tia_b), .p6532_b(p6532_b), + //.ram0_b(ram0_b), .ram1_b(ram1_b), + //.riot_ram_b(riot_ram_b), + .cs(CS), .bios_en(bios_en), + .drive_AB(drive_AB), + .ctrl(ctrl), + .color_map(color_map), + .status_read({VBLANK, 7'b0}), + .char_base(char_base), + .ZP(ZP), + .sel_slow_clock(sel_slow_clock), + .deassert_ready(deassert_ready), + .zp_written(zp_written), + .sysclock(sysclk), .reset_b(~reset), + .pclk_0(pclk_0), .pclk_2(pclk_2) + ); + + dma_ctrl dma_ctrl_inst ( + .AddrB(AB_out), .drive_AB(drive_AB), + .DataB(read_DB_in), .ZP(ZP), + .palette_w(palette_w), .input_w(input_w), .pixels_w(pixels_w), + .wm_w(wm_w), + .zp_dma_start(zp_dma_start), .dp_dma_start(dp_dma_start), + .dp_dma_kill(dp_dma_kill), + .zp_dma_done(zp_dma_done), .dp_dma_done(dp_dma_done), + .dp_dma_done_dli(dp_dma_done_dli), + .sysclk(sysclk), .reset(reset), + .last_line(last_line), + .character_width(ctrl[4]), .char_base(char_base) + ); + +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/memory_map.sv b/Atari - 7800_TeST/rtl/memory_map.sv new file mode 100644 index 00000000..2c993781 --- /dev/null +++ b/Atari - 7800_TeST/rtl/memory_map.sv @@ -0,0 +1,232 @@ +`timescale 1ns / 1ps + +`include "atari7800.vh" + +module memory_map ( + input logic maria_en, + input logic tia_en, + input logic [15:0] AB, + input logic [7:0] DB_in, + output logic [7:0] DB_out, + input logic halt_b, we_b, + + output `chipselect cs, + input logic bios_en, + input logic drive_AB, + + output logic [7:0] ctrl, + output logic [24:0][7:0] color_map, + input logic [7:0] status_read, + output logic [7:0] char_base, + output logic [15:0] ZP, + + // whether to slow pclk_0 for slow memory accesses + output logic sel_slow_clock, + + // when wait_sync is written to, ready is deasserted + output logic deassert_ready, zp_written, + + input logic sysclock, reset_b, pclk_0, pclk_2 +); + + logic [3:0] signals_out; + + // Internal Memory Mapped Registers + logic [7:0] ZPH, ZPL; + logic [7:0] wait_sync; + + logic [7:0] read_addr_found, write_addr_found; + + (* KEEP = "true" *) + logic [7:0] ctrl_kept; + + assign sel_slow_clock = (drive_AB) ? 1'b0 : ((tia_en) ? 1'b1 : ((cs == `CS_TIA) || (cs == `CS_RIOT_IO) || (cs == `CS_RIOT_RAM))); + + assign ZP = {ZPH, ZPL}; + logic [1:0] zp_byte_written; + + assign zp_written = &zp_byte_written; + + always_comb begin + // Generate Chip Select (cs) Signal + cs = `CS_CART; + + if (~tia_en) casex (AB) + // RIOT RAM: "Do Not Use" in 7800 mode. + 16'b0000_010x_1xxx_xxxx: cs = `CS_RIOT_RAM; + 16'b0000_0010_1xxx_xxxx: cs = `CS_RIOT_IO; + + // 1800-1FFF: 2K RAM. + 16'b0001_1xxx_xxxx_xxxx: cs = `CS_RAM1; + + // 0040-00FF: Zero Page (Local variable space) + // 0140-01FF: Stack + 16'b0000_000x_01xx_xxxx, + 16'b0000_000x_1xxx_xxxx, + + // 2000-27FF: 2K RAM. Zero Page and Stack mirrored from here. + 16'b001x_xxxx_xxxx_xxxx: cs = `CS_RAM0; + + // TIA Registers: + // 0000-001F, 0100-001F, 0200-021F, 0300-031F + // All mirrors are ranges of the same registers + 16'b0000_00xx_000x_xxxx: cs = `CS_TIA; + + // MARIA Registers: + // 0020-003F, 0120-003F, 0220-023F, 0320-033F + // All ranges are mirrors of the same registers + 16'b0000_00xx_001x_xxxx: cs = `CS_MARIA; + + endcase else casex (AB) + 16'bxxx0_xx0x_1xxx_xxxx: cs = `CS_RIOT_RAM; + 16'bxxx0_xx1x_1xxx_xxxx: cs = `CS_RIOT_IO; + 16'bxxx0_xxxx_0xxx_xxxx: cs = `CS_TIA; + endcase + + if (bios_en & AB[15]) + cs = `CS_BIOS; + + // If MARIA is selected, handle memory mapped registers + if (cs == `CS_MARIA) begin + if (we_b) begin + read_addr_found = AB[7:0]; + write_addr_found = 8'h0; + end + else begin + write_addr_found = AB[7:0]; + read_addr_found = 8'h0; + end + end else begin + read_addr_found = 8'h0; + write_addr_found = 8'h0; + end + + /* + //Find write addresses on bus to latch data on next tick + casex ({AB, we_b}) + {16'b0000_00xx_001x_xxxx,1'b0}: wr_addr_found = AB[7:0]; + default: wr_addr_found = 8'b0; + endcase + + casex ({AB, we_b}) + {16'b0000_00xx_001x_xxxx,1'b1}: read_addr_found = AB[7:0]; + default: read_addr_found = 8'b0; + endcase + */ + + + end // always_comb + + always_ff @(posedge pclk_0, negedge reset_b) begin + if (~reset_b) begin + ctrl <= {1'b0, 2'b10, 1'b0, 1'b0, 1'b0, 2'b00}; // 8'b0 + ctrl_kept <= 8'b0; + //color_map <= 200'b0; + //////// TESTING COLOR MAP ///////// + // Background + color_map[0] <= 8'h0c; + // Palette 0 + color_map[3:1] <= {8'h32, 8'h55, 8'h55}; + // Palette 1 + color_map[6:4] <= {8'h83, 8'h55, 8'h55}; + // Palette 2 + color_map[9:7] <= {8'h1c, 8'h55, 8'h55}; + // Palette 3 + color_map[12:10] <= {8'h25, 8'h55, 8'h55}; + // Palette 4 + color_map[15:13] <= {8'hda, 8'h55, 8'h55}; + + color_map[24:16] <= 'b0; + + wait_sync <= 8'b0; + char_base <= 8'b0; + {ZPH,ZPL} <= {8'h18, 8'h20}; + zp_byte_written <= 2'b0; + end + + else begin + ctrl_kept <= ctrl; + deassert_ready <= 1'b0; + //Handle writes to mem mapped regs + case(write_addr_found) + 8'h20: color_map[0] <= DB_in; + 8'h21: color_map[1] <= DB_in; + 8'h22: color_map[2] <= DB_in; + 8'h23: color_map[3] <= DB_in; + 8'h24: begin + wait_sync <= DB_in; + deassert_ready <= 1'b1; + end + 8'h25: color_map[4] <= DB_in; + 8'h26: color_map[5] <= DB_in; + 8'h27: color_map[6] <= DB_in; + //8'h28: status_read <= DB_in; Read only + 8'h29: color_map[7] <= DB_in; + 8'h2a: color_map[8] <= DB_in; + 8'h2b: color_map[9] <= DB_in; + 8'h2c: begin + ZPH <= DB_in; + zp_byte_written[1] <= 1'b1; + end + 8'h2d: color_map[10] <= DB_in; + 8'h2e: color_map[11] <= DB_in; + 8'h2f: color_map[12] <= DB_in; + 8'h30: begin + ZPL <= DB_in; + zp_byte_written[0] <= 1'b1; + end + 8'h31: color_map[13] <= DB_in; + 8'h32: color_map[14] <= DB_in; + 8'h33: color_map[15] <= DB_in; + 8'h34: char_base <= DB_in; + 8'h35: color_map[16] <= DB_in; + 8'h36: color_map[17] <= DB_in; + 8'h37: color_map[18] <= DB_in; + //8'h38: NOT USED + 8'h39: color_map[19] <= DB_in; + 8'h3a: color_map[20] <= DB_in; + 8'h3b: color_map[21] <= DB_in; + 8'h3c: ctrl <= DB_in; + 8'h3d: color_map[22] <= DB_in; + 8'h3e: color_map[23] <= DB_in; + 8'h3f: color_map[24] <= DB_in; + default: ; + endcase // case (wr_addr_found) + + case(read_addr_found) + 8'h20: DB_out <= color_map[0]; + 8'h21: DB_out <= color_map[1]; + 8'h22: DB_out <= color_map[2]; + 8'h23: DB_out <= color_map[3]; + 8'h25: DB_out <= color_map[4]; + 8'h26: DB_out <= color_map[5]; + 8'h27: DB_out <= color_map[6]; + 8'h28: DB_out <= status_read; + 8'h29: DB_out <= color_map[7]; + 8'h2a: DB_out <= color_map[8]; + 8'h2b: DB_out <= color_map[9]; + 8'h2c: DB_out <= ZPH; + 8'h2d: DB_out <= color_map[10]; + 8'h2e: DB_out <= color_map[11]; + 8'h2f: DB_out <= color_map[12]; + 8'h30: DB_out <= ZPL; + 8'h31: DB_out <= color_map[13]; + 8'h32: DB_out <= color_map[14]; + 8'h33: DB_out <= color_map[15]; + 8'h34: DB_out <= char_base; + 8'h35: DB_out <= color_map[16]; + 8'h36: DB_out <= color_map[17]; + 8'h37: DB_out <= color_map[18]; + //8'h38: NOT USED + 8'h39: DB_out <= color_map[19]; + 8'h3a: DB_out <= color_map[20]; + 8'h3b: DB_out <= color_map[21]; + 8'h3c: DB_out <= ctrl; + 8'h3d: DB_out <= color_map[22]; + 8'h3e: DB_out <= color_map[23]; + 8'h3f: DB_out <= color_map[24]; + default: DB_out <= 8'hbe; + endcase // case (wr_addr_found) + end // else: !if(~reset_b) + end // always_ff @ +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/mist_io.sv b/Atari - 7800_TeST/rtl/mist_io.sv new file mode 100644 index 00000000..ab9ef8ad --- /dev/null +++ b/Atari - 7800_TeST/rtl/mist_io.sv @@ -0,0 +1,532 @@ +// +// 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, + + // ARM -> FPGA download + input ioctl_force_erase, + output reg ioctl_download = 0, // signal indicating an active download + output reg ioctl_erasing = 0, // signal indicating an active erase + output reg [7:0] ioctl_index, // menu index used to upload the file + output reg ioctl_wr = 0, + 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 [7: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; + +// 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]; + + 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 + case(ioctl_index) + 0: addr <= 'h080000; // BOOT ROM + 'h01: addr <= 'h000100; // ROM file + 'h41: addr <= 'h000100; // COM file + 'h81: addr <= 'h000000; // C00 file + 'hC1: addr <= 'h010000; // EDD file + default: addr <= 'h100000; // FDD file + endcase + 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 + +reg [24:0] erase_mask; +wire [24:0] next_erase = (ioctl_addr + 1'd1) & erase_mask; + +always@(posedge clk_sys) begin + reg rclkD, rclkD2; + reg old_force = 0; + reg [5:0] erase_clk_div; + reg [24:0] end_addr; + reg erase_trigger = 0; + + rclkD <= rclk; + rclkD2 <= rclkD; + ioctl_wr <= 0; + + if(rclkD & ~rclkD2) begin + ioctl_dout <= data_w; + ioctl_addr <= addr_w; + ioctl_wr <= 1; + end + + if(ioctl_download) begin + old_force <= 0; + ioctl_erasing <= 0; + erase_trigger <= (ioctl_index == 1); + end else begin + + old_force <= ioctl_force_erase; + + // start erasing + if(erase_trigger) begin + erase_trigger <= 0; + erase_mask <= 'hFFFF; + end_addr <= 'h0100; + erase_clk_div <= 1; + ioctl_erasing <= 1; + end else if((ioctl_force_erase & ~old_force)) begin + erase_trigger <= 0; + ioctl_addr <= 'h1FFFFFF; + erase_mask <= 'h1FFFFFF; + end_addr <= 'h0050000; + erase_clk_div <= 1; + ioctl_erasing <= 1; + end else if(ioctl_erasing) begin + erase_clk_div <= erase_clk_div + 1'd1; + if(!erase_clk_div) begin + if(next_erase == end_addr) ioctl_erasing <= 0; + else begin + ioctl_addr <= next_erase; + ioctl_dout <= 0; + ioctl_wr <= 1; + end + end + end + end +end + +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/osd.sv b/Atari - 7800_TeST/rtl/osd.sv new file mode 100644 index 00000000..c62c10af --- /dev/null +++ b/Atari - 7800_TeST/rtl/osd.sv @@ -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/Atari - 7800_TeST/rtl/pll.v b/Atari - 7800_TeST/rtl/pll.v new file mode 100644 index 00000000..e38a7e4c --- /dev/null +++ b/Atari - 7800_TeST/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.4 Build 182 03/12/2014 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 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 = 27, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 25, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 189, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 50, + altpll_component.clk1_phase_shift = "0", + altpll_component.clk2_divide_by = 108, + altpll_component.clk2_duty_cycle = 50, + altpll_component.clk2_multiply_by = 25, + 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 "27" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "189" +// Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "108" +// 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 "25.000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "7.142857" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "6.250000" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "deg" +// 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 "25" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "50" +// Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "25" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "25.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "7.14300000" +// Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "6.25000000" +// 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 "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.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 "27" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "25" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "189" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "108" +// Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "25" +// 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/Atari - 7800_TeST/rtl/ram2k.v b/Atari - 7800_TeST/rtl/ram2k.v new file mode 100644 index 00000000..a57abe06 --- /dev/null +++ b/Atari - 7800_TeST/rtl/ram2k.v @@ -0,0 +1,177 @@ +// megafunction wizard: %RAM: 1-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: ram2k.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 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 ram2k ( + address, + clken, + clock, + data, + wren, + q); + + input [10:0] address; + input clken; + input clock; + input [7:0] data; + input wren; + output [7:0] q; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clken; + tri1 clock; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [7:0] sub_wire0; + wire [7:0] q = sub_wire0[7:0]; + + altsyncram altsyncram_component ( + .address_a (address), + .clock0 (clock), + .data_a (data), + .wren_a (wren), + .clocken0 (clken), + .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), + .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 = "NORMAL", + altsyncram_component.clock_enable_output_a = "NORMAL", + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 2048, + 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 = 11, + altsyncram_component.width_a = 8, + 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 "1" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "1" +// Retrieval info: PRIVATE: Clken NUMERIC "1" +// 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 "2048" +// 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 "11" +// Retrieval info: PRIVATE: WidthData NUMERIC "8" +// 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 "NORMAL" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "NORMAL" +// 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 "2048" +// 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 "11" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: USED_PORT: address 0 0 11 0 INPUT NODEFVAL "address[10..0]" +// Retrieval info: USED_PORT: clken 0 0 0 0 INPUT VCC "clken" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +// Retrieval info: USED_PORT: data 0 0 8 0 INPUT NODEFVAL "data[7..0]" +// Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +// Retrieval info: USED_PORT: wren 0 0 0 0 INPUT NODEFVAL "wren" +// Retrieval info: CONNECT: @address_a 0 0 11 0 address 0 0 11 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: @clocken0 0 0 0 0 clken 0 0 0 0 +// Retrieval info: CONNECT: @data_a 0 0 8 0 data 0 0 8 0 +// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL ram2k.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram2k.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram2k.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram2k.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram2k_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL ram2k_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf diff --git a/Atari - 7800_TeST/rtl/riot.vh b/Atari - 7800_TeST/rtl/riot.vh new file mode 100644 index 00000000..74090777 --- /dev/null +++ b/Atari - 7800_TeST/rtl/riot.vh @@ -0,0 +1,26 @@ +/* Atari on an FPGA +Masters of Engineering Project +Cornell University, 2007 +Daniel Beer + RIOT.h +Header file that contains useful definitions for the RIOT module. +*/ +`define READ_RAM 7'b01xxxxx +`define WRITE_RAM 7'b00xxxxx +`define READ_DRA 7'b11xx000 +`define WRITE_DRA 7'b10xx000 +`define READ_DDRA 7'b11xx001 +`define WRITE_DDRA 7'b10xx001 +`define READ_DRB 7'b11xx010 +`define WRITE_DRB 7'b10xx010 +`define READ_DDRB 7'b11xx011 +`define WRITE_DDRB 7'b10xx011 +`define WRITE_TIMER 7'b101x1xx +`define READ_TIMER 7'b11xx1x0 +`define READ_INT_FLAG 7'b11xx1x1 +`define WRITE_EDGE_DETECT 7'b100x1x0 +`define NOP 7'b0100000 +`define TM_1 2'b00 +`define TM_8 2'b01 +`define TM_64 2'b10 +`define TM_1024 2'b11 \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/rom/7800ntsc.hex b/Atari - 7800_TeST/rtl/rom/7800ntsc.hex new file mode 100644 index 00000000..3bec21bc --- /dev/null +++ b/Atari - 7800_TeST/rtl/rom/7800ntsc.hex @@ -0,0 +1,257 @@ +:10000000486CF400FFFFFFFFFFFFFFFFFFFFFFFF54 +:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 +:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 +:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 +:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:10008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:10009000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:1000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:1000B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:1000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:1000D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:1000E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:1000F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:10010000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:10011000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF +:10012000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:10013000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF +:10014000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:10015000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF +:10016000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:10017000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +:10018000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:10019000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F +:1001A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:1001B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +:1001C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:1001D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F +:1001E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:1001F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F +:10020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:10022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:100400004CC2264CC226A9168501A0FFA27FBD00C2 +:10041000FED980FDD0EA88CA10F4ADFCFF2DFDFFA7 +:10042000C9FFF0DCADFCFF0DFDFFF0D4ADF8FF0916 +:10043000FEC9FFD0CEADF8FF49F029F0D0C5ADF927 +:10044000FF290BC903D0BCADF9FF29F085EE8D065D +:1004500024C94090AEE901CDFDFFB0A7203625A903 +:100460000085F0201B24A9168501A2008A9D001892 +:10047000CAD0FA48A07FB900FF99001888C0F8D008 +:10048000F5A92E8D0924A9248D0A24201B24682077 +:10049000FF2348EE0624AD0624C9FFD0EE201B241E +:1004A000201224201224A9368D0924A9248D0A247F +:1004B000CE0624201B246820FF2348CE0624AD0648 +:1004C00024C5EEB0EEA960853CA277BD00185D5052 +:1004D000185D88189D001ACA10F1AD001A29078D01 +:1004E000001AA900A2049D001A9D0020A277BD0059 +:1004F00020DD001AD006CA10F54CB9264CC226A23F +:10050000007D00187D00FFA8B9D52D9D0018E8D00A +:10051000F060A2003E0018E8D0FA6008C6F0100CA7 +:10052000A9028501A5F030FCA91685012860C765E0 +:10053000ABCAEEF78309E1D0926762B672558E912D +:10054000DCC581BE782059B7E63D0645AFC8083105 +:1005500038D1FB7384A917FC3487A394FA90B8EDC3 +:10056000CE3B5B0A43D9F35382B30D6D5A609D5164 +:10057000A7B91110BCE47F8041E7E3F6562635ECBD +:10058000D6DF0C7FF49EAC5246EFCFBFA23FA41340 +:1005900015974A1CB0428CB105588018772B023E43 +:1005A000A8491A6ACB6E0B8AEBF14F14798BD89F4E +:1005B0009B5719F82A2D760EE82E4BF90703DE9388 +:1005C000167ED4E5B2F07D7ADAD2A1CC1DE05E23AE +:1005D000A095221E3685FE1F39AA8996AD0F2FC021 +:1005E00047275D24EAC3A5F5215F1B408FAE742524 +:1005F000DDC17CCDA670D7337B2C75BB8699BD54ED +:100600009A6C6332484C8DBA5C61C44E293712C66D +:10061000989CD5696BE2044DE9C2883ADB640144D9 +:100620006FB5F23028FD50713CB46668C9D3CA83F7 +:10063000C7ABF76509EEA27786E486E5BD80FF9D2E +:1006400001199D0020CA10F4A90285012084FB2015 +:100650007B25C6F2A27786E4BDD5FE9D0119CA109E +:10066000F7A5E185E320E125C6F2A5E08D7225A27C +:1006700077BD00189D0020CA10F760203926A4E538 +:10068000C884E1981865E248AAA9008D71269D00EA +:1006900018CAD0FA8D0018C88C6E268C74268C7CF3 +:1006A000268C8126A200CE6E26CE7426CE7C26CE47 +:1006B0008126C6E1301BA4E1B900203DD925F0090F +:1006C000BD62268D7226206A26E8E00830E84CA438 +:1006D000256885E1A90185E0600102040810204039 +:1006E00080203926A5E338E5E485E085E1A2008E87 +:1006F00000188E8F268EAC26CA8EA9268E8C268E4A +:1007000092268E9A268E9F26A207EEA926EE8C268A +:10071000EE9226EE9A26EE9F26C6E13017BD62269F +:100720008D90268DAD2620A6269003208826CA10FF +:10073000EC4C0826A5E385E160A6E4E886E2A0008B +:100740008C0019B962268D5526C8B962268D5926A6 +:10075000A6E218BD00192A9D0019CA10F6C007307C +:10076000E260191A1B1C1D1E1F21A4E218B90018F3 +:100770007900199900188810F4900CB900176900D5 +:10078000990017884C792660A4E238B90018F9005E +:10079000199900188810F4B00CB90017E9009900F5 +:1007A00017884C972660A000B90018D90019F001ED +:1007B00060C4E2F0FBC84CA826A21686019AF86C29 +:1007C000FCFFA9028501A27FBDD4F79D8004CA1059 +:1007D000F74C8004A900AA85019503E8E02AD0F926 +:1007E0008502A904EA3023A204CA10FD9A8D1001E3 +:1007F00020CB0420CB048511851B851C850FEA8541 +:1008000002A900EA300424033009A90285098D12E7 +:10081000F1D01E2402300CA90285068D18F18D60DE +:10082000F4D00E852CA908851B20CB04EA240230C5 +:10083000D9A9FD85086CFCFFEAFFFFFFFFFFFFFF62 +:10084000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 +:10085000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:10086000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 +:10087000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 +:10088000A91D850178D8A9028501A9FB85F5A912C2 +:1008900085F4A97F853CA9008520A205BD1DF9A08E +:1008A00000990020D90020D027990021D90021D01B +:1008B0001F88D0EDCA10E5A9438D8020C580D00BDC +:1008C0008D8021CD8001D0034C38F9A0044C80F8F4 +:1008D0008D0018CD0018D00AA0014C80F8A0024C61 +:1008E00080F8A0034C80F8A90085F085F2A0078469 +:1008F000F4B923F985F1B92BF985F3A205BD1DF9EA +:10090000A00091F0D1F0D0D091F2D1F2D0CF88D028 +:10091000F1CA10E9C6F4A4F410D74C17FB00FF5538 +:10092000AA690F222324252627222318191A1B1C03 +:100930001D1E1FA0004C80F8A9AAF0F710F5300387 +:100940004C33F9D0034C33F985AAC5AAD0E5A900E8 +:10095000D0E130DF10034C33F9F0034C33F9C90018 +:10096000D0D190CFB0034C33F9C901B0C690034C3D +:1009700033F9A255E056F0BB8EAA01ECAA01D0B320 +:10098000A4AAC0ABF0AD8C5501CC5501D0A5CA9A34 +:10099000E868C9AAD0558A48EC5501D04E98C9AA32 +:1009A000D049AABD0001A8C055D040B500C5AAD005 +:1009B0003AC9AAD03649FF990000C555D02DD900B3 +:1009C00001D028DDAB20D023A92085F1A9CC85F06A +:1009D0008146C5CCD01591F0CD2121D00EA9EE8550 +:1009E000F0A9F985F16CF0004CEBF94C33F9A955FD +:1009F000186955EAB0F510F3F0F1C9AAD0ED6955C0 +:100A0000EA90E830E6D0E4E955B0E010DEF0DCC969 +:100A1000ABD0D818E9AA90D330D1D0CFA9FFAAE89B +:100A2000D036CAF0331031E0FFD02DA8C8D02988C5 +:100A3000F026C8D02385F0E6F0D01DC4F0D019C64A +:100A4000F0F015C5F0D011A9AA182A2A2AC952D047 +:100A5000076A6A6AC9AAF0034C33F90A90FA0AB025 +:100A6000F70AC950D0F249054A90ED4AB0EA4AC99E +:100A70000AD0E5A955091BC95FD0DD2955291BC935 +:100A800011D0D50955491BC94ED0CD2091FA4C58EB +:100A9000FABAE052D0C268C98DD0BD68C9FAD0B8E0 +:100AA000A9F848A9E648604C58FA8A48A943853C09 +:100AB000A20FA5EF852224F3500610028524852479 +:100AC000852438E910C910B002E90F8522CA10EC5C +:100AD000A240863C29F0090E8527A5EF29F00906DA +:100AE000852529F01869409002690F09038526C6FB +:100AF000F11019A5F369609011A5EF186910900223 +:100B0000690F85EFA5F285F1A90085F3A90285F0AB +:100B100068AA68404C14FBA2FF9AA900AA9501E8B4 +:100B2000E02CD0F9A9028501A2008620BD00F49D29 +:100B30000023BD00F59D0024BD00F69D0025BD00ED +:100B4000F79D0026BD00F89D0027BDBEFB9D00223D +:100B5000E000302ABD4BFC9D841FBDC6FC9D84195E +:100B6000BD3DFD9D841ABDB4FD9D841BBD18FE9D39 +:100B7000841CBD57FE9D841DBD96FE9D841ECAD05B +:100B8000AB4C0623ADF9FF2904F032A90385F185AA +:100B9000F2A94985EFA9668525A9568526A92E853E +:100BA00027A9AA85F4A9FA85F5242830FC24281061 +:100BB000FCA9848530A91F852CA943853C60841F2E +:100BC00019BB00008440191FBB0000851C194A0096 +:100BD00000891C194A00008D1C19480000911B193E +:100BE0004600009619194200009D17193E0000A604 +:100BF00017193E0000AF2C1C00AF2C1C500000AF9A +:100C00002C1D00AF2C1D500000AF2D19280000C274 +:100C10002D19280000D52D19280000E82D192800CD +:100C200000AF2D1A280000C22D1A280000D52D1A59 +:100C3000280000E82D1A280000AF2D1B280000C254 +:100C40002D1B280000D52D1B2800000F22060F2287 +:100C5000000F22000F220003220085220D0522131F +:100C600005221905221F05222505222B0522310FF9 +:100C7000220001223700224B022237002251022299 +:100C80003700225702223700225D022237002263FA +:100C900002223700226902223700226F0222370027 +:100CA000227502223700227B022237002281022293 +:100CB000370022870122410F22000F22000F22005D +:100CC0000F22000F2200007C7F8F80FC7F8FC01FCF +:100CD00087F87E0FE07F81FC07FF807F807FF81F11 +:100CE000FFF0007F8003FFFE1F0000007F800000F8 +:100CF0003E00000C003FFFFFFFF000C000003FFF80 +:100D0000FF0003FC00003F003FFFFFFFF003F00087 +:100D1000003FFFFFFC03FC0000FFC00003FF0000DA +:100D20000FFC00003FF003FFC3FC0003FFF00003D3 +:100D3000FF00003FFF00003FF0003FC3FC007C7F4E +:100D40008F807C7F8F801F87F87E0FF07F83FC0170 +:100D5000FF807F807FE01FFFF8007F8007FFFE1F7E +:100D6000F000007F800003FE000FF3FC0003FF0093 +:100D700000FF3FC0003FF000FFC3FC003FC0FF008A +:100D800003FF0003FC0FF0003FF03FFC03FC00FFFB +:100D9000003FC003FF000FF003FC003FF0FFC00363 +:100DA000FC03FFFFFFF003FF003FFFFFFF003FF0EA +:100DB0003FF003FC007C7F8F807C7F8F801F87F853 +:100DC0007E07F07F83F800FFC07F80FFC01FFFFC1D +:100DD000007F800FFFFE1FFC00007F80000FFE0FD2 +:100DE000FFFFFFFC03FF00FFFFFFFFC03FF00FFC12 +:100DF00003FC3FF00003FF03FF03FF00003FF03F51 +:100E0000F003FF03FCFFC00000FFC3FF0FFC000066 +:100E10000FFC3FF000FFC3FC007C7F8F807C7F8F46 +:100E2000800F87F87C07F07F83F8007FC07F80FF0A +:100E3000801FFFFE007F801FFFFE1FFF00007F80DE +:100E4000003FFE5555555555555555555555555514 +:100E500055555555555555007C7F8F807C7F8F802B +:100E60000FC7F8FC03F07F83F0003FE07F81FF00B5 +:100E700001FFFE007F801FFFE01FFFC0007F80009A +:100E8000FFFEAAAAAAAAAAAAAAAAAAAAAAAAAAAA19 +:100E9000AAAAAAAAAAAA007C7F8F807C7F8F800F33 +:100EA000C7F8FC03F87F87F0001FE07F81FE000099 +:100EB0001FFF007F803FFE001FFFE0007F8001FFDB +:100EC000FE55555555555555555555555555555529 +:100ED000555555555509CAC9C6B412081B605881E5 +:100EE0004B8601D8BFD925A07BDC3279843B7CBC02 +:100EF0002FE2E2FA8D0A003BC5ECAF2D8ACD0693B6 +:100F00006AA5144677C46AB25336EF8CCE0CA26839 +:100F100071D373E8F76D06B520EF23470C5155C820 +:100F2000FEF458C43F20A76738B076E2C4D8056302 +:100F3000F83C583B2D22CC88B3718F1D800A87BDA9 +:100F4000A15923E970E2D3EC4668804239EAFFFFF9 +:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFF474385 +:100FF00043284329313938342DF700F084F833F988 +:00000001FF diff --git a/Atari - 7800_TeST/rtl/rom/7800ntsc.rom b/Atari - 7800_TeST/rtl/rom/7800ntsc.rom new file mode 100644 index 00000000..c91490c2 Binary files /dev/null and b/Atari - 7800_TeST/rtl/rom/7800ntsc.rom differ diff --git a/Atari - 7800_TeST/rtl/rom/7800pal.hex b/Atari - 7800_TeST/rtl/rom/7800pal.hex new file mode 100644 index 00000000..97141817 --- /dev/null +++ b/Atari - 7800_TeST/rtl/rom/7800pal.hex @@ -0,0 +1,1025 @@ +:1000000003FC0003FC0003FC0003FC0003FC0003F2 +:10001000FC0003FC0003FC0003FC0003FC0003FCE9 +:100020000003FC0003FC0003FC0003FC0003FC00D5 +:1000300003FC0003FC0003FC0003FC0003FC0003C2 +:10004000FC0003FC0003FC0000F00000F00000F0E6 +:100050000000F00000F00000F00000F00000F000F0 +:1000600000F00000F00000F00000F00000000000D0 +:100070002300001000000800002000000000000025 +:100080000000000000000000000000000000000070 +:100090000000000000000000000000000000000060 +:1000A0000000000000000000000000000000000050 +:1000B0000000000000000000000000000000000040 +:1000C0000000000000000000000000000000000030 +:1000D0000000000000000000000000000000000020 +:1000E0000000000000000000000000000000000010 +:1000F0000000000000000000000000000000000000 +:100100000FAA000FAA000FAA000FAB000FAF000F3D +:10011000B6000FAA000F6A000FAB000FAD000FADC5 +:10012000000FB5000FEA000FDA000FE9000FE90039 +:100130000FEA000FF5000FB9000FEB000FFA000FE8 +:10014000E9000FE9000FEA000FFF000FFF000FFFAB +:10015000000FFF000FFF000FFE000FBF000FFF009A +:100160000FFF000FFF000FFF000FFF000000000057 +:1001700010000008000810402304000000000000E8 +:10018000000000000000000000000000000000006F +:10019000000000000000000000000000000000005F +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000000000000000000000000000000002F +:1001D000000000000000000000000000000000001F +:1001E000000000000000000000000000000000000F +:1001F00000000000000000000000000000000000FF +:100200000FF6000FA5000FA5000FA5000FAF000F00 +:10021000BF000FD5000DA5000F99000E9D000FB572 +:10022000000FB7000FA5000FA5000FA9000FA90030 +:100230000FA5000FB9000FAD000FA5000FA9000F0B +:10024000A6000FAA000F95000FAA000FAA000FAA80 +:10025000000FAA000FAA000FA6C00FDE000FBA0001 +:100260000EAA000FAA000FAA000FAA0000010000AA +:10027000109000200808104000000000000000005E +:10028000000000000000000000000000000000006E +:10029000000000000000000000000000000000005E +:1002A000000000000000000000000000000000004E +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:100300003F55803E95403E95803E95403EA5403EFF +:10031000BD403EFD403F56403E95403EA5C03EB5E7 +:10032000403ED6803F99403F69403EA5403E9540C3 +:100330003E95403EA5403EED403E95C03EA5403F27 +:10034000A5403EA5403E95403E96803E96803E9616 +:10035000803E96803E95C03E9FC03E75803FD680D1 +:100360003B96803E96803E96803E9680002000041C +:100370001440012910010448004000000000000062 +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B0000000000000010004000000000000000038 +:1003C000000000000000000000000000000000002D +:1003D00000000000400000000000000000000000DD +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:100400003F75403F99403E95403E65403E95403E99 +:1004100055403EF6403FF5403E55403E95403E57E4 +:10042000C03ED6803EA5403FA5403F99403E654036 +:100430003E55403E95403E95803E55C03E55403F1E +:1004400095403ED5403E55403E95403E55403E5538 +:10045000803E55C03A55803AD7403A954039D5400C +:100460002E55403E55403E55403E55400038801088 +:10047000948080515003490000010003F000F00017 +:10048000F000F003F003F003F000F00FF00FF00EB7 +:10049000F00FF00FF003F003F003F00FF00FF00F88 +:1004A000F00FF00FF00FF00FF00FF0000000000061 +:1004B0000000000420010004800200000000000091 +:1004C000000000000002000000000000000000002A +:1004D00000020008400000000000000002000000D0 +:1004E000000000000000000000000000000000000C +:1004F00000000000000000000000000000000000FC +:10050000FD6D50FD5550FE6550FE5550FE5550FE98 +:100510009550FE9550FBD550FFD9D0FE5550FE9515 +:10052000D0FE9FD0FE6550FF9550FF9550FED650EF +:10053000FE9550FA6550FF5550FF5DD0FE5570FE98 +:10054000A550FFD550FF7550FA6560FA9560FA55D1 +:1005500060FA5D70FA76F0FA5960FE5560FF5560FA +:10056000FA5560FA5560FA5D60F9B56002258005BC +:10057000690426994000620001040803F00FF00BA3 +:10058000F00EF00FB00FEC0FF803FC2FFC3FFC3F18 +:10059000FC3FBC0FFC03FC03FC03FC3FFC3FFC3FA7 +:1005A000FC3FFC3FFC3FFC3FFC3FFC000000000523 +:1005B0002004080000202003804200080000000002 +:1005C00000000000800200080000000000000000A1 +:1005D0008002040B00000000200008010000000061 +:1005E0000800000000000000000000000000000003 +:1005F00000000000000000000000000000000000FB +:10060000FD6D50FF5570FF5550FA5550FA9550FA50 +:100610005550FA5550F95550FF6550FF9550F95512 +:1006200050F96750FAD550FA9950FAD550F6E5507E +:10063000FA9590FE9650FA9550FB65D0F99770FAAE +:100640009550FF5550FFF550F9D550FD5550F955CF +:1006500050F95570FA56D0F95550F95550FA555091 +:10066000F95550F95750F95A50FA59500A570002A3 +:1006700075800155100202180600C20FFC0FFC0F16 +:10068000FC0FF00FF80FFF0FFC0FFF3FD83BD83ED9 +:10069000A83EA83EA83E983FA83FD83EA83EA83E08 +:1006A000A83EA83EA83EE83DA83EA80000003001B4 +:1006B000400910C0082FE002800E000A002C000044 +:1006C0000000E0028002000A002C00000000E002AE +:1006D0008002C00A000104041000A002400280024F +:1006E000000000000000000000000000000000000A +:1006F00000000000000000000000000000000000FA +:10070000F95D50F5D550FD55D0F95550FA5550FAD0 +:100710006550F96550F59550F95550FD5D50FD96C1 +:1007200050FA5550FAF750FA9550F9D650FAB5509C +:10073000F99D50F69550FB9550FFD550F97570FA1C +:1007400055D0FA9550FBD950FDD550FF5550F9556D +:1007500090F96570F95550F95550F95950F96550AF +:10076000FA5650F95590F96650FE6D5000B580006C +:1007700096600075600108888000800EE83FBC3FED +:10078000AC3EA83BA83EF40FBF0FAFFBFBFBFBFA50 +:10079000FBFA5BFA5BFA97FA9BFBDBFA5BFA5BF915 +:1007A0005BFA5FFB58FAABF69FFA6F00000100019D +:1007B00040006220303AB0EA800AC04A802A002A0B +:1007C000C002A00E800EC00A002A000EA002A00ADD +:1007D000840E800AAC01040A90021000A003880075 +:1007E0000000000000000000000000000000000009 +:1007F00000000000000000000000000000000000F9 +:10080000F97550F9D550F75550F65750FA5550F93B +:100810005550FA5550F95550FA5550FA5550FA5569 +:1008200050FA5950FAFF50FE9D50FB9550F97590C3 +:10083000FA5D50F99560FA9550FD9550FA7550FAA9 +:100840009D50FA5570FA9550FAE550FB5590FD55BC +:1008500050F95550F99550FA5650F95650F95990AB +:10086000F995D0FA55D0F96750F9AD50006480047D +:100870005D281015622050000052002F983ABB3EB0 +:10088000AF3E973FA43ED63FB63EB4FAF6FAFDF926 +:10089000FEFD7EF996FE56F956F956F956F95AF9C3 +:1008A00074FD5CF954F976F97FF95E02000980065F +:1008B000C8111000000A802A803A800EB00AB03AAF +:1008C000A83AB00A800A800A803AB0AAB03A803AC0 +:1008D000C00AB00AA00254096006100A12002000E3 +:1008E0008000000000000000000000000000000088 +:1008F00000000000000000000000000000000000F8 +:10090000FA5550FFD570F76570FE6570FD5D50FAC1 +:100910005550FA9550FA5550F96550FA5550FAD598 +:1009200050F95550FE7D50FE5F70FB5750FAD55080 +:10093000FA9D60FA55D0FA5950FA9550FAFD50FADE +:100940005D50FA5750FA5550FFD550FB9550EE596F +:1009500050F95950F95550F95590F95550F95570CD +:10096000F956D0F956D0F96F50F9B650004400004E +:10097000E5000246400062C00010003EB4FE5CFE8E +:1009800057FF943DD63E753E9E3E94E955E97EE67E +:100990007CFD7CEB5CED96FB55E956E956E5DEF90E +:1009A0007CEA5CE9D5E9FFE976EA56024001601588 +:1009B000A0888000400A803A80AA800AAC4AA80A2F +:1009C000ACAA803A800A800AB00AA8EA80AA84EA1F +:1009D000800AA80AB000540150019804600208007F +:1009E000000AA00AA00AA00AA0000000000000005F +:1009F00000000000000000000000000000000000F7 +:100A0000FE9540FF5570FF55F0FE55F0FE95D0FD68 +:100A10005570FE5550FE5550FE5570FD5550FD5514 +:100A200050FF5550FE9570FE9FF0FE57D0FED5D07A +:100A3000FA7D50FE55D0FE5570FA5590FED550FA0D +:100A4000BF50FD9750FE95D0FF5560FB5660ED55A9 +:100A500060B95560F95550F95550F95550F955B0F0 +:100A6000F957D0F95B50FA6D50FE5550010800025D +:100A70004404011410810410818008FE56FD54FDC9 +:100A800055FE55FBD5F9F5FA7DF95BE955E556A913 +:100A90005CFD5CEF5CEAD6EF55EDD6E776E5FCE968 +:100AA0007CE554EBFEE5D5E956E95601800B4002A2 +:100AB00040311800010A800A803AB03AA80AB00E04 +:100AC000B03A802A800A800AA00AB03AC03A80AAC6 +:100AD000B03AB00A80006403420250001000800067 +:100AE000003AA82FA82AF82ABC000000003C3C3C91 +:100AF0003C3C3C3C3C3C3C3C3C00080808080000BA +:100B00003E55403E95403D65403E95C03E57C03EF7 +:100B100057403ED5403DA5403E95403E65403E5540 +:100B2000403E95403E65403E57C03E97C03ED5C0D2 +:100B30003EB5403E55C03E95403D55403D5D403E32 +:100B400075403A5FC03E55C03A95403E55403E56CE +:100B5000402E55403A55D03A55403A55C03A55C0C6 +:100B60003A5B403A55403E55803E554000080008EB +:100B70000800040404060042100800FB553AD53969 +:100B8000753E5DEA54F954FA54F955EB75E956E5AA +:100B900054EA54EF58EBD4E574EBD6EBFEE5FCE5F4 +:100BA0005DED56EB56E956E956EDD6008006500548 +:100BB0004C014381300EC0028002A02AC02A004AA4 +:100BC000800AC0EA803AB00AAC0E800A8402A00E05 +:100BD000A02A000A00061405D0240000800000802E +:100BE00000AAAAAAAAAAAAAAAA383C2C28383B3842 +:100BF000F83BFBFBFBFBF7FFF708101000000000C1 +:100C00003EA5403E55403E55403E97403E5F403EEB +:100C10005F403F55403F95403E65403E55403E67F2 +:100C2000403E55403E95003E55403E55C03F65C054 +:100C30003EB9403EA7C03E95403EA5403E55403E91 +:100C400097403E5D403E65C03E55803E56403E5515 +:100C5000403E55402E55403E55403E55C03E56C044 +:100C60003E55403E55403E55803E95800008000070 +:100C700008002004C00000000000203A96396439C2 +:100C8000543A543954395439543A54F5F6F5DEF59A +:100C900056F954FD58FBD4F9F4F95EF7FEF976F9EC +:100CA00055FFD6F956F956FB56FFF6000001000431 +:100CB00050091000000200028000E000002C000A31 +:100CC000000E0002802FE00A0002C0028000E00057 +:100CD000002C000A00051025041A22280088202074 +:100CE000003954395439543954AAAAAAAAE535F519 +:100CF000ECE5F5DDE5D415D6D524B6020C0C0000E4 +:100D00000E95000EA5000E65000E95000E9D000EBE +:100D1000BC000EBD000E96000EA5000E95000D97AE +:100D2000000E9D000E95000E95000E95000E5500CC +:100D30000F55000EA7000E95000E55000E55000E23 +:100D400095000E95000E97000EF5000EE5000EF5CD +:100D5000000EF5000EF5000EF7000EF7000EF50080 +:100D60000EF5000EF5000FF5000FF5000000000075 +:100D70000800004000081000001000395439540EDB +:100D8000543A943A503E903D603E583954397C393B +:100D900074395839583B5839F8395C39D439543F8B +:100DA00054395439543E543FD83FF80000000010E5 +:100DB000800408000002000080000000000000081D +:100DC000004200038020200B00020400800000008D +:100DD0000000000800060017009A00A820E00000AC +:100DE000080E500E500E500E5075757575D5F5DD08 +:100DF000E7F5D5DDD7D4D5D5DD180488020200008B +:100E00000FA9000F95000F95000FA5000FA5000F6B +:100E1000B5000FF5000FF5000FE9000FA5000FA5B5 +:100E2000000FAD000FA5000FA5000FA5000F950046 +:100E30000FA5000FFE000FE5000FE5000FD5000F16 +:100E4000D5000FD5000FD5000F96000F96000F9616 +:100E5000000F96000F96000F96000FE6000FD600C9 +:100E60000FD6000FD6000F96000FD600000000002E +:100E700000000008000004300C00000A500A500D69 +:100E8000500D500E500E500F500D503A5C3A543ADF +:100E90005C3A6C3A6C395C3AE83A7C3A583E583ADB +:100EA000583A580A580F5C0FDB3B5800000000000E +:100EB000004080200302000000000000000000004D +:100EC0000002000480010008400200000000000051 +:100ED0000000000000070020000000248028080017 +:100EE0000002400240024002403C282828E6E4D6A6 +:100EF000E5D6DDE5E4D51535DD201E020000000C49 +:100F000003F80003E80003E80003E80003E8000337 +:100F1000E80003D80003E80003E80003E80003E862 +:100F20000003E80003F80003E80003E80003F8000A +:100F300003F80003F80003FC0003FC0003F80003BF +:100F4000F80003F80003F80000E00000E00000E013 +:100F50000000E00000E00000E00000E00000E00031 +:100F600000E00000E00000E00000E0000000000001 +:100F7000000000000000040000200002800080004B +:100F800080028000800200028003400EB00EA00D9F +:100F9000A00EA00EA00EA00EA00EB00EA00EA00ED1 +:100FA000A00EA002A000A002A00EA0000000000061 +:100FB00000000042000000000000000000000000EF +:100FC00000000004000100004000000000000000DC +:100FD00000000000000400000000000000002020CD +:100FE000000240024002400240343434343434348D +:100FF00034343834383404043400202020204000B5 +:10100000A9148D8302A90085388D820220B5F4AD24 +:101010008402291F854018691F8541A236BD00D072 +:101020009D0021CA10F7A9018583868220B5FF2083 +:101030003AF42065FCA901857BA2FF9AE8867C86AC +:101040007D20D0F420A6F120DBF420A5FA20E8F4DE +:10105000A57629FE8576A57BC904F00DA57638E531 +:1010600077C90290F7A5768577E67DD002E67C20E9 +:101070002BD620BED12007FAA57BC905F076C9037F +:10108000F048C902F07AC901F006C904F04ED0C098 +:10109000A5B93007A2FF86FECA86FFA5BF2908F0C2 +:1010A00013AD800205FF25FE85FE3826FFC9F0D06E +:1010B000034CA2D2A57CD00B205AD120EFF920CB33 +:1010C000D19016C902D0F74CE1D1A57CC904D00358 +:1010D0004C09D220F3F720CBD14C50D020C5FFA62D +:1010E00055E8E00CB00B8655AAD0F120CBD14C507E +:1010F000D04C0ED220F3F7206ED120D8D14C50D056 +:10110000A57CC907F0CA2021D2205AD1A20A8A1888 +:101110006583A82037FAA20BA90F186582A820378B +:10112000FA20B1F9A9FF85988599A20CA016A5828D +:101130003012C8A582F008C902D002C8C8C8C820A9 +:1011400037FAC8E82037FAA50C100CA5093008A515 +:10115000BF4AB0034C50D04CFBD1A209A0092037A4 +:10116000FA88CA10F9A90E85F1A90785F360A5BF11 +:101170002908F02DA906857BA9008519851A857C8B +:10118000857D242830FC242810FCE67DD004E67CF4 +:10119000302220BED12908F009A905857BA9408508 +:1011A0003C60AD800249FFD00FA50C250D10092031 +:1011B000D8D190CEA960D002A940853CD0B6AE82ED +:1011C000028A45BE25BE85BF86BE60A5BC102CAD7B +:1011D000800229F049F0D012A5BF4AB01E4AB00AD9 +:1011E00060A9008555A9044C37D0A91085FAA9003B +:1011F000855285538554A9024C37D0203AF4204FAC +:10120000F420B1F9A9054C37D0A9014C37D0A90079 +:1012100085528553855420B1F9204FF4A9034C37EA +:10122000D0AD800229F049F0D028AD82022902F029 +:1012300005A90085FA60C6FA1061A21086FA20712D +:10124000D2D058A90085832063D2D04FA9FF8582D0 +:10125000D03EC6FA1045A21086FA0AB0140AB01B96 +:101260000AB022A682E001F032E8BD9ED28582104B +:101270001FA583C903F024E6831015A583C900F0D8 +:101280001AC683100BA682E0FFF010BD9CD28582A7 +:10129000A900857C857D20B5FFA91160FF020002B1 +:1012A0001101A208A0B2948CBD16FD9DD71AADE81D +:1012B000F39D2E19CA10EFA5762903D00CA5764808 +:1012C0004A8576204DDA68857620A5FAA9728DD1F7 +:1012D00018A9DE8D3719A94A8DE01A2024FA202B8F +:1012E000D620BED120CBD190CE488A489848D8A5E8 +:1012F00078D031AD9E1A100D297F8D9E1A20CDF128 +:10130000E6764C24D3AD0120186D00208D0020908E +:1013100008AD9E1A09808D9E1A20BCFA20CDF1E6F8 +:10132000762076FA68A868AA6840A679B57EF001AA +:1013300060A68BBD5918100549FF1869018555BD78 +:101340009B18100549FF1869011865558555A909AD +:10135000E5558555A679B5BA3003203ED5A5BDA67D +:1013600079F0040A0A0A0A0A48B003208FD3680AEF +:1013700048B0032087D3680A48B006204DD520B76F +:10138000D5680AB01F9057B5C138E5554C94D3B510 +:10139000C118655595C1A48B4A4A4A29FE1869B5FA +:1013A00099461960A582C901300DA57E057FD00739 +:1013B000A5BD3DA7D6F005A91120B7F1A5790A0A68 +:1013C000A8A90099E900204DD520B7D5A679B5B8D0 +:1013D0003007B5DBD0074C92D4A90095DB60A9118A +:1013E000205EF1A5790A0AA8A94F99E900A679B566 +:1013F000C14A4A4A4AA8A68BBD38188556BD591815 +:101400004A66564A66564A66564A6656BD7A1885F0 +:1014100057BD9B184A66574A66574A66574A6657E9 +:10142000B91DFE100AA6561014C5569010B008A695 +:1014300056300AC556B006204DD54C55D4B9DDFD01 +:101440000A0A0AA68B187D38189D3818BD591879D4 +:10145000FDFD9D591898186910A8B91DFE100AA61F +:10146000571014C5579010B008A657300AC557B08A +:101470000620B7D54CCCD3B9DDFD0A0A0AA68B18D5 +:101480007D7A189D7A18BD9B1879FDFD9D9B184C9F +:10149000CCD3A582C901100AA203B5A83014CA1082 +:1014A000F960A679F002A202B5A83006E8B5A83026 +:1014B0000160A479B9C1004A4A4A4AA8A90695A878 +:1014C000A9EC95DF8655A68BBDBC18A6551879BD2D +:1014D000FDC99F9002E99F9DC018A68BBDE018A68C +:1014E000551879CDFDC9BF9002E9BF9DE418A68BC0 +:1014F000BD0419A6559D0819A68BBD2519A6559D95 +:101500002919B9DDFDA68B187D5918A6559D5D18C2 +:10151000A68BBD3818A6559D3C18B9EDFDA68B18B5 +:101520007D9B18A6559D9F18A68BBD7A18A6559D24 +:101530007E18A90E206BF1A679A90195DB60A6792A +:10154000B57ED008A902957EA92C958060A68BBD9A +:1015500038181D5918F05FBD38180A8556BD59183E +:101560002A8555BD38181865568556BD591810037B +:10157000FE591865558555A679BD921A38E5569DD0 +:10158000921AA68BBD3818E5559D3818BD5918E933 +:10159000009D5918A90085F8BD5918F00E18690169 +:1015A000D014BD3818C9E0900DB007BD3818C92057 +:1015B000B004A90185F860A68BBD7A181D9B18F0B0 +:1015C00069BD7A180A8556BD9B182A8555BD7A18BB +:1015D0001865568556BD9B181003FE9B18655585EA +:1015E00055A679BD941A38E5569D941AA68BBD7AF6 +:1015F00018E5559D7A18BD9B18E9009D9B18BD9B69 +:1016000018F00E186901D022BD7A18C9E0901BB0FD +:1016100007BD7A18C920B012A5F8F00EA9009D38B0 +:10162000189D59189D7A189D9B1860AD800285BD44 +:10163000A2012068D6CA10FAA5B885BCA57BC9034B +:10164000D025A9FF85B885B985BA85BBA576290CB3 +:10165000D015A5764A2901AAA97F95B820AEF82908 +:1016600007AABDA9D685BD60B40C1019A5C03DA3BD +:10167000D6D01C8A0AA8B9090049FF95B8B9080054 +:1016800049FF95BA60A5C01DA3D68D820285C0947E +:10169000B8A9FF95BAA5BD3D14D8DDA5D6D0E5A95A +:1016A0007FD0DF0410D00D01107FBFEFF7FBFEFFEE +:1016B000EEA679B57EF01F100160D680C901F05505 +:1016C000C902D0034C16D8C904D0034C98D8C9031A +:1016D000D0034CBBD860A5FCF0FB20FBD630F6C590 +:1016E00079D0F2AAA904957EA9FF85FCA90095529C +:1016F000A90D8D121BA9002070F160A200B546D57E +:101700004A900CF002B00BE8E005D0F1A9FF60A907 +:101710000160A90060A48BB9A4003010A905A47BC6 +:10172000C005D003A5760A205AFAA679B580C979F2 +:10173000F00BC951F011C929F062901060A582C95F +:1017400001100320E5DF60A9FF85AE60A57BC90518 +:10175000D010B5B835BA1020AD800249FF3D14D87D +:10176000D016B580C901B00FA58B186918AA20380A +:10177000F9F005A679F68060A90220B7F1A9032047 +:1017800070F1A5790A0AAABDF8FC95EABDF9FC95A5 +:10179000EBA679A90195DBA900957E60A5A530038C +:1017A000F68060A57BC903F016A582C901D00BA500 +:1017B00054C901B003F68060A202D65220C3DFA94B +:1017C000022070F1A68BA9009D59189D9B189D3889 +:1017D000189D7A188D131BA582C9013007A479B909 +:1017E00012D81002A9509DBC18186DFCF39D8A19DF +:1017F000A9509DE018186D03F49DB619A679B5C1DE +:101800004A4A4A29FE1869B5A68B9D4619A923950F +:10181000A4603070F00FB580C929F005C901F01B34 +:1018200060A9012070F1A68BA9FF95A4A9009D389D +:10183000189D59189D7A189D9B1860A91818658BDA +:10184000AA20AEF84A690D9DA41820AEF84A691086 +:101850009DC8182038F9F005A679F6806020AEF80A +:10186000C932B022A91818658BAAA9A3958CADE935 +:10187000F39D2E19A9052070F1A679A903A67995E3 +:101880007EA9DE958060A9032070F1A923A6559555 +:101890008CA679A900957E60AD121BEE121BC920A3 +:1018A000F012C92ED0034C7BD82CF7F9F002491F57 +:1018B000205AFA60A68BA9FF95A460B580C9B6F03E +:1018C0004BC9A6D0034CA3D9C9A1D0034C6DD9C92B +:1018D00071F015C961F02CC901D00C20A6F120DBF4 +:1018E000F420B8FF4C09D260A9FF85AE85AF8A49C4 +:1018F00001A8A9FFD97E00F0EE957EA582D0E84C24 +:10190000A3D960A20220E5DF208BDF6020AEF1A921 +:101910001120B7F1A679A482A554C001F002B552F6 +:10192000C9019011C000D03A8A4901AAB552C90133 +:10193000B0B54C42DAC0FFF01EC001D01E8A49018A +:10194000AAB57EC901D01BA58B4908A8B9A400C9B6 +:1019500023F00FA9FF957EA964D002A9A4A67995CA +:101960008060A679A901957EA92C958060A679A5AD +:10197000FC3029F01620FBD6AA1021AD131BD00491 +:10198000A6791018A9FF85AE85AF6020E5DFA20219 +:1019900020E5DFA682E002D00286FC6020E5DFA21F +:1019A0000310ED8A4901AA8579F002A908858BA95F +:1019B000FFA20795A4CA10FBA90085FBA95085E4E6 +:1019C000A99285E585E620A6F1A017B68CB9001886 +:1019D000998C008A990018BE2E19B95219992E199E +:1019E0008A995219BED71AB9FB1A99D71A8A99FB44 +:1019F0001ABE4118B9CA199941188A99CA19BE83E1 +:101A000018B9EA199983188A99EA19BE2018B94AAF +:101A10001A9920188A994A1ABE6218B96A1A9962E4 +:101A2000188A996A1ABEA418B90A1A99A4188A9928 +:101A30000A1ABEC818B92A1A99C8188A992A1A887F +:101A40001089A679A901957EA999958060A020B9F1 +:101A50008C001031C9FFF02D980A65764A2903D011 +:101A600024B98C00290FAAB92E19DDEEF3D00FE0AE +:101A700003B004A679D6C5A9FF998C003007187D5C +:101A800089DA992E198810C7600102030201020049 +:101A9000A5FD3002C6FDA220B58C3016BCC6DDB94E +:101AA0008C00300B865884594CB8DAA658A4598853 +:101AB00010EDCAE01810E160BD721938F97219B062 +:101AC0000449FF6901C992900FE019F00BC019F0A9 +:101AD0000738E9A049FF6901C90AB05C8555BD9E78 +:101AE0001938F99E19B00449FF6901C9AE9006E999 +:101AF000C049FF6901C90EB03F8556186555855725 +:101B0000B58C290F855AB98C00290F855B845EA896 +:101B1000B9F7DDA45A79F7DDC557301AB9E7DDA466 +:101B20005B1879E7DDC555900DB9EFDDA45A18793A +:101B3000EFDDC556B022A45EC028F00CB016E02838 +:101B4000F03AE0259036B008E0259030B000A02BA8 +:101B5000CA4CB8DA884CB8DAA920A482C001300295 +:101B6000A91E8555A45EE020F015E018F04FC018BE +:101B7000F031A658A45920D1DC4CB2DA4CABDAA52E +:101B80007FD0F9A582C902F004C01CB0EFA22720C3 +:101B900014DCC018D024A582C902F007A57ED0DCD1 +:101BA0004C8BDDA57ED0D5E01C900AA582C901F042 +:101BB000CBE45590C7A02B20C5DB4CB8DAA57ED06E +:101BC000BBA22BD0F2865DA5C14A4A4A4AAABDBD36 +:101BD000FD186DBC188D9A19BDCDFD6DE0188DC630 +:101BE00019BD1FDE6DBC188D9B19BD2FDE6DE01871 +:101BF0008DC719BDFFDD6DBC188D9C19BD0FDE6D45 +:101C0000E0188DC819AD8A198D9D19ADB6198DC909 +:101C100019A65D60865DA5C24A4A4A4AAABDBDFDB5 +:101C2000186DC4188D9619BDCDFD6DE8188DC219BB +:101C3000BD1FDE6DC4188D9719BD2FDE6DE8188DA0 +:101C4000C319BDFFDD6DC4188D9819BD0FDE6DE899 +:101C5000188DC419AD92198D9919ADBE198DC5197C +:101C6000A65D60865DB58C0980958C290F855BC962 +:101C700006B020C904B025C903B041690A48A90AC1 +:101C800020B7F1A90B20B7F1A90C20B7F16820709B +:101C9000F1A65DA45BB9E6F39D2E1960AA38E902AE +:101CA000209AF8E004D008A5E7C9049002C6E78AA4 +:101CB00018690248690220B7F16810D2A55DA20038 +:101CC000C920D001E8A903957EA9DE9580A9051059 +:101CD000BD2063DCA55B855AA6592063DCA65BA406 +:101CE0005820F2DCA65AA45920F2DCC0189024A691 +:101CF0005860C4551019C01C100DC018D010E00356 +:101D0000D005A9118D131BA579857A203FDE60A926 +:101D10000110F6B98C0038E991301F855CA9508517 +:101D2000E4A583F010C9039009A5402903D003203E +:101D30003BDD203BDD203BDDA65860A217B58CC9FA +:101D4000FFF004CA10F760B9EC189DEC18B9A4189C +:101D50009DA418B90D199D0D19B9C8189DC818B9B9 +:101D600072199D7219B99E199D9E19B9D71A1869D1 +:101D7000019DD71AA55C958C290FA8B9F6F39D2E65 +:101D80001920F5F8A679F6C5A45960A5FD1048AD4F +:101D90005918C9806A48AD38186A48AD6118C980B9 +:101DA0006A8D5918AD40186A8D3818688D401868CA +:101DB0008D6118AD9B18C9806A48AD7A186A48AD24 +:101DC000A318C9806A8D9B18AD82186A8D7A18682D +:101DD0008D8218688DA318A90185FD4CABDA171800 +:101DE0001818191919191D02040503020401010329 +:101DF00006080602030101030609060203020101A7 +:101E0000000001010203040505060505040302059F +:101E100007090B0C0D0E0E0D0B0907060504040532 +:101E20000403020101000001020304050506050583 +:101E30000404050607090B0D0E0E0D0C0B0907A572 +:101E40007BC905D0102056DEA582C901D007A902A2 +:101E5000857A2056DE6086628463A57A0A0AA8F82D +:101E600018BDADFD794900994900BDB5FD7948001F +:101E70009948009024A582C901D006A57AC902D04C +:101E800017D8A900209AF8A67AF652200DDFA904E7 +:101E90002070F1A57A0A0AA838A900F879470099B4 +:101EA0004700A900794600994600D820B7DEA6620F +:101EB000A4636086628463A57A0A0AAA0A0A856412 +:101EC0008A1869048561B5464A4A4A4AD01F2003E8 +:101ED000DFB546290FD0202003DFE8E46130E7A911 +:101EE00001C6642005DF60B5464A4A4A4A186901BE +:101EF0002005DFB546290F1869012005DFE8E461F8 +:101F000030E560A900A46499141BE66460A67A8A8F +:101F10000A0A0A0A186908A8A90099141BC8846447 +:101F200099141BC899141BC899141BC899141BA693 +:101F30007AB552F00FC9059002A904AAA90B200591 +:101F4000DFCAD0F860A2008664B5424A4A4A4AD045 +:101F50001A2081DFB542290FD01B2081DFE8E00481 +:101F600030E74C80DFB5424A4A4A4A18690C208360 +:101F7000DFB542290F18690C2083DFE8E00430E563 +:101F800060A900A46499441BE66460A000A58230A7 +:101F90000DA008C901F007A00020A5DFA00420A51E +:101FA000DF2045DF60A200B94600D5429014F00C56 +:101FB0009542C8E8B94600E00490F560C8E8E0043E +:101FC00090E560A582C901D008A902857A200DDFBD +:101FD00060A900857A200DDFA582100160A9018526 +:101FE0007A200DDF60A57BC905D0F98A186912A88F +:101FF0008AC902B004A2221002A2234C37FA0000C0 +:1020000000A8A8A8A808A8A820A8A8000000000068 +:1020100000000000000000000000000000000000C0 +:1020200000000000000000000000000000000000B0 +:102030000000000000000000000000000000003F61 +:10204000F03FF003FFFFF0003FC000FFFFFF00FF85 +:10205000C0FFC0FFFFFFC0FFF03FFFFF0003FFFF17 +:10206000F0000000000000411541411545504410AA +:1020700010154411011545411040405555111005EA +:1020800051040400551045500401544101015441CC +:102090000401105500401544101015441154040556 +:1020A000510440404015441010551544044015405B +:1020B00040404045510400401544101000055000B8 +:1020C0000000000000000000000000000000000010 +:1020D0000000000041150141044115455150200AFE +:1020E00000020200A8002A8200008008A000002848 +:1020F00000288200FFFFFFFFFFFFFFFFFFFFFFFF42 +:1021000000882080080808882088080C000000004B +:1021100000000000000000000000000000000000BF +:1021200000000000000000000000000000000000AF +:102130000000000000000000000000000000003F60 +:10214000F03FF003FFFFF0003FC000FFFFFF00FF84 +:10215000C3FFC0FFFFFFC0FFF03FFFFFC003FFFF53 +:10216000F0000000000000451045511004004450EC +:10217000101004510110041115404040401110048A +:1021800001140400411144000401005501010045FF +:10219000040444410040100550101004500404048D +:1021A00001544040401005501040104404401000BD +:1021B000404040441114004010055010001004002D +:1021C000545515455001040404110440055154416F +:1021D000100400005510455154451004010488288E +:1021E00082888888820080820000202A88000082FD +:1021F00000820200FFFFFFFFFFFFFFFFFFFFFFFF67 +:10220000008820800808088820880838000000001E +:1022100000000000000000000000000000000000BE +:1022200000000000000000000000000000000000AE +:102230000000000000000000000000000000003569 +:10224000703570035555700035C000D5555700D511 +:10225000CFD5C0D55555C0D570355555C00355554A +:102260007000000100000055104411100540455059 +:102270001015054111150411104040545404154522 +:10228000415004004115454005410041054150546D +:102290000404444100541004105415054050040532 +:1022A0004104444054100410544010444455150057 +:1022B0004040404411540055100410540011440093 +:1022C000100110401001540405511440040104454C +:1022D00010040000411044110455100541048220EF +:1022E000822888220002802000002AA208000082A2 +:1022F00000820200FFFFFFFFFFFFFFFFFFFFFFFF66 +:102300000088208008A808882088A8A8000000006D +:1023100000000000000000000000000000000000BD +:1023200000000000000000000000000000000000AD +:102330000000000000000000000000000000003568 +:10234000703570035555700035C000D5555700D510 +:10235000CF5700D55555C0D57035555570035555D7 +:1023600070000000000000511044111004004510DE +:102370001010041145100411104040404011104449 +:1023800001040400411444000411004114510041AF +:1023900004044441004110041145100411000404D8 +:1023A00001045140411004114540104514411000F2 +:1023B0004040404411440041100411450011040004 +:1023C00010551545500104040411504004010454F3 +:1023D00015000000411044110451100401048280D2 +:1023E0008A088822A802002008080A8008020082C1 +:1023F00000820000FFFFFFFFFFFFFFFFFFFFFFFF67 +:10240000008820A82888A8A808A888E8000000005C +:10241000000000000000400551010101544040014E +:1024200050400551010101544040015455444115AB +:1024300040554404404550055010154404AAAAB51F +:10244000703570A80035702AB5C2AAD5555708D581 +:10245000CF5402D5C2D5C2D542B5555570AA003564 +:1024600072AAA800000000411544111545504411FE +:10247000551545510115454105055455551115454D +:1024800051545540551045500551001410115455E4 +:102490005544045500551001410115455154554509 +:1024A0005050404055100141015515440455154503 +:1024B0005445544551040055100141010011440098 +:1024C000504110441001040404110440040104416B +:1024D0001040000014150410504115455150228041 +:1024E0002208882202080020022880000A8A00822E +:1024F00000820000FFFFFFFFFFFFFFFFFFFFFFFF66 +:10250000008820080888808008888828000000004B +:1025100000000000000040040101010100404000F3 +:1025200040400401010101004040010044444100D9 +:1025300040404404404400041044100404000035AA +:10254000F03D7000003D700035C000D5C00000D7E0 +:10255000CF5C00D5C0D5C035C03570157000003DCA +:1025600070000000000000000000000000000000FB +:10257000000000000000000000000000000000005B +:10258000000000000000000000000000000000004B +:10259000000000000000000000000000000000003B +:1025A000000000000000000000000000000000002B +:1025B0000000000000000000000000000010040007 +:1025C0001055154550005055414154400551545542 +:1025D000154000000000000000000000000008801E +:1025E0002088882202080020028228A808A08022D1 +:1025F00000820200FFFFFFFFFFFFFFFFFFFFFFFF63 +:1026000000A8A0A8A880A8A8A8A8A8080000000062 +:1026100000000000000040040101010100404000F2 +:1026200040400401010101004040010044444500D4 +:10263000404044044044000411011004040AAAB7B5 +:10264000FFFF70BFFFFF702AB5C2AAD7C00008DF26 +:10265000FFDF02D5C2D5C2B5C2B570BD70BFFFFFE6 +:1026600072AA8000200000000000000000000000AE +:10267000000000000000000000000000000000005A +:10268000000000000000000000000000000000004A +:10269000000000000000000000000000000000003A +:1026A000000000000000000000000000000000002A +:1026B00000000000000000000000000000055000C5 +:1026C000000000000000000000000000000000000A +:1026D000000000000000000000000000000000807A +:1026E000208888220200008002022288A880802A96 +:1026F00000820200FFFFFFFFFFFFFFFFFFFFFFFF62 +:1027000000000000000000000000000800000000C1 +:1027100000000000000040040101010100404000F1 +:1027200040400401010101004040010044444500D3 +:1027300040414404404400041101100404000035E9 +:10274000555570355555700035C000DFFFFF00D579 +:102750005555C0D5C0D5C035C035703570355555C7 +:1027600070000000000000000000000000000000F9 +:102770000000000000000000000000000000000059 +:102780000000000000000000000000000000000049 +:102790000000000000000000000000000000000039 +:1027A0000000000000000000000000000000000029 +:1027B0000000000000000000000000000000000019 +:1027C0000000000000000000000000000000000009 +:1027D0000000000000000000000000000000008079 +:1027E00020282020A8002A800082208A0820800A31 +:1027F000A8820200FFFFFFFFFFFFFFFFFFFFFFFFB9 +:1028000000000000000000000000000000000000C8 +:10281000000000000000554401551551545540007A +:1028200040554401551551545540015440445115EB +:102830004040055440455004110115455400AAB5C7 +:10284000555570B55555702AB5C002D5555708D5A0 +:102850005555C2D5C2D5C2B5C0B570B570B55555C0 +:1028600072A800000000000000000000000000004E +:102870000000000000000000000000000000000058 +:102880000000000000000000000000000000000048 +:102890000000000000000000000000000000000038 +:1028A0000000000000000000000000000000000028 +:1028B0000000000000000000000000000000000018 +:1028C0000000000000000000000000000000000008 +:1028D0000000000000000000000000000000008078 +:1028E000200000000000AA00008220820820800250 +:1028F00002820200FFFFFFFFFFFFFFFFFFFFFFFF5E +:102900000000000000000000000000005454545477 +:10291000045454105454404401011011004100006B +:102920004040440101101100410000044044511096 +:102930000040440444440004110110041000003518 +:10294000555570355555700035C000D5555700D5D3 +:102950005555C0D5C0D5C035C035703570355555C5 +:1029600070000000000000000000000000000000F7 +:102970000000000000000000000000000000000057 +:102980000000000000000000000000000000000047 +:102990000000000000000000000000000000000037 +:1029A0000000000000000000000000000000000027 +:1029B0000000000000000000000000000000000017 +:1029C0000000000000000000000000000000000007 +:1029D0000000000000000000000000000000008077 +:1029E00080000000000080000088088208220002A9 +:1029F00000820200FFFFFFFFFFFFFFFFFFFFFFFF5F +:102A0000000000000000000000000000441040042E +:102A1000040444104404404401011011004100002A +:102A200040404401011011004100000440444110A5 +:102A300000404404444400041101100410000AB58D +:102A4000703570B5700002AAB5C002D5C00008D5B7 +:102A5000C0D5C2D5C0D5C2B5C0B5703D70B5700087 +:102A60000A80000000C0000000000000000000001C +:102A70000000000000000000000000000000000056 +:102A80000000000000000000000000000000000046 +:102A90000000000000000000000000000000000036 +:102AA0000000000000000000000000000000000026 +:102AB0000000000000000000000000000000000016 +:102AC0000000000000000000000000000000000006 +:102AD0000000000000000000000000000000008076 +:102AE000800000000002000000A008820828000208 +:102AF00000800200FFFFFFFFFFFFFFFFFFFFFFFF60 +:102B0000000000000000000000000000441040042D +:102B100054044410445455440155101154550001B7 +:102B2000405544015510115455000154404441157D +:102B30004055455455455005510115455000003547 +:102B4000F03D7035F000000035C000D7C00000D760 +:102B5000C0F5C0D7C0F5C035C035F03F7035F000C6 +:102B60000000000000000000000000000000000065 +:102B70000000000000000000000000000000000055 +:102B80000000000000000000000000000000000045 +:102B90000000000000000000000000000000000035 +:102BA0000000000000000000000000000000000025 +:102BB0000000000000000000000000000000000015 +:102BC0000000000000000000000000000000000005 +:102BD000000000000000000000000000000008826B +:102BE0000000000000020020002002820008008295 +:102BF00000800200FFFFFFFFFFFFFFFFFFFFFFFF5F +:102C00000000000000000000000000004410541408 +:102C1000445454045444000000000000000000002C +:102C200000000000000000000000000000000000A4 +:102C3000000000000000000000000000000000B7DD +:102C4000FFFF7AB7FFFFA8FFFDFFFADFFFFFA8DF56 +:102C5000FFFDEADFFFFDEAFDFAB7FFF57AB7FFFFF8 +:102C6000A8000000000000000000000000000000BC +:102C70000000000000000000000000000000000054 +:102C80000000000000000000000000000000000044 +:102C90000000000000000000000000000000000034 +:102CA0000000000000000000000000000000000024 +:102CB0000000000000000000000000000000000014 +:102CC0000000000000000000000000000000000004 +:102CD000000000000000000000000000000002886A +:102CE0000000000000020020000000000000202280 +:102CF00000820208FFFFFFFFFFFFFFFFFFFFFFFF54 +:102D00000000000000000000000000004410040467 +:102D10004440400444440000000000000000000063 +:102D200000000000000000000000000000000000A3 +:102D3000000000000000000000000000000000355E +:102D400055557035555700D5555570D5555700D543 +:102D50005555C0D55555C0D5703555557035555755 +:102D60000000000000000000000000000000000063 +:102D70000000000000000000000000000000000053 +:102D80000000000000000000000000000000000043 +:102D90000000000000000000000000000000000033 +:102DA0000000000000000000000000000000000023 +:102DB0000000000000000000000000000000000013 +:102DC0000000000000000000000000000000000003 +:102DD000000000000000000000000000000000A053 +:102DE0000000000000008080000000000000200AB9 +:102DF00000820202FFFFFFFFFFFFFFFFFFFFFFFF59 +:102E00000000000000000000000000005450545476 +:102E100040545454545400000000000000000000CE +:102E200000000000000000000000000000000000A2 +:102E3000000000000000000000000000000000355D +:102E400055557035555700D5555570D5555700D542 +:102E50005555C0D55555C0D570355555C035555704 +:102E60000000000000000000000000000000000062 +:102E70000000000000000000000000000000000052 +:102E80000000000000000000000000000000000042 +:102E90000000000000000000000000000000000032 +:102EA0000000000000000000000000000000000022 +:102EB0000000000000000000000000000000000012 +:102EC0000000000000000000000000000000000002 +:102ED00000000000000000000000000000000020D2 +:102EE0000000000000008280000000000000200AB6 +:102EF00000800202FFFFFFFFFFFFFFFFFFFFFFFF5A +:102F000000000000000000000000000000000000C1 +:102F100000000000000000000000000000000000B1 +:102F200000000000000000000000000000000000A1 +:102F3000000000000000000000000000000000355C +:102F400055557035555700D5555570D5555700D541 +:102F50005555C0D55555C0D57035555700355557C1 +:102F60000000000000004000000000000000000021 +:102F70000000000000000000000000000000000051 +:102F80000000000000000000000000000000000041 +:102F90000000000000000000000000000000000031 +:102FA0000000000000000000000000000000000021 +:102FB0000000000000000000000000000000000011 +:102FC0000000000000000000000000000000000001 +:102FD00000000000000000000000000000000008E9 +:102FE00000000000000028000000000000000802AF +:102FF00000800002FFFFFFFFFFFFFFFFFFFFFFFF5B +:103000004041424446480A090807060504030201F4 +:10301000FF4D03020102032098FEBC0D241F1D1B5F +:103020001A18171514131211100F0E0D2C860A857D +:103030000806900402FF06040105020301060405C8 +:103040000203040103254501010203040608080CDC +:103050000F0FFF861F181F9514FF080008000800B7 +:10306000FE075F88034909070907FE0B8A09430722 +:10307000230F0307234B515A030F12131314141574 +:10308000161617FF03050784060504820302010CC8 +:103090000D0E0F101112131415161718191A1B1CE8 +:1030A0001D1E1FFF82FE075309FF54100E0D0E0C4C +:1030B0000E0F2E10130C0805030221A007050301B3 +:1030C000FF07210102030405060708FE080905079A +:1030D0002A8C07000500030001FF1A122D9BFEBC7D +:1030E0000400040004008A000400040004008504B5 +:1030F00000040004FF04062692010203FE0C1112D4 +:1031000018031B1D2D010336460205004703035318 +:103110005A030562060905636603056C66046F00C1 +:103120000303710203050575080405760806057793 +:10313000070803788402038FA40104A7A80604AA41 +:10314000A80604AB030203B3BB0403C1C30803CD49 +:10315000D10303DADD090100E00501F5F806A2015B +:10316000D5CDF006CA10F92070F1604820B7F1689B +:10317000A201B4CD3011CA10F9C910B009A201D50D +:10318000CD9004CA10F96095CD0A0AA8B9FEF09551 +:10319000CFC8E8E8E00690F4B9FEF0CACA30E79D6F +:1031A0008A1A95D510F5A20120C1F1CA10FAA920FA +:1031B00085CAA99085CB60A201D5CDF004CA10F9CB +:1031C000608A2901AAA0FF94CDC8941960A57BC983 +:1031D00005D0B3A5A53008290F186904205EF1A217 +:1031E000018A48B5CD300320F0F168AACA10F26018 +:1031F000B4CFB900F0C9FFF0C8C9FEF035C9FDF081 +:103200003AC980B021291F9515D6D5D012BD8A1A8A +:1032100095D5B900F0C940B006C920B02AF6CFE86C +:10322000E8E00690CB60297F9D8A1A95D5F6CF4CB1 +:10323000F0F1C8B900F095CF4CF0F1C8B900F048F2 +:1032400020C1F1684C70F18A2901A8B9CD000A0AA1 +:1032500085658A4A186565A8B9FEF095CF4C1FF2BE +:10326000A5762906D00D20AEF8C906B00618691259 +:103270002070F1E6CBD010A99085CBC6CAA5CAC9EB +:1032800005B004A90585CAC6C91010A5CA85C9A577 +:10329000CC490185CC18690F2070F160A220B58C53 +:1032A0001004CA10F960290FA818BD20187DEC1869 +:1032B0009DEC18BD41187DA418C99F9010E019F02D +:1032C0000CBD41183005A9004CCDF2A99F9DA41852 +:1032D0001879F9F39D721918BD62187D0D199D0DAD +:1032E00019BD83187DC818C9BF900CBD831830055F +:1032F000A9004CF7F2A9BF9DC818187900F49D9E4B +:1033000019C003B09DB58C30998A0A65764A3DC2D2 +:10331000F3D08FBDAAF33039C0019024F011A8BDBD +:103320002E196902D9DBF33069B9DAF34C92F3A8AC +:10333000BD2E196901D9DFF33058B9DEF34C92F391 +:10334000A8BD2E196901D9E3F33047B9E2F34C92D5 +:10335000F3297FC001902AF014A8BD2E19E903D9E2 +:10336000DAF3102EB9DBF338E9034C92F3A8BD2E43 +:1033700019E902D9DEF3101AB9DFF338E9024C92E9 +:10338000F3A8BD2E19E900D9E2F31006B9E3F3382A +:10339000E9019D2E194CA2F2A205B5A63008F6DD72 +:1033A000D004A9FF95A6CA10F160008001810282B5 +:1033B00000800181028200800181028200800181FF +:1033C0000282010300010300010300010300030066 +:1033D000010300010300010300010024486C7B8B02 +:1033E0009BABEDF1F5F9F9AB6CD5F9ABFED5FDB3BF +:1033F00078DFFDB3FEDFED7B00020305030203006F +:103400000D0A08090D0C00A9FFA217958CCA10FB24 +:10341000A479B6C5CAA932958CBDAAF3297FA8B9EB +:10342000DAF39D2E1920CFF820F5F8CA10E7A22074 +:10343000BD16FD9DD71ACA10F760A20BA9009546CC +:10344000CA10FB60A90085428543854485456020FC +:10345000A6F1A907AA95B0CA10FBA483B9B1F48557 +:1034600084C898A20395850ACA10FAA903855285D3 +:1034700053A9068554A9FF85C385C485FDA9008588 +:10348000C585C68579858B85C185C285FB85FCA9E7 +:1034900001857EA9208589858AA5821009A9FF85D5 +:1034A0007FA939858060A901857FA97A858085817A +:1034B00060406080DFA900A88555A21F86569155FF +:1034C00088D0FBCAE017D0F4A2BE9541CAD0FB60F9 +:1034D000A20FBDF6FC95E8CA10F860A223A9FF95DB +:1034E0008C9D0018CA10F860A23FBDBAFC9D981AC6 +:1034F000CA10F7242810FCA91A852CA9008D971A48 +:103500008578A9E08534A940853C6060A5A5300395 +:103510004CC0F5C9FFD0F4A583F0F0A582C90130F5 +:1035200008A57E257FD0E4F006A679B57ED0DCA57F +:10353000762902D0D6A679B5C5F0D0A4E4F002C6AB +:10354000E4C6E6D0C6E6E6C000F004D5C7B0BCA528 +:10355000E538E906C914900285E5A5E585E6A915D3 +:1035600085E320AEF84A69108DE118AE2FFDA582E3 +:10357000C901D004A0081005A5790A0AA8B9470016 +:10358000C902B010A5E5301120AEF88555A5E54A71 +:10359000C555B005E8A014D002A02584A58EF01A68 +:1035A00020AEF84A9009A9A38DBD18A9FF3007A93C +:1035B000FC8DBD18A9018D5A18A9008D3918F0226B +:1035C000A576C9FE9034A583C901F01620AEF8C9CE +:1035D000AAB019C955B019ADE118C9ABB01CC90AD8 +:1035E0009018A9008D9C188D7B18F00EA9FF300251 +:1035F000A9018D9C18A9008D7B18AD5A18186DBDB6 +:1036000018C9A39013C9FDB00FA9FF85A5A908206B +:10361000B7F1A90920B7F160A201B5A63005CA101B +:10362000F93059C6E3D055A92085E3A90695A6A986 +:10363000EC95DDAD8B19C99F9002E99F9DBE18AD39 +:10364000B719C9BF9002E9BF9DE218A9009D0619EC +:103650009D2719A5A5C914F03D20AEF8291FA8B9CA +:1036600063F79D5B18B983F79D3A18B9A3F79D9D41 +:1036700018B9C3F79D7C18A90D2070F1A5764A4AA8 +:103680002903A4A5C014F0070A1869E14C92F618A2 +:1036900069E98D471960A900855785588559A58224 +:1036A000C9013018A57E257FF008A57ED00AA000AC +:1036B000100C20AEF80A90F6A0081002A48BB98A6C +:1036C0001938ED8B19B006E65749FF69018555B9E0 +:1036D000B61938EDB719B006E65849FF69018556A5 +:1036E0004A855A4A4A18655AC555B007E659A8A5E9 +:1036F0005584554A4A8556A5554A4A855A4A1865F9 +:103700005A855BA5554A855A4A4A18655AA000C58C +:10371000569006A002A900F002A55518655BC55693 +:103720009001C88455A459F007A90738E555855577 +:10373000A458F007A90F38E5558555A457F007A9F7 +:103740001F38E5558555A5E74A855B20AEF8A45B93 +:10375000395EF7C5E7B0F4655538E55B4C5CF603B8 +:1037600007070F0000010203030404040404030319 +:1037700002010000FFFEFDFCFCFBFBFBFBFBFCFC75 +:10378000FDFEFF00DBAD6E18A30B4A604A0BA318C9 +:103790006EADDB00265493E95EF6B7A1B7F65EE99D +:1037A000935426070606050403020100FEFDFCFBF8 +:1037B000FAF9F9F9F9F9FAFBFCFDFE00010203043C +:1037C00005060600DE78D2F3E4AE5E00A3531D0EBC +:1037D0002F89230123892F0E1D53A3005EAEE4F32E +:1037E000D278DE0123892F0E1D53A3005EAEE4F3D1 +:1037F000D278DEA679B5898D911A4A8D901AB5C511 +:10380000D065A5A5C9FFD05FA57E257FC902B057A9 +:10381000A582D007A48BB9A400304CC6FB1048A9E0 +:103820002585FBF6C3B5C3186902658395C5A483D6 +:10383000B992F8D5C5B00295C595C72065FCA90118 +:10384000209AF8A95085E4A683BD96F8A67938F5A4 +:10385000C3F5C3F5C385E585E6A90985E7A92885EC +:10386000E320AEF12007F420B1D6202AD3A582C9E7 +:1038700001300C20FAF920B1D6202AD320FAF92001 +:103880009CF22098F32090DA204DDA200CF520608D +:10389000F260080C0E1000A7958FA8B98500A479D6 +:1038A00018798900C5849002A58499890060A44094 +:1038B000B9002118A441790021A440990021C640F3 +:1038C0001004A0368440C6411004A0368441602014 +:1038D000AEF84A9010A9BF9DC81820AEF8C999B09B +:1038E000F99DA41860A99F9DA41820AEF8C9BFB087 +:1038F000F99DC8186020AEF82A900FED901A9D200F +:1039000018A9FFE9009D4118B00C6D901A9D201870 +:10391000A9002A9D411820AEF82A900FED911A9D1A +:103920006218A9FFE9009D8318B00C6D911A9D6281 +:1039300018A9002A9D8318608655A900855A855BC1 +:10394000BDA4186DAFF98556E99F9004E65A8556D7 +:10395000BDA418EDAFF9B004E65A699F8557BDC8FC +:10396000186DB0F98558E9BF9004E65B8558BDC86D +:1039700018EDB0F9B004E65B69BF8559A220B58C9B +:103980003027A900BCA418C4562AC4576900455A58 +:103990006A9016A900BCC818C4582AC459690045C1 +:1039A0005B6A9005E455F00160CA10D2A000601077 +:1039B0001A20EFF92045DFA582C901D019A9028597 +:1039C0007A20B3DE200DDFA900857A20B3DEA901BD +:1039D000857A20B3DE60A900857A20B3DE200DDF72 +:1039E000A582300AA901857A20B3DE200DDF60A20E +:1039F00037A9009D141BCA10FA60A5794901857981 +:103A0000F002A908858B6020AEF84A90054A900222 +:103A1000E6F64A90054A9002E6F7A57BC905F0163E +:103A2000C903F012A5764AB00DE660A5602CF7F93F +:103A3000D002491F85F260B939FD9D2E19B973FD79 +:103A40009DA418B990FD9DC818B956FD9DD71AA917 +:103A500007C0169002A923958C60290F1D37FD48D9 +:103A60004A29071D37FDE000F002A20495EB689596 +:103A7000EAA90095E960A21FBDF6FC9520CABDF633 +:103A8000FC9520CABDF6FC9520CACAE010B0E9B585 +:103A9000E89520CAB5E89520CAB5E89520CACA10AD +:103AA000EEE8862060A90185F9A5F9F00E2428101A +:103AB000F8242810F42076FA20BCFA60A904A20B9E +:103AC000956ACA10FBA223B58CF049C9FFF04529BD +:103AD0000FC906D045BDC81849FF290F8569BDC863 +:103AE000184A4A4A4AA8B96A001879A2FC8565B9F9 +:103AF000AEFC8566B96A006904996A00A000A9FE57 +:103B00009165C8A97F9165C8A56909C09165C8BDBF +:103B1000A4189165CA10B04CABFBBDC81849FF2969 +:103B20000F8569BDC8184A4A4A4AA8B96A00187977 +:103B3000A2FC8565B9AEFC8566B96A006904996A1C +:103B400000C8C00C9003A00018B96A0079A2FC85D7 +:103B500067B9AEFC8568B96A006904996A00A0007B +:103B6000BD2E1991659167C8BDD71A91659167C837 +:103B7000B58CC90718D006A56969D1D004A56969B3 +:103B8000B1916569109167C8BDA41891659167C925 +:103B9000979081E019F011C9F0B008E99F9DA41831 +:103BA0004C1AFB699F9DA4184C14FBA000A5751826 +:103BB0006DADFC8565ADB9FC8566A9449165C8A964 +:103BC000609165C8A91B9165C8A9789165C8A93994 +:103BD0009165A582C901D019C8A9349165C8A960A9 +:103BE0009165C8A91B9165C8A9909165C8A939912B +:103BF00065A000A574186DACFC8565ADB8FC856644 +:103C0000A9149165C8A9609165C8A91B9165C8A947 +:103C1000109165C8A9079165C8A9249165C8A960D4 +:103C20009165C8A91B9165C8A9309165C8A965911E +:103C300065A5751869058575A682E001D005186926 +:103C4000058575A57418690A8574A20BA001B56A6B +:103C5000187DA2FC8565BDAEFC8566A9009165CA8C +:103C600010EC85F960A20BBDA2FC8565BDAEFC859C +:103C70006620AEF82903186963A0009165C8BD9657 +:103C8000FC9165C8A9E0916520AEF84A6910A003CF +:103C90009165CA10D2607F9F7F7FBF7FDF7F7FFFEC +:103CA0009FDF008000800080008000800080222252 +:103CB000232324242525262627270F1A960B1A9618 +:103CC0000F1A96071A964F27804F27004F26804FCE +:103CD00026004F25804F25004F24804F24004F237E +:103CE000804F23004F22804F22008F1A960F1A9682 +:103CF0000F1A960F1A960000FDF500009D95008A98 +:103D00007146000F07E5000A060400D7D4D1003938 +:103D1000242100B6B3B09DBDDDFD9DBDDDFD9DBD83 +:103D2000DDFD9DBDDDFD9DBDDDFD9DBDDDFD1E5EA1 +:103D30007F7F7F7F7F7F3EF0903D43474B4F5357C0 +:103D4000595DBC676ED47C84909EA91621312CB538 +:103D5000B5B5B5B5BDCD5A5C5C5C5C5C5E5C5A6863 +:103D6000797276787472756D757574751E1E3E1E47 +:103D70003E1E3E061E2D3D4C5C6C74842306205076 +:103D80007C38373C2941413F4150505030703070B1 +:103D90007272727272727272720013131313505035 +:103DA00050507676686831382C31313131005020EE +:103DB00000000000000100000510020000030405DF +:103DC000060606050403020100000001020E0D0CA8 +:103DD0000A0908060504050608090A0C0D00020375 +:103DE000040504030200FEFDFCFBFCFDFE070605C6 +:103DF0000200FEFBFAF9FAFBFE00020506000000D5 +:103E0000000000000000FFFFFFFFFFFFFF000000B9 +:103E10000000FFFFFFFFFFFFFF00000000000B1886 +:103E20001F201F180B00F5E8E1E0E1E8F533301939 +:103E30000B00F5E7D0CDD0E7F5000B19300040F0CE +:103E40001FBB00008F270078D8A9028501A2FF9A26 +:103E5000A97F853CA9008520A27FBD51FF9D8004DC +:103E6000CA10F7A2ADBDA3FE9DFF22CAD0F7A900DC +:103E7000AA9501E8E02CD0F9A9028501A9FFA23F8B +:103E80009D00209D0021CA10F7A209BD3DFE9D00A6 +:103E900027CA10F7E8A050BD07279D0A27E888D059 +:103EA000F64C0723A91385014CC8FFA9168501A06C +:103EB000FFA27FBD00FED980FDD0E988CA10F4AD15 +:103EC000FCFF2DFDFFC9FFF0DBADFCFF0DFDFFF09A +:103ED000D3ADF8FF09FEC9FFD067ADF8FF49F0295F +:103EE000F0D05EADF9FF290BC903D055ADF9FF291C +:103EF000F0C940904CE901CDFDFFB045ADEA1B494A +:103F0000FF8DEA1BA8A205BDFAFFDDFADFD008CAC3 +:103F100010F5CCEA1BD02AA902850120A423A927E9 +:103F2000852CA9078530A9438578853CA20120A46A +:103F300023CA10FAA960853CA21686019AF86CFC87 +:103F4000FFA90285014C8004242830FC242810FCA1 +:103F500060A900AA85019503E8E02AD0F98502A9A5 +:103F600004EA3023A204CA10FD9A8D100120CB046C +:103F700020CB048511851B851C850FEA8502A900CD +:103F8000EA300424033009A90285098D12F1D01EFC +:103F90002402300CA90285068D18F18D60F4D00E34 +:103FA000852CA908851B20CB04EA240230D9A9FD61 +:103FB00085086CFCFF2044F4A5821002A9000A0ABF +:103FC0001865838555A901602048FF242830FCA985 +:103FD0009EA000A2002428300785248524CAD0F59D +:103FE000E078B004A998A02B85308C01204C00D03B +:103FF00000000000000000000000E9D247FE29D3C5 +:00000001FF diff --git a/Atari - 7800_TeST/rtl/rom/7800pal.rom b/Atari - 7800_TeST/rtl/rom/7800pal.rom new file mode 100644 index 00000000..51d0d12f Binary files /dev/null and b/Atari - 7800_TeST/rtl/rom/7800pal.rom differ diff --git a/Atari - 7800_TeST/rtl/rom/Defender (1981) (Atari).a26 b/Atari - 7800_TeST/rtl/rom/Defender (1981) (Atari).a26 new file mode 100644 index 00000000..d9843f2b Binary files /dev/null and b/Atari - 7800_TeST/rtl/rom/Defender (1981) (Atari).a26 differ diff --git a/Atari - 7800_TeST/rtl/rom/Defender.hex b/Atari - 7800_TeST/rtl/rom/Defender.hex new file mode 100644 index 00000000..c8eda243 --- /dev/null +++ b/Atari - 7800_TeST/rtl/rom/Defender.hex @@ -0,0 +1,257 @@ +:1000000078D8A2FF9AA9009502CAD0FBA2FF8698D1 +:10001000869B203BFD201CFD85A22017FD208CF037 +:10002000A5CBD013A5B4D00620F0F020D6F1202720 +:10003000F220E8F2203CF320EAF32051F520FFF50E +:100040002028F6206EF6205BF420A2F44CC7F6A51B +:10005000CBF00FC884E6C6CBA5CBD02820C3FD20AB +:10006000E3FC20ABF82069F920A2F920FBF9204F2E +:10007000FAA591D00620DDFA2037FB2090FB200C5A +:10008000FC2043FCAD8402D0FB4C1DF0A9FF85028F +:10009000850085018502850285028502A9368D9637 +:1000A00002A000840D8400A27F8601A4A2B9C20030 +:1000B00085C0B9C40085C1A5980A45980A0A269842 +:1000C000A5CBF009A90085BD85BF20ACFCAD8002A1 +:1000D000A4A239DDFF85B3C001D0060A0A0A0A8549 +:1000E000B3A68DD0028691C9F0F004A978858D6001 +:1000F000207BFCA5CD3043C901F073C902F04AC989 +:1001000003F055A6BBB58029F0D03DB580290FC9B5 +:1001100004D035A5AA3031A5CE302DA5A8C5A9D0CB +:1001200027A9FF85CD85C685AFA5AC38E9010A0AA8 +:100130000A0A85C7A5CE85CA86B9A5A32593D00886 +:10014000A5C7C9179020C6C760C5AFB06BA5A329C6 +:1001500003D0F5C6AFC6C760A5ADC91ED0EA858A73 +:10016000A9058599D063E6AFA5AFC90E90DAA5C7FA +:10017000A00184CDC987B010A5A32593D0CAE6C736 +:10018000A5C738E90C85AF60A6B9A9059580A4CAB2 +:10019000A591D035A6A2A931858AB5CF1912FF95B0 +:1001A000CFC9FFD02485CBA207B580290FC904D0C1 +:1001B00002F680CA10F33011A5BAC932F0D0202F50 +:1001C000FDA905859AA9028599A96485CA85B9A959 +:1001D0000085CD85AF60207BFCA4B8BE06FFA5A33B +:1001E0002593D024A589D020C005F004E000D018C4 +:1001F000E6E3A5B0C5AD9004C6E3C6E3F6E0A5A569 +:10020000C5A6B004D6E0D6E0E6E4A5A32907D0163B +:10021000C6C8C6AEC6E2A58B1004E6C8E6C8A59857 +:100220003004E6E2E6E260A591F005A90185CC6024 +:10023000A208A5B4D0F0BD8EFEC5B3F003CAD0F6B7 +:10024000BD97FE8593BDA0FEAAC5CCF012A5A3293B +:100250000FD00EA9FF85B5E000F004A90085E68661 +:10026000CCA5CDC903D008A982C5ADB00285ADA586 +:10027000ADC919D006A5A3291FD040A000A6A2BDD4 +:10028000E6FE2D8202F001C88494A5A32594D00730 +:10029000A5AD18659385ADA5ADC9AA9018A9AA8585 +:1002A000ADA90085B185E6A588F00AA93B85CBA557 +:1002B0009885C885AEA5ADD002E6ADA5CDC903D061 +:1002C00026A5CAC5CED020A5AD38E90F85C785AF14 +:1002D000A205E48BF002A2018693A5A5186593857B +:1002E000A44A18695885C660A5CC8594C901D00474 +:1002F000A205868BC9FFD004A9FB858BA58BA20024 +:100300008689C905D01B860BA5B4D02FA5A5C91F0A +:100310009029A5A32901D002C6A5A90185898594A4 +:1003200060A0FF840BA5B4D012A5A5C982B00CA50E +:10033000A32901D002E6A58489849460A5B4D0FBEA +:10034000A58B8595A589F01AA205E495D002A2FF98 +:100350008695A900C5B6F00AC5CCF014C5B5F00263 +:100360008594A594F00AA5B6C930F020E6B6D01C55 +:10037000A5B6F054C6B6A5B6D00285B5A594D00CE6 +:10038000A201A595C905F002A2FF8694A5B6F03892 +:10039000F818690D4A4A4A4AD8AAA5A33DB5FED025 +:1003A00027A5943024C6C9C6C9C6C8A5CD3002C683 +:1003B000C6A20356DC36D876D4B5D42908F006B5E3 +:1003C000DC098095DCCA10EB60E6C9E6C9E6C8A581 +:1003D000CD3002E6C6A2031836D476D836DC9006B5 +:1003E000B5D4091095D4CA10EE60A591F008A58D7A +:1003F000F004A53C1006AD82026AB010A59B100463 +:10040000E69BE69B203BFD201CFDF0386A9006A28F +:100410000186E7D02F2017FD20E3FDC6E71025A9B0 +:100420002D85E7A59B1002E69BA59BF81869018521 +:100430009BA278868DA20086A386A2C9219004A9DA +:1004400001859BD8A91085048505A6E88609A20523 +:10045000A5A3290FD002A225860A60A58DD004A9E4 +:10046000FF8591A5A3D00DE68CA591D007C68D1070 +:10047000032017FDAD8202A0F7A20F2908F002A207 +:10048000FFA5913002A0FF258C859586968497A2C2 +:1004900006BDEFFF45952596259795E8CA10F2858C +:1004A0002C60A200A0008619A591D057A5CBC997B2 +:1004B000F0469011A007A5982907AAB5E899E80089 +:1004C0008810F33035A5B4D033A5CBC93CB039A5DD +:1004D000CD1013A5AFC904B00DA205A5982937A862 +:1004E000A90E8519D01DA58AF036C68AC920B00A82 +:1004F000C91FD023868AF00B86CBA598293FA8A2D6 +:100500000886198615841760A5A3292FA8A201A91A +:100510000A8519A5D1F0ECA5A32922A8A20ED0E145 +:10052000A5ADC9AAD004A5CBD0D0A5E5D0CCA5CB8C +:10053000D00EA5B3C9F0F008A030A208A903851910 +:10054000A5E6F0052A2AA8D0B6A5B2C938F0ABD0E6 +:10055000B2A5C0F008A58DF004A591D06BA4A2A50A +:100560009AF01FAAA59D1879DBFF859DCAD0F58654 +:100570009A39D9FFD9D5FFD009E699A59D39DDFF74 +:10058000859DA599F078C699A202B59C1879DBFFE4 +:10059000959C39D9FFD9D7FFD007B59C39DFFF9596 +:1005A0009C39D9FFD9D5FFD055B59C39DDFF959C35 +:1005B000E8E004D0032025FDE006D0CECAB59C3982 +:1005C000E1FF959CCA10F660A20A869D869CA00455 +:1005D000E8969C8810FAA59B3024A5C0F02020093D +:1005E000FE859DA59BA201C9119001E8869C290F5B +:1005F00085A0A59B29F0F0064A4A4A4A85A160A534 +:10060000A58595A5B1C960D007A5A538E58B85A5B9 +:10061000A5A3291FF011A5E6F00D85A52034FDA99D +:100620006B85B1A91F850460A5D1F041A5CBC90197 +:10063000F03BA96485B0A95D85ADA246A5A32901BB +:10064000D002A24E86A586A6A5EC858EA5E8858F4C +:10065000A95285B1A5D2E04EF00B4A4A4A4AD005CC +:10066000A98585B260290FAABDBAFE85B260A980AE +:10067000C5B0B00285B0A204A5A4F00E85A7A0FF66 +:10068000A5CAC5CED002A4AF84ABA000B5A5C952FF +:100690009004E94BA005E0026902C8E90FB0FB49EC +:1006A000FFE9060A85020A0A0A95208810FD9510BE +:1006B000CA10D78502852AA0058810FD852B8502E2 +:1006C000852AA59585A560A000A200B59C8693A665 +:1006D000A2F0044A4A4A4A290FA69385940A0A0AB4 +:1006E00038E59418695F99EF00A9FF99F000C8C830 +:1006F000E8E006D0D6AD8402D0FB85028501E6A3F2 +:10070000A5908507A5D22903AAB5EB85028508A97E +:10071000FF850FA901850EA00BA2008502B9A9FED5 +:10072000850FC4AAD001CA861F8502A200C4ACD01E +:1007300001CA861E8810E28502C8841D841F888431 +:100740000D840E840FA00FA6A2B5CFA6E9C9FFD0D5 +:1007500004A000A6E884978696A58F8506A58E85B9 +:1007600007A9F0850AA0848502A900850D850E855C +:100770000FA900C4B0B009A6B2BD26FFF002C6B2F0 +:10078000C4ADA6B18502851CB00BBD1AFEC9F0F040 +:1007900004851BC6B1A20198E5AB2592D001E8867D +:1007A0001D88C497D0CBA5968508A200861B984AC1 +:1007B0004A8502AAB5D4850DB5D8850EB5DC850F5E +:1007C0008693A20198E5AB2592D001E8861DA693F9 +:1007D0008810DB8502A900840D840E840FA2018697 +:1007E0000AA4EE85028409851D851C8407850D8574 +:1007F0000E850F850BA90385048505A00686258631 +:1008000026849384028810FDEA85108511A9F0855D +:10081000208502852AA0FEA5E885088502840FA60A +:10082000EC86068607A493B1F9851B8502B1F7858E +:100830001CB1F5851BB1F38594B1F1AAB1EFA8A560 +:1008400094851C861B841C851BC69310D8A9008523 +:10085000258526851B851C85208502850FA5EA85B3 +:10086000068507A008851088D0FD8511C88502A2DD +:1008700003B9C000C903B001AABDDEFE990400BDE2 +:10088000E2FE9996008810E7A20BA0058502BD1A2A +:10089000FE2596851BB983FE2597851CCA8810EC1A +:1008A000A9268D9602A2FF9A4C4FF0E6BBA5BB2964 +:1008B0000785BBAA20A0FC8593C8B58029F0F0026B +:1008C000A000B9E8008590A493A5CDF009E4B9D0C3 +:1008D00005A5C64CD9F820B5FC4A4A18692F85A849 +:1008E000A5CDF009E4B9D005A5C74CF0F820CAFCA5 +:1008F0004A4A4A4A18690285ACA4A2A9FF85AAD926 +:10090000CF00F045E6CEA5CEC9059004A90085CE5E +:10091000AAB9CF003D12FFD030A5C9187DF2FE4A1A +:100920004A18693085A9A90185AAA5CDF01BA5CAD9 +:10093000C5CED015A5CD3011A5C74A4A4A4A85AAC9 +:10094000A5C64A4A18693085A9A5A3290FD019A9B7 +:10095000FF85CEA5AD4A4A4A4A85AAA5A54A186987 +:10096000584A4A18692F85A960A90085A4A4A2B98C +:10097000CF00C9FFF02B3D12FFD026A5C9187DF28C +:10098000FEE4CAD008A4CD100285C6A5C6C95990F8 +:1009900010C9A8B00C38E958859418659469028587 +:1009A000A460A0078494A5A68595A5B78596A5B053 +:1009B0008597E6B7A5B7290785B7AAB5803014296A +:1009C0000FA820B5FCE4B9D002A5C6C9599004C946 +:1009D000A5900DC69410DBA9FF85B7A90085A66078 +:1009E00020CAFCE4B9D002A5C785B020B5FCE4B9A3 +:1009F000D002A5C638E9580A85A66020EEFDA6B744 +:100A0000304C84B8C8B9E800858E88B920FF85B21B +:100A1000A5CDC903D00EA925C5D2D008C5AD900477 +:100A2000A9AE85B2B5802910F024A93885B2E4B901 +:100A3000D00285B920A0FCA9809580C002D00FA566 +:100A4000E5D00BC8948085B2A5801002848060A593 +:100A500091D06CA5B4D0398593A5E6D0F1A5302905 +:100A600040F01BA692E0FCD01385B9A6CDE002D0E1 +:100A70000BE6CDA2058699202FFDA9008593A53709 +:100A800010028593A593F008A90085B6A91E85B428 +:100A9000A4B4F048A5A32903D002C6B42034FDC0F5 +:100AA00005B039B989FE85B1A5B4D03020C9F1A906 +:100AB0003285CB20ACFCA6A2D6C2D00320EBFCA58D +:100AC000C2D019A59BC9119010A5C3D00FA5A32909 +:100AD0001FD006A5A2490185A22017FD60A696A5F4 +:100AE000B2C938F051B5803004A5373015A5E5F00E +:100AF00045A599D041A6B71009A6A2D6C4A90085DC +:100B0000E56020A0FCA90085E6B9FAFE859AB90047 +:100B1000FF8599B58009109580E4B9D019A5CD104D +:100B200007A5AF1003E6CD60A90285CD85BAA9322D +:100B3000C5C7B00285BA60A5B4D054A6A2B53C1012 +:100B400009A9008588A5E6D02060A588D0F7201CDB +:100B5000FDC688A914C5ADB02AA5A538E90285E669 +:100B6000A68B100538E91785E6A207A58B1002A20F +:100B7000F98A1865E6AAC982B004C900B002A200C9 +:100B800086E660A5C1F008A9FFC5B7F00285E5605B +:100B9000A2A0A000A9FC8592A5A4D06BA5BFD032CD +:100BA000A5B73063A4B8C002F05DA201A5B085BCB2 +:100BB000C5AD9002A2FF86BEA58AD002E68AA5A690 +:100BC00085BDC5A59002A2FE86BFC000D004A9F0D5 +:100BD00085BFA6BCA4BDC9F0D008A5A3295AF01DA5 +:100BE000D0218A1865BE85BCC90F9011AAA5BD1871 +:100BF00065BF85BDA8A5B4D004C0A09006A00084A0 +:100C0000BFA2A0A9FE859286AB84A760A207B5808B +:100C10001030CA10F9A900A818659A659965B4D072 +:100C200021A6A2B5CFA2076AB001C8CA10F984995B +:100C3000A99685CB85D185B9A5E5F006A6A2D6C42F +:100C4000E6E560A5D3F033A5982907AAE4B9F02A10 +:100C5000B5801026A4A2B9CF00C9FFD004A005D04A +:100C60000AA004A5A3291FD002A00120B5FCC959E0 +:100C70009004C9A890049480C6D36020A6FCBDC48B +:100C8000FE8593E000F018A6D28497A001E00790BB +:100C90000188CAF008C493F0044693D0F5A4976085 +:100CA000B580290FA860A59B290FAA60A9A085ABD4 +:100CB00085AC85AA608693BE06FFA900E003F0021A +:100CC000B5E0A69365C87DF2FE608693BE0CFFA9D1 +:100CD00000E003F002B5E3A69365AE7DF2FE4A188C +:100CE000691860A5D1F0FBA90085D1A59BC9119019 +:100CF00018A5A24901AAB5C2F00F86A2E001D00949 +:100D0000F8A5D238E90185D2D84C73FD20A6FCBDE8 +:100D1000CDFE85CF85D060A9FF859160A978858DAE +:100D2000A9008591608693A6A2F6C4F6C2A693A9EF +:100D30001E858A60A6BBB5E8858F60A90085A2855F +:100D4000D185CD85A4859A859985B4850BA996858D +:100D5000CB20E3FD2009FE200CFDBDE8FE85D2A2DC +:100D600003BDE3FF95D4BDE7FF95D8BDEBFF95DC50 +:100D7000CA10EEA59885C985E385E485AEA90085EE +:100D8000B685BD85BF85CDA9FE859285B985CAA5E5 +:100D9000D2290FF004C905D003200CFDF8A5D21804 +:100DA000690185D2D8A90F85D3A207BD18FF958008 +:100DB000A4A2B9CF00C9FFD004A9059580CA10EB41 +:100DC00020EEFDA93285ADA91E85A520ACFC85C805 +:100DD00085ABA905858BA90085E085E185E285CCF9 +:100DE00085E660A90385C285C385C485C560A91051 +:100DF00085B1A5EA858FA5B4D00EA5A32907D00893 +:100E0000A96085B1A5EE858F60A900859C859DA907 +:100E1000AA859E859F85A085A160F0000000000046 +:100E200000387F7C70200000000000F0000000040B +:100E3000084428261C280420000000F000000800B8 +:100E40004220044110420840022000F000100240FD +:100E50000041002002004004004012F00001400068 +:100E60000000000001000000400021F0FF0000F041 +:100E7000007CFE3C3CFE7C00000000F000FE7F0099 +:100E80000000000000005C3E5C0050403020F0E0BC +:100E9000D070B0605090A00001FF000001FFFF0182 +:100EA00000000001FF0101FFFFC000000000000082 +:100EB00000000000C0FF070301013F464D545B6284 +:100EC0006970777E0F070307070307070307070704 +:100ED000FF0707FF0707FF07070707070707F0F0E8 +:100EE000F1F300FFFFFF4080000000000202020457 +:100EF0000404002850789BAF645A050000000505E3 +:100F000002020A05010103000200020101000300C0 +:100F1000030080402010080400020204040404803E +:100F20000810182028300000000000F8D8D8F80079 +:100F3000000000007EE77E00105438FE3854100098 +:100F400042E742044EE44000FF7E24183C3C180077 +:100F5000C33C24183C3C4400102040142854207EFC +:100F600072727272727E1C1C1C1C1C1C3C7E407EA9 +:100F70000E0E4E7E7E4E0E1C0E4E7E1C1C7E5C5C4B +:100F80005C7C7E4E0E7E404E7E7E4E4E7E404E7E81 +:100F90000E0E0E0E0E4E7E7E4E4E7E72727E7E7255 +:100FA000027E72727E000000000000007985B5A507 +:100FB000B58579171515775555774141414141411F +:100FC00040494949C94949BE555555D955559900D2 +:100FD000C4A4C6A5C60AA00BB00FF00110F00FF113 +:100FE0001FFAAFE06040407B795910CEC6C6C00002 +:100FF000888FFF1D1A3700000000000000F000F08D +:00000001FF diff --git a/Atari - 7800_TeST/rtl/rom/Joust.a78 b/Atari - 7800_TeST/rtl/rom/Joust.a78 new file mode 100644 index 00000000..b8104d6f Binary files /dev/null and b/Atari - 7800_TeST/rtl/rom/Joust.a78 differ diff --git a/Atari - 7800_TeST/rtl/scandoubler.sv b/Atari - 7800_TeST/rtl/scandoubler.sv new file mode 100644 index 00000000..5a3ccd17 --- /dev/null +++ b/Atari - 7800_TeST/rtl/scandoubler.sv @@ -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 + +`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 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 + +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/Atari - 7800_TeST/rtl/sigma_delta_dac.sv b/Atari - 7800_TeST/rtl/sigma_delta_dac.sv new file mode 100644 index 00000000..29daea6e --- /dev/null +++ b/Atari - 7800_TeST/rtl/sigma_delta_dac.sv @@ -0,0 +1,33 @@ +// +// PWM DAC +// +// MSBI is the highest bit number. NOT amount of bits! +// +module sigma_delta_dac #(parameter MSBI=0) +( + output reg DACout, //Average Output feeding analog lowpass + input [MSBI:0] DACin, //DAC input (excess 2**MSBI) + input CLK, + input RESET +); + +reg [MSBI+2:0] DeltaAdder; //Output of Delta Adder +reg [MSBI+2:0] SigmaAdder; //Output of Sigma Adder +reg [MSBI+2:0] SigmaLatch; //Latches output of Sigma Adder +reg [MSBI+2:0] DeltaB; //B input of Delta Adder + +always @(*) DeltaB = {SigmaLatch[MSBI+2], SigmaLatch[MSBI+2]} << (MSBI+1); +always @(*) DeltaAdder = DACin + DeltaB; +always @(*) SigmaAdder = DeltaAdder + SigmaLatch; + +always @(posedge CLK or posedge RESET) begin + if(RESET) begin + SigmaLatch <= 1'b1 << (MSBI+1); + DACout <= 1; + end else begin + SigmaLatch <= SigmaAdder; + DACout <= ~SigmaLatch[MSBI+2]; + end +end + +endmodule diff --git a/Atari - 7800_TeST/rtl/tia.vh b/Atari - 7800_TeST/rtl/tia.vh new file mode 100644 index 00000000..04c8510a --- /dev/null +++ b/Atari - 7800_TeST/rtl/tia.vh @@ -0,0 +1,81 @@ +/* Atari on an FPGA +Masters of Engineering Project +Cornell University, 2007 +Daniel Beer + TIA.h +Header file that contains useful definitions for the TIA module. +*/ +`define CXM0P 7'h70 +`define CXM1P 7'h71 +`define CXP0FB 7'h72 +`define CXP1FB 7'h73 +`define CXM0FB 7'h74 +`define CXM1FB 7'h75 +`define CXBLPF 7'h76 +`define CXPPMM 7'h77 +`define INPT0 7'h78 +`define INPT1 7'h79 +`define INPT2 7'h7A +`define INPT3 7'h7B +`define INPT4 7'h7C +`define INPT5 7'h7D +`define VSYNC 7'h00 +`define VBLANK 7'h01 +`define WSYNC 7'h02 +`define RSYNC 7'h03 +`define NUSIZ0 7'h04 +`define NUSIZ1 7'h05 +`define COLUP0 7'h06 +`define COLUP1 7'h07 +`define COLUPF 7'h08 +`define COLUBK 7'h09 +`define CTRLPF 7'h0A +`define REFP0 7'h0B +`define REFP1 7'h0C +`define PF0 7'h0D +`define PF1 7'h0E +`define PF2 7'h0F +`define RESP0 7'h10 +`define RESP1 7'h11 +`define RESM0 7'h12 +`define RESM1 7'h13 +`define RESBL 7'h14 +`define AUDC0 7'h15 +`define AUDC1 7'h16 +`define AUDF0 7'h17 +`define AUDF1 7'h18 +`define AUDV0 7'h19 +`define AUDV1 7'h1A +`define GRP0 7'h1B +`define GRP1 7'h1C +`define ENAM0 7'h1D +`define ENAM1 7'h1E +`define ENABL 7'h1F +`define HMP0 7'h20 +`define HMP1 7'h21 +`define HMM0 7'h22 +`define HMM1 7'h23 +`define HMBL 7'h24 +`define VDELP0 7'h25 +`define VDELP1 7'h26 +`define VDELBL 7'h27 +`define RESMP0 7'h28 +`define RESMP1 7'h29 +`define HMOVE 7'h2A +`define HMCLR 7'h2B +`define CXCLR 7'h2C + +`define CXM0P_7800 7'h40 +`define CXM1P_7800 7'h41 +`define CXP0FB_7800 7'h42 +`define CXP1FB_7800 7'h43 +`define CXM0FB_7800 7'h44 +`define CXM1FB_7800 7'h45 +`define CXBLPF_7800 7'h46 +`define CXPPMM_7800 7'h47 +`define INPT0_7800 7'h48 +`define INPT1_7800 7'h49 +`define INPT2_7800 7'h4A +`define INPT3_7800 7'h4B +`define INPT4_7800 7'h4C +`define INPT5_7800 7'h4D \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/timing_ctrl.sv b/Atari - 7800_TeST/rtl/timing_ctrl.sv new file mode 100644 index 00000000..b40e1aef --- /dev/null +++ b/Atari - 7800_TeST/rtl/timing_ctrl.sv @@ -0,0 +1,361 @@ +`timescale 1ns / 1ps + +// Number of sysclk cycles needed for the halt signal to take on the CPU +`define DMA_STARTUP_CYCLES 9 + +// Number of sysclk cycles that the cpu gets at the start of a line +`define START_OF_LINE_CYCLES 24 + +// At which column we terminate DP DMA +`define DP_DMA_KILL_COL 435 + +// Column to start the ZP DMA, given that about 29 cycles are needed +// and there are 452 columns total. Plus some slack cycles. +// 9 for startup, 7 for access, 13 for shutdown +`define ZP_READY_COL 420 + +// VGA Row to start the ZP DMA. Rows 0-1 are the first visible line, +// rows 523-524 are the virst invisible line, rows 521-522 are buffering +// for the first invisible line, so ZP needs to be fetched by row 521. +`define ZP_READY_ROW 520 + +`define VGA_VISIBLE_COLS 640 + +`define NTSC_SCANLINE_COUNT 242 + +`define COOLDOWN_CYCLES 1 + +//`define OVERCLOCK + + + +module timing_ctrl ( + input logic enable, + + // Clocking + input logic sysclk, reset, pclk_2, + output logic pclk_0, tia_clk, + input logic sel_slow_clock, + + // Outputs to 6502 + output logic halt_b, int_b, ready, core_latch_data, + output logic VBLANK, + + // Signals to/from dma_ctrl + output logic zp_dma_start, dp_dma_start, + input logic zp_dma_done, dp_dma_done, + input logic dp_dma_done_dli, + output logic dp_dma_kill, + output logic last_line, + + // Signals to/from line_ram + output logic lram_swap, + + // VGA Status + input logic [9:0] vga_row, vga_col, + + // Signals from memory map + input logic deassert_ready, zp_written +); + + // Output buffers + logic [5:0] int_b_sr; + assign int_b = &int_b_sr; + + // Current NTSC row and col + logic [8:0] row, col; + + logic [9:0] vga_row_prev, vga_row_prev_prev; + + // Each ntsc line is two vga lines. Asserted => we are on second one + logic second_vga_line; + + // vga_row has changed in the last cycle + logic vga_line_delta; + + // Clock division + `ifndef OVERCLOCK + logic fast_ctr; + `endif + + logic [1:0] slow_ctr; + logic fast_clk, slow_clk; + + logic ready_for_lswap, ready_for_lswap_prev; + + // Ready to move to ZP_DMA_STARTUP + logic zp_ready; + + // interrupt on next cycle + logic dli_next, raise_dli; + + logic [4:0] startup_ctr; + logic cooldown_count; + + enum logic [31:0] { + VWAIT = 'h0, // Waiting for VSYNC to complete before starting ZP DMA + HWAIT = 'h1, // Waiting for HSYNC to complete before starting DP DMA + ZP_DMA_STARTUP = 'h2, // Waiting for HALT to reach CPU before starting ZP DMA + ZP_DMA = 'h3, // Waiting for DMA CTRL to finish ZP DMA + START_OF_LINE = 'h4, // Waiting for first 7 CPU cycles of line before DP DMA + DP_DMA_STARTUP = 'h5, // Waiting for HALT to reach CPU before starting DP DMA + DP_DMA = 'h6, // Waiting for DMA CTRL to finish DP DMA + DP_DMA_WAITSWAP = 'h7, // Done with DP DMA, but not ready to swap linerams yet + VWAIT_COOLDOWN = 'h8, + HWAIT_COOLDOWN = 'h9 + } state; + + assign vga_line_delta = vga_row_prev_prev != vga_row_prev; + + // In general, we are on the second row if the row number is odd (vga_row[0]) + // However, above 512 (521/522, 523/524) we are on the second row if the row + // number is even. + assign second_vga_line = vga_row[9] ^ vga_row[0]; + + assign dp_dma_kill = ((enable) & + (state == DP_DMA) & + (second_vga_line) & + (col == `DP_DMA_KILL_COL)); + + assign zp_ready = ((enable) & (vga_row == `ZP_READY_ROW) & + (col == `ZP_READY_COL)); + + assign last_line = (row == (`NTSC_SCANLINE_COUNT - 1)); + + assign VBLANK = (row >= 9'd241); + + assign pclk_0 = sel_slow_clock ? slow_clk : fast_clk; + + assign ready_for_lswap = ((enable) & second_vga_line & + (vga_col > `VGA_VISIBLE_COLS)); + assign lram_swap = (ready_for_lswap & + (((state == DP_DMA) & (dp_dma_done | dp_dma_kill)) || + (state == DP_DMA_WAITSWAP))); + + + always @(posedge sysclk, posedge reset) begin + if (reset) begin + state <= VWAIT; + row <= 9'b0; + col <= 9'b0; + vga_row_prev <= 10'd0; + fast_clk <= 1'b0; + cooldown_count <= 1'b0; + slow_clk <= 1'b0; + `ifndef OVERCLOCK + fast_ctr <= 1'b0; + `endif + slow_ctr <= 2'b0; + int_b_sr <= 6'b111111; + raise_dli <= 1'b0; + startup_ctr <= 4'd0; + dli_next <= 1'b0; + halt_b <= 1'b1; + zp_dma_start <= 1'b0; + dp_dma_start <= 1'b0; + core_latch_data <= 1'b0; + ready_for_lswap_prev <= 1'b0; + ready <= 1'b1; + tia_clk <= 1'b0; + end else begin + // Clock generation + tia_clk <= ~tia_clk; + core_latch_data <= 1'b0; + if (sel_slow_clock) begin + `ifndef OVERCLOCK + fast_ctr <= 1'b0; + `endif + + fast_clk <= 1'b1; + if (slow_ctr == 2'd2) begin + slow_ctr <= 2'b0; + slow_clk <= ~slow_clk; + if (slow_clk == 1'b0) + core_latch_data <= 1'b1; + end + else + slow_ctr <= slow_ctr + 2'b01; + end + else begin + slow_ctr <= 2'b00; + slow_clk <= 1'b1; + `ifdef OVERCLOCK + fast_clk <= ~fast_clk; + `else + fast_ctr <= ~fast_ctr; + if (fast_ctr) begin + fast_clk <= ~fast_clk; + if (fast_clk == 1'b0) + core_latch_data <= 1'b1; + end + `endif + end + + // Interrupt generation + int_b_sr <= {int_b_sr[4:0], ~(dli_next & enable)}; + //int_b_reg <= ~(dli_next & enable); + + vga_row_prev <= vga_row; + vga_row_prev_prev <= vga_row_prev; + ready_for_lswap_prev <= ready_for_lswap; + + // Column counting + if (vga_line_delta & ~second_vga_line) // Just changed to first line + col <= 0; + else + col <= col + 1; + + // Row counting + if (vga_line_delta & ~second_vga_line) begin + if (vga_row == 10'd521) + row <= 0; + else + row <= row + 1; + end + + // Ready signal + if (enable & deassert_ready) + ready <= 1'b0; + else if (ready_for_lswap & ~ready_for_lswap_prev) + ready <= 1'b1; + + // Next state logic + case (state) + VWAIT: begin + if (zp_ready & zp_written) begin + halt_b <= 1'b0; + raise_dli <= 1'b0; + dli_next <= 1'b0; + state <= ZP_DMA_STARTUP; + startup_ctr <= 1; + end + end + HWAIT: begin + if (~enable) begin + state <= VWAIT_COOLDOWN; + halt_b <= 1'b0; + raise_dli <= 1'b0; + dli_next <= 1'b0; + cooldown_count <= `COOLDOWN_CYCLES; + end else if (vga_line_delta) begin + state <= START_OF_LINE; + startup_ctr <= 1; + end + end + ZP_DMA_STARTUP: begin + startup_ctr <= startup_ctr + 1; + if (~enable) begin + state <= VWAIT_COOLDOWN; + raise_dli <= 1'b0; + halt_b <= 1'b0; + cooldown_count <= `COOLDOWN_CYCLES; + end else if (startup_ctr == `DMA_STARTUP_CYCLES) begin + zp_dma_start <= 1'b1; + state <= ZP_DMA; + end + end + ZP_DMA: begin + zp_dma_start <= 1'b0; + if (~enable) begin + state <= VWAIT_COOLDOWN; + raise_dli <= 1'b0; + halt_b <= 1'b0; + cooldown_count <= `COOLDOWN_CYCLES; + end else if (zp_dma_done) begin + state <= HWAIT_COOLDOWN; + raise_dli <= dp_dma_done_dli; + raise_dli <= 1'b0; + halt_b <= 1'b0; + cooldown_count <= `COOLDOWN_CYCLES; + end + end + START_OF_LINE: begin + startup_ctr <= startup_ctr + 1; + if (~enable) begin + state <= VWAIT_COOLDOWN; + raise_dli <= 1'b0; + halt_b <= 1'b0; + cooldown_count <= `COOLDOWN_CYCLES; + end else if (startup_ctr == `START_OF_LINE_CYCLES) begin + halt_b <= 1'b0; + state <= DP_DMA_STARTUP; + startup_ctr <= 1; + end + end + DP_DMA_STARTUP: begin + startup_ctr <= startup_ctr + 1; + if (~enable) begin + state <= VWAIT_COOLDOWN; + raise_dli <= 1'b0; + halt_b <= 1'b0; + cooldown_count <= `COOLDOWN_CYCLES; + end else if (startup_ctr == `DMA_STARTUP_CYCLES) begin + dp_dma_start <= 1'b1; + raise_dli <= 1'b0; + state <= DP_DMA; + end + end + DP_DMA: begin + dp_dma_start <= 1'b0; + if (~enable) begin + state <= VWAIT_COOLDOWN; + halt_b <= 1'b0; + cooldown_count <= `COOLDOWN_CYCLES; + end else if (dp_dma_done | dp_dma_kill) begin + halt_b <= 1'b0; + raise_dli <= dp_dma_done_dli; + cooldown_count <= `COOLDOWN_CYCLES; + if (ready_for_lswap) begin + state <= last_line ? VWAIT_COOLDOWN : HWAIT_COOLDOWN; + end else begin + state <= DP_DMA_WAITSWAP; + end + end + end + DP_DMA_WAITSWAP: begin + if (~enable) begin + state <= VWAIT_COOLDOWN; + end else if (cooldown_count == 0) begin + if ((sel_slow_clock && slow_ctr != 2'b10) || + (~sel_slow_clock && fast_clk == 1'b1)) begin + halt_b <= 1'b1; + raise_dli <= 1'b0; + dli_next <= raise_dli; + end + end else begin + cooldown_count <= cooldown_count - 1; + end + if (ready_for_lswap) begin + state <= last_line ? VWAIT_COOLDOWN : HWAIT_COOLDOWN; + end + end + VWAIT_COOLDOWN: begin + if (cooldown_count == 0) begin + if ((sel_slow_clock && slow_ctr != 2'b10) || + (~sel_slow_clock && fast_clk == 1'b1)) begin + halt_b <= 1'b1; + raise_dli <= 1'b0; + dli_next <= raise_dli; + state <= VWAIT; + end + end else begin + cooldown_count <= cooldown_count - 1; + end + end + HWAIT_COOLDOWN: begin + if (cooldown_count == 0) begin + if ((sel_slow_clock && slow_ctr != 2'b10) || + (~sel_slow_clock && fast_clk == 1'b1)) begin + halt_b <= 1'b1; + raise_dli <= 1'b0; + dli_next <= raise_dli; + state <= HWAIT; + end + end else begin + cooldown_count <= cooldown_count - 1; + end + end + endcase + end + end +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/uv_to_vga.sv b/Atari - 7800_TeST/rtl/uv_to_vga.sv new file mode 100644 index 00000000..f890e5aa --- /dev/null +++ b/Atari - 7800_TeST/rtl/uv_to_vga.sv @@ -0,0 +1,218 @@ +`timescale 1ns / 1ps +/** Line buffer to VGA Interface + * + * input lbuffer is the line buffer. + * For column c, 0 <= c < 640, where 0 is left and 639 is right, + * lbuffer[c][0] is RED, where 4'hF is the most intense red and + * 4'h0 is the least intense red. + * lbuffer[c][1] is GREEN and lbuffer[c][2] is BLUE. + * + * output line_number indicates the current row, where the top + * of the screen is 0 and 479 is the bottom of the screen. Other + * values indicate that no line is currently being drawn. + * + * clk should be hooked up to a 25MHz clock (or 25.175 if available.) + * reset should be hooked up to system reset. + * RED, GREEN, BLUE, HSync, and VSync should be hooked up to the + * appropriate VGA pins. + **/ + +//`define FRAMEBUF + +module uv_to_vga ( + input logic clk, reset, + input logic [7:0] uv_in, + + output logic [9:0] row, col, + output logic [3:0] RED, GREEN, BLUE, + output logic HSync, VSync, + + input logic tia_en, tia_clk, + input logic tia_hblank, + input logic tia_vblank +); + + + + logic col_clear, row_clear; + logic col_enable, row_enable; + + // Chrominance-Luminance palettes (represented as rgb) + logic [255:0][3:0] red_palette, green_palette, blue_palette; + + logic [7:0] rbuf, gbuf, bbuf; + logic [7:0] uv; + + logic visible, tia_visible; + assign visible = (row < 10'd480) & (col < 10'd640); + + `ifdef FRAMEBUF + assign tia_visible = (row >= 10'd48) & (row <10'd432) & (col < 10'd640); + + logic [9:0] tia_row, tia_col; + assign tia_row = row - 10'd48; + assign tia_col = col; + + logic [7:0] fbuf_uv1, fbuf_uv2; + (* keep = "true" *) logic [7:0] fbuf_uv1_kept, fbuf_uv2_kept; + assign fbuf_uv1_kept = fbuf_uv1; + assign fbuf_uv2_kept = fbuf_uv2; + + logic [14:0] buf_w_addr, buf_r_addr; + (* keep = "true" *) logic [14:0] buf_w_addr_kept; + (* keep = "true" *) logic [14:0] buf_r_addr_kept; + assign buf_w_addr = tia_write_row*14'd160+tia_write_col; + assign buf_r_addr = tia_row[8:1]*14'd160+tia_col[9:2]; + assign buf_w_addr_kept = buf_w_addr; + assign buf_r_addr_kept = buf_r_addr; + logic write_buf1; + + Frame_Buf frame_buffer1( + .clka(tia_clk), // input wire clka + .ena(~tia_vblank & ~tia_hblank & write_buf1), // input wire ena + .wea(write_buf1), // input wire [0 : 0] wea + .addra(buf_w_addr), // input wire [14 : 0] addra + .dina(uv_in), // input wire [7 : 0] dina + .clkb(clk), // input wire clkb + .enb(tia_visible), // input wire enb + .addrb(buf_r_addr), // input wire [14 : 0] addrb + .doutb(fbuf_uv1) // output wire [7 : 0] doutb + ); + + Frame_Buf frame_buffer2( + .clka(tia_clk), // input wire clka + .ena(~tia_vblank & ~tia_hblank & ~write_buf1), // input wire ena + .wea(~write_buf1), // input wire [0 : 0] wea + .addra(buf_w_addr), // input wire [14 : 0] addra + .dina(uv_in), // input wire [7 : 0] dina + .clkb(clk), // input wire clkb + .enb(tia_visible), // input wire enb + .addrb(buf_r_addr), // input wire [14 : 0] addrb + .doutb(fbuf_uv2) // output wire [7 : 0] doutb + ); + + logic [7:0] tia_write_row; + logic [7:0] tia_write_col; + (* keep = "true" *) logic [7:0] tia_write_row_kept; + (* keep = "true" *) logic [7:0] tia_write_col_kept; + assign tia_write_row_kept = tia_write_row; + assign tia_write_col_kept = tia_write_col; + + logic tia_hblank_buf, tia_vblank_buf; + + always_ff @(posedge tia_clk, posedge reset) begin + if (reset) begin + tia_write_row <= 0; + tia_write_col <= 0; + tia_hblank_buf <= 0; + tia_vblank_buf <= 0; + end else begin + tia_hblank_buf <= tia_hblank; + tia_vblank_buf <= tia_vblank; + if (~tia_vblank_buf & tia_vblank) + write_buf1 <= ~write_buf1; + if (tia_hblank) begin + tia_write_col <= 8'b0; + if (~tia_hblank_buf & ~tia_vblank) begin + tia_write_row <= tia_write_row + 1; + end + end else begin + tia_write_col <= tia_write_col + 1; + end + + if (tia_vblank) + tia_write_row <= 8'd0; + end + end + + logic [7:0] uv_from_fbuf; + assign uv_from_fbuf = (write_buf1) ? fbuf_uv2 : fbuf_uv1; + assign uv = tia_en ? (tia_visible ? uv_from_fbuf : 8'd0) : (visible ? uv_in : 8'd0); + `else + assign uv = uv_in; + `endif + + + assign RED = rbuf; + assign GREEN = gbuf; + assign BLUE = bbuf; + // UV Palette data found at: http://atariage.com/forums/topic/209210-complete-ntsc-pal-color-palettes/ + // These three assign statements generated by Atari7800/palettes.py + assign red_palette = {4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'hf, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'hf, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0}; + assign rbuf = red_palette[uv]; + + assign green_palette = {4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'hf, 4'hf, 4'hf, 4'hf, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h2, 4'h1, 4'h0, 4'hf, 4'hf, 4'he, 4'hd, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h1, 4'h0, 4'h0, 4'hf, 4'he, 4'hd, 4'hc, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h1, 4'h0, 4'h0, 4'h0, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'he, 4'hd, 4'hc, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h0, 4'h0, 4'h0, 4'h0, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'hf, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'he, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0}; + assign gbuf = green_palette[uv]; + + assign blue_palette = {4'ha, 4'h9, 4'h8, 4'h7, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'ha, 4'h9, 4'h8, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'hf, 4'he, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h4, 4'h3, 4'h2, 4'h1, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'hf, 4'hf, 4'hf, 4'hf, 4'hd, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h4, 4'h3, 4'h2, 4'h1, 4'hf, 4'he, 4'hc, 4'hb, 4'ha, 4'h9, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'hb, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'ha, 4'h9, 4'h8, 4'h7, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'h0, 4'hf, 4'hf, 4'he, 4'hd, 4'hc, 4'hb, 4'ha, 4'h8, 4'h7, 4'h6, 4'h5, 4'h4, 4'h3, 4'h2, 4'h1, 4'h0}; + assign bbuf = blue_palette[uv]; + + + // Row counter counts from 0 to 520 + // count of 0 - 479 is display time (row == line_number here) + // count of 480 - 489 is front porch + // count of 490 - 491 is VS=0 pulse width + // count of 492 - 525 is back porch + + always @(posedge clk, posedge reset) + if (reset) begin + row <= 10'd519; + end else if (row_clear) + row <= 10'd0; + else + row <= row + row_enable; + + assign row_clear = (row == 10'd524) & row_enable; + assign row_enable = (col == 10'd799); + assign VSync = (row < 10'd490) | (row > 10'd491); + + // Col counter counts from 0 to 799 + // count of 0 - 639 is display time + // count of 640 - 655 is front porch + // count of 656 - 751 is HS=0 pulse width + // count of 752 - 799 is back porch + + always @(posedge clk)//, reset) + if (reset | col_clear) + col <= 10'd0; + else + col <= col + col_enable; + + /*logic [7:0] tia_buf_col; + logic write_buf1; + logic [7:0][159:0] tia_buf1; + logic [7:0][159:0] tia_buf2; + integer i; + + always @(posedge tia_hblank) + write_buf1 <= ~write_buf1; + + always @(posedge tia_clk, posedge reset) begin + if (reset) begin + tia_buf_col <= 7'b0; + tia_buf1 <= 1280'b0; + tia_buf2 <= 1280'b0; + end else if (tia_en & tia_vsync_delta) begin + tia_buf_col <= 7'b0; + for (i=0;i<160;i=i+1) begin + tia_buf1[i] <= 8'b0; + tia_buf2[i] <= 8'b0; + end + end else if (tia_hblank) + tia_buf_col <= 8'd160; + else if (tia_buf_col == 8'd227) + tia_buf_col <= 8'd0; + else begin + tia_buf_col <= tia_buf_col + 1; + if (write_buf1) + tia_buf1[tia_buf_col] <= uv_in; + else + tia_buf2[tia_buf_col] <= uv_in; + end + end*/ + + assign col_clear = row_enable; + assign col_enable = 1'b1; + assign HSync = (col < 10'd656) | (col > 10'd751); + +endmodule \ No newline at end of file diff --git a/Atari - 7800_TeST/rtl/video_mixer.sv b/Atari - 7800_TeST/rtl/video_mixer.sv new file mode 100644 index 00000000..ec953e53 --- /dev/null +++ b/Atari - 7800_TeST/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'd7, + 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