From 3f2dc3572270d000fa8bc330d9519603552421dd Mon Sep 17 00:00:00 2001 From: Gehstock Date: Fri, 5 Oct 2018 22:38:42 +0200 Subject: [PATCH] Reupload Electron --- Acorn - Electron_MiST/AtomElectron_Mist.qpf | 30 + Acorn - Electron_MiST/AtomElectron_Mist.qsf | 126 ++ .../Snapshot/AtomElectron_Mist.rbf | Bin 0 -> 276283 bytes Acorn - Electron_MiST/clean.bat | 38 + .../rtl/AtomElectron_Mist.sv | 134 ++ .../rtl/ElectronFpga_MiST - Kopie.vhd | 113 ++ .../rtl/ElectronFpga_MiST.vhd | 106 ++ .../rtl/ElectronFpga_core.vhd | 400 ++++++ Acorn - Electron_MiST/rtl/ElectronULA.vhd | 817 +++++++++++ .../rtl/RAM_32K_DualPort.vhd | 48 + Acorn - Electron_MiST/rtl/RomBasic2.vhd | 169 +++ Acorn - Electron_MiST/rtl/RomOS100.vhd | 169 +++ Acorn - Electron_MiST/rtl/RomSmelk3006.vhd | 143 ++ Acorn - Electron_MiST/rtl/T65/T65.vhd | 666 +++++++++ Acorn - Electron_MiST/rtl/T65/T65_ALU.vhd | 291 ++++ Acorn - Electron_MiST/rtl/T65/T65_MCode.vhd | 1239 +++++++++++++++++ Acorn - Electron_MiST/rtl/T65/T65_Pack.vhd | 180 +++ Acorn - Electron_MiST/rtl/build_id.tcl | 35 + Acorn - Electron_MiST/rtl/build_id.v | 2 + Acorn - Electron_MiST/rtl/hq2x.sv | 454 ++++++ Acorn - Electron_MiST/rtl/keyboard.vhd | 186 +++ Acorn - Electron_MiST/rtl/m6522.vhd | 920 ++++++++++++ Acorn - Electron_MiST/rtl/mist_io.v | 491 +++++++ Acorn - Electron_MiST/rtl/osd.v | 179 +++ Acorn - Electron_MiST/rtl/pll.vhd | 446 ++++++ Acorn - Electron_MiST/rtl/pll_inst.vhd | 6 + Acorn - Electron_MiST/rtl/ps2_intf.vhd | 119 ++ Acorn - Electron_MiST/rtl/roms/basic2.hex | 514 +++++++ Acorn - Electron_MiST/rtl/roms/os100.hex | 514 +++++++ Acorn - Electron_MiST/rtl/scandoubler.v | 195 +++ Acorn - Electron_MiST/rtl/video_mixer.sv | 242 ++++ 31 files changed, 8972 insertions(+) create mode 100644 Acorn - Electron_MiST/AtomElectron_Mist.qpf create mode 100644 Acorn - Electron_MiST/AtomElectron_Mist.qsf create mode 100644 Acorn - Electron_MiST/Snapshot/AtomElectron_Mist.rbf create mode 100644 Acorn - Electron_MiST/clean.bat create mode 100644 Acorn - Electron_MiST/rtl/AtomElectron_Mist.sv create mode 100644 Acorn - Electron_MiST/rtl/ElectronFpga_MiST - Kopie.vhd create mode 100644 Acorn - Electron_MiST/rtl/ElectronFpga_MiST.vhd create mode 100644 Acorn - Electron_MiST/rtl/ElectronFpga_core.vhd create mode 100644 Acorn - Electron_MiST/rtl/ElectronULA.vhd create mode 100644 Acorn - Electron_MiST/rtl/RAM_32K_DualPort.vhd create mode 100644 Acorn - Electron_MiST/rtl/RomBasic2.vhd create mode 100644 Acorn - Electron_MiST/rtl/RomOS100.vhd create mode 100644 Acorn - Electron_MiST/rtl/RomSmelk3006.vhd create mode 100644 Acorn - Electron_MiST/rtl/T65/T65.vhd create mode 100644 Acorn - Electron_MiST/rtl/T65/T65_ALU.vhd create mode 100644 Acorn - Electron_MiST/rtl/T65/T65_MCode.vhd create mode 100644 Acorn - Electron_MiST/rtl/T65/T65_Pack.vhd create mode 100644 Acorn - Electron_MiST/rtl/build_id.tcl create mode 100644 Acorn - Electron_MiST/rtl/build_id.v create mode 100644 Acorn - Electron_MiST/rtl/hq2x.sv create mode 100644 Acorn - Electron_MiST/rtl/keyboard.vhd create mode 100644 Acorn - Electron_MiST/rtl/m6522.vhd create mode 100644 Acorn - Electron_MiST/rtl/mist_io.v create mode 100644 Acorn - Electron_MiST/rtl/osd.v create mode 100644 Acorn - Electron_MiST/rtl/pll.vhd create mode 100644 Acorn - Electron_MiST/rtl/pll_inst.vhd create mode 100644 Acorn - Electron_MiST/rtl/ps2_intf.vhd create mode 100644 Acorn - Electron_MiST/rtl/roms/basic2.hex create mode 100644 Acorn - Electron_MiST/rtl/roms/os100.hex create mode 100644 Acorn - Electron_MiST/rtl/scandoubler.v create mode 100644 Acorn - Electron_MiST/rtl/video_mixer.sv diff --git a/Acorn - Electron_MiST/AtomElectron_Mist.qpf b/Acorn - Electron_MiST/AtomElectron_Mist.qpf new file mode 100644 index 00000000..739a9d66 --- /dev/null +++ b/Acorn - Electron_MiST/AtomElectron_Mist.qpf @@ -0,0 +1,30 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2013 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II 64-Bit +# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition +# Date created = 07:11:53 March 09, 2017 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "13.1" +DATE = "07:11:53 March 09, 2017" + +# Revisions + +PROJECT_REVISION = "AtomElectron_Mist" diff --git a/Acorn - Electron_MiST/AtomElectron_Mist.qsf b/Acorn - Electron_MiST/AtomElectron_Mist.qsf new file mode 100644 index 00000000..66ca86d7 --- /dev/null +++ b/Acorn - Electron_MiST/AtomElectron_Mist.qsf @@ -0,0 +1,126 @@ +# -------------------------------------------------------------------------- # +# +# 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 = 07:11:53 March 09, 2017 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# AtomElectron_Mist_assignment_defaults.qdf +# If this file doesn't exist, see file: +# assignment_defaults.qdf +# +# 2) Altera recommends that you do not modify this file. This +# file is updated automatically by the Quartus II software +# and any changes you make may be lost or overwritten. +# +# -------------------------------------------------------------------------- # +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_global_assignment -name FAMILY "Cyclone III" +set_global_assignment -name DEVICE EP3C25E144C8 +set_global_assignment -name TOP_LEVEL_ENTITY AtomElectron_Mist +set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1 +set_global_assignment -name PROJECT_CREATION_TIME_DATE "07:11:53 MARCH 09, 2017" +set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1" +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files +set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (VHDL)" +set_global_assignment -name EDA_OUTPUT_DATA_FORMAT VHDL -section_id eda_simulation +set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 +set_global_assignment -name CYCLONEIII_CONFIGURATION_SCHEME "PASSIVE SERIAL" +set_global_assignment -name USE_CONFIGURATION_DEVICE OFF +set_global_assignment -name GENERATE_RBF_FILE ON +set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF +set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" +set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name 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 +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)" +set_global_assignment -name SEARCH_PATH roms/ -tag from_archive +set_global_assignment -name SEARCH_PATH src/ -tag from_archive +set_global_assignment -name SEARCH_PATH src/MC6522/ -tag from_archive +set_global_assignment -name SEARCH_PATH src/RAM/ -tag from_archive +set_global_assignment -name SEARCH_PATH src/T6502/ -tag from_archive +set_global_assignment -name SEARCH_PATH src/ps2kybrd/ -tag from_archive +set_global_assignment -name VHDL_FILE rtl/ElectronULA.vhd +set_global_assignment -name VHDL_FILE rtl/RomSmelk3006.vhd +set_global_assignment -name VHDL_FILE rtl/RomOS100.vhd +set_global_assignment -name VHDL_FILE rtl/RomBasic2.vhd +set_global_assignment -name VHDL_FILE rtl/RAM_32K_DualPort.vhd +set_global_assignment -name VHDL_FILE rtl/ps2_intf.vhd +set_global_assignment -name VHDL_FILE rtl/m6522.vhd +set_global_assignment -name VHDL_FILE rtl/keyboard.vhd +set_global_assignment -name VHDL_FILE rtl/T65/T65_Pack.vhd +set_global_assignment -name VHDL_FILE rtl/T65/T65_MCode.vhd +set_global_assignment -name VHDL_FILE rtl/T65/T65_ALU.vhd +set_global_assignment -name VHDL_FILE rtl/T65/T65.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/AtomElectron_Mist.sv +set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top +set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top +set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top +set_global_assignment -name VHDL_FILE rtl/ElectronFpga_core.vhd +set_global_assignment -name VHDL_FILE rtl/pll.vhd +set_global_assignment -name SYSTEMVERILOG_FILE rtl/video_mixer.sv +set_global_assignment -name VERILOG_FILE rtl/scandoubler.v +set_global_assignment -name VERILOG_FILE rtl/osd.v +set_global_assignment -name VERILOG_FILE rtl/mist_io.v +set_global_assignment -name SYSTEMVERILOG_FILE rtl/hq2x.sv +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Acorn - Electron_MiST/Snapshot/AtomElectron_Mist.rbf b/Acorn - Electron_MiST/Snapshot/AtomElectron_Mist.rbf new file mode 100644 index 0000000000000000000000000000000000000000..636bb217dcc512bbee047cd08db0516234f37b6d GIT binary patch literal 276283 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 z zpzkJqW9pAIZGGOlUnt&v z*RNayQ{g^sj0%^-vE2UfsnGs@uCf-+aFZ#oDw12>C3$ekdn;m}7|A{Qm{7m?-IaRP z>)T?l@>XGou1zjKJMm}kU1IeqQ^7{N=o!0t^`A}fJI5*kh~K^1*xJ@?S9ALzavYo3 zXoScQrv>m~Q(o9b^g!Gx(C8rOhdM$lJz@_+J^Mqc%bwP>ub)6rsqZci?-hG^vo$Dg zIf1a)dYOOoTde1WE}|T>4$B8c4>02qiGd4UhLAu(gRdFWC10P`9=*A$na2;_7_IWu8-@iU^T)K4LX745C|)Alw#7@xMevCZD|m2#5v<~H zUMcEAaU;+S%XlP*(A596ojq^eCHSwqtnY^|{ElCDOWscVW?RM~f{3{L`AD^%Ueg2rBK;u}B!yBRn1jkJx)^}RNN`ugj)-!oK+IrDPP_a*2 zSupPOFw`O2bX-FG6QRo6HsZL*9UPSVP`L3c(V!K~4G>|}D`9>r*UoSj0#T%Jt5uSn zOlYm@HaL%Z#Pd)1h1bHTeEC)5{s~3Z`tcQ$g%$MnL*ahd5e12tZ7d@_*w(|SvAqaw z9iWj$ny!EW_*;Lyj6*Q$o*cr`h|csQbl0YYcW{QN43LZ=UV~~B&(p9fFtvb%6`m*} zqEpRSDg7RC%$57ZGp;;>IO%wlg;cUq6$V>yQe3Bugu09>eL^Xm#M%gvp+h2(1L4Df zB0z*NN>1Rt6G$OWlZ3?xjru2``XA)gT;YJ|=itS0v0m12%8D28#RL>8i%)f+E=?L* zQ%4Rk4Neahr<;$j2xLr{_gY41wXAbrwO?PYsSk>$CqD0vh<%7}jX}QmbNRmEHz#20 zX#1jO8KEEqru3q)@5Iz&1IGnOf>x#TDe-BN^0S~<3@7JSaN-3TLE9vD`fQUp<=N70 zlXq~nP*k+rCO0AQa{D8<`Roo((JSDE)P}WK6QWD>JqPMRGD3m@<%{2Z8)wdU&HQ&n z&VSkk9XJ1r&zs|7-vk6Gn!rN$(xfsnJh1ZB0ihfd6#`ltI(6r?=@wB4YgEM||Qe&KrXlMGm;PuUmR z7;c&lvWM{H62lv?(NYYK^DYH@y|;x-MToJO=Td~D zHIU&UGG@DN0eS7WA!}ml{VzMPHQ8WJAnrd|v^iud^c`h_;#K2fkMC-Ow#^SfTY%&+ z-_fK%5}u7@2>p&SAT&h$?oZS?t>&snXfHGXf$GaEnFyO-ZXg@02?X?)%O;{mM_jkQ3#Z#Pv$3EKBbZX1# zK64kL`N-<_y3;SHvved2{8sVrep2TanVbLzzCm)7riI>hP7)c1)qwvD(My=r1PBdb zF9tUbHW(;+Q`Chf;~_|+UkHmt@J#U$2gCg76Mw8@_Fpi#4iK9&#mVBG1=#%eUi*$o z=I^$AX7of>;F&T-k9_@*>ST1;)z?Od)G%kuM1<25dIx6PL5RM@>3t0twnSXm1#cMp zZpt6}C-MkNAe=#mA0oCM2PP~;ZZ(!GU>_<^+y1bpvD28He)GEl90r^fG3aFo*K%QB z>#{}kxm%5>jjzDl(st*^bl9-yF)t{hL7y5t4${ClOz{=j zs3;A?8HZ!UM&R#Udl-n(qy?|a0N#kXJ&|S{!z%>_zK;tV=kQw5L##-#*^MI9Jq!~c zgzb(9#ek1^FdcOufUh9Kc6Z2ZkG(1ylqc_5k#(i2V{#DVn0M{O_8*+0K5w{Wh1cZl z+|}6Cb}JzleOS}DgB3}0u)7^*B|Wz>qvkpGTCC2TE99xI!7 znN=3v$20fkuf(e`nI`i@k*x_$-D@2lwkFu#&=%Eit*l&g+`m!lRa&|g?+Xn z!il<1U1^&b@Ww5C`9L<~e^R?X)BHkY74JfL5nkJ!6bZH0j~T<=@`;xN;Y$3Pe~5~` zlN;cnZba-8$EOYqd3im9ue=WbW_NDLa5vhSf-S5qW}h^o^?SY&HWzn<>h+S%^j`b; zqipI=cjYk;Jx40C77`|mzh**wAy%#xIT;<{ql{~?yNYWN5#zisV?nx9-?@timYP%e zb=oIen0f#eKpy{EJ_C_Zm{9^UkB%Z`Wqfsk=Ji4zb;$}O_MRVH$$Xmoz7C>!h-n95 zwQLl%fs9d@UJVdXOdu9>)o%>q2Xiqc{jbC6|a+4OKPj)4H;Ulh`?zEXEzW=@^QE*Kc3T%8?ekxJM!dL zRi*67%th=2lNZyj(k!*$SX@z9-8&7(-aV2 z5@H_kdup|kE3xA4MfP%^@;9=`#nmEFu5vv}(cDES%SIINEmgV2&5z6h9l@&AUT%UKE1 zj=?WtDT7=Z;5ulh`GY^*K$9kdoptyzm1W(`K*d^!HOXKi0eD11hJ}Wnp3J?C6^j%Q zVmULA^rGn<2vG?;DbUl1etCM%$UxJgG0R1wWnBU%kbgGDY6gO43B5y5gy*~Saz zP*bjpFI3p5M2;olSl+dE2Hv9O_7sE68cr)LVp}*rrat%Hx6|5&kR!X+-fWm`T*U&I zl?K=GW8CJlAL9KursC9I7AN{3VD2rhBiUWb?LyB-c_rNHBVKFdd|#z}^(D*j)RmR34YY1Y^eefE++G$>Sl|lXZ&` zy6EQ-qZ1*F7)S9O2^HA5iEL;<`eGz38JIo+7A^X=Cr5t2oEtZoXE7A-2j6e~6D7oU zyaZ2_J8Ev5x(i47+)?khJsa`uu2U`+F??}>%$#je-!odrNk@roVAgW zlqE62lti{g;aLOw@(=`Qy;=>n=`XMBQ!K1JH{g9o@6)*oxR!5y+J!FDPjfni3U@wX0w~Tq1;E^`9UgtHcT?Lm`LaeN?$e+)HX1JRW_h#9`_{1VzRvN&i)1`|j-ftE3~Biw@Vte+G$@W}XsH&(5PK2(VTngypQp=)Fhc2EM?|V)=JmbVa%OuDxFutJboQi#2w9XjJ1bC4W-w<#M_b@0^-@3+;vR9DNjPQlQj)$fr<6DdH zg-5ibBJ~)IzdH(c`rFV|&aZ`8?jQut@{T7voAE-hpNY_W9F*L$F%LTg=LWMrR*+jj zwZXv-DBDcW^#`!(Vb0Sza}THJRrmA{e&aslhue$SneKLP$A$;ImrYB)P4KP<2Pfgz z?!gJ#JvkocZ!qk4<~k!I_mp|4>z(G!O@|C~_3Peb|Arr);E0^w$NdieP0`)KkBKn% zEDj+0ujQf#a+PLH&8>3Z|LLTWiRjn)CwE$#x=+n%X5buE-0v^c%Fukmq*ZR)4s+E8 z+qBTc>Ccuh2e+A+>mGiLgh3}kUSVHkr8POTmIdYQVpfNX%}Y>bv5f{1#I_K^AVA4l zP5IXM|Dv_wGv>7~f9w{oO)h@QtNvZbV7C%>i<5lq^;|E0%Xs8{9a`?4s&-@X*S3Em zbhqEqwz>Fg8@fL4uHm0LQ7gW8P`g9>T2WCCU4QWXy}h~njqs%Ua`Pve>=gTnHo5E6 zhVJM0eQlEC3;NE5{yW7}ANv(X``ztU+XTPy8=z*-PZ6uqaIotJZP5Hn zVODa5!|Mv8xsC^RRW~4X-afir$B}4kvSSuOtZkExm_hH6yLOi1{L-iil|*?X6sj}~ zseROFk48&)QoyD#fSqRSo+4HsR&qFtRj{m#yIsGkEG)Ss zBh*{AS0GcGI*#b^4cIxz4TgUmem`2<(b3tQ*6=r*;J+mG3_-Gc|L{)9Oy>bmS zSzsRZ{J@MX3!Z!lQ(8js@&3Q==(xVca<&BAE2?Uwp2F*@l!|HO$>wHuMY5ybOR z@Ua|lv`5WmZ}Z`tS!zDo>bILmZFCvE$00M=K#0+;XWe7Ak6u$SqKc^& zDn;8I*{-8`Ip#7Bq)Z1!dbS#nKh+=BVeJBT?l0jCcmO8Q9nxd#}Wqhuz`+ zu#y{G*MZ@vGux}z5{B*NvC-${5+9ok zzTQgO)bM(%; z&7&K3nMXh2f@d7ri2xR`vpBM@{R+FidDL}5)={gp`m3UB4L&hBF){hPZI21@=wsKF z4fI`I2PPLVK9xJ~Hh6V=uv#fsPw0bBbWb9%ild1*hhF&MmP133-9e0J#n@|WBWh5}8AE z(L8K|U(FhDxt&peD}Q32{rKuCf8JURTsTN13K&>opsKbTVTNrk9r4VP$yb)Guf7mK zd@)(DXKpCW-t@UERc)`fCx^iKNl`JhPNQ;7XC+sveEM#P(k|Xw-Hw4FxuO{X(V|Ic znwZ9Jp}Kx#d+92BmkCY>U^XNVJy3%%I&5~DmF7ZpHu$?L-UHaR9S_A!o{r93~Pup5& zcvx*8-Bzl6@F5N*0Va-acYP9l3>ncU6{Plvbc9)PZGRUx`(<<)Qx*imkc1#;dUP1N z0rU4ru2A)My6vm&$0N*E;g_xIAm0BmFvu8PXq*sAYn`eaEuonyagh;`ANe}B5lI?` z2C#4btt)Vj5ocHt&)**HfeJ9S!qE>Ej<)Qoegf2Cpon)R&f|#*Ll$`PKVxfJ=i#-T zl{*o$w}RGwOl+T20n;H|LB+7!4fBfj(OkP_M5C7NyX^>Kl&sZ!brnG_VxfUAJvO3V z5LsRSP$c^$JF0e1z@tYv5NG;T%(WkW?=+6)5%hS^Pm@PWGxX;&1Xpgu#NA?Zd%wL3bYjKh|y(Ozv0s{N60-N~{7 zjfbGxaN#j*i$m{)8ExH2ZcC|Z=xFK$l6glYMLf-PsU`#oF|C^U}6~rM?PLU>g|FJ;KRQo=~OYiP%U;RO^~SK zJ=6;EfTnwVtTZ_}SsLV)fOe@oQm9;q;n!5XvJUetSL&<&CPc`6JTub${A$H5$#l?| z!jgsX9a6HF?KVYD>h7>0?GD=~?9S$BbZv)wcV)+}{^}=o zwN{CPzDsN*JxKfR&QCRWRQe;&T_ZES$1}zR0BL{{tP#y1irvknmh~Li`=*@(h zsbL2f#I#$Zp4(13E>^V|UC2EsD^%8YMv)mEUf0oH`E+O195GES!SVEtXE@%>z#3v> zp=O#{3j3>WU_So%Wa$ZB8slyW;h^BLVH{(@vX==Y^Fb_~?#PCb9Z^)m92xURPSA#= zKp%}ae)&ob(_n=m=CQ|Fad53a^59T;6~y3$H-z!&d? zs92S|)RJsMn%of|7SSYd!J*ddCtr~Fz?Q*Dt7)yn-fMRnP+n%~NU>l+y&T<6OhkDa zU|M^@d9&Tj1ie>orfd6XD{LsRoFor^f5iw!uj!0>D_xzHmUWCxU{@~!<$hVg;cxBH z3YNf}TDU^b*t!Yz$6GUqj061$uw$Pyl-R@n`5lmRycwa|H`q6I6q=i*k-JJqK4F%Q zLfrbTt3U}Y8E6kZl!8%nWL=>boZC|B9R*)A_6PP;K31j>1MD!AlGS^u>TNg+&dkd1veB4tslh>rq-^U1)8n zZ5maYF*#K~yiPLaUb5!zhTx^$awDeYdn7W7#i! zSGZ+}9!`(ZF*}g>9NtgKVsBp>+ao0Teo8+gCs!vlGvf`L`YO-Vq&z1u(_+4sj!$c zB#{I%$OlhI$&IRZXQg>$M>{5>IWpE>?G6-IU>go|0;?eyEWskmja;jZSnkL-TnuJZ zdct?3$q87}3XTLx_NL*Lq1ub6qrDsJm)$w~zRuAPm5$zq(QF6nM&0f4goxKz7|Mnr zq1|oJwfH;|EJEj7bMw->I@FaLH9VV2uTH;4NbLYxRS1_#uHf2$zC1R9|a(VTjQkF~LUIaTCrx}dtzq=DF?NeH~R_oYf?8o$m zdk|JXSgKmIgtfO;K^jI4+)HPKreRUQa(+W=E^!7 z>_wSATBsoy8_F;XpWqV_L}rkVBb3`#Xgd0<+A7hgOFK;$KH`}0vCP47!zqdgqO$2v z-i}$=)B(rEgaU>Z=qSAROFKHNE*bFt#l;66H+8f zWBU$=YcxJz)n= zbU!}^w-$Z|?2uttcx_nl)}r6dmCYp#^G-B0;qHv}3Xj~$33LT44PnYiQ-AV(9F}hy z#&mkX7EjxiX4~wvzVyMJyD&hlt>_l4ftZu=9DxQ0t!77|x1zRJHlrEWWF<4Ro#~h& zB>H$sm6_}GkXP^Dm2okjOlae>z0zff3JCaV&?!>K|Hst(0LgKlXMQuY!{va6DD41* zntd**`!Oqv;_x^d_=Y8I0m1G?3s>Ia+_t17waf8+L>`aiqpieEbU&W73kLSEAnB~J8AhD@y z?_7S2&KioGQA%|h_f@Jhxqj2MHk-4a-;AwhHDG0|i_k(WHgM}`*;CGDR8^kxTtfmL zyF~^|O{Ze(WQzQ_$3vCU5i^(bvEU-ARtD@ItlSgk#7@a`$G|yfTKdd%NQWv@$pYkJ zQ{dv>3;`r{Mn3fSvX7%Cxuc!f2Ozhb^E#mMSZDe?sPU|yyT-E60vL9&J`#|vwb&SC zT07T*Xjui-fJ9aW>p+wnk($|FMs&<%89oyrQ5(7^MBMx-};nvbgtbp zHk%n(qevR~E}Im9@W=_2ubf&-^}W8o$&U72+!n`Wat-uJpk^BxV7=ZS06w#1@%jiO zKS<^m2p(+F{8|0E`HI0Zp_K@v!^yD?wtRL~Ijf^=|Dbk|)cm7BXdu_KKyB@hW?v(; zd`x>SG~dv!gxc1$q3J`C&s5n0epRJ7T*~Iyp_#T3}Slde9#JC}}MqUlV;w zRH1xodZy$Og@{jC_V&UV*z^5^-DJ-@m~-a1$Ab`N3IYp@;-FcnbBc;IYf=k1iy7Z~ zP$gMXZORlY#pK%-SP7C~g_9mn8(XBfAwU>BTBnSW1Xe85kVUYOQ&S`QwSuLz3yx-^ zT=(#-fvB7XL6R?~h9rMAoN^Dd9n7;uen7$>0qHO`);ZZ4K^V0qA5A&%GqS{+d=ma- zFXB9n2pc?0WvLY%s^4+9v{&Y%05MoGM7-qF6=)_W2533xjh$FpmL&1Gc>FcpWE=uH+;?bKxB!C_Y2 zHgXI_u4D`NfW#RRTR@uxnA3N5u;C^}e?E7z@9iJtFUK*HRkXRY?!=q%%mvEC z;?B5>xH~tmz_Tcuz;#iNXHDDBuSrpbQ%SZaS(Sq_Hruf4{>jj)x&vfON#X*Utkt9z z>CZj4C0lNkjmhWh?7K<^HPhSHiIEDn->+bPwRu{_X$u!<_2Hgo5t7woXnyLvT~( z&hde&4kAT{sd^sd2GLPa3vLU`4ZD}Mv=*3P-H)i41}dsb0Fq6WFEl2E20|W{hE@l> zspjiZPkxGD^`R$)n;cqqCjizvv-A4>E0_sYI582+WA6+=JwZh< zccW|rOj$XP@fLlAZnC%M3&v08ckT&{!<+54E{M5h`zOs9HrvlKug6a!CBO)4cSnGM z@;810h{&A=TPV?ne-bsaMkm90H}aE|oDy|d8yirBK0>}RQIPIxdgkWjILAr_0G(eI zizDQ)%K(>#8HJV3q~}jws@px=nMKh-d^8=?>L710<^HV9oCi3CltRRsaEF74z@)D$ zZ?u|N`GrzY3nq60epvapst~+)$S`F#@(0ly8chYr;dr)AVD6QAe6Q>tj079Lq$qP? z3I`LjZxerP8>10q2+S)(@0TDp6#r1>vGl9zpqBX62+%@|(1iIDVq-;;N@^11k5LMd zq>a((q>9`a&qjzhVx&yI@BM%A>!0K=0Jw;#^dK8~?w+>?w|ls2+UUWvL@`aT zqz%W+&JOYyNJ2K~e34N)jjWuSdDQ~n)b805`Ty$gKTWce=*-9q&=6`K%74Y~wQnd~ zj-$;XPr#$>O;E-umz>4~f+#eX_#@S`0|lriR)}MWJiA@jjEqjp+F)m0QjD{iY}$G3 zdC@+*qHWV(0EJ9cyTu8#TYfnG0!;wrMh=N?OhpW`B{!OLtfZ{JckBP*Djxx`9kLi^ z8cEj8zhF}^VX8)KVcYW6QgXCG+cYe~p?ZZSD%Y7=PDQvA94C|RGs|qq%ZoLGuOy^L^Ubr_z<)%ZXHCG zww=D{(bXeO1dF~uf3#ORsJdV-<_+q1r6ncUw$TWuEj|C}Wr&hgJo_MXaURQt+b@;m z!jj;<|Nh@%Q1uvYa}G&9H%L0RBt)QHqDZWaIu zvXqSrNMmIQQ5YxW2Z!rN6(55-n7<`?mbB!t8xhxzJa`szY7J5|gm=x{OZE-B*B^{B zKN`X5kE^8!&+3IT{jh$5byeyensXO#Y~-f|LO}uZo&081SUa#QqlwTW zfc7@nKZl(SKt&XB?3*|Z8z%{R$(h#cUTa`Avw!1Pyb)!HED+eTeecLUQZ<2&Fxem; z)4zD8PaVhp&Yk9*z5+O)N@Nb6D+2*azxL^;1+0FOcuazAZeue*jr*52cDhFH_Uyjo zi$el1z+s6{c$>0=Fy5^AmHr^gieSP+Ncl!ERHaTuYpV?iJ)!F@Ofx#z?M5W3+9)x> z(%82?g|TkoerM>6SyUv%;cL#k=Z^A(dZ{R?l6x4_yZ_O>Pih8pR*=*6+pXJcl8Ra# zv+OD#&bG(*;t}$_m?*sh{?MQ%*i;cPcr(Id#Ayh_(#a}Q>Kp7oMc!4>T%krr(pM2vhzI(P-D4AgmdxJVo{pl?IjyWxRrI48dUd2 ztJ#>~>+T!2Ffa7iK#wd;)jJKMl{5KV%T-2{*$aw}82PP0I)-0NaLZ@E{8We|&=7AA z?+CAM<2+Ydends+%^& zH~MKNP2hSEZ<4s|Xq?B8?OqCCq8-YJh0fY5FhQ3F3jF>kMMvUMbyX8$cD&^fSaAMV7Wbhpk{$EQ?HKat@`oUU4dZd`ngQO$u^;l;ktX zr1-BQC`+qy-HG5{a-~Lqv;+o^NCiNvVP3*`W13}sy590%0q{V2+R^A}vQJvUEt73V z&A3y+E)UI%$q*c;-8Q#K1RXP5OP}#4SEzAasUzd67m$slj-~sll{!o0p-#Ty4`*Gw zS0ZUpNAj<%jwWBZHc$CAl*ovRMaknFSuilDvq z8RPy{BYUXmh3)UrY^d%rjwJzwLEyjo*wgG=Sl@bsK|t8Np#ag&PMr#k6_MFoPAp(o z3P=ggqJ1Ga^NJ&D@1s^x>Tq$iq@;vp+tM}7iEf?Tx$5LS+a1l{O82queUib51u|h6 zl2wS73gQ%Y>$2XQxr3+~W!~P1_8N^A7dNg+VZm9w_bcxeuv`OKhA$3Zi=^|_nXJ_} zOw=uftrr=dz#*leEe3*6MgjB(d5@UaD}jHCqZcEGnSll%M+%`pxb-1s<|AX-g{>up zvcd`NDQVn-$0etc^_tVq**+youKYQ;Bc`(EM4-L3yTtd@{Hp^TsQj-IxaB)G&ra?o zf}G=ol(P&Vr!*1E0{QT94OoM1f;?~BK$igXsW@QyknA#Wi=$iWRNAtW`jfr1n_8n9 zY8raBRY~5p5ijgz3n<%7m7am3`O-$%+&Pa3L5)=QD6p)A%8Pc!d`qz4uUw#zz9Z7O zf0dY$-Hvhe(_?kdwnugpqEQw%Pl~GR3z|86j#&r6Ev1t*h>>h~SD7;$O3UOCB z$xFU@(!`aLgD9u2PcH;G#XQ;G#;;0k8X;vxlCE}|adY!kC%dpuWKLrWLJm{h>ldCz z0zx2J(`@`;!b#Q9WlXy%hSKzuOK2)iNr0|i0e~-w1m#mS%A(CG0r1dO*edKNP>oCl zrgbZ#-8aaieaG7MBI-W4F1qRx9NPh;bITcuv9Zw(dy8J(00#%PyA+VdyZ`)`cxNp= zf$_zp{^{fmJ3^({=HdHkS4^i;WNY%Z&VHI@8>1jaWz76#AJ`dOT5X$tImv0}`t2q9jYT zgjmWMhWWaI!pzBH1ry{6xlWk}F~?kefW4bI38k)cALv_ka75VAZp3kjsx6sgm&W)1 z$P{naYP&D6&3kq$RDuRW1a?&e-JR+-teUnK8$|jbanQevo zqI`4bxSqSN>+B|PDe6fwH(vxg1!5aSu&mw|<_v8>Q=v@4#PQYAo@`)FfU;><2WdE!MTM>3i(uYy1!z`E zu%G&uRbD(7Ue{_6Epdp>;Ki2R;RrmAuvdb0ie<|HiRp?BO{~ByVM76(vo6eLK(Wcn zK#?V5Nu1r(t@~Y3B3bb~Q84M?{zrZc_Ge}DP;O#CibT^5GWU!#{hU5qC!ku8?+a4W zI4K@Am~Z2S+JE);zDe7kbjeio?4%ruMwu}=tK;FYy-JhDk z4{XiJ&X;%uIdAektX#R>q9=XXx57=zu55pi$5iaBGR75YS>F|pgwhbg0Qc;tj;5G75gGV zRVht#V5E_xpuz(n&S+g7W=pn~xjt`d=djL3@`@!)BoHAqQQeE`QNM^XLsXFo)%m*6#`3a?Q!l z?|E3)L((!7E+)1DyG+Pa6Xgtt@C%bK%W3+%PShiJ?*|wnHRe4N5vTTpU-+>t=(F&a z_Ez|An^1sr(jqwvR-p~qqelh5-F1b;Woz&$vUpnr2-FT|(x0#g%MMLG$f|-uYjR}=J8q;e;5J?AYpI932E05n@76ROykH_Vf{qRb(6!Yuna8J&-e9&AZ075zjT!`^@ao+*S5nW8!98n8x^ zs=ygRNJ{+dzpvnSXq-d+42p0>Wq9cFh6PF|u-S@4%P%&BkT5YzSPCCGH9g+htdLDf z7Sw!VZvR`B@Yy~Xt14TRDl9dSA3YnYmRl=uG0HC5LYoCB%`u1S(C5?GmXyRC7ycL%NDN_ z`6B448ad#IafHUtm#?rUosrnvMR-lg?CNH2q7b3}JCDbb1W1q^Vqs$@d=g%YZRrzB z33J0ojEet3SYi3dOj5I?S6`L{N~6sky}pkso~p2hMyM!T2sZd8vhlW?_WFG2akR)D zB{Z(3Ig}=-G@ zJt`H>_wWx(kWs4AN>2pRqndT+q^n)vv|)i1B`Zu!nwe?>P9mBehRWCH5w$1_vJz4f zKtui=l}q;TpDQz#!#y1wlHI=Df{r2`L9U5uIkP6lB9XgDh?M#S$ySTJl&zGUn2+Gb z5ulreiOtiQhI-+DZN$^{Ah(i*t;V3Jhpdo&*#1CQD3Oe>(TBJA`4uP6BAR_L#&*ps z`o7Q#HSpFqKKo-_!~Z6sdrf<7_&EBOW>PwK?w=z&xh@No-@sLDOun3oB?3>C`W$2z zk0bsQ$f}3YA_xULDjshsJzu|68dNjenLnfw$uFd1(JF5}c$OSM?rPbHZJU`%G~!6C z`9T`*Mf5cy^du1};O*!mNw}sVE(Btel~&OBm^{+u!6rbHO+({busfnEGR+BpMtp^4 zx&MMcxoV)}4y=eQAPShfZ?bB<%mAQMw+C8X>aZFu? zTJ!GF{cEe z8vtcOrzAziFmv4^#$s@?H^dAH9g1oVGYNMZex{g}5DoRAD{$=81Z89DYJJc#`Q9Bl z**@Zied;t=PHH038;m>ED+39~>l;CUlmo-VG-HT4K7aXUM72t#S1O7af;vG~ArduA6|2nZ z_5As4f3a%SA|4GZf^6Sr4n_LSJQytNaXzWyL$xe^-)WrqoeuLa{^yzEwL-Y`@Z<9EFeVyh%VAOn9J!Achh8&~^} zJuF|^T=RzpcB9<|t&7Z&%pxWonLD)A(&!*_T)G4!a`LDa*hk?0Y1jRu=GV0NgndV& zwGOtV&Vo2^{6V*fkO09{yM6p80asst~J{DenFoDha(+XcFFmY_z~DHXExoCxd{>H5Uk zDU!dRuP!K_lKCS}6AVNYMMS}Y3Ne(mbU_*s^yUt$c_Or9R^9B1r2NNIt|CEn{;gsX$PKGzo}& zJU}~L@wA@J`etv}7S@<<66F&Si-Q$p+t856Wv!d$Nn9v(;U;X$nvY!rA5OQqJP^zI z*rSiU1=o&j2BM5%j0`NlnJi+dgLU}Yv#30{raz?jM{x)+AGxKfh=pO&6Aq=%4o7fpJ8iit`1v_^M z2rCjj_@S*UVf-3l)8XVqR4TTf^5oLp7wL^(QAcW;EpR#hlFr^I&$gS|B|*-f|Gm&KtSgOTRaFW+Q)fHRgQj z6^gBIlUyk4DI+0iCu$5KV{jhF{GGMlz=}3^9oSNs2W+&;-{4j=njFZ)-|K%IRxKu{ zUZ;Ff??SqW#B0Sl8BSf)`mWOi(^iRaM3(?MfL&aww~=;dXI%;PJ)xjDe0d0wXO-y# zmz+uqoumE=D^I(F`96-}c?Xp6I0wElxr5!B6OiCBSeD79x<>CdrpjDY_aR0fMpUKT z4@gs4d*>%_zy|P4hzA?rPa2Kkl1jgfOIS{`Na~n2c7>Ny0Hmfy58k9cUWa3zLB9oYobN!gySoP`vA z07g3OjM(Vm<4-)HuP5++=yvRHwzCEa|BU8mFZ!8aG(*}eX&0k6=u1tZF@1zEH|$RCYrBsB0+ZS-Izx+jgM!)^|ig##gC zp;p|iss##MqejtJGv;5%1xsHU{}^vbNl^UKkbMJ1mWG{jYR5JrN`X=jyW*=QrtlNX z0o5`B1m)+Zf^udlB>rMy2EJhOXQfV9MI+W!aWrx`^sk}e2S!ouBB{hiOxk%CJ83MWuzf{(IBKe&Gda4j-(ReYl%_=u+y#vc%6 zs#kV;!R#umsf_FvQIHR$a`6LOwzKY^TpCoAJDTtB?fdzdDp_(@gfLA&mf$xjDp8aw zDd$}$%bhtK^~koZWVHt2Eix?a_x>Al#Cl(P#UE?mR%5iH5+YyR*jevWF1RYlx)>6; zoBg5>$4{1SGLi@B0Pw$5FR+j%6gwI~Er7+4C72onh>M=D*K?CW6@9)3ONIVs3!7$R zffZOshfz&y32~+xMOn0maRL^NDd{Z;aA%Y3>wmGIR3sj!A zyvvY^en$8uuBTmBjtvtRQU&6c{27^>m7ZOq$nhjGuymG1ebNx#BR>bEX~ybRs!Ud8 z&B?0dBBoYE2g9HgPnVs6+BqW=+SpFs98haH_HKNz>y;p!k<4t>QH#{OM%G`$-|C&EjmD-J_+oRBUBEUWDR~@XaL5!6 z9}VCC%>&WMVtTjbo>O$)QWUnKNITPum|-VV1QguTX~JOz9HN{w>^KlFLtP+Ck9j^bCpfYKo?OG#-J-@-) z2eY29nsXJ*yXf+gy$ChnWD9PVftL24bCNQ53$IF0elgm@S@^wk_Og(HIC6TPBliSR zVUIi@_`6|bXXt<&*f$kR zES`k&gN-6h1F>krM7Q$e8|Xp0uF4YM8iR9S1tA4c(a44>V0{N(JZ$6)rp~ajEL$kh zKROMcB8BLPTYlnqm$+@G=!9QyzZGHDQVmRw+c&8>W^k{Wiw6-M0SC|(A*CEKs52ux zHHA6osS<&c;1d9@iQRlkwYBNM9M9UL5;IFG0N9^QYbWjs1CexaC8BHq+ zz-f!&x@oI(YPtf6N{X16R}2nI!jepclPk(l#u)!uZ(~Y!t*9PN70_&~Y` zcaW0vNq&odUj7&Hak8?3#G&h)CU__LLpq8iAWV-ql}O1uS^13y>${x%G*?&FsDiv6 zRkTlclKB~NPzfXK8{H3%wbL-Ecbw%us!~!8EK-qDhzA@5hAU;=&iclV>9C>mS0h## zbM3%9mZr=$Vq!TlngT>cf*Xlt=b09Q^fVhS9v`gYKw~nQ%)}DB`E~s_s$4lM$2uNH z{K~kl*LoP{hQCyE$=3wb2A`sRHc!tE`h3`ha`uTl~*f4w3~DYN`j z&wNPmN*K~zPOqj`K%s~y@SXCt{0NMl;&}r9(BNHC>}#~F((`yq5uy33a6i$6lHbbL zE&(tsnuKhd#Z$>If(w5(tq&#_H!@Mtbl=VvfC7u76 z;g+OUU~8mFDZL>OLCLYA*~z|75{fHwtg>^QZAC`CspO*UI1lV{st7CKgNS!>uKW^R zO9}x-z`3=IjU&`{DhI5=jscp&XO>F;@*jP~^DZa1$&2G9E7kq zY)ER7Tsh18=RDhGbBSuMLFHI{S-@cYTB{Z0&umy`mD&f20TET<1$@A$q(o-y`=V~4 z!6Dr>7mH29u14+w;gsbhe9gP>{w&wP@oVd@y@kzG0t-%&-BUrc>JmxWUnr77xWN1x zXY_DVECBcl}&@zP)qkv(1xQl}Wpqo(E zXT4sk`rso{sMv7PX`shoDg=*sHp1zb(q{V5A4NygSW2%bx?8_j{F#=v6r)+w=k;6n z&0fFcWPRoB(@LvJ!sp_J8hPxU7hW^UaXqg8oV^bnSV>zwVTl4owkt|GAsVDn#qcxj zbA?#y3duR|`I|@=h^Qaf2mJ%~VXegnX~Kf`)KQN+W%7r6@RT9VM^VaW$J$6h$VU^A z@LnBdqsPWkpm3?QZIGjl@*n>vPlo>`Z=g=LBFguuZ1+-zPXRsG1kzN4!kmi|iWxt) z9f4fu)XqycMMghUT!Bez=~(% zwTN02w+97r&D#%Z($nDm3T5ppzxJV@CL(%RVkK3o?+Hm;mB`J!Nnx}_XV^r2tV*4e z`5JtJUmYVJo7MCHNic$^f!YNcQp5&ZesWbGz8 zm_Ej34U$S42RNI2M(1TMlEB{l-qSq6_)_vU`>=JwT8u-0K(YYfR{+uk>xxdhLvFBH z?z!S={F0zRg9*1#KDa;>$qxsMz5Qf=KltEC@j|NCC_4|M&n-bzmXSaKzXo6gI>_8J zFQN7ief~0cr$-gg#(BcnW~Jmb4}*_@X;QOE2UgHDr58fXh@a-O=YWE)L?GY*kc<02 z(22JCgEALWKsn4AIou!3AK^nVW%GppE5GSdOGKnF6n9twa$D~^QYSyT5z`?inJpINi+!pjBys=$RS`wyA60dh`Ddntf~UBQZMYT|1%-xO<&VGq z6n9?(1O8zYIu&ABGul*a9Op))C&fxd3F1MJ+AxVJ`u&siOz1Yk>LD*6Bnbq-z704X zNbIS3S&$!v$$Y$c{gDjbfrgJY=f1sIrO<}!Sv$I$un@-Ms~GFf&~B+DHfCC zmr#0b2HRI$xg;!W9?X4~bUn_y(nL{0 zsrDP61&f8ZYH>4x5)GD0P+}4?5h0V`FtQ>FA2xIu!h=ORixR+;J}0oAo&}%4z{KQX zCD`4D;{3@uizuPYjnl4y~0FKb{wcPBnG`>K*bztX;?v&1p~wFnSkWx6v}S?KV0~2OmKS%C?b0VVYz|@HV)?dRqymvnr0%LCdIM zCC#!Z30JZiP_JuPS+rB9v*&_t>;;`zfZPT6SB^4@>a=GR7fY)=Et|3*|9#mj5wyx!3!>6_oy*+k&CS13e$_4KkWiVn|NXrVIYtuyr++6 zfWo1u@2H8{x>TpbFo>9`SdgHSWDmZKRvPDoCD~uRaRdSK8pU><8#r#Oc95NEb*Sc> zPY~A8(c%h!6HIw#MZ*g1NcOy2_n9+dX;2$QZ6-cSal(4}lfnd{F~QtJ8f>Kuiru=2&FW}x@>Pd!*hxXP7a_2Gn9mdMoW zB|Yo*oXy+~DkNobQZ_=!Vkik(^%IxtQ<@|RlAfwaktZJz(jvepBNd(u(cuR`I{0&& zcTZUG=e5yu_?jFx>bi;9Swh2jj@;Jkr`dv1LBuc!Bq&iQ1X*f<_cnhqUEyWNAsy_k zFSYFq2I?66tuUs3L_tDID?%3A0n3kxrHUGRdi;{hZGYCFLXjX`Iu9T$0A-I;5gNqS zC(me*0O>>3ckKL;N5gzfF*x78$M7bnM7k%2AeLR)IEfBL1xJHg&q$)`Wfk+|B+>(e3DA0nn%t1@jol1i= zB{c8~dhV0)4*9{K{i&}O2m6Stm{eRP{Y1K1FizM7dq5j==4u^M`ixjr0euD*!B5Hs z(|q$AymN#(_gCb7T~1U_l-ZaZOFv@|sGlo}l8M8Tm;kB31l^=T85n_IsmBUHC=o?~ zKIT(WCA)QV($&%ZS=F}}eG<-IL}DTv&LLu++akd8z(d(oH-*FQy3WF~-;Qel>=M$w z=O(-#y((sWMpa*D2rl)(9MEC$z4`+;-ZkN^2Z1; z1vVDi2=sbpn=zHiu^x)wl;|+p^)WFHCXWw5Gz9m;4nft^75J7j`p(4;bjvb>b!suk zKju=t5{Dn$k+Av3FI9%zuOJ*EVfNeY3iW?y*qB^|izW#5D5r>_gv(*FGPX|G2C_=M zLv}>ssh0cPsij;>QmM@dKLMTxsE6yPezdPH?!(h`6%VBrAc z20u*gbnQV5=a!vk&0=Hx47@U>+n&|E4&$Z$^lFktFz@?h>aOU|cncWbC@ohM80bmr z{hQ{FX#i^W7Evu7r}W2aMv|aDV}P@_k)kB|TA?T5G77dgBb`BBG(5W}HNH^RB_07& zY}d&}m3rxAqe_ry0^>h8OB?UG%9uY$5n^jK2n zh@YQSeeUcTZCZH@XGoU>twLnL&foax5$+ig5h2G&Emx#)Cxcp^m<9P@EJFlJ03{NT zrkAu9|G{b@6~JCdy*$iM+=Bp2;Gyz!8X0ZMimP+eOYRaSG8iL&mo5$#mLQTAVFqhM zc?;voovGGDrPrLu-kiq?AjsVZ(=(s2PH?I$G@q`{W9VjRE+jw9^nYo z9AnTI!{A~>Wtnav=+!UdskyQTRcExy{_aKl2Bv0iJwRF720H6{Lo-R6?T82G z<_Li6Go9Hrrf48%Xvx8b6hTe8giLyHp;hJPE$co!DNGcgn?JVX1M=qq>Iq5()o7SI zryyrsu-*v4BLgVpMF>db1$QMfDjEAbrq9k&VK@;T{ix68yC=z3_ectNSRY{IQiJHQcnWKexqRF)0IMe}>){Jx#O6e%TR5X(ah0 zcOPDtpsd{`M80>r!^N2dkgsYdzN7s~_y@^9<@Vcfa!J4Sq@r;VECZ(tU&W5tGpY>Q zKW+UM<`p$(SE(Bz&Z$_cSVuu-+9Y-X-m{gL38qBGaW;yGZlfC6v34(cz+KPBEP{uKnSAd3t@{!K4qf8*+DGOlyA6GO*3+Y^ zi=QtSeIucGG!mX_gL&@a^ zD7G7_u~KXeZc} zbgC(^mqc!;l#9X07fT_^HY-W~c>dWNDVyqp0;6g`{$j_Z(BLEB7xwLvdx_pQ3Lqi5ZjWS&K>MZF z5l09@dV?9~kJ(#XLIdsY%#L#dcctfH3|-G-`#y*$OoS*UjE&abxTR)_8x3%t<+K|V zA0ZHi>;8~DI<`>ADN$Kw0f?B3C%TfW)=1CKNvOA(DhVHt` zXQVBH>wt`Y=sd;Sa>@SX*I*l*KS-oVz%+(s(Klw+AdZ%aC`I8X2vdo;kL0Pjl<;Y{ z2ev;9pi<%E5U}}6w1GVLhA-vKNT$QPqw2_t0dh&W^*{<`gJJ_5>)hv}!Krq`zO%5=d_mpRP_yr98_S&Q7ZYn>|R-W=kM+YfOEd~_R2e4+f*ltLySJ(nXEf- z;xr#<+!O%UV6TPZ!1PfA(G(1)XSq8nyGrFYqW~l?5|R(=Fox5EN&V6#YP!-}=M%46MgmY>O z8UOHT9Ie*eC@Sf2G~`1P9gADhqx+X!mjX76GW%_$ht!(H6Tw$f!M^{0y$P;+lYl^B z-;yhD38Zyzqq#%-zi%iqMIkjPcwPEcc!Zu^p@J@q5^9M(EBG0~Oc)F8E+`3ZkxpOa z#3I_ZR1Wkj5@33njx7+vY&&KK7f)z9CnP!@g26)VCEh_|p-5r#(yvFHC6@HhfAmfK z^#^!_BxL8?b~q)6PoDR)F9glZCAarSoqI$#fZ%?w|YTk zPz_j|WV+&POF@QQ&$cf+`4!5xo(&mj%pdLvJw#*qS>OawU+#6K=IERpPB_S|qx=f~dSaWaWrw#FSPMih5Q9oGP^yVL2-XE`$wQC}OdLYh z)yDl(Ky}2Cs0!G&qTYslKv+<2$$c_c7>MGLD3p`=s|QDY$*@P^uFM*rB6llPaBaFm ziZaJ>oNN;&B#m*MRq`-927ZEp{@n?w42cV&Y9$#mpEfzB^!z8_q0dvW!uk^F0ygC^ zkTBtFcFGj72(#<7(c13|YU8qYAgby8>oyi0Y(*J4qavx_*R~;%WzBWo9j@ZEY zHd*Zm4-3$s5M#tSm`cLV_IT~a;wbbE!Gw$)LGKh7@4ff27SmH^nYXKQRU}Ub-NS5i zwhrd%c|KWRYHK0}=S!(YZ--GOItXTVZX=3R1ylz3lywSPz;jC|h81b!vLBO>6LnBn z<*KM{*_r1|c|kC2m9R1`67E^KzoqHV9s}^RWPe29k*GM|PULdZpfyMDM zxA0qD#?ip}Ew68IRSw_ISK|xBVlGk>t7+Nw%a;dHv{?lKJDfdR$KKNFr;TDP$>r}f zZQapmfkU~Y8hU!b2lw_xY#iH0PXJmSy~xg07~kG}v~YWj5*k%X-6EuvQu8Z6`Q#Ar zR8YQc8zK%s$fiIRDhNtTRsMS7O<1G`cQzpcdqQ(6K4zt8afl8aPsM`iVTY(0kYrW{ zJEliQpTC{;Gw_h;r@`Z+BQmjS@}aE30MVp%36(n7*>aM_!5-QUB$e)-l;M$HBfL$_ zzvy$bH*Xh~OENomkp*xj;mP~QJ6V_dP!N*Xlbk9K43jDJ17aYLA!B1kn5&e?u*A87 zxM0_~h$7|Z_R{12%<{0u3^m3a(uAr9Thd15pqz3#%y$S~dj92`mBH+)Lmh6Pj&~m& z*t-uYEFxyhLrR`s{a@gIA#+&Vn4TaOFLY*At{W@UpQGmzwY(=0hP{R{?M;M1Y$(Is93Jl(A5wbJT51f3^cf~DUIe% z%!vc}_mHta2%*}4;8c)qV*Of7)Ss?#Rl?fMo$d`}N%^&sBfI5G>qSW2)Kqk5XLuSHEx+@LP#%G+5yKVxPMh#kPruaR&J3qIScYzs^iQk9QVI_=#^vmo!<%onA(_xKXls~%^?pZsS`)l zK#`8X8vG)I2t&z{QoT#V*T`i%p5h+_C^%0-)!RB%S#_!N^C0Hm1CuNUxp`m{MlqfgyujC;2v&X3pzT zz#D}~Tr^R?F4}(m-9H;4bmGMsOx<$PC4;_PAZ|{s5MpP9UScB5G+!=lB1S}bvj&Y8 z!`!*%(EKRaP1yYpdh##pp&zj zernmtuTo|_-g9{!lN-?yu0_1HLdUnu_P_hv0esW1JFV zP$WQyNd{nN=<$jOoB^in>?QF{k-(Q0eVMFjVs z(esnE?=5Cm2`WXrV`YNl@D4iew6Q`+rk-mDv-3Eu(1^H>*ge&)sQ!p}RbY@yH+Byo zlB}Zn2BJ~7+6CEUqK9S&RjV&ID)szXkF;<1@Q(|ee?pz{9CuFhBhBCc*IZB3*1#nC zopzl93}va=YTuk(bnKJQS_Oy!joFOS%1z|42|j zCB*Q%_E+sK;rnUHPL6FToGEi1wJe7!iHgh!Z-Gq#f`e0G_F~GdKbxxZfz82IfL8=z z(x-kwGBP#oX~r7?j1Q^zWyP_) z7wac6612IWji`*$GMcMg5GaEan)mS9f zJ`EjG-W`BC_W6lN=%%4#5InpF!^$)zec$KxvM)QRDvI-w1!8wZ3zINFKZFnX_fJ7L z6~l>ApZ)f|IVy+7@1c@z#9nT7quT(Kl| z^W=;xjRfd1+_oC9K#42ljZ%sCTb0$|)-r|T)ju$Jap+srE=BOp^ zz+;E|&fG~HbS3`LJvNT=i=jF8ja~l4#iwqs7~fBLIly-`^AG6gQ2SB9a!bT18+nf) zH(45%AcjN3zJYyG_K@yx!f}hZk>}Ry+<2>K0pSqxQ3~7Yu?I+fd8~`+(=N zF1nwd@7Sy8gAV4HSB<+i?!Y_XD>xkaHDb7FGv`D=tyb3c09}Mxn0C^=`H9~+!eY2` zKoZAV=P}AQ5mg);ggGX{V}Y(Pe?bNT`x8znf#Y@c`tO)0)oavI#t zwBd*OixgJ~%V$430xWTaMRmVDlF2L58hvPP3#P8(k{X>5-^{EC*2y~R2DJ8Y$+G_b z|M3fqO4A*4XWI|$Mk4BtFwqAX5Tf&9B4TLhNdP>1omsv5*1*RqEV&2 z{XL)I2zVOG$rOqse0Tn%uN6$<#~>z%$OwOt%2gQ$gWwZ3x63yk8a&4tE-`>i*l~8w zmuTzeO(7X2;^3^5wN>k#rCt^p&Jjd++UOGLxEE%9Ibvww`42;D>n;Ch?UFd-g$8)eS` z-(hc(r|`v+fw6ICK)Ed~{xv;3b)SNr;vS(8&p^_S2>DG9#uk?p`sjQ%4G7a=KYTSu=X|UYuaczUYTBU;XAS6J~$z6kUf8(c~(mvwV z;?(?PF@U;$gKDv>{EAaiMP`@4MJ-4fs*nt}QnxQkS9Gj!7FD<&mJP2-g3zNzNTX9G zEAd`CStw*U91xn97~DDMrWc8+q!`rk^f<{2({(DhC|9G^rwpsc;Q*ZqkNC_#19JW$ zE&kWS^;+vT-pyZWb#g9jW>qvK6u?N#sLY0>YbevBXzEe{M7S|%qQ@Wc=hSwbk=<%5 zV`_TPAVeJ6RHIS87jV-P{3gE`Ik+21%Ar=oTe1dy;hl3dxHqfR9Dx8oj~|a}hYS;z z?f>k(QYqHH*1m1N5;;m`K%$TOJ6HUy*SBrX-6&#~4DBLgB_L6=H!5-o=T*;8^uG>g zCIa?qSax_pryrV64rb@)1AFm%BWw4=UoI!Kl9@Wt^&rr*}KC)LS3lX%hR-@9r2VcJjhL_>i6&d)> zKBwPrq|Ltbl!FdqJda&IDzObD_0D&HB;cob^Us^1d6&9@2t%ygFn3%aL^JONgarBS zqO%|Xt|U#PbbT;c-ykGcjO9YkB+Unr%^G22Xqu}0@_@6NLBn?))DJ$IIgiMe6W0Jf zBVPMrilMbgw^Jrs^Xr!e&_;vZEE~vh^KEu9!$K0qFWdwgRmh^A-)LA6C2{T&j07FCI6xxp zq6*rQ%;lA2)NSx3v&Gw1a`a$zw=0YeZ<$FB)82%bEN@_;Tq2cK3~qaonf3f(Q9B+X zwtwT7pOzN_6WQM6h2w2f2dW&>$Og6(;gG^LfoCPG3R*17gfwy?Xs(r;B-^ZMG$ZmD zM4f!3BV`)rPl5G@NcM!8_xFX+5$_1XnOHW|d@7Fh) z6Yvv)D$Gq>IRK(yBfN);?LQ-L6ub&q?WTJ{!VvsX-htq9U=%EO1nTm|oERD~Ngj6Z zt-)xv>4GRroGkY+Zt-P^H`IR`tk+^*@>prk8^qRVShf4APrjrIl+(fiN(Lemvhf*x zNz*7|ky|JiSc9~W6Xkn2P3{e2@VwKA%^9(;x3{nsV}EzwuMyjzWF9m4&+2X^qfg;)w? zPD*;ZBmQIDh;JjHRN*rt{SP0T{)PIsIh2=p@m0dwjRVL<5(BK)HUp zAE9Zhr&l_b^$L82kt=aPl0Dxpy&}4Ul!L@$#aLY4?31=g^HN8aC@}$&aEUF=c>?h& zW1~HH0dmDIxC(*^g1Szerwju0u{306XVDY8%3CBew-oJ>T;S_qJ0Yj)zkljOlzhxJ ztZ&;PYA)12r|z2_rog%Lov#;5<3PcQ{rUo;c@Q%pm6v>{*VF=2_9I-ZjAn3al zoU|rx$vdz|TqBh4v#v;LWDN?-#QwQy>KIMw=?Rx^7^o=A(k``^=N?eVgCq&v?VtJY zj506jF|QP@-mh|p1yvLM^5cEZ5X?e4rwW$clD+~RpE8YbS}k#7m?@WDSH%V03OSAc z3WH9*I-b7d_FdOWtY*GX&Eye6Yl*SNIYVM(#}tvX>cq6W5wBb1FbO;8fFQfP=}tgVmWn@s6w$C8A==R3;Bf(ra~Ez zuJnvhIGJqL4|tW0&rRH*2sNi9Jnii8=T2;RN? zPb3V3BF1L<6$%4^Pb-(Wq6#X*D)oDZy>22Wi=rn)OCO?u*T|(Xtti|r8&zCUA_#TD z3%22G=mf0$yo{2%l}^>>0Ui7Nf)V42qmcV}O46LnxLSs3p^v_NgDJ=!3_eE(sWi%C zmjgs3&zx59{_ba~D>*x6f5T+4+Q^fD$o3E z;2$037u*A}`Q!+`QPRKv^GicQSb6JWV#ldmkHpM51e@|CcoJRqCku!V2pS{%c*|SxYjt>QO!`!b@t3ccnz<54EKWFr; zrS)%4KE2MV|3FCp7cVGoq>GRn0H{LrRys`6)?Kf#jT`v4Rq&~}ubKR`t8O2du# z8bMB#-ua*ZJ|lFBjPmgBlX#G_vzEbw;R_;_HkLnkwuSwLSabSLml$ zwqo5y=$9Wzc;z1h%$V`=?FbdQ#hY#5b*d3xjbNbk&Y%DI-+XgW1$vQFeR6LJj8|}% zWyTC(-ZF(Oh@x5kNAaG?L-XNd8Iqm~QgDE=1T|tEm_+AnmZF;w=V?37|k4TwR~>o`w8VeV+#==W-b0Dh2GNJq$EmquT=+ z&9>*wx85GjfA#<`nO|`C6Mk(o#U;6(iA{)CGB*P=7u)nrj5v>Y-)e%QYX86{4BnNy zsLk?k|DR9EFmG&cq38@)oMrQVS1S69{}eHoY)UF;LbTB3PG8_^C&!A(Ax_o6T4nWR z11KQ-p~_BnmiAI=?T<#Q3q&-#j}G$KmlewWs9(QVAQ7EAbA)i<_w=J1JB>aQ)zN%0 z8zUWZBUoWzRk&5WFXxLNe}ehhkWuK{ijZg16(3|>!=kqaF(g|f@Sb8uZm^;gvC>M< zZETW)u+Q@)toi?A?fv89IPd$;XI3M6L?h13aIhXi2(`1AB^L-K6Ex!@Jhz!y%#uS0 zigsa0ff-&*AfN&%PDSd}JJxB>`z)RX2NWog4DF*`Cm|q^h7~FP@se|KUwK`z6lg;# zU6GD_W!>CaRNTgO(}qmkzSLf?zW1}BY$tuC?H{)!7K`24ndkXF-{xS0#_7D%#D~do7d}(k3M;~kdd`8)m#7pDdq}l(-U|nGKNAYi0lO1Mx&@B$eyLAcI&9S zD2jzm47;u!YE8ua5f}2F%OK6M>B`F5WmdCaUf0bc2jo`uI=fUHJX*jNUF?u@Cv=AQxocMjm-z9`x#a!ztuGrz4L8U0E10gLD z-BH46thA25w9nfcTspEB*sWmlpQ9M{0-%XrL&es##l`&vU?z%NFTAj{z(}rNZmz$^ z1SD~o|1jLr?_Kz9*7;w8=Y2?BP?oYW01m1&l0?W`tHgI^R`$-^*X(wc1^C_ zcbA|vxi~z=k}5HhZ60|M<_a>u)*0$Z|907^3Nibc#6^}h;E?vBAAV+uG@?@I&pLXOTJAfK%=v6HEW zUOScO*no72z=fm|$_ViTG)QeB)AHq$FeDi41@`j#;p`y2>WmFk23|e?{=GXs%Sxmv z766>gF70DM45>s#!x6YXO+yHdy?B>kqafRAxMfVWHknJ06;u#r_|DtpPhP{=IEQ8zXlwjir(nOyjE;1n-OOF*X zd;_%Zg1)#`YaJ+3yrqebE}@k!b&n0e4QIc_eLCaNLL@#RJ|-TJi^Yay%T~&W(=>7g z`%>vNbB*wXhH}I1&ut~BD2j+sO_v4R{%P z!-N(EP!mnsSBn8RMW>DHFD#T_WH$(C>WZeKho6E(z0q+k$-d{`59O!lv%@&J3#_;( za?m;Y^dWe*RbAgChD?dA4#MlfVQa0=zIaC7!@r-f5sDqy(+$^H~kD#I0Eu z1CWO&sEUzs?*kyIbPP2?iC)tLv;fA)y~be&h9i1>*V(_|wHMc3!(#tvxI37-Hi=vC zBRZLYMEnF*!zaix_oXMThT5sYgPwcNQi{0tTRFjmSuf9ji9QsOV`B*~vPs|fsuT2W zKs%7af~CQp;!@vJ5P1fc2nkG3JF;!8HC9KPYpNbw_VzWKJ9M`D*oa9BUqgZmc)Ae% zqJeizHj2|h?644&kM!&9nmo)J9)g&Rvt=0@kPs$+JA04b@T)P^oX>F|&8CSEbIeHc zGe(<>GEXi9+&rhdpAa-IH1(h8U%WF(?EXd z<&GFLUgCkb;&8OlLJKu(|FhK|Ij5E$E1$Fmx+)pzfFkM6bpC5R`R@%OZMJDDxBL~* zCSaW+=^6nUnOQ^2gN-3|HIvm~8z=*m-D6L%Zql48Pcc0xeGx7ZAK+?+m?mtFy;Pw- zbxD1%Gq9JbevEE-V7;Rj(?i#QHnt;UZtPvE_dH)3Se_cly_Q`XZI0|@8TuO00igAH z4b8Ye_?^2X*4iH0kQvP)FfL9NFfkXBjwgdE3=;f2D_#Zg!e{rVR#!ds`PL3GSDczsDV7UR-~TiTjS|xY>FKg2Ge=#C`AIjnn+t zvg3|Wr)q-7QVmX-+a_=jp18AFp6|Xdzge^_)mkr00>YzgF zmR|4IN4^<)+;;^RL=G+0chMlLl6239m+b$R`=-cXdl2;=e(4XLyOULZT5U44rcGzkxf zN+2VRPoRH{3$-`Ba1>x%%#!Iv9qR zK*TY{GZ?&+I1PX>rm$w5vb(W{Ds=EX1T}~s=#V>>9>a*{zSnhO0k{Uw(O3aok>=6aTf$P-Mw3UljApVynNkrQddf^4>58sA%7-u}cU#<{c0HdYtyBZx65OY6$<;Dx@A zsqGiZM8yCp2D+&SpIHKzUB{`5Q)G$>{%7f{C-L~&ERPZ*ti7g3HapLfK897xW;dp9 zFV2^(>@Kp2<))EM<&(urYp_p2!U@M93Vd2)zn>3rzU)tT3YWpAWpkg6$+?OtHzMgI zA6i0O-v_@1+3WbnF{};;%uF@#e0+|#FbHxl=!Mr8K@xHo_OTH@4O_U7our^bIHEl+ zhDApOgA^6D8{7N*F$w~mko>U$b&?R3#J{Yuy#~o0J0cP`{n@`|gGhEjJ6}G9!Q~c8u1Yp_8 zm6aEC^mp|#n{0OMAMq8k!->&Zf@mbSzg928J1!l2hLLNB>r@ zmbk_16LR3L3-3pVHnF}&m%oUMwQRI{VYJ!UKvQF%C&AE3H0C?h06cRRctnTSnqIcK)SU0_{j6S9TN!CCEv>M{9AT+d z;kX8I*cp(IH$QClbXxZuF`K?0TA#?sWt^0ON)z7%5RbX#=w5jJ<9ia3Xr!feAbqaKdl@?{TsU&yPKLa@g(=ocl#TY&I zJ}k199#@p+*n>JFR|P>0qwR5mM&=<1^E}Bx@lXQn9cnz6fO|iJRf{)(JNNc z0ovB=ti|2XDz2~VQH#LbG9)};AT+6?+}OaMn7GW;F(Ec|NNofy5K}*y$&(R%~Qk$rv2=2 zg~bd5gyK`h0{J4YN*fD21^7DsEG$iO^GMWhj?INoHa^8g;OIcSxHrt$6v8AnZB`l! zEC{C>VK%7?a03pyL~2?tvaSMW%Rbk^Ot~_$^uj>#1$7eiO)#S~pDhvyih_@SX|vy> z?~R<-bz%+my}#$uqXMjn*}61^*tDGm_|XI%fZ+?c!!3m+FFm+ad4jTA8C|RBrfF&F ziW|NJ7Z?w;v<%b>Fk5ugel=^raRS42(I7^Uxe~y`{`LM3HQ`tM6G3-;90qS$0vL z7+C_@C%jo{Qi&gVG08wLM#yyhPiqF9Q~vG$^seA^Wic8HPbG5IJ1V_%YQb7?om`kT z>Y=}9;quz}$^-I4L)9H+(Z8osa_h}k{Bv?xrp5IYxjiSFr)ek$li0IUIp%i{xR+HpZY4Kuv*ji*NLQc84JyrwjIQ!lwPR2HY3hrW^&yH>rvviFZ=VN80($S;lu zbBP&wcdOpaP*J+vEH~0hvKW@kt(%`M&*c&o%C98mX=jUXl!m<800)KKKv67LKAbrG z18m4lTB#1iCWw=A4KJ~+exvrKeg1pO%~~pyh@O7fiXIDvJTvU&y1ixj$)U4-eqGK^ zxubG zWSxFy_1y4GY$uzZ2?`ZMwHMAMqj9c#JjiCho8_DxO%aN)QaXRGaK?)drwf(Go1W}m z501yfX5jnlWDL>exg<<0;jQ=1+qg^NVFIGNLSWydVbSzNiqlvk8x2}@ZNttrQng1# zuBF)e7-uISfct*88yk&grIPE%$|&2+vQgjT!$@0b&kIDcT&o1S)|QM~!blWHo$~->Z&@a<-EzIwFk1B)6KzDvNXzBTg)ep71CPYVDnZ*bUGv0ocUJlAg|O1K&boqNyp!M#{CMG8 z^(c{hq4%zO;hXKZ=7*@C!OBljPw4dg3Ez-fAIcq1aF0x_w5_s zzH?9Vx$mD$_H+2?diKhYdd0VtYB_Bu&$og>T6Zsp@1AmZxZ5Y6`sicH{mH&Pl^qG! zI;0-T=7-drbxP4VC7=BKPty7Se;&7fq5i`Y1sksdl;NERuZr)y-WUQ~kHeke&}yK) z$A+fp*F0|h(?5?kogTL>FDS{}^8}TZT)|(H#nQ}-Q!Cd3`{15<)!EZL7y3 zF(0&Uo7ooC%yI_vo0nIN|S`alNHlEGkDU_bfQ(Nn>u4?O!hc;L^M8 z+(g0fBI!=Pkl9n^Xi3H1{Y5rFuq`K%PZw6C(>#!7!MiUg>9xY$#Kz}s!#O=7syV@g zm=BK22TV15rX2N{3unry;KncSdPq8_tD6Kcs{bk$Bm1E)bTB%Iz+?M#$f#>*dj;+U`ducZJ z-d5;*SRTvFxvJ;I*UJ^h*k(S}~)` z&CuRrg$#2u9#8Qr_DPGfxKPYQrmGd(R<{>t^)gJu+K79=Krv)wM(e%MIZ=?%9`Yp< z*tS-C#cXWENt9ZR*i^4-+^b=rHSNf>ttY4Nvd7A{SsFjqA#&rExT&l2Ic*5l7}>nXg#0gZ?mk zhe+F0B8kGdtE0$v$i+{@n3G-JuRSD!fNwX?cp~Yxs*aVovvKN;j{1J@bbQ+L?Ke__q1ig9;jpx- z)-~nCe&U%d>M@iYrVWKj8gbf7klK*<;71vclry>fZx@@jvbZ`Ew!6LWx_;9!0#}9i z2769bu5F(Pe=8kM4pctaOp@gOrovIpPBiVrPXlApMLs*eG{0pyZJwz-|3*a}I}cF# ziRrBSGv$}OcywB-cy%cD_cxdA`MY}u*81km9HCLNx4z{24-(^?k-ug&_2WsL){qZuE#Xt_Bm=?1}r1*YOqrz?_k@ z=TlYE{%7^9s_m@$nd_Q14mLDYAfh@mHxZ>=>WR3f8g5QTMj98+_}7}qGcdx~7hwa7 zbL)X2A;QFSXfbNIka_!zIm35EX{xvybdRT^w0!PBQW+1$>Ov^&3O6y%RCETTDX;Z4 zb4lo?mA=r)h*HK+dj)Jza&AaGRQ75zEy$!D(7OwPud2m!iWyn;tz}X(rR=U{(fFdj zCu@WfkSJ_<|LJ?bjspy%u25tRYf&xuO>L(0o43u0xuO-$ZANOg<%$I(jI6*7^AoJX zXA~r}FOORubfiaklnEGvXsY zh$@?#Z^jlg5(dXTgdiXo#^SXy<@TspFH^E9JN)5G+X7iATu+U|Z6V!Vo*y6P%$y<7 zE#k9Pjww4`n265XSO~2YKX>CNh{1B$0ex-`pBu`AY?jtlko8->jUnP~CTX9eUjVT* zjQKb-h?sN>*J^ZDafgK1O_+18-??bPp!?HOcgPpD)Lqk+KiwJx_4*(DWK7QxQYYY$ zI`+b-$U-T0W%LD}Rl{H$?A-GVhF)~(LO-OfYYT>d zKsx4WZ`f!!T)1JxbdOfMu^uhu&N>#dphdK=VBC6gzm^@7w8Wb>Ha!sBXEmr5?aO{& zI#DG2qQ6K}H=itmQJ{xh3=uVq$dvLGPG~lq5Ye6Pb(I~qy}WNF^01ucj_{x=LUs~Z zef7vnl3O!HA!?T~WG1%2LVGYfz337dk=0k{zN^$VjWx*_DEOM46?!$I1`=<)Ey zE|0&3SoMhaqr{3iGh5v8PQlsZW5*NQT@ z=%Vb(;1o19`DcQn&o+FxXQL>t>&tmZ`O+^g84Hpt7X;UAb;Gg3~`SIE}=B) z&J-oq-Q~5$)BFc}up!HpM3>rX1?94R{h~g z+_G%X*VU-LRpfq&f{K=TP08D5G40&ZNA$@O-JFB(8sc zQNE9x*WvORURi2R%9hKMBm%jZV?$d@|FBki)yGT0q2_asrz_)$pHDp%#QYeIW1eR| zHPtCE=00;NPa7uyhv0;rA6VkT&wG2EkNo<(!csoh8k_1fPWdG_cOTmV zrt+=wcgt4my9?#>mDYbed9vSXxBO;&@P$Au2YxFp8qc0TY1#d6IoGqXa^q$YnEh|8 z)K|pUvevrlVXYKEk(FO@3i_Uu7o3*=cf*83*JJ;=;MnNsxym;7$lImVsI{&4O4mST zTyapB+nQLYE<5w}Q~N94{FrLo_ItjjPFLiWF87smUES*KZCOXX1RhP*eEoZys*i3D zWc8P}i|Y7va3Mp4Z+6=Kc9seCJ}`Y?(bl&rmZV>iJC=!{_4`0^uy8_N)hWRqDuP|)>)Be>q=jyN;;MMYNd$LKsf~((u>_R0Wku;kqHh`5>WU`Pswp|R zIr>}LReuwzrzGix6`lB*?Q&;nS>on(GxEkyetPi8-z9rgX3-x@0h zQ4WMTcc*c!99xmnFeUW1UsR4Ruu~*hlAt%wNrToWzLH#WBBkh`a7lX^30pn4d%dd3 zQbMPea8T8pcgA_qI+UFDX`xiru%0Qw9&A^I%h#={`SIU+53!P(7PUky+jm-rbU(k+ zk)2r0Udlum(1zem1Sb?Y5Ypm)o&Z`_PfXLWd4`snlDG$bg+!lhp$@q+vZ6y-p-;oV zr+oBLYhD80TE!(Jxlv5xtzJ)DOX$;;L*uvp$(N%sjCT-C>=Vx-o*-Ib!}n)1QCm4_ z5t3u$QWt+A3bDl*5ec_k*Fy|HsAY95G{zQ@Xt`C*6ZlXTQH>{9;g%)7j&O>MhhA5u z2hg5CM6zmqfjtL=#8guIa%N-BrA3s8=dRyXeYA*vjTc2VpL-K^60H|9@myv_2a6}I zmc>_!f%|D%kIwMFm2+ne+@aPf?0y4{!qU2YQYA;g@IuRV5;LzoN^MP)t0seLGYql? zZw*C?Xcc7KZC{K;C91pII&G`&`4NP>VqwJdhLxoG)tKg7<|{c|k~ zhF-MNwAs-iP~^^J)J_G_tmE^PP@U7ZOrd8SC-E)!${{^$Tnrc~HRTl=k{(K2i58>L zNF(D4%q$im6`L$ZQFf7DkbTf5`rupEs6@{|!t zmjm2u6_Y5Rh9n6g7cks&AH7Er_=n`rL`0=oZTp4%=~RSGzH9jlY3{IW(wkM3qqcj< zX7?tU5>NX1b%g=afe?P&t$AfPX&A}lCKg<{rx-O!Sj0yQMyCgT2A}qud0MH6Xow_Y z=Gzy0H|O8@TQA3NHIMmk{NBs)RP#jqYs2^M`M{0z?YYXm-Un_>ynSNonS7q#t>P1t z@};kRWMRq8-`M-|l_huE!k-Pj9P?Z0-)}W<`|3$vOf{d2-<})3FZt!!Q|ig`%LgWB zPqjW?{=FHNbhbWHUgB&Y`vboIV`uq(TpqX?zy0j+z2O7C{`Q0ShTGrXI9=x~D=)|Y z?X$eomM`CF%kRI_mIwcu9u53>kG}s+_9voC<>gYREn^2adQ`p`eth@C1orw-D`q5L zP1af=_=qUKr7dT-7?S1F5F-!TY19ZLfZs#`xFFx`YIeVWqTX9oh@O_n$O711nA)73(w7+tr z9K@B>O)j6^`MGB4*_l|(&xD~mQC687ik=jk2L!l^i}yz-Dy!#0lwH^(n@@S|jmnzgCJv7P1?o3cZL<&rgXP9qg0UgOm&Tww@3@KeCo>`ml*}eSf$Ubb+s#o0QfBwlXSu2JiQNI>|My>-guhJiu zgPU2L3l5j%{qAXZL0U?YW5}=#f_08~pdg)dKDj;+PhQ2nula`w%p*mb?b{|(+HEBk z*hQI(8W>7@T5AXf<1mnR-YV#u;!2thl#s;V{+-QHw|~!atzzdE*KBvJB5lVX#(SZ~ zl2*Wyam|7it~G1vB_@exV}fP7c|A4`%UBFM$_NW+XKP#)ZvXMPNYr9!tQ;joJEbnP4W;lMf2{1h*gor{ zAUn$TSaZi>!j_#P`YayeXFIU%LnRjwe#D~`SyYl>r9FkDH>c$ zS9@nAl|f4$sC!D0Z`RbjlYYhnEeQ+PJwgLVp7vt4cTqaij$f&#$?)yv|4h!A;u@OE zQLY*F;DcxV^zm#l%vUNm1_rYOLH+WMe*1s+a&zmhZ3SdTfm_9VE3)TxKX%E~Tq%jH z<%0ov&1OGU%nM&!b^a(dXn{WyC+erzj75^O$fOXoPwpoTYKu|FGiMDICnN-{GVxyp zo5Opw66LIUt}BP*^zC2V5i%lF5`q$%X`8?%7jxlG1HBP8dr3&6Nt%b&X-SZ$Xm^M% zBr%yAvZtT4nKzt7D^SXjvHqOWBl@O910QVjCchiTlj}xkTXwpc&rdZK<3DFLQmaso zvvtoGK`muOLLpnlfYcZ*Bq>G}eI};ANQQ2<67oI-vjuoFBa58v9HvuTP>+_W(`TFH z+jTV>Iv?J!e`9XWCPfUSQZ)}?6sb>lH^2yaz|;hNz!hRJkrvdD%^!Q zDzae6Xpa}u8*OX}igdT<&w~I6(T-Vvu+;&LV1li+tJ8UtpMBH%XAR07l>q zu5;_+M2JyCsUlMp&U4~|#ow8o3q@0As&geeQZP7Aton>qFEZoEtLW%Pv<2uhCu$fm z&nTBfGN=wf61_{>2RK|r3N1=RAuyiYXO)-$DJVoDJCdHm65AHLNK@@MI3gr_6>Rwj zCMELbTEIN$H=?ZV`F?yF1)xV95xYs=1Yro!3kB@Rkm;)vz*Px1X-Y#kAkXj}!2dw+poW_ zd%}_Ygt%Ffwy0?YT3{UkvPF|V5l!G{!2lw5xw@dNk>Ct4O6UeM)6gSBv~iw|FKBht zP%lJ-TfKj>tGQV6D?dLnvRP_Tm(#u3f^W^`LKUcI`OY-H|Pj93^Q%Q6l zY6-<2JT3-N%XdFGPog5zbq}`aG;EZ=*(BrLS)f=vR|N2)2F0jX+pj_rt zX7bBJS#zgv9nPc*Wxm{Q3X=@Gjt(4m+D59MXzjIy>1Oos45z z90ME$ycGE)Ip?{7%IQ7+|_i~+?vP*o2ol}?wK#9}^(H}k8plKC!P zhl&?k7xzzcM&PB*=t-BKA1CcO5y#Puv<@)UL7x87(=JcaTj2KCBIU!Yy@O9pBvlpE zIh9-W6iot}GX4E=+@Pgf2LDh@2Xeal0hb+Q!BHmU_A$47A}hJ>@pOfZ^Wx^CpEV&28?!bh)nc`sCGIPH{4iC5hd zYaG6f;)&T*8JY4`djjovyBFN!&mO(IIvxh9>gH-!tNF34)sw5O5RHLugssg-v#}LH z>=-`V{DSYSWcE;&*%PDSVDgGtaQv6udR8?_&A~fP0S3TGXicm!NE&cT8J=EJ?nAsD zt(qj);6@-58gtQ50MH2Syh75h6ZbddwZ)UMr8%S>b?(kRUZxQiRDmS zG3|+!pq4EQc_E8(yefe%U-WagnoaE5NlPtcU*r$WLW_4YEoT2p8af~#t#mvAfuo_UL2J|(wEK|{ zI?1hPUlenuN{*Ns@&gxO{E6%X3=D0WcY1O@zfXR+_@=y>-4o4ZjX3o?ZNu->lEO`b zv1=NQr2Emt8dDb|-3W-D#D>852<%2%r5d6;foJkNpcyCG=2v@hwXT1~@?)XEjf{_f z)x<+g11EwqY3T~pZ?#auTGnX}?i?IaBUOhXBmycLS}>e=n=js!hL{I>d&mQ_NbmG# zL1=_g))Jth`a+e<^#D&b47N4HFQ5Zl6*5_RykXjfB z-s&h;nLeJR&_dB8Bo<&2&>*loa3%$4B7n^Jzwry0r3wnQ^bhS~b+Sf&baHa*cmKGSOluHUTmhbHO{^fG<&s;`g3+&Q z1AV|$J-IJ5{VDkzjfswD03aGjwJtb#K%uuv7k;~NJu&c%B#uO@*axspqQF?o#nnoN z!}^ixL?KR5s|DcVAw~oJLqQ5eU|N>q+m}toPb05>H39r>9dygJav)@?QO5k(RMQPF zZhmv+D@_Y{>LgF|Oc?2v8CCZ*aVpbop@A8#t%(M>5aNgy2NAvC!$hnSC!s7T5=kKi z0GW#uJ~`@xYqmg?7)laelD&itM;iiFn$1bzO|@EyTsP;Jyk=ZsmX&g| zK!)><<#AL-6F9u;m_K;_J#!kD(qNMCfCz**X$oKG0CEbVNXR8~$pV^4Ja83*zBjODaeWmB9CQ2<0e)c2zIXBt zI`zcK4m$N$5h0MEAAwWf{7c}}m;YLbt8JwmvVoI*c>`@LL!H$yS>+vQYB~J;?XD&>R~HaF4=_srDveQPeHrWB*{Gwz z0Fl&-xDe+=0ka|k-asq#7swEJmP)_wJYwJspN_rFlqc1i$-TAEZtH^WZ$KUu% zuNykD`|-!dU#-r?Hs1g3eZx)S`Gb{UaWaruW1=i;faz?^XKcDjMAV~{Lxt1xBuX8g+c<~ z^vRMbqoE?w34(n(*6dmD@xwj&3e`+#3jV6!oS%^RC)YQXpQySk4j6~!f&tKA_*7{V zMa3XO`6sJgq1}2N#I@+qNyUA$nAS`Ro})G&FP!lt z+L?Z5(VTB-b)k-53lpUp_RREK4_tm0j6>EIrBi}OaM?p|v;`!-1#{Gl`0TkSdSP0ZL2t~vGAC;aZGd%@3+ zZ>cbH{!31LWGcqzOjmsnto(s=&7Td7V(FZ>FgUc`|0&-)U#_^zJ;gykIglA~%XAVc zqh9~AKN^!lLF^)LI___LN11j30?Ga=?G(rV>a!I$8-_^#to z^@~Hr(91n;_ka=9CL%Xh@uZC1E4v+0EjkaH2`&mzMHwL^S+IKsHMOE|Dzkmyu_12J{6-ry|d_{H=~}+SX3jqef4oK;N{xqtqFJN{Cr$DAH|O zg9*kDH%PF=xBnd$62>`^w~P0tAGGz17dowqfhH5>08T}|XSFt+26bzhD6Qys%!W~F z8sJ_W077B}#1`|H%Tcb-^sF-ZG1KubAe~l@tlQV@LhWOj;9NcOZ}0vZ^3s>8g-mK0 zlKv|Sozb38r4@$mn9w}?Yc zOp6jV5sD)z6TGs|v&7EK8Lx!YpF_u^-KZsW(e!R4P7e}oENo>AGc@{KoV4RKLG@zl z()`T^c0@QDuc4EXNvAPZN_=}g&Xr72gYxZCyx_Y@DX}7e9dVX`M_Ta5oncEbkitDT zDfc_oEIx@g(>1N4`ckmkd@tP@qcM1^*vcbRFhJe!xN)82y$u-!@8m_EB^iEjks9+_ z-Z%6U#8MR!53PDhWG$9(R}h+LV)gyBatMWwBPXkS;FqQ!oTI@Sz~hnZ(hcH=k=b}0 z0I?0P|IT9S6m+JO`ZP zcVO4r!pVY;WIC#2`x@ca-D^mrLqo%vag6Nbl3I`T<0JoJ6M;bl=*&;#Cl#$xQQ5Hq zzj?a3pE^cjI|e?+6@@x8))XM2)WgrfN$PZivrB`lKns!qYUr-g=!0J}B>Z z^5gL*>v24I>Jz{Gvwrnw{n8&b+rEFluXf0X+=Y5?^}K)7RcG?<{jS?@?DE{vcsh>h zC%CvP2`<`Htr9q9kfbQ%5exC0FH^(X1soQy^+x`>H;fEH;t4^>O`s6 zI1yLV%2miexTB_wUGU`7XKVsY!Iw?z3((fD>z+fJ%=g!F%W zdvq|319dS!2S=-!O->&9kTX9S|H|*PiP+O~Ta4sahPF=1Z;n3(5H|5hb8_*Uk8}f< zwSJ-M@0T=jGCo4h-`k{NE>fy@I9fmYtzFE5s zalY;SWLWA_R}Ss#GZsk9KQi;(feE+#^@V3uEqi_KyJ_Z4tUsJu|JZ2(D16=hy6RqZ z9-jQLCVj-uO1E|1|ApfLn8)#O+&xupO-u*!7vAVzte=oFzIEPjSXaz1__D4zzM6#2 z`QC)pYTYvcY|qItvhe2?Csp#(G5n~}@QXl99n9>CDg9~}JF77s^YOAX>)ijAbEbTy z7sk?4srA!!8JS+6uwjxKE5)cV+h?~P@z zXLlg1a|^$+?(}@|+|88R)t+eIn|ZahhiCk^Wc}4@Ey} zRS+h=d{w;u-Fw0Sz^_W7_;5GNo9d6$vheR1v-K4ai$mPj7JLU-C^j`*)B`#ys$G8Vs>bkW zE2vhXzNR#slz-c!PZMhi`{V+wCBQ}<(hlZ`O%ZBW*X~ezl3V|9EZW_KrdG|tZ3g$c zw(|RP7I3Bpu&(^aCJ2h;|NkYOFL-aaq^9wWi&s;RKFK%Uvjs+W5;HBT#;G~)@8R?qd1I)|K|+uqqHXC~Zh;q7J< zxp&{^I3S|LIRMk&M6FNAM*wKs08CKv8ujVm0@(&Q7g|~E4UbVg=Em|WKI&UB+N|kg zs(`uOreQub1Tj40z=(2D4){O`=p;H(h076Hw^n{#$05}mc-*Ge+e%e)N0ljtee(;- zhXrW$+{`8}ce7`~^kC01|3A~f+FEj-W7NXK=(_*Sy5p*DmJ9Qzl_)8P=nmk@7CBf7cpo)EB>GiK_D z21=RgUtoW_KtI_mKeo2HVc&}L@OS^&Z}P$0^Ahd6c|@bp{xQc%0aCl`-CRpl$F|rY ztYq-)^#bwjgnXTA$rdoPr4i;tgO3`W29^VlcJ({}T|F#OYExb5WsK1w-q8>*2(#v+ z5niBJ+x+C#6aPx@f@bqgJyEP@W%&ZPC&=`2Ui$ojX3rP1s;%K zrqy9cbZe!yc0hI1JZ|jM%9r6)F{H{ie~@hkRG%R2TOjvUt;(5Vv^lWXDz!3N(Rz;? zP8W=@;CO~#8}wZOxc=Qf$-#t5-TC^b68BWkyl+z0AjOgUrH1h$9~cg=ryT!}D$I#A ziPjeyH{-f0Otxct-HRIltr1Y30xLOR(Lq=iYya+2k-YEG+?-E%g0B}zRpyxgr}ssv ztAgtz)a9sL_T~+@$~Zhdcb6-@A%&Z8&R2+auIajK(3q4lUnV})fE>{YsAhpbuH%5I z1496(t&*eoF2Q+V^y61FUZ?e(U@-Z^J7^s>onM3f^;fuL=XU(g1`F)*d4RT+FU>qY zugPRzDn2e>8vezd&kfu`$zIq1><)adLnr(Fmk(^v$sYU%d-iKO*~<41Y_QUvc;cA% zBUaik?tEVbb{Z$zIM2NsKpEiS!=3Z|h?e%>fwuj(xov;-B+u=;)0n^Q?S~^rD|BP% z-A>)B%Foj(4ck3)hut=EZ}`lXut|E65au2(XBw=V$%ve1vQy1wza>tTv%d9gPL|JS zq`zpdWF3vE={K=CPS7UAq)3i{Ax9mEP6x~X#iO&jEi$Fj|EL0kMWx?A|37dXu;@%&(~xN_Y)^Hb^!d0uj+uccGdZCsVS zU?IIB$#Y+=r{im^qL7360$dq@HiAil->pzf%pDT8lqURpgqI(JiU8(64t%i13>J*m z%frk`rc7EQ7b3%@q`f8+*2KDLxIjXi#%cVh*IY;|RH7y-5*CGA8@9a2@jvLz$H`)h zjc-anxk4r(l0^-a0-2d4oKi6hMI*i^A(cp@aO-&=2EFYcX|s}oYEf@wwH!kRl(~QP z52H$ggcfa<{5BJ>(zRd-J$?5FOni{GiqkYl>ux?5?Qsf^jPwmXN^;VA!@Hh36gVbS zKm?yZhk1uUxZn@Pwz=O~t2zJ?rvJ-;X<{KZ!Qn@ZRhiV%qilWQ<^*-&JlS|eX-G8u zO}qTsxrhI8mki=XL==i~SY_j7@IlbavL#BCT0S=|OV*Lf8CRZL%$rKB9bS~`KoD<| zNBm!FhFgv9vDDq=`tPmG*WvHow9P{0&|G4V7q2n^ySzN{bJd?&V&P8cd&7a#>y3ly z567GAaq2Z;a+5NDm=q>;dhN3|q2D+hy!p?`tt^_-T|qLNpZE8me)w}EVAfqEIuYhV2dyVAS4mADf{R(W=7d|>3Rq{;%LK0hrw z_hR>CDal>SJ7fLV%0_8oDv!uY-q{}iUp(bal&cfH^SR!^{MurEqUh(7LsRynQ*nv7 zA*@VP)@1D8-z(Qvy&7@O+Wcg*4_f&ie>?_}j@Rt)dRk8xkGgP8Ce=rsF7zxIg)Tve zNmoiuP-XYw-J9*$YI`@^ZS-uc81G2KdEeXHTKmqc%(pidclo7ve{olLcq?<`(s}2| zFUsz{{vvBBOXCk*sfXaFPPy#^T)%hn+zuGyWxs#W0}Km`nr%Vi7KDEagtXO36EjQ( z+FszZa?2TO=hqZDTlEG>g=dv|(oISQb61^F&B-|Lm2Pk&>S(-7p&x;V`StMQ>vxfV zMmRf6L^TKdP{txId7JIZhh+3FFo2;gH#JwWh6(KUo_2EXbiv5y9CeLk@|T@WQL||v zf_AOq!lNMDC#Pv^qLmwwMr*^SX^3{ktCz{w#h(NrCV`l36oLKDKM^b?@Q(PV6Ux$N zc67_)$v9evaDwMo0m$j$uQ3;$g>% zEhu)ufYoGAm1`Q`laE5a2HdcQjX0SED4BiSLP1` zZvsjdNl|SUuNxvL{@fl)G?G~bWfQiHh99C$rE0|G$I4sK2O3F^*I$cxf}SEzJ4}lQ6ehR zFl2m`x}S_oybE^b0(`7{e3Q{&HUPVDRzMZRXZyFm{m*G!M2sEA94&aqwr;oCkmt~_8a=iB3o5=N|pA8L>k z=S&pNFGTBn{?9iDyhO7BRmVnAuRzoW|>R&KEIeRmM4k|vTf<(~>hO}vOOKT_1eJ3&+@x7@V7$v`Hz$p*i=%gXS z)9wNOvSG1*&Y(991ELu!VQ<5lj!RTPmu6+L)SY!SU+1hWFo`x{?(w5rdXgogjzXcCD&(|p; z2G@&0{jBrS7Wb5!Kihl1XR9x68!P6!T3%AA^gE(tqP~Uqr zKNI*n;{A)${?`IGco1t4jjs0&UoW!g+dUD_N(gkpEA`9$#{GJsaMeGQNBVC3ocz$A9%)_A zjab7jE%x5_hgyDk#{b${GQsuZ zquE3@YP}9#2Ky_qT0lEhO~C6=^xgV5Zx zgJ+Y~p5+UGob`Rd14G}z;Ktwp8d^!!SeKi zdgS+9XX3j@zU1;PKn*3ri@MdztO^v8VFN|H@=N=AjBpaH4q%NarU%cn4J`mKnhxF! z>XlWnX8Y#YhIEBQz^e5qkOFkX(MJr1etzX_7Z1ln63JIh%+pGQp>7_`5ikcPDtP*;35qQ=`Jig(O8A$mT48o zRER;lXo3qlYsm>Gcli(XR=wNv`^Awwev|-$)&bot9|49123fYBYa zdrGFPz5j1G0Q{^6ynRHq{VS}1)@v$7Ypf#n$EZ+J&AStSS^}s^V<17j-ZSos+%X1s zCAj7H{0qy6K8GkZs9QzNCPF4aeWmn!E^9X3ZElI?ZR-gb$3Q$B#~^~nt$*~Z;FD1W zkUG?mS&Y2--!Lw+CUo3EMQYCBU{ZvC=YQG44MF^x6ZTEwJaz$R35Jeo)Dyc)#XKN; zjSjZ_QDoEgroUTflh@Uy;;M^}b^Y!c1{FKy+2XqCdIKk9v znOf^W%GyW`J%FzE(?GYs^jNiaFpH=kc;pL)$5$-$HA>?eq`89Ajwkk?r!A% zGuItLfxbGbSnEE3%CWTgRK^j&_Y36C>s6NWhb7Za{&$xJx{vjBRzZ&Ko9v0dG36t; zd@etl&!Gql^=bYHOTSUqQ^YP|2alRIli!Rf&LfayAGM@Rm_ zJ1E_c^XmTcqR)4hYrY)6wbUW!efgcGqxbIFv9WaY4#)4`&vkc=ADJC{}qzoJB@i~?dX3A7nwPqp~FW&8vTg4z>gl^{#{M{3T=OrSSC@kcXP2`vzl_#4gd5r z?qKXCpLoiLnxW*V<9~Rk`<>Cc&nhbKxHCFF_oCrOn~xk!rI*j`bW*m(*y=$FH`GIZ ztu0hH%dkF7=6@nk$~oPWL~ry@*4z2S9|In8sm8DQ>jjhIuphS@= z696H=&Ta8w#}3A%QsQU9y1g3Mhjj*CMdYxLi!@w_To${LF`e=`K(||e{EQYBaIg+@)hwwUj>bV|<3IXJzIGwex3{uGlxaq$Mco1gn*LtLy_K^P@Y zE(qo=_E=FKYrK@d9M@(eHiNP9I*+rTCZ*iPfUku|-GnVu>QgoMlh&C7oFv)GqN=#& zmmp)Ypt5SMC2^cjCWBTkk@-QONuYmhY}!>d;M=&>8;WJQcYo-Z$JUZDX`WzFY0TD4 zh1=VI5%pv(7pu8IF2Hm!Cvy1|xI(`JJWxrWf*8owVPFeEs7PG#vMkpM(CaA2A}|Y% z0*iW3?TSm}l&?%lPgN_>BVAn-g8?UvSB-h2)L>IK_Y(jo=JCknjK9 zW1_aCYEyQ8d{Kn8X5>0Oeg&S~-k#^B!|pT)o!K+d%!6#yinVaRoD5q{$4`^4)A_~O zNx3742cPxr=@{I%8zLLyl+4z5Le$yg&$qW#pYqLD>+$`pDF(8N9t-j_(q4D|Ki=Ly zI*#kQ^L$k*!7ZA0x=N*Xse?#eg=(q+K@!0*4z2h{y+SqEgdwW|!y1I+!~_h`v?5!g ztex>Vn^jk%nrzaLO>$_D;v{Q=0u|chj4iF5$)1xR00r8#t&B*Ivct{sY%GtIV`sf1 zP%EEJva{>`+-gui9M7Kov1f|}&_Al)kNfWXalh|-@0&Die|Ze%gVDI9~gT`tdj zpMY%#-LC#6?=4agK!o6ur@s^8zT->>9iuZh8P4C(o@8q&@WL>hFKx5mm+e^d2S%>< z2PbO}LAa^T`_B4p&iHXK4zONUY&)n2+e4cB%oy%H*&F|{d8Y|CZlATyMmM&(xwU*G_?o7@ImwK~nd&pAS`b=5F~$pmWd zw{&2vm(3h~VX#V}ePn9U@J8V|1=p z_e(<;cO`3;fig1O48q<7m>i+abOg+BWW@15Xf)$y+gVq>?~SA_qiFgaE7FDA*c}LI znE^KmvQw@I$ z9k;8(Ayvy>v1{1L?o@@v9n9rXEWWAX4VJcj#_4DZi*ef1^AQ%>Z?oTE08#AI^Nd`4 z&2S{cddt{mf+STzCVchqU2ndl3oHSO#Eqq?BZ^I1Rj6fm~q{LIU~&7xYAc-N$r@r38Q&TgA^g9g7))X+yRLDhAks_8ACU z+L~ZRIcWGwZ+y4S%tHV;K~I)LYAdtP;;d%$@Kh^Z!(Jawjn<_az~Yfh84k@SywMSF z{R`sii0FH;lSWZcl0*=tY+WTs5UW7A*&ZWn`M@)YHEJY9L|*KJCm_IEGFu9bPyg`e zGU|?IF@WT)UMS9K-ikcri^g<(3sJ!YMqr{bGhgTgbualWVR;jf58tnvtd%0D(z8lc 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

w3ogwNsQ9gP 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 literal 0 HcmV?d00001 diff --git a/Acorn - Electron_MiST/clean.bat b/Acorn - Electron_MiST/clean.bat new file mode 100644 index 00000000..748b4d5b --- /dev/null +++ b/Acorn - Electron_MiST/clean.bat @@ -0,0 +1,38 @@ +@echo off +del /s *.bak +del /s *.orig +del /s *.rej +del /s *~ +rmdir /s /q db +rmdir /s /q incremental_db +rmdir /s /q output_files +rmdir /s /q simulation +rmdir /s /q greybox_tmp +rmdir /s /q hc_output +rmdir /s /q .qsys_edit +rmdir /s /q hps_isw_handoff +rmdir /s /q sys\.qsys_edit +rmdir /s /q sys\vip +cd sys +for /d %%i in (*_sim) do rmdir /s /q "%%~nxi" +cd .. +for /d %%i in (*_sim) do rmdir /s /q "%%~nxi" +del build_id.v +del c5_pin_model_dump.txt +del PLLJ_PLLSPE_INFO.txt +del /s *.qws +del /s *.ppf +del /s *.ddb +del /s *.csv +del /s *.cmp +del /s *.sip +del /s *.spd +del /s *.bsf +del /s *.f +del /s *.sopcinfo +del /s *.xml +del *.cdf +del *.rpt +del /s new_rtl_netlist +del /s old_rtl_netlist +pause diff --git a/Acorn - Electron_MiST/rtl/AtomElectron_Mist.sv b/Acorn - Electron_MiST/rtl/AtomElectron_Mist.sv new file mode 100644 index 00000000..cca76be7 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/AtomElectron_Mist.sv @@ -0,0 +1,134 @@ +module AtomElectron_Mist +( + output LED, + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + output VGA_HS, + output VGA_VS, + output AUDIO_L, + output AUDIO_R, + input SPI_SCK, + output SPI_DO, + input SPI_DI, + input SPI_SS2, + input SPI_SS3, + input SPI_SS4, + input CONF_DATA0, + input CLOCK_27 + ); + +`include "rtl\build_id.v" + localparam CONF_STR = { + "Electron;;", + "T6,Reset;", + "V,v1.00.",`BUILD_DATE +}; + +wire clk_16M00, clk_33M33, clk_40M00, clk_4M00; +wire ps2_clk, ps2_data; +wire [31:0] status; +wire [1:0] buttons; +wire [1:0] switches; +wire [7:0] kbjoy; +wire [7:0] joystick_0; +wire [7:0] joystick_1; +wire scandoubler_disable; +wire ypbpr; +wire hs, vs; +wire [2:0] r,g,b; + + +wire pwrup_RSTn; +wire reset = ~(status[0] || status[6] || buttons[1]); +wire ERSTn; +reg [7:0]reset_ctr = 8'b0; + +pll pll( + .inclk0(CLOCK_27), + .c0(clk_40M00), + .c1(clk_16M00), + .c2(clk_33M33), + .c3(clk_4M00)//8,3325 + ); + +ElectronFpga_core ElectronFpga_core( + .clk_16M00(clk_16M00), + .clk_33M33(clk_33M33), + .clk_40M00(clk_40M00), + .ps2_clk(ps2_clk), + .ps2_data(ps2_data), + .ERSTn(ERSTn), + .RESET(reset), + .red(r), + .green(g), + .blue(b), + .vsync(vs), + .hsync(hs), + .audiol(AUDIO_L), + .audioR(AUDIO_R), + .casIn(), + .casOut(), + .LED1(LED), + .SDMISO(), + .SDSS(), + .SDCLK(), + .SDMOSI() + ); + + assign ERSTn = pwrup_RSTn; + +always @ (posedge clk_16M00) +begin + if (pwrup_RSTn == 1'b0) reset_ctr <= reset_ctr + 1; +end + +assign pwrup_RSTn = reset_ctr[7]; + +video_mixer #(.LINE_LENGTH(480), .HALF_DEPTH(0)) video_mixer +( + .clk_sys(clk_33M33), + .ce_pix(clk_4M00), + .ce_pix_actual(clk_4M00), + .SPI_SCK(SPI_SCK), + .SPI_SS3(SPI_SS3), + .SPI_DI(SPI_DI), + .R({r,r}), + .G({g,g}), + .B({b,b}), + .HSync(hs), + .VSync(vs), + .VGA_R(VGA_R), + .VGA_G(VGA_G), + .VGA_B(VGA_B), + .VGA_VS(VGA_VS), + .VGA_HS(VGA_HS), + .scandoubler_disable(1'b1),//scandoubler_disable), + .ypbpr_full(1), + .line_start(0), + .mono(0) +); + +mist_io #(.STRLEN(($size(CONF_STR)>>3))) mist_io +( + .clk_sys (clk_33M33 ), + .conf_str (CONF_STR ), + .SPI_SCK (SPI_SCK ), + .CONF_DATA0 (CONF_DATA0 ), + .SPI_SS2 (SPI_SS2 ), + .SPI_DO (SPI_DO ), + .SPI_DI (SPI_DI ), + .buttons (buttons ), + .switches (switches ), + .scandoubler_disable(scandoubler_disable), + .ypbpr (ypbpr ), + .ps2_kbd_clk (ps2_clk), + .ps2_kbd_data (ps2_data), + .joystick_0 (joystick_0 ), + .joystick_1 (joystick_1 ), + .status (status ) +); + + + +endmodule \ No newline at end of file diff --git a/Acorn - Electron_MiST/rtl/ElectronFpga_MiST - Kopie.vhd b/Acorn - Electron_MiST/rtl/ElectronFpga_MiST - Kopie.vhd new file mode 100644 index 00000000..56c13fec --- /dev/null +++ b/Acorn - Electron_MiST/rtl/ElectronFpga_MiST - Kopie.vhd @@ -0,0 +1,113 @@ +-------------------------------------------------------------------------------- +-- Copyright (c) 2015 David Banks +-------------------------------------------------------------------------------- +-- ____ ____ +-- / /\/ / +-- /___/ \ / +-- \ \ \/ +-- \ \ +-- / / Filename : ElectronFpga.vhf +-- /___/ /\ Timestamp : 28/07/2015 +-- \ \ / \ +-- \___\/\___\ +-- +--Design Name: ElectronFpga +--Device: Spartan6 LX9 + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity ElectronFpga_MiST is + port ( + CLOCK_27 : in std_logic; + + VGA_R : out std_logic_vector (2 downto 0); + VGA_G : out std_logic_vector (2 downto 0); + VGA_B : out std_logic_vector (2 downto 0); + VGA_VS : out std_logic; + VGA_HS : out std_logic; + AUDIO_L : out std_logic; + AUDIO_R : out std_logic; + casIn : in std_logic; + casOut : out std_logic; + LED : out std_logic; + SDMISO : in std_logic; + SDSS : out std_logic; + SDCLK : out std_logic; + SDMOSI : out std_logic + ); +end; + +architecture behavioral of ElectronFpga_MiST is + + signal clk_16M00 : std_logic; + signal clk_33M33 : std_logic; + signal clk_40M00 : std_logic; + signal ERSTn : std_logic; + signal ps2_clk : std_logic; + signal ps2_data : std_logic; + signal pwrup_RSTn : std_logic; + signal reset_ctr : std_logic_vector (7 downto 0) := (others => '0'); + + component pll27 + PORT + ( + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + c1 : OUT STD_LOGIC ; + c2 : OUT STD_LOGIC + ); +end component; + + +begin + +pll27_inst : pll27 PORT MAP ( + inclk0 => CLOCK_27, + c0 => clk_40M00, + c1 => clk_16M00, + c2 => clk_33M33 + ); + + + inst_ElectronFpga_core : entity work.ElectronFpga_core + port map ( + clk_16M00 => clk_16M00, + clk_33M33 => clk_33M33, + clk_40M00 => clk_40M00, + ps2_clk => ps2_clk, + ps2_data => ps2_data, + ERSTn => ERSTn, + red => VGA_R, + green => VGA_G, + blue => VGA_B, + vsync => VGA_VS, + hsync => VGA_HS, + audiol => AUDIO_L, + audioR => AUDIO_R, + casIn => casIn, + casOut => casOut, + LED1 => LED, + SDMISO => SDMISO, + SDSS => SDSS, + SDCLK => SDCLK, + SDMOSI => SDMOSI + ); + + ERSTn <= pwrup_RSTn; + + -- This internal counter forces power up reset to happen + -- This is needed by the GODIL to initialize some of the registers + ResetProcess : process (clk_16M00) + begin + if rising_edge(clk_16M00) then + if (pwrup_RSTn = '0') then + reset_ctr <= reset_ctr + 1; + end if; + end if; + end process; + pwrup_RSTn <= reset_ctr(7); + +end behavioral; diff --git a/Acorn - Electron_MiST/rtl/ElectronFpga_MiST.vhd b/Acorn - Electron_MiST/rtl/ElectronFpga_MiST.vhd new file mode 100644 index 00000000..3c7a209f --- /dev/null +++ b/Acorn - Electron_MiST/rtl/ElectronFpga_MiST.vhd @@ -0,0 +1,106 @@ +-------------------------------------------------------------------------------- +-- Copyright (c) 2015 David Banks +-------------------------------------------------------------------------------- +-- ____ ____ +-- / /\/ / +-- /___/ \ / +-- \ \ \/ +-- \ \ +-- / / Filename : ElectronFpga.vhf +-- /___/ /\ Timestamp : 28/07/2015 +-- \ \ / \ +-- \___\/\___\ +-- +--Design Name: ElectronFpga +--Device: Spartan6 LX9 + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity ElectronFpga_MiST is + port ( + CLOCK_27 : in std_logic; + + VGA_R : out std_logic_vector (2 downto 0); + VGA_G : out std_logic_vector (2 downto 0); + VGA_B : out std_logic_vector (2 downto 0); + VGA_VS : out std_logic; + VGA_HS : out std_logic; + AUDIO_L : out std_logic; + AUDIO_R : out std_logic; + casIn : in std_logic; + casOut : out std_logic; + LED : out std_logic; + SDMISO : in std_logic; + SDSS : out std_logic; + SDCLK : out std_logic; + SDMOSI : out std_logic + ); +end; + +architecture behavioral of ElectronFpga_MiST is + + signal clk_16M00 : std_logic; + signal clk_33M33 : std_logic; + signal clk_40M00 : std_logic; + signal ERSTn : std_logic; + signal ps2_clk : std_logic; + signal ps2_data : std_logic; + signal pwrup_RSTn : std_logic; + signal reset_ctr : std_logic_vector (7 downto 0) := (others => '0'); + + + + +begin + +pll_inst : entity work.pll + PORT MAP ( + inclk0 => CLOCK_27, + c0 => clk_40M00, + c1 => clk_16M00, + c2 => clk_33M33 + ); + + + inst_ElectronFpga_core : entity work.ElectronFpga_core + port map ( + clk_16M00 => clk_16M00, + clk_33M33 => clk_33M33, + clk_40M00 => clk_40M00, + ps2_clk => ps2_clk, + ps2_data => ps2_data, + ERSTn => ERSTn, + red => VGA_R, + green => VGA_G, + blue => VGA_B, + vsync => VGA_VS, + hsync => VGA_HS, + audiol => AUDIO_L, + audioR => AUDIO_R, + casIn => casIn, + casOut => casOut, + LED1 => LED, + SDMISO => SDMISO, + SDSS => SDSS, + SDCLK => SDCLK, + SDMOSI => SDMOSI + ); + + ERSTn <= pwrup_RSTn; + + -- This internal counter forces power up reset to happen + -- This is needed by the GODIL to initialize some of the registers + ResetProcess : process (clk_16M00) + begin + if rising_edge(clk_16M00) then + if (pwrup_RSTn = '0') then + reset_ctr <= reset_ctr + 1; + end if; + end if; + end process; + pwrup_RSTn <= reset_ctr(7); + +end behavioral; diff --git a/Acorn - Electron_MiST/rtl/ElectronFpga_core.vhd b/Acorn - Electron_MiST/rtl/ElectronFpga_core.vhd new file mode 100644 index 00000000..b88598f1 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/ElectronFpga_core.vhd @@ -0,0 +1,400 @@ +-------------------------------------------------------------------------------- +-- Copyright (c) 2015 David Banks +-------------------------------------------------------------------------------- +-- ____ ____ +-- / /\/ / +-- /___/ \ / +-- \ \ \/ +-- \ \ +-- / / Filename : ElectronFpga_core.vhd +-- /___/ /\ Timestamp : 28/07/2015 +-- \ \ / \ +-- \___\/\___\ +-- +--Design Name: ElectronFpga_core + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity ElectronFpga_core is + port ( + clk_16M00 : in std_logic; + clk_33M33 : in std_logic; + clk_40M00 : in std_logic; + ps2_clk : in std_logic; + ps2_data : in std_logic; + ERSTn : in std_logic; + RESET : in std_logic; + red : out std_logic_vector (2 downto 0); + green : out std_logic_vector (2 downto 0); + blue : out std_logic_vector (2 downto 0); + vsync : out std_logic; + hsync : out std_logic; + audiol : out std_logic; + audioR : out std_logic; + casIn : in std_logic; + casOut : out std_logic; + LED1 : out std_logic; +-- LED2 : out std_logic; + SDMISO : in std_logic; + SDSS : out std_logic; + SDCLK : out std_logic; + SDMOSI : out std_logic +-- DIP : in std_logic_vector(1 downto 0); +-- test : out std_logic_vector(7 downto 0) + ); +end; + +architecture behavioral of ElectronFpga_core is + + signal RSTn : std_logic; + signal cpu_R_W_n : std_logic; + signal cpu_addr : std_logic_vector (15 downto 0); + signal cpu_din : std_logic_vector (7 downto 0); + signal cpu_dout : std_logic_vector (7 downto 0); + signal cpu_IRQ_n : std_logic; + signal cpu_NMI_n : std_logic; + signal ROM_n : std_logic; + + signal rom_basic_data : std_logic_vector (7 downto 0); + signal rom_os_data : std_logic_vector (7 downto 0); + signal rom_mmc_data : std_logic_vector (7 downto 0); + signal ula_data : std_logic_vector (7 downto 0); + + signal clken_counter : std_logic_vector (3 downto 0); + signal cpu_cycle : std_logic; + signal cpu_clken : std_logic; + signal cpu_clken_1 : std_logic; + signal cpu_clken_2 : std_logic; + signal cpu_clken_4 : std_logic; + + signal key_break : std_logic; + signal key_turbo : std_logic_vector(1 downto 0); + signal sound : std_logic; + signal kbd_data : std_logic_vector(3 downto 0); + + signal ula_irq_n : std_logic; + + signal via1_clken : std_logic; + signal via1_clken_1 : std_logic; + signal via1_clken_2 : std_logic; + signal via1_clken_4 : std_logic; + signal via4_clken : std_logic; + signal via4_clken_1 : std_logic; + signal via4_clken_2 : std_logic; + signal via4_clken_4 : std_logic; + signal mc6522_enable : std_logic; + signal mc6522_data : std_logic_vector(7 downto 0); + signal mc6522_irq_n : std_logic; + -- Port A is not really used, so signals directly loop back out to in + signal mc6522_ca2 : std_logic; + signal mc6522_porta : std_logic_vector(7 downto 0); + -- Port B is used for the MMBEEB style SDCard Interface + signal mc6522_cb1_in : std_logic; + signal mc6522_cb1_out : std_logic; + signal mc6522_cb1_oe_l : std_logic; + signal mc6522_cb2_in : std_logic; + signal mc6522_portb_in : std_logic_vector(7 downto 0); + signal mc6522_portb_out : std_logic_vector(7 downto 0); + signal mc6522_portb_oe_l : std_logic_vector(7 downto 0); + signal sdclk_int : std_logic; + + signal rom_latch : std_logic_vector(3 downto 0); + + signal contention : std_logic; + signal contention1 : std_logic; + signal contention2 : std_logic; + signal rom_access : std_logic; -- always at 2mhz, no contention + signal ram_access : std_logic; -- 1MHz/2Mhz/Stopped + + signal clk_state : std_logic_vector(2 downto 0); + + signal scanSW : std_logic; --q + signal mode_video : std_logic_vector(1 downto 0); + +begin + + cpu : entity work.T65 port map ( + Mode => "00", + Abort_n => '1', + SO_n => '1', + Res_n => RSTn or RESET, + Enable => cpu_clken, + Clk => clk_16M00, + Rdy => '1', + IRQ_n => cpu_IRQ_n, + NMI_n => cpu_NMI_n, + R_W_n => cpu_R_W_n, + Sync => open, + A(23 downto 16) => open, + A(15 downto 0) => cpu_addr(15 downto 0), + DI => cpu_din, + DO => cpu_dout + ); + + rom_basic : entity work.RomBasic2 port map( + clock => clk_16M00, + address => cpu_addr(13 downto 0), + q => rom_basic_data + ); + + rom_os : entity work.RomOS100 port map( + clock => clk_16M00, + address => cpu_addr(13 downto 0), + q => rom_os_data + ); + +-- rom_mmc : entity work.RomSmelk3006 port map( +-- clock => clk_16M00, +-- address => cpu_addr(13 downto 0), +-- q => rom_mmc_data +-- ); + + via : entity work.M6522 port map( + I_RS => cpu_addr(3 downto 0), + I_DATA => cpu_dout(7 downto 0), + O_DATA => mc6522_data(7 downto 0), + I_RW_L => cpu_R_W_n, + I_CS1 => mc6522_enable, + I_CS2_L => '0', + O_IRQ_L => mc6522_irq_n, + I_CA1 => '0', + I_CA2 => mc6522_ca2, + O_CA2 => mc6522_ca2, + O_CA2_OE_L => open, + I_PA => mc6522_porta, + O_PA => mc6522_porta, + O_PA_OE_L => open, + I_CB1 => mc6522_cb1_in, + O_CB1 => mc6522_cb1_out, + O_CB1_OE_L => mc6522_cb1_oe_l, + I_CB2 => mc6522_cb2_in, + O_CB2 => open, + O_CB2_OE_L => open, + I_PB => mc6522_portb_in, + O_PB => mc6522_portb_out, + O_PB_OE_L => mc6522_portb_oe_l, + RESET_L => RSTn or RESET, + I_P2_H => via1_clken, + ENA_4 => via4_clken, + CLK => clk_16M00); + + -- SDCLK is driven from either PB1 or CB1 depending on the SR Mode + sdclk_int <= mc6522_portb_out(1) when mc6522_portb_oe_l(1) = '0' else + mc6522_cb1_out when mc6522_cb1_oe_l = '0' else + '1'; + SDCLK <= sdclk_int; + mc6522_cb1_in <= sdclk_int; + + -- SDMOSI is always driven from PB0 + SDMOSI <= mc6522_portb_out(0) when mc6522_portb_oe_l(0) = '0' else + '1'; + + -- SDMISO is always read from CB2 + mc6522_cb2_in <= SDMISO; + + -- SDSS is hardwired to 0 (always selected) as there is only one slave attached + SDSS <= '0'; + + ula : entity work.ElectronULA port map ( + clk_16M00 => clk_16M00, + clk_33M33 => clk_33M33, + clk_40M00 => clk_40M00, + + -- CPU Interface + cpu_clken => cpu_clken, + addr => cpu_addr, + data_in => cpu_dout, + data_out => ula_data, + R_W_n => cpu_R_W_n, + RST_n => RSTn or RESET, + IRQ_n => ula_irq_n, + NMI_n => cpu_NMI_n, + + -- Rom Enable + ROM_n => ROM_n, + + -- Video + red => red, + green => green, + blue => blue, + vsync => vsync, + hsync => hsync, + + -- Audio + sound => sound, + + -- Casette + casIn => casIn, + casOut => casOut, + + -- Keyboard + kbd => kbd_data, + + -- MISC +-- caps => LED1, +-- motor => LED2, + + rom_latch => rom_latch, + +-- mode_init => DIP, + mode_init => mode_video, --00 = RGB, 10 = VGA 50Hz + + contention => contention + ); + + input : entity work.keyboard port map( + clk => clk_16M00, + rst_n => ERSTn, -- to avoid a loop when break pressed! + ps2_clk => ps2_clk, + ps2_data => ps2_data, + col => kbd_data, + row => cpu_addr(13 downto 0), + break => key_break, + turbo => key_turbo + ,scanSW => scanSW --q + ); + + mc6522_enable <= '1' when cpu_addr(15 downto 4) = x"fcb" else '0'; + cpu_IRQ_n <= mc6522_irq_n AND ula_irq_n; + cpu_NMI_n <= '1'; + + RSTn <= (ERSTn and key_break) or RESET; + audiol <= sound; + audior <= sound; + cpu_din <= rom_basic_data when ROM_n = '0' and cpu_addr(14) = '0' else + rom_os_data when ROM_n = '0' and cpu_addr(14) = '1' else + rom_mmc_data when cpu_addr(15 downto 14) = "10" and rom_latch = "0111" else + mc6522_data when mc6522_enable = '1' else + ula_data; + +-------------------------------------------------------- +-- clock enable generator +-------------------------------------------------------- + + -- ROM accesses always happen at 2Mhz + rom_access <= not ROM_n; + -- RAM accesses always happen at 1Mhz and subber contention + ram_access <= not cpu_addr(15); + -- IO accesses always happen at 1MHz and don't suffer contention + + clk_gen1 : process(clk_16M00, RSTn) + begin + if RSTn = '0' then + clken_counter <= (others => '0'); + elsif rising_edge(clk_16M00) then + -- clock state machine + if clken_counter(0) = '1' and clken_counter(1) = '1' then + case clk_state is + when "000" => + if rom_access = '1' then + -- 2MHz no contention + clk_state <= "001"; + else + -- 1MHz, possible contention + clk_state <= "101"; + end if; + when "001" => + -- CPU is clocked in this state + clk_state <= "010"; + when "010" => + if rom_access = '1' then + -- 2MHz no contention + clk_state <= "011"; + else + -- 1MHz, possible contention + clk_state <= "111"; + end if; + when "011" => + -- CPU is clocked in this state + clk_state <= "000"; + when "100" => + clk_state <= "101"; + when "101" => + clk_state <= "110"; + when "110" => + if ram_access = '1' and contention2 = '1' then + clk_state <= "111"; + else + clk_state <= "011"; + end if; + when "111" => + clk_state <= "100"; + when others => null; + end case; + end if; + -- clken counter + clken_counter <= clken_counter + 1; + -- Synchronize contention signal + contention1 <= contention; + contention2 <= contention1; + -- 1MHz + -- cpu_clken active on cycle 0 + -- address/data changes on cycle 1 + cpu_clken_1 <= clken_counter(0) and clken_counter(1) and clken_counter(2) and clken_counter(3); + via1_clken_1 <= clken_counter(0) and clken_counter(1) and clken_counter(2) and clken_counter(3); + via4_clken_1 <= clken_counter(0) and clken_counter(1); + -- 2MHz + -- cpu_clken active on cycle 0, 8 + -- address/data changes on cycle 1, 9 + cpu_clken_2 <= clken_counter(0) and clken_counter(1) and clken_counter(2); + via1_clken_2 <= clken_counter(0) and clken_counter(1) and clken_counter(2); + via4_clken_2 <= clken_counter(0); + -- 4MHz - no contention + -- cpu_clken active on cycle 0, 4, 8, 12 + -- address/data changes on cycle 1, 5, 9, 13 + cpu_clken_4 <= clken_counter(0) and clken_counter(1); + via1_clken_4 <= clken_counter(0) and clken_counter(1); + via4_clken_4 <= '1'; + end if; + end process; + + clk_gen2 : process(key_turbo, clken_counter, clk_state, + cpu_clken_1, cpu_clken_2, cpu_clken_4, + via1_clken_1, via1_clken_2, via1_clken_4, + via4_clken_1, via4_clken_2, via4_clken_4) + begin + case (key_turbo) is + when "01" => + -- 2Mhz Contention + cpu_clken <= '0'; + via1_clken <= '0'; + via4_clken <= '0'; + if clken_counter(0) = '1' and clken_counter(1) = '1' then + -- 1MHz/2MHz/Stopped + if clk_state = "001" or clk_state = "011" then + cpu_clken <= '1'; + end if; + -- 1MHz fixed + if clk_state = "011" or clk_state = "111" then + via1_clken <= '1'; + end if; + -- 4MHz fixed + via4_clken <= '1'; + end if; + when "10" => + -- 2Mhz No Contention + cpu_clken <= cpu_clken_2; + via1_clken <= via1_clken_2; + via4_clken <= via4_clken_2; + when "11" => + -- 4MHz No contention + cpu_clken <= cpu_clken_4; + via1_clken <= via1_clken_4; + via4_clken <= via4_clken_4; + when others => + -- 1MHz No Contention + cpu_clken <= cpu_clken_1; + via1_clken <= via1_clken_1; + via4_clken <= via4_clken_1; + end case; + end process; + + LED1 <= not sdclk_int; --Q + --00 = RGB, 10 = VGA 50Hz + mode_video <= "10";--scanSW & '0'; + +end behavioral; + diff --git a/Acorn - Electron_MiST/rtl/ElectronULA.vhd b/Acorn - Electron_MiST/rtl/ElectronULA.vhd new file mode 100644 index 00000000..2d67b25b --- /dev/null +++ b/Acorn - Electron_MiST/rtl/ElectronULA.vhd @@ -0,0 +1,817 @@ +-------------------------------------------------------------------------------- +-- Copyright (c) 2015 David Banks +-------------------------------------------------------------------------------- +-- ____ ____ +-- / /\/ / +-- /___/ \ / +-- \ \ \/ +-- \ \ +-- / / Filename : ElectronFpga_core.vhd +-- /___/ /\ Timestamp : 28/07/2015 +-- \ \ / \ +-- \___\/\___\ +-- +--Design Name: ElectronFpga_core + + +-- TODO: +-- Implement Cassette Out + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; + +entity ElectronULA is + port ( + clk_16M00 : in std_logic; + clk_33M33 : in std_logic; + clk_40M00 : in std_logic; + + -- CPU Interface + cpu_clken : in std_logic; + addr : in std_logic_vector(15 downto 0); + data_in : in std_logic_vector(7 downto 0); + data_out : out std_logic_vector(7 downto 0); + R_W_n : in std_logic; + RST_n : in std_logic; + IRQ_n : out std_logic; + NMI_n : in std_logic; + + -- Rom Enable + ROM_n : out std_logic; + + -- Video + red : out std_logic_vector(2 downto 0); + green : out std_logic_vector(2 downto 0); + blue : out std_logic_vector(2 downto 0); + vsync : out std_logic; + hsync : out std_logic; + + -- Audio + sound : out std_logic; + + -- Keyboard + kbd : in std_logic_vector(3 downto 0); + + -- Casette + casIn : in std_logic; + casOut : out std_logic; + + -- MISC + caps : out std_logic; + motor : out std_logic; + + rom_latch : out std_logic_vector(3 downto 0); + + mode_init : in std_logic_vector(1 downto 0); + + contention: out std_logic + ); +end; + +architecture behavioral of ElectronULA is + + signal hsync_int : std_logic; + signal vsync_int : std_logic; + + signal ram_we : std_logic; + signal ram_data : std_logic_vector(7 downto 0); + + signal master_irq : std_logic; + + signal power_on_reset : std_logic := '1'; + signal rtc_counter : std_logic_vector(18 downto 0); + signal general_counter: std_logic_vector(15 downto 0); + signal sound_bit : std_logic; + signal isr_data : std_logic_vector(7 downto 0); + + -- ULA Registers + signal isr : std_logic_vector(6 downto 2); + signal ier : std_logic_vector(6 downto 2); + signal screen_base : std_logic_vector(14 downto 6); + signal data_shift : std_logic_vector(7 downto 0); + signal page_enable : std_logic; + signal page : std_logic_vector(2 downto 0); + signal counter : std_logic_vector(7 downto 0); + signal display_mode : std_logic_vector(2 downto 0); + signal comms_mode : std_logic_vector(1 downto 0); + + type palette_type is array (0 to 7) of std_logic_vector (7 downto 0); + signal palette : palette_type; + + signal hsync_start : std_logic_vector(10 downto 0); + signal hsync_end : std_logic_vector(10 downto 0); + signal h_active : std_logic_vector(10 downto 0); + signal h_total : std_logic_vector(10 downto 0); + signal h_count : std_logic_vector(10 downto 0); + signal h_count1 : std_logic_vector(10 downto 0); + + signal vsync_start : std_logic_vector(9 downto 0); + signal vsync_end : std_logic_vector(9 downto 0); + signal v_active_gph : std_logic_vector(9 downto 0); + signal v_active_txt : std_logic_vector(9 downto 0); + signal v_total : std_logic_vector(9 downto 0); + signal v_count : std_logic_vector(9 downto 0); + + signal v_rtc : std_logic_vector(9 downto 0); + signal v_display : std_logic_vector(9 downto 0); + + signal char_row : std_logic_vector(3 downto 0); + signal row_offset : std_logic_vector(14 downto 0); + signal col_offset : std_logic_vector(9 downto 0); + signal screen_addr : std_logic_vector(14 downto 0); + signal screen_data : std_logic_vector(7 downto 0); + + -- Screen Mode Registers + + signal mode : std_logic_vector(1 downto 0); + + -- the 256 byte page that the mode starts at + signal mode_base : std_logic_vector(7 downto 0); + + -- the number of bits per pixel (0 = 1BPP, 1 = 2BPP, 2=4BPP) + signal mode_bpp : std_logic_vector(1 downto 0); + + -- a '1' indicates a text mode (modes 3 and 6) + signal mode_text : std_logic; + + -- a '1' indicates a 40-col mode (modes 4, 5 and 6) + signal mode_40 : std_logic; + + -- the number of bytes to increment row_offset when moving from one char row to the next + signal mode_rowstep : std_logic_vector(9 downto 0); + + signal display_intr : std_logic; + signal display_intr1 : std_logic; + signal display_intr2 : std_logic; + + signal rtc_intr : std_logic; + signal rtc_intr1 : std_logic; + signal rtc_intr2 : std_logic; + + signal clk_video : std_logic; + + signal ctrl_caps : std_logic; + + signal field : std_logic; + + signal caps_int : std_logic; + signal motor_int : std_logic; + + -- Supports changing the jumpers + signal mode_init_copy : std_logic_vector(1 downto 0); + + -- Stable copies sampled once per frame + signal screen_base1 : std_logic_vector(14 downto 6); + signal mode_base1 : std_logic_vector(7 downto 0); + + -- Tape Interface + signal cintone : std_logic; + signal cindat : std_logic; + signal databits : std_logic_vector(3 downto 0); + signal casIn1 : std_logic; + signal casIn2 : std_logic; + signal casIn3 : std_logic; + signal ignore_next : std_logic; + +-- Helper function to cast an std_logic value to an integer +function sl2int (x: std_logic) return integer is +begin + if x = '1' then + return 1; + else + return 0; + end if; +end; + +-- Helper function to cast an std_logic_vector value to an integer +function slv2int (x: std_logic_vector) return integer is +begin + return to_integer(unsigned(x)); +end; + +begin + + -- video timing constants + -- mode 00 - RGB/s @ 50Hz non-interlaced + -- mode 01 - RGB/s @ 50Hz interlaced + -- mode 10 - SVGA @ 50Hz + -- mode 11 - SVGA @ 60Hz + + clk_video <= clk_40M00 when mode = "11" else + clk_33M33 when mode = "10" else + clk_16M00; + + hsync_start <= std_logic_vector(to_unsigned(759, 11)) when mode = "11" else + std_logic_vector(to_unsigned(759, 11)) when mode = "10" else + std_logic_vector(to_unsigned(762, 11)); + + hsync_end <= std_logic_vector(to_unsigned(887, 11)) when mode = "11" else + std_logic_vector(to_unsigned(887, 11)) when mode = "10" else + std_logic_vector(to_unsigned(837, 11)); + + h_total <= std_logic_vector(to_unsigned(1055, 11)) when mode = "11" else + std_logic_vector(to_unsigned(1055, 11)) when mode = "10" else + std_logic_vector(to_unsigned(1023, 11)); + + h_active <= std_logic_vector(to_unsigned(640, 11)); + + vsync_start <= std_logic_vector(to_unsigned(556, 10)) when mode = "11" else + std_logic_vector(to_unsigned(556, 10)) when mode = "10" else + std_logic_vector(to_unsigned(274, 10)); + + vsync_end <= std_logic_vector(to_unsigned(560, 10)) when mode = "11" else + std_logic_vector(to_unsigned(560, 10)) when mode = "10" else + std_logic_vector(to_unsigned(277, 10)); + + v_total <= std_logic_vector(to_unsigned(627, 10)) when mode = "11" else + std_logic_vector(to_unsigned(627, 10)) when mode = "10" else + std_logic_vector(to_unsigned(311, 10)) when field = '0' else + std_logic_vector(to_unsigned(312, 10)); + + v_active_gph <= std_logic_vector(to_unsigned(512, 10)) when mode = "11" else + std_logic_vector(to_unsigned(512, 10)) when mode = "10" else + std_logic_vector(to_unsigned(256, 10)); + + v_active_txt <= std_logic_vector(to_unsigned(500, 10)) when mode = "11" else + std_logic_vector(to_unsigned(500, 10)) when mode = "10" else + std_logic_vector(to_unsigned(250, 10)); + + v_display <= std_logic_vector(to_unsigned(513, 10)) when mode = "11" else + std_logic_vector(to_unsigned(513, 10)) when mode = "10" else + std_logic_vector(to_unsigned(256, 10)); + + v_rtc <= std_logic_vector(to_unsigned(201, 10)) when mode = "11" else + std_logic_vector(to_unsigned(201, 10)) when mode = "10" else + std_logic_vector(to_unsigned(100, 10)); + + ram : entity work.RAM_32K_DualPort port map( + + -- Port A is the 6502 port + clka => clk_16M00, + wea => ram_we, + addra => addr(14 downto 0), + dina => data_in, + douta => ram_data, + + -- Port B is the VGA Port + clkb => clk_video, + web => '0', + addrb => screen_addr, + dinb => x"00", + doutb => screen_data + ); + + sound <= sound_bit; + + -- FIXME: This should probably be gate with a clock enable + ram_we <= '1' when addr(15) = '0' and R_W_n = '0' else '0'; + + -- The external ROM is enabled: + -- - When the address is C000-FBFF and FF00-FFFF (i.e. OS Rom) + -- - When the address is 8000-BFFF and the ROM 10 or 11 is paged in (101x) + ROM_n <= '0' when addr(15 downto 14) = "11" and addr(15 downto 8) /= x"FC" and addr(15 downto 8) /= x"FD" and addr(15 downto 8) /= x"FE" else + '0' when addr(15 downto 14) = "10" and page_enable = '1' and page(2 downto 1) = "01" else + '1'; + + -- ULA Reads + RAM Reads + KBD Reads + data_out <= ram_data when addr(15) = '0' else + "0000" & kbd when addr(15 downto 14) = "10" and page_enable = '1' and page(2 downto 1) = "00" else + isr_data when addr(15 downto 8) = x"FE" and addr(3 downto 0) = x"0" else + data_shift when addr(15 downto 8) = x"FE" and addr(3 downto 0) = x"4" else + x"F1"; -- todo FIXEME + + -- Register FEx0 is the Interrupt Status Register (Read Only) + -- Bit 7 always reads as 1 + -- Bits 6..2 refect in interrups status regs + -- Bit 1 is the power up reset bit, cleared by the first read after power up + -- Bit 0 is the OR of bits 6..2 + master_irq <= (isr(6) and ier(6)) or + (isr(5) and ier(5)) or + (isr(4) and ier(4)) or + (isr(3) and ier(3)) or + (isr(2) and ier(2)); + IRQ_n <= not master_irq; + isr_data <= '1' & isr(6 downto 2) & power_on_reset & master_irq; + + rom_latch <= page_enable & page; + + process (clk_16M00, RST_n) + begin + if (RST_n = '0') then + isr <= (others => '0'); + ier <= (others => '0'); + screen_base <= (others => '0'); + data_shift <= (others => '0'); + page_enable <= '0'; + page <= (others => '0'); + counter <= (others => '0'); + comms_mode <= "01"; + motor_int <= '0'; + caps_int <= '0'; + rtc_counter <= (others => '0'); + general_counter <= (others => '0'); + sound_bit <= '0'; + mode <= mode_init; + mode_init_copy <= mode_init; + ctrl_caps <= '0'; + cindat <= '0'; + cintone <= '0'; + + elsif rising_edge(clk_16M00) then + -- Detect control+caps 1...4 and change video format + if (addr = x"9fff" and page_enable = '1' and page(2 downto 1) = "00") then + if (kbd(2 downto 1) = "11") then + ctrl_caps <= '1'; + else + ctrl_caps <= '0'; + end if; + end if; + -- Detect "1" being pressed + if (addr = x"afff" and page_enable = '1' and page(2 downto 1) = "00" and ctrl_caps = '1' and kbd(0) = '1') then + mode <= "00"; + end if; + -- Detect "2" being pressed + if (addr = x"b7ff" and page_enable = '1' and page(2 downto 1) = "00" and ctrl_caps = '1' and kbd(0) = '1') then + mode <= "01"; + end if; + -- Detect "3" being pressed + if (addr = x"bbff" and page_enable = '1' and page(2 downto 1) = "00" and ctrl_caps = '1' and kbd(0) = '1') then + mode <= "10"; + end if; + -- Detect "4" being pressed + if (addr = x"bdff" and page_enable = '1' and page(2 downto 1) = "00" and ctrl_caps = '1' and kbd(0) = '1') then + mode <= "11"; + end if; + -- Detect Jumpers being changed + if (mode_init_copy /= mode_init) then + mode <= mode_init; + mode_init_copy <= mode_init; + end if; + -- Synchronize the display interrupt signal from the VGA clock domain + display_intr1 <= display_intr; + display_intr2 <= display_intr1; + -- Generate the display end interrupt on the rising edge (line 256 of the screen) + if (display_intr2 = '0' and display_intr1 = '1') then + isr(2) <= '1'; + end if; + -- Synchronize the rtc interrupt signal from the VGA clock domain + rtc_intr1 <= rtc_intr; + rtc_intr2 <= rtc_intr1; + if (mode = "11") then + -- For 60Hz frame rates we must synthesise a the 50Hz real time clock interrupt + -- In theory the counter limit should be 319999, but there are additional + -- rtc ticks if not rtc interrupt is received between two display interrupts + -- hence the correction factor of 6/5. This comes from the probability + -- of the there not being a 50Hz rtc interrupts between any two successive + -- 60Hz display interrupts. + if (rtc_counter = 383999) then + rtc_counter <= (others => '0'); + isr(3) <= '1'; + else + rtc_counter <= rtc_counter + 1; + end if; + else + -- Generate the rtc interrupt on the rising edge (line 100 of the screen) + if (rtc_intr2 = '0' and rtc_intr1 = '1') then + isr(3) <= '1'; + end if; + end if; + if (comms_mode = "00") then + if (casIn2 = '0') then + general_counter <= (others => '0'); + else + general_counter <= general_counter + 1; + end if; + elsif (comms_mode = "01") then + -- Sound Frequency = 1MHz / [16 * (S + 1)] + if (general_counter = 0) then + general_counter <= counter & "00000000"; + sound_bit <= not sound_bit; + else + general_counter <= general_counter - 1; + end if; + end if; + + + -- Tape Interface Receive + casIn1 <= casIn; + casIn2 <= casIn1; + casIn3 <= casIn2; + if (comms_mode = "00" and motor_int = '1') then + -- Only take actions on the falling edge of casIn + -- On the falling edge, general_counter will contain length of + -- the previous high pulse in 16MHz cycles. + -- A 1200Hz pulse is 6666 cycles + -- A 2400Hz pulse is 3333 cycles + -- A threshold in between would be 5000 cycles. + -- Ignore pulses shorter then say 500 cycles as these are + -- probably just noise. + + if (casIn3 = '1' and casIn2 = '0' and general_counter > 500) then + -- a Pulse of length > 500 cycles has been detected + + if (cindat = '0' and cintone = '0' and general_counter <= 5000) then + -- High Tone detected + cindat <= '0'; + cintone <= '1'; + databits <= (others => '0'); + -- Generate the high tone detect interrupt + isr(6) <= '1'; + + elsif (cindat = '0' and cintone = '1' and general_counter > 5000) then + -- Start bit detected + cindat <= '1'; + cintone <= '0'; + databits <= (others => '0'); + + elsif (cindat = '1' and ignore_next = '1') then + -- Ignoring the second pulse in a bit at 2400Hz + ignore_next <= '0'; + + elsif (cindat = '1' and databits < 9) then + + if (databits < 8) then + if (general_counter > 5000) then + -- shift in a zero + data_shift <= '0' & data_shift(7 downto 1); + else + -- shift in a one + data_shift <= '1' & data_shift(7 downto 1); + end if; + -- Generate the receive data int as soon as the + -- last bit has been shifted in. + if (databits = 7) then + isr(4) <= '1'; + end if; + end if; + -- Ignore the second pulse in a bit at 2400Hz + if (general_counter > 5000) then + ignore_next <= '0'; + else + ignore_next <= '1'; + end if; + -- Move on to the next data bit + databits <= databits + 1; + elsif (cindat = '1' and databits = 9) then + if (general_counter > 5000) then + -- Found next start bit... + cindat <= '1'; + cintone <= '0'; + databits <= (others => '0'); + else + -- Back in tone again + cindat <= '0'; + cintone <= '1'; + databits <= (others => '0'); + -- Generate the high tone detect interrupt + isr(6) <= '1'; + end if; + end if; + end if; + else + cindat <= '0'; + cintone <= '0'; + databits <= (others => '0'); + ignore_next <= '0'; + end if; + + -- ULA Writes + if (cpu_clken = '1') then + if (addr(15 downto 8) = x"FE") then + if (R_W_n = '1') then + -- Clear the power on reset flag on the first read of the ISR (FEx0) + if (addr(3 downto 0) = x"0") then + power_on_reset <= '0'; + end if; + -- Clear the RDFull interrupts on reading the data_shift register + if (addr(3 downto 0) = x"4") then + isr(4) <= '0'; + end if; + else + case addr(3 downto 0) is + when x"0" => + ier(6 downto 2) <= data_in(6 downto 2); + when x"1" => + when x"2" => + screen_base(8 downto 6) <= data_in(7 downto 5); + when x"3" => + screen_base(14 downto 9) <= data_in(5 downto 0); + when x"4" => + data_shift <= data_in; + -- Clear the TDEmpty interrupt on writing the + -- data_shift register + isr(5) <= '0'; + when x"5" => + if (data_in(6) = '1') then + -- Clear High Tone Detect IRQ + isr(6) <= '0'; + end if; + if (data_in(5) = '1') then + -- Clear Real Time Clock IRQ + isr(3) <= '0'; + end if; + if (data_in(4) = '1') then + -- Clear Display End IRQ + isr(2) <= '0'; + end if; + if (page_enable = '1' and page(2) = '0') then + -- Roms 8-11 currently selected, so only selecting 8-15 will be honoured + if (data_in(3) = '1') then + page_enable <= data_in(3); + page <= data_in(2 downto 0); + end if; + else + -- Roms 0-7 or 12-15 currently selected, so anything goes + page_enable <= data_in(3); + page <= data_in(2 downto 0); + end if; + when x"6" => + counter <= data_in; + when x"7" => + caps_int <= data_in(7); + motor_int <= data_in(6); + case (data_in(5 downto 3)) is + when "000" => + mode_base <= x"30"; + mode_bpp <= "00"; + mode_40 <= '0'; + mode_text <= '0'; + mode_rowstep <= std_logic_vector(to_unsigned(633, 10)); -- 640 - 7 + when "001" => + mode_base <= x"30"; + mode_bpp <= "01"; + mode_40 <= '0'; + mode_text <= '0'; + mode_rowstep <= std_logic_vector(to_unsigned(633, 10)); -- 640 - 7 + when "010" => + mode_base <= x"30"; + mode_bpp <= "10"; + mode_40 <= '0'; + mode_text <= '0'; + mode_rowstep <= std_logic_vector(to_unsigned(633, 10)); -- 640 - 7 + when "011" => + mode_base <= x"40"; + mode_bpp <= "00"; + mode_40 <= '0'; + mode_text <= '1'; + mode_rowstep <= std_logic_vector(to_unsigned(631, 10)); -- 640 - 9 + when "100" => + mode_base <= x"58"; + mode_bpp <= "00"; + mode_40 <= '1'; + mode_text <= '0'; + mode_rowstep <= std_logic_vector(to_unsigned(313, 10)); -- 320 - 7 + when "101" => + mode_base <= x"60"; + mode_bpp <= "01"; + mode_40 <= '1'; + mode_text <= '0'; + mode_rowstep <= std_logic_vector(to_unsigned(313, 10)); -- 320 - 7 + when "110" => + mode_base <= x"60"; + mode_bpp <= "00"; + mode_40 <= '1'; + mode_text <= '1'; + mode_rowstep <= std_logic_vector(to_unsigned(311, 10)); -- 320 - 9 + when "111" => + -- mode 7 seems to default to mode 4 + mode_base <= x"58"; + mode_bpp <= "00"; + mode_40 <= '1'; + mode_text <= '0'; + mode_rowstep <= std_logic_vector(to_unsigned(313, 10)); -- 320 - 7 + when others => + end case; + comms_mode <= data_in(2 downto 1); + when others => + -- A '1' in the palatte data means disable the colour + -- Invert the stored palette, to make the palette logic simpler + palette(slv2int(addr(2 downto 0))) <= data_in xor "11111111"; + end case; + end if; + end if; + end if; + end if; + end process; + + -- SGVA timing at 60Hz with a 40.000MHz Pixel Clock + -- Horizontal 800 + 40 + 128 + 88 = total 1056 + -- Vertical 600 + 1 + 4 + 23 = total 628 + -- Within the the 640x512 is centred so starts at 80,44 + -- Horizontal 640 + (80 + 40) + 128 + (88 + 80) = total 1056 + -- Vertical 512 + (44 + 1) + 4 + (23 + 44) = total 628 + + -- RGBs timing at 50Hz with a 16.000MHz Pixel Clock + -- Horizontal 640 + (96 + 26) + 75 + (91 + 96) = total 1024 + -- Vertical 256 + (16 + 2) + 3 + (19 + 16) = total 312 + + process (clk_video) + variable pixel : std_logic_vector(3 downto 0); + begin + if rising_edge(clk_video) then + -- pipeline h_count by one cycle to compensate the register in the RAM + h_count1 <= h_count; + if (h_count = h_total) then + h_count <= (others => '0'); + col_offset <= (others => '0'); + if (v_count = v_total) then + v_count <= (others => '0'); + char_row <= (others => '0'); + row_offset <= (others => '0'); + screen_base1 <= screen_base; + mode_base1 <= mode_base; + if (mode = "01") then + -- Interlaced, so alternate odd and even fields + field <= not field; + else + -- Non-interlaced, so odd fields only + field <= '0'; + end if; + else + v_count <= v_count + 1; + if (v_count(0) = '1' or mode(1) = '0') then + if ((mode_text = '0' and char_row = 7) or (mode_text = '1' and char_row = 9)) then + char_row <= (others => '0'); + row_offset <= row_offset + mode_rowstep; + else + char_row <= char_row + 1; + row_offset <= row_offset + 1; + end if; + end if; + end if; + else + h_count <= h_count + 1; + if ((mode_40 = '0' and h_count(2 downto 0) = "111") or + (mode_40 = '1' and h_count(3 downto 0) = "1111")) then + col_offset <= col_offset + 8; + end if; + end if; + -- RGB Data + if (h_count1 >= h_active or (mode_text = '0' and v_count >= v_active_gph) or (mode_text = '1' and v_count >= v_active_txt) or char_row >= 8) then + -- blanking and border are always black + red <= (others => '0'); + green <= (others => '0'); + blue <= (others => '0'); + contention <= '0'; + else + -- Indicate possible memory contention on active scan lines + contention <= not mode_40; + -- rendering an actual pixel + if (mode_bpp = 0) then + -- 1 bit per pixel, map to colours 0 and 8 for the palette lookup + if (mode_40 = '1') then + pixel := screen_data(7 - slv2int(h_count1(3 downto 1))) & "000"; + else + pixel := screen_data(7 - slv2int(h_count1(2 downto 0))) & "000"; + end if; + elsif (mode_bpp = 1) then + -- 2 bits per pixel, map to colours 0, 2, 8, 10 for the palette lookup + if (mode_40 = '1') then + pixel := screen_data(7 - slv2int(h_count1(3 downto 2))) & "0" & + screen_data(3 - slv2int(h_count1(3 downto 2))) & "0"; + else + pixel := screen_data(7 - slv2int(h_count1(2 downto 1))) & "0" & + screen_data(3 - slv2int(h_count1(2 downto 1))) & "0"; + end if; + else + -- 4 bits per pixel, map directly for the palette lookup + if (mode_40 = '1') then + pixel := screen_data(7 - sl2int(h_count1(3))) & + screen_data(5 - sl2int(h_count1(3))) & + screen_data(3 - sl2int(h_count1(3))) & + screen_data(1 - sl2int(h_count1(3))); + else + pixel := screen_data(7 - sl2int(h_count1(2))) & + screen_data(5 - sl2int(h_count1(2))) & + screen_data(3 - sl2int(h_count1(2))) & + screen_data(1 - sl2int(h_count1(2))); + end if; + end if; + -- Implement Color Palette + case (pixel) is + when "0000" => + red <= (others => palette(1)(0)); + green <= (others => palette(1)(4)); + blue <= (others => palette(0)(4)); + when "0001" => + red <= (others => palette(7)(0)); + green <= (others => palette(7)(4)); + blue <= (others => palette(6)(4)); + when "0010" => + red <= (others => palette(1)(1)); + green <= (others => palette(1)(5)); + blue <= (others => palette(0)(5)); + when "0011" => + red <= (others => palette(7)(1)); + green <= (others => palette(7)(5)); + blue <= (others => palette(6)(5)); + when "0100" => + red <= (others => palette(3)(0)); + green <= (others => palette(3)(4)); + blue <= (others => palette(2)(4)); + when "0101" => + red <= (others => palette(5)(0)); + green <= (others => palette(5)(4)); + blue <= (others => palette(4)(4)); + when "0110" => + red <= (others => palette(3)(1)); + green <= (others => palette(3)(5)); + blue <= (others => palette(2)(5)); + when "0111" => + red <= (others => palette(5)(1)); + green <= (others => palette(5)(5)); + blue <= (others => palette(4)(5)); + when "1000" => + red <= (others => palette(1)(2)); + green <= (others => palette(0)(2)); + blue <= (others => palette(0)(6)); + when "1001" => + red <= (others => palette(7)(2)); + green <= (others => palette(6)(2)); + blue <= (others => palette(6)(6)); + when "1010" => + red <= (others => palette(1)(3)); + green <= (others => palette(0)(3)); + blue <= (others => palette(0)(7)); + when "1011" => + red <= (others => palette(7)(3)); + green <= (others => palette(6)(3)); + blue <= (others => palette(6)(7)); + when "1100" => + red <= (others => palette(3)(2)); + green <= (others => palette(2)(2)); + blue <= (others => palette(2)(6)); + when "1101" => + red <= (others => palette(5)(2)); + green <= (others => palette(4)(2)); + blue <= (others => palette(4)(6)); + when "1110" => + red <= (others => palette(3)(3)); + green <= (others => palette(2)(3)); + blue <= (others => palette(2)(7)); + when "1111" => + red <= (others => palette(5)(3)); + green <= (others => palette(4)(3)); + blue <= (others => palette(4)(7)); + when others => + end case; + end if; + -- Vertical Sync + if (field = '0') then + -- first field of interlaced scanning (or non interlaced) + -- vsync starts at the begging of the line + if (h_count1 = 0) then + if (v_count = vsync_start) then + vsync_int <= '0'; + elsif (v_count = vsync_end) then + vsync_int <= '1'; + end if; + end if; + else + -- second field of intelaced scanning + -- vsync starts half way through the line + if (h_count1 = ('0' & h_total(10 downto 1))) then + if (v_count = vsync_start) then + vsync_int <= '0'; + elsif (v_count = vsync_end) then + vsync_int <= '1'; + end if; + end if; + end if; + -- Horizontal Sync + if (h_count1 = hsync_start) then + hsync_int <= '0'; + if (v_count = v_display) then + display_intr <= '1'; + end if; + if (v_count = v_rtc) then + rtc_intr <= '1'; + end if; + elsif (h_count1 = hsync_end) then + hsync_int <= '1'; + display_intr <= '0'; + rtc_intr <= '0'; + end if; + end if; + end process; + + process (screen_base1, mode_base1, row_offset, col_offset) + variable tmp: std_logic_vector(15 downto 0); + begin + tmp := ("0" & screen_base1 & "000000") + row_offset + col_offset; + if (tmp(15) = '1') then + tmp := tmp + (mode_base1 & "00000000"); + end if; + screen_addr <= tmp(14 downto 0); + end process; + + vsync <= '1' when mode(1) = '0' else vsync_int; + hsync <= hsync_int and vsync_int when mode(1) = '0' else hsync_int; + caps <= caps_int; + motor <= motor_int; + + casOut <= '0'; + +end behavioral; diff --git a/Acorn - Electron_MiST/rtl/RAM_32K_DualPort.vhd b/Acorn - Electron_MiST/rtl/RAM_32K_DualPort.vhd new file mode 100644 index 00000000..4063c163 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/RAM_32K_DualPort.vhd @@ -0,0 +1,48 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity RAM_32K_DualPort is + + port ( + clka : in std_logic; + wea : in std_logic; + addra : in std_logic_vector(14 downto 0); + dina : in std_logic_vector(7 downto 0); + douta : out std_logic_vector(7 downto 0); + clkb : in std_logic; + web : in std_logic; + addrb : in std_logic_vector(14 downto 0); + dinb : in std_logic_vector(7 downto 0); + doutb : out std_logic_vector(7 downto 0) + ); +end; + +architecture behavioral of RAM_32K_DualPort is + + type ram_type is array (32767 downto 0) of std_logic_vector (7 downto 0); + shared variable RAM : ram_type; + +begin + + process (clka) + begin + if rising_edge(clka) then + if (wea = '1') then + RAM(conv_integer(addra)) := dina; + end if; + douta <= RAM(conv_integer(addra)); + end if; + end process; + + process (clkb) + begin + if rising_edge(clkb) then + if (web = '1') then + RAM(conv_integer(addrb)) := dinb; + end if; + doutb <= RAM(conv_integer(addrb)); + end if; + end process; + +end behavioral; diff --git a/Acorn - Electron_MiST/rtl/RomBasic2.vhd b/Acorn - Electron_MiST/rtl/RomBasic2.vhd new file mode 100644 index 00000000..5b83a96b --- /dev/null +++ b/Acorn - Electron_MiST/rtl/RomBasic2.vhd @@ -0,0 +1,169 @@ +-- megafunction wizard: %ROM: 1-PORT% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altsyncram + +-- ============================================================ +-- File Name: RomBasic2.vhd +-- Megafunction Name(s): +-- altsyncram +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.0.1 Build 232 06/12/2013 SP 1 SJ Full Version +-- ************************************************************ + + +--Copyright (C) 1991-2013 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY RomBasic2 IS + PORT + ( + address : IN STD_LOGIC_VECTOR (13 DOWNTO 0); + clock : IN STD_LOGIC := '1'; + q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); +END RomBasic2; + + +ARCHITECTURE SYN OF rombasic2 IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + address_aclr_a : STRING; + clock_enable_input_a : STRING; + clock_enable_output_a : STRING; + init_file : STRING; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_reg_a : STRING; + widthad_a : NATURAL; + width_a : NATURAL; + width_byteena_a : NATURAL + ); + PORT ( + address_a : IN STD_LOGIC_VECTOR (13 DOWNTO 0); + clock0 : IN STD_LOGIC ; + q_a : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q <= sub_wire0(7 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + address_aclr_a => "NONE", + clock_enable_input_a => "BYPASS", + clock_enable_output_a => "BYPASS", + init_file => "../rtl/roms/basic2.hex", + intended_device_family => "Cyclone III", + lpm_hint => "ENABLE_RUNTIME_MOD=NO", + lpm_type => "altsyncram", + numwords_a => 16384, + operation_mode => "ROM", + outdata_aclr_a => "NONE", + outdata_reg_a => "CLOCK0", + widthad_a => 14, + width_a => 8, + width_byteena_a => 1 + ) + PORT MAP ( + address_a => address, + clock0 => clock, + q_a => sub_wire0 + ); + + + +END SYN; + +-- ============================================================ +-- 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/roms/basic2.hex" +-- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "16384" +-- 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 "14" +-- 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/roms/basic2.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 "16384" +-- 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 "14" +-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +-- Retrieval info: USED_PORT: address 0 0 14 0 INPUT NODEFVAL "address[13..0]" +-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +-- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +-- Retrieval info: CONNECT: @address_a 0 0 14 0 address 0 0 14 0 +-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +-- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomBasic2.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomBasic2.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomBasic2.cmp FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomBasic2.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomBasic2_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf diff --git a/Acorn - Electron_MiST/rtl/RomOS100.vhd b/Acorn - Electron_MiST/rtl/RomOS100.vhd new file mode 100644 index 00000000..9cd45b21 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/RomOS100.vhd @@ -0,0 +1,169 @@ +-- megafunction wizard: %ROM: 1-PORT% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altsyncram + +-- ============================================================ +-- File Name: RomOS100.vhd +-- Megafunction Name(s): +-- altsyncram +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.0.1 Build 232 06/12/2013 SP 1 SJ Full Version +-- ************************************************************ + + +--Copyright (C) 1991-2013 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY RomOS100 IS + PORT + ( + address : IN STD_LOGIC_VECTOR (13 DOWNTO 0); + clock : IN STD_LOGIC := '1'; + q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); +END RomOS100; + + +ARCHITECTURE SYN OF romos100 IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0); + + + + COMPONENT altsyncram + GENERIC ( + address_aclr_a : STRING; + clock_enable_input_a : STRING; + clock_enable_output_a : STRING; + init_file : STRING; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + numwords_a : NATURAL; + operation_mode : STRING; + outdata_aclr_a : STRING; + outdata_reg_a : STRING; + widthad_a : NATURAL; + width_a : NATURAL; + width_byteena_a : NATURAL + ); + PORT ( + address_a : IN STD_LOGIC_VECTOR (13 DOWNTO 0); + clock0 : IN STD_LOGIC ; + q_a : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + q <= sub_wire0(7 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + address_aclr_a => "NONE", + clock_enable_input_a => "BYPASS", + clock_enable_output_a => "BYPASS", + init_file => "../rtl/roms/os100.hex", + intended_device_family => "Cyclone III", + lpm_hint => "ENABLE_RUNTIME_MOD=NO", + lpm_type => "altsyncram", + numwords_a => 16384, + operation_mode => "ROM", + outdata_aclr_a => "NONE", + outdata_reg_a => "CLOCK0", + widthad_a => 14, + width_a => 8, + width_byteena_a => 1 + ) + PORT MAP ( + address_a => address, + clock0 => clock, + q_a => sub_wire0 + ); + + + +END SYN; + +-- ============================================================ +-- 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/roms/os100.hex" +-- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "16384" +-- 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 "14" +-- 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/roms/os100.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 "16384" +-- 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 "14" +-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +-- Retrieval info: USED_PORT: address 0 0 14 0 INPUT NODEFVAL "address[13..0]" +-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +-- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +-- Retrieval info: CONNECT: @address_a 0 0 14 0 address 0 0 14 0 +-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +-- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomOS100.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomOS100.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomOS100.cmp FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomOS100.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomOS100_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf diff --git a/Acorn - Electron_MiST/rtl/RomSmelk3006.vhd b/Acorn - Electron_MiST/rtl/RomSmelk3006.vhd new file mode 100644 index 00000000..b24d03c3 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/RomSmelk3006.vhd @@ -0,0 +1,143 @@ +-- megafunction wizard: %ROM: 1-PORT% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altsyncram + +-- ============================================================ +-- File Name: RomSmelk3006.vhd +-- Megafunction Name(s): +-- altsyncram +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.1.0 Build 162 10/23/2013 SJ Web Edition +-- ************************************************************ + + +--Copyright (C) 1991-2013 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.altera_mf_components.all; + +ENTITY RomSmelk3006 IS + PORT + ( + address : IN STD_LOGIC_VECTOR (13 DOWNTO 0); + clock : IN STD_LOGIC := '1'; + q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) + ); +END RomSmelk3006; + + +ARCHITECTURE SYN OF romsmelk3006 IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0); + +BEGIN + q <= sub_wire0(7 DOWNTO 0); + + altsyncram_component : altsyncram + GENERIC MAP ( + address_aclr_a => "NONE", + clock_enable_input_a => "BYPASS", + clock_enable_output_a => "BYPASS", + init_file => "./roms/smelk3006.hex", + intended_device_family => "Cyclone III", + lpm_hint => "ENABLE_RUNTIME_MOD=NO", + lpm_type => "altsyncram", + numwords_a => 16384, + operation_mode => "ROM", + outdata_aclr_a => "NONE", + outdata_reg_a => "CLOCK0", + widthad_a => 14, + width_a => 8, + width_byteena_a => 1 + ) + PORT MAP ( + address_a => address, + clock0 => clock, + q_a => sub_wire0 + ); + + + +END SYN; + +-- ============================================================ +-- 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 "./roms/smelk3006.hex" +-- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "16384" +-- 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 "14" +-- 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 "./roms/smelk3006.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 "16384" +-- 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 "14" +-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +-- Retrieval info: USED_PORT: address 0 0 14 0 INPUT NODEFVAL "address[13..0]" +-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +-- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +-- Retrieval info: CONNECT: @address_a 0 0 14 0 address 0 0 14 0 +-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +-- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomSmelk3006.vhd TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomSmelk3006.inc FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomSmelk3006.cmp TRUE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomSmelk3006.bsf FALSE +-- Retrieval info: GEN_FILE: TYPE_NORMAL RomSmelk3006_inst.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf diff --git a/Acorn - Electron_MiST/rtl/T65/T65.vhd b/Acorn - Electron_MiST/rtl/T65/T65.vhd new file mode 100644 index 00000000..906a1b6b --- /dev/null +++ b/Acorn - Electron_MiST/rtl/T65/T65.vhd @@ -0,0 +1,666 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- Ver 313 WoS January 2015 +-- Fixed issue that NMI has to be first if issued the same time as a BRK instruction is latched in +-- Now all Lorenz CPU tests on FPGAARCADE C64 core (sources used: SVN version 1021) are OK! :D :D :D +-- This is just a starting point to go for optimizations and detailed fixes (the Lorenz test can't find) +-- +-- Ver 312 WoS January 2015 +-- Undoc opcode timing fixes for $B3 (LAX iy) and $BB (LAS ay) +-- Added comments in MCode section to find handling of individual opcodes more easily +-- All "basic" Lorenz instruction test (individual functional checks, CPUTIMING check) work now with +-- actual FPGAARCADE C64 core (sources used: SVN version 1021). +-- +-- Ver 305, 306, 307, 308, 309, 310, 311 WoS January 2015 +-- Undoc opcode fixes (now all Lorenz test on instruction functionality working, except timing issues on $B3 and $BB): +-- SAX opcode +-- SHA opcode +-- SHX opcode +-- SHY opcode +-- SHS opcode +-- LAS opcode +-- alternate SBC opcode +-- fixed NOP with immediate param (caused Lorenz trap test to fail) +-- IRQ and NMI timing fixes (in conjuction with branches) +-- +-- Ver 304 WoS December 2014 +-- Undoc opcode fixes: +-- ARR opcode +-- ANE/XAA opcode +-- Corrected issue with NMI/IRQ prio (when asserted the same time) +-- +-- Ver 303 ost(ML) July 2014 +-- (Sorry for some scratchpad comments that may make little sense) +-- Mods and some 6502 undocumented instructions. +-- Not correct opcodes acc. to Lorenz tests (incomplete list): +-- NOPN (nop) +-- NOPZX (nop + byte 172) +-- NOPAX (nop + word da ... da: byte 0) +-- ASOZ (byte $07 + byte 172) +-- +-- Ver 303,302 WoS April 2014 +-- Bugfixes for NMI from foft +-- Bugfix for BRK command (and its special flag) +-- +-- Ver 300,301 WoS January 2014 +-- More merging +-- Bugfixes by ehenciak added, started tidyup *bust* +-- +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65.vhd 1347 2015-05-27 20:07:34Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author(s), but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- ----- IMPORTANT NOTES ----- +-- +-- Limitations: +-- 65C02 and 65C816 modes are incomplete (and definitely untested after all 6502 undoc fixes) +-- 65C02 supported : inc, dec, phx, plx, phy, ply +-- 65D02 missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 +-- Some interface signals behave incorrect +-- NMI interrupt handling not nice, needs further rework (to cycle-based encoding). +-- +-- Usage: +-- The enable signal allows clock gating / throttling without using the ready signal. +-- Set it to constant '1' when using the Clk input as the CPU clock directly. +-- +-- TAKE CARE you route the DO signal back to the DI signal while R_W_n='0', +-- otherwise some undocumented opcodes won't work correctly. +-- EXAMPLE: +-- CPU : entity work.T65 +-- port map ( +-- R_W_n => cpu_rwn_s, +-- [....all other ports....] +-- DI => cpu_din_s, +-- DO => cpu_dout_s +-- ); +-- cpu_din_s <= cpu_dout_s when cpu_rwn_s='0' else +-- [....other sources from peripherals and memories...] +-- +-- ----- IMPORTANT NOTES ----- +-- + +library IEEE; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + use work.T65_Pack.all; + +entity T65 is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + Res_n : in std_logic; + Enable : in std_logic; + Clk : in std_logic; + Rdy : in std_logic; + Abort_n : in std_logic; + IRQ_n : in std_logic; + NMI_n : in std_logic; + SO_n : in std_logic; + R_W_n : out std_logic; + Sync : out std_logic; + EF : out std_logic; + MF : out std_logic; + XF : out std_logic; + ML_n : out std_logic; + VP_n : out std_logic; + VDA : out std_logic; + VPA : out std_logic; + A : out std_logic_vector(23 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0); + DEBUG : out T_t65_dbg + ); +end T65; + +architecture rtl of T65 is + + -- Registers + signal ABC, X, Y, D : std_logic_vector(15 downto 0); + signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; + signal PwithB : std_logic_vector(7 downto 0);--ML:New way to push P with correct B state to stack + signal BAH : std_logic_vector(7 downto 0); + signal BAL : std_logic_vector(8 downto 0); + signal PBR : std_logic_vector(7 downto 0); + signal DBR : std_logic_vector(7 downto 0); + signal PC : unsigned(15 downto 0); + signal S : unsigned(15 downto 0); + signal EF_i : std_logic; + signal MF_i : std_logic; + signal XF_i : std_logic; + + signal IR : std_logic_vector(7 downto 0); + signal MCycle : std_logic_vector(2 downto 0); + + signal Mode_r : std_logic_vector(1 downto 0); + signal ALU_Op_r : T_ALU_Op; + signal Write_Data_r : T_Write_Data; + signal Set_Addr_To_r : T_Set_Addr_To; + signal PCAdder : unsigned(8 downto 0); + + signal RstCycle : std_logic; + signal IRQCycle : std_logic; + signal NMICycle : std_logic; + + signal SO_n_o : std_logic; + signal IRQ_n_o : std_logic; + signal NMI_n_o : std_logic; + signal NMIAct : std_logic; + + signal Break : std_logic; + + -- ALU signals + signal BusA : std_logic_vector(7 downto 0); + signal BusA_r : std_logic_vector(7 downto 0); + signal BusB : std_logic_vector(7 downto 0); + signal BusB_r : std_logic_vector(7 downto 0); + signal ALU_Q : std_logic_vector(7 downto 0); + signal P_Out : std_logic_vector(7 downto 0); + + -- Micro code outputs + signal LCycle : std_logic_vector(2 downto 0); + signal ALU_Op : T_ALU_Op; + signal Set_BusA_To : T_Set_BusA_To; + signal Set_Addr_To : T_Set_Addr_To; + signal Write_Data : T_Write_Data; + signal Jump : std_logic_vector(1 downto 0); + signal BAAdd : std_logic_vector(1 downto 0); + signal BreakAtNA : std_logic; + signal ADAdd : std_logic; + signal AddY : std_logic; + signal PCAdd : std_logic; + signal Inc_S : std_logic; + signal Dec_S : std_logic; + signal LDA : std_logic; + signal LDP : std_logic; + signal LDX : std_logic; + signal LDY : std_logic; + signal LDS : std_logic; + signal LDDI : std_logic; + signal LDALU : std_logic; + signal LDAD : std_logic; + signal LDBAL : std_logic; + signal LDBAH : std_logic; + signal SaveP : std_logic; + signal Write : std_logic; + + signal Res_n_i : std_logic; + signal Res_n_d : std_logic; + + signal really_rdy : std_logic; + signal WRn_i : std_logic; + + signal NMI_entered : std_logic; + +begin + -- gate Rdy with read/write to make an "OK, it's really OK to stop the processor + really_rdy <= Rdy or not(WRn_i); + Sync <= '1' when MCycle = "000" else '0'; + EF <= EF_i; + MF <= MF_i; + XF <= XF_i; + R_W_n <= WRn_i; + ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1'; + VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1'; + VDA <= '1' when Set_Addr_To_r /= Set_Addr_To_PBR else '0'; + VPA <= '1' when Jump(1) = '0' else '0'; + + -- debugging signals + DEBUG.I <= IR; + DEBUG.A <= ABC(7 downto 0); + DEBUG.X <= X(7 downto 0); + DEBUG.Y <= Y(7 downto 0); + DEBUG.S <= std_logic_vector(S(7 downto 0)); + DEBUG.P <= P; + + mcode : entity work.T65_MCode + port map( +--inputs + Mode => Mode_r, + IR => IR, + MCycle => MCycle, + P => P, +--outputs + LCycle => LCycle, + ALU_Op => ALU_Op, + Set_BusA_To => Set_BusA_To, + Set_Addr_To => Set_Addr_To, + Write_Data => Write_Data, + Jump => Jump, + BAAdd => BAAdd, + BreakAtNA => BreakAtNA, + ADAdd => ADAdd, + AddY => AddY, + PCAdd => PCAdd, + Inc_S => Inc_S, + Dec_S => Dec_S, + LDA => LDA, + LDP => LDP, + LDX => LDX, + LDY => LDY, + LDS => LDS, + LDDI => LDDI, + LDALU => LDALU, + LDAD => LDAD, + LDBAL => LDBAL, + LDBAH => LDBAH, + SaveP => SaveP, + Write => Write + ); + + alu : entity work.T65_ALU + port map( + Mode => Mode_r, + Op => ALU_Op_r, + BusA => BusA_r, + BusB => BusB, + P_In => P, + P_Out => P_Out, + Q => ALU_Q + ); + + -- the 65xx design requires at least two clock cycles before + -- starting its reset sequence (according to datasheet) + process (Res_n_i, Clk) + begin + if Res_n = '0' then + Res_n_i <= '0'; + Res_n_d <= '0'; + elsif Clk'event and Clk = '1' then + Res_n_i <= Res_n_d; + Res_n_d <= '1'; + end if; + end process; + + process (Res_n_i, Clk) + begin + if Res_n_i = '0' then + PC <= (others => '0'); -- Program Counter + IR <= "00000000"; + S <= (others => '0'); -- Dummy + D <= (others => '0'); + PBR <= (others => '0'); + DBR <= (others => '0'); + + Mode_r <= (others => '0'); + ALU_Op_r <= ALU_OP_BIT; + Write_Data_r <= Write_Data_DL; + Set_Addr_To_r <= Set_Addr_To_PBR; + + WRn_i <= '1'; + EF_i <= '1'; + MF_i <= '1'; + XF_i <= '1'; + + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + WRn_i <= not Write or RstCycle; + + D <= (others => '1'); -- Dummy + PBR <= (others => '1'); -- Dummy + DBR <= (others => '1'); -- Dummy + EF_i <= '0'; -- Dummy + MF_i <= '0'; -- Dummy + XF_i <= '0'; -- Dummy + + if MCycle = "000" then + Mode_r <= Mode; + + if IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + + if IRQCycle = '1' or NMICycle = '1' then + IR <= "00000000"; + else + IR <= DI; + end if; + + if LDS = '1' then -- LAS won't work properly if not limited to machine cycle 0 + S(7 downto 0) <= unsigned(ALU_Q); + end if; + end if; + + ALU_Op_r <= ALU_Op; + Write_Data_r <= Write_Data; + if Break = '1' then + Set_Addr_To_r <= Set_Addr_To_PBR; + else + Set_Addr_To_r <= Set_Addr_To; + end if; + + if Inc_S = '1' then + S <= S + 1; + end if; + if Dec_S = '1' and RstCycle = '0' then + S <= S - 1; + end if; + + if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + -- + -- jump control logic + -- + case Jump is + when "01" => + PC <= PC + 1; + when "10" => + PC <= unsigned(DI & DL); + when "11" => + if PCAdder(8) = '1' then + if DL(7) = '0' then + PC(15 downto 8) <= PC(15 downto 8) + 1; + else + PC(15 downto 8) <= PC(15 downto 8) - 1; + end if; + end if; + PC(7 downto 0) <= PCAdder(7 downto 0); + when others => null; + end case; + end if; + end if; + end if; + end process; + + PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1' + else "0" & PC(7 downto 0); + + process (Res_n_i, Clk) + variable tmpP:std_logic_vector(7 downto 0);--Lets try to handle loading P at mcycle=0 and set/clk flags at same cycle + begin + if Res_n_i = '0' then + P <= x"00"; -- ensure we have nothing set on reset + elsif Clk'event and Clk = '1' then + tmpP:=P; + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = "000" then + if LDA = '1' then + ABC(7 downto 0) <= ALU_Q; + end if; + if LDX = '1' then + X(7 downto 0) <= ALU_Q; + end if; + if LDY = '1' then + Y(7 downto 0) <= ALU_Q; + end if; + if (LDA or LDX or LDY) = '1' then + tmpP:=P_Out; + end if; + end if; + if SaveP = '1' then + tmpP:=P_Out; + end if; + if LDP = '1' then + tmpP:=ALU_Q; + end if; + if IR(4 downto 0) = "11000" then + case IR(7 downto 5) is + when "000" =>--0x18(clc) + tmpP(Flag_C) := '0'; + when "001" =>--0x38(sec) + tmpP(Flag_C) := '1'; + when "010" =>--0x58(cli) + tmpP(Flag_I) := '0'; + when "011" =>--0x78(sei) + tmpP(Flag_I) := '1'; + when "101" =>--0xb8(clv) + tmpP(Flag_V) := '0'; + when "110" =>--0xd8(cld) + tmpP(Flag_D) := '0'; + when "111" =>--0xf8(sed) + tmpP(Flag_D) := '1'; + when others => + end case; + end if; + tmpP(Flag_B) := '1'; + if IR = "00000000" and MCycle = "100" and RstCycle = '0' then + --This should happen after P has been pushed to stack + tmpP(Flag_I) := '1'; + end if; + if SO_n_o = '1' and SO_n = '0' then + tmpP(Flag_V) := '1'; + end if; + if RstCycle = '1' then + tmpP(Flag_I) := '0'; + tmpP(Flag_D) := '0'; + end if; + tmpP(Flag_1) := '1'; + + P<=tmpP;--new way + + SO_n_o <= SO_n; + if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510), not best way yet, though - but works... + IRQ_n_o <= IRQ_n; + end if; + end if; + -- detect nmi even if not rdy + if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510) not best way yet, though - but works... + NMI_n_o <= NMI_n; + end if; + end if; + end if; + end process; + +--------------------------------------------------------------------------- +-- +-- Buses +-- +--------------------------------------------------------------------------- + + process (Res_n_i, Clk) + begin + if Res_n_i = '0' then + BusA_r <= (others => '0'); + BusB <= (others => '0'); + BusB_r <= (others => '0'); + AD <= (others => '0'); + BAL <= (others => '0'); + BAH <= (others => '0'); + DL <= (others => '0'); + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + NMI_entered <= '0'; + if (really_rdy = '1') then + BusA_r <= BusA; + BusB <= DI; + + -- not really nice, but no better way found yet ! + if Set_Addr_To_r = Set_Addr_To_PBR or Set_Addr_To_r = Set_Addr_To_ZPG then + BusB_r <= std_logic_vector(unsigned(DI(7 downto 0)) + 1); -- required for SHA + end if; + + case BAAdd is + when "01" => + -- BA Inc + AD <= std_logic_vector(unsigned(AD) + 1); + BAL <= std_logic_vector(unsigned(BAL) + 1); + when "10" => + -- BA Add + BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9)); + when "11" => + -- BA Adj + if BAL(8) = '1' then + BAH <= std_logic_vector(unsigned(BAH) + 1); + end if; + when others => + end case; + + -- modified to use Y register as well + if ADAdd = '1' then + if (AddY = '1') then + AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0))); + else + AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0))); + end if; + end if; + + if IR = "00000000" then + BAL <= (others => '1'); + BAH <= (others => '1'); + if RstCycle = '1' then + BAL(2 downto 0) <= "100"; + elsif NMICycle = '1' or (NMIAct = '1' and MCycle="100") or NMI_entered='1' then + BAL(2 downto 0) <= "010"; + if MCycle="100" then + NMI_entered <= '1'; + end if; + else + BAL(2 downto 0) <= "110"; + end if; + if Set_addr_To_r = Set_Addr_To_BA then + BAL(0) <= '1'; + end if; + end if; + + if LDDI = '1' then + DL <= DI; + end if; + if LDALU = '1' then + DL <= ALU_Q; + end if; + if LDAD = '1' then + AD <= DI; + end if; + if LDBAL = '1' then + BAL(7 downto 0) <= DI; + end if; + if LDBAH = '1' then + BAH <= DI; + end if; + end if; + end if; + end if; + end process; + + Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8)); + + with Set_BusA_To select + BusA <= + DI when Set_BusA_To_DI, + ABC(7 downto 0) when Set_BusA_To_ABC, + X(7 downto 0) when Set_BusA_To_X, + Y(7 downto 0) when Set_BusA_To_Y, + std_logic_vector(S(7 downto 0)) when Set_BusA_To_S, + P when Set_BusA_To_P, + ABC(7 downto 0) and DI when Set_BusA_To_DA, + (ABC(7 downto 0) or x"ee") and DI when Set_BusA_To_DAO,--ee for OAL instruction. constant may be different on other platforms.TODO:Move to generics + (ABC(7 downto 0) or x"ee") and DI and X(7 downto 0) when Set_BusA_To_DAX,--XAA, ee for OAL instruction. constant may be different on other platforms.TODO:Move to generics + ABC(7 downto 0) and X(7 downto 0) when Set_BusA_To_AAX,--SAX, SHA + (others => '-') when Set_BusA_To_DONTCARE;--Can probably remove this + + with Set_Addr_To_r select + A <= + "0000000000000001" & std_logic_vector(S(7 downto 0)) when Set_Addr_To_SP, + DBR & "00000000" & AD when Set_Addr_To_ZPG, + "00000000" & BAH & BAL(7 downto 0) when Set_Addr_To_BA, + PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when Set_Addr_To_PBR; + + -- This is the P that gets pushed on stack with correct B flag. I'm not sure if NMI also clears B, but I guess it does. + PwithB<=(P and x"ef") when (IRQCycle='1' or NMICycle='1') else P; + + with Write_Data_r select + DO <= + DL when Write_Data_DL, + ABC(7 downto 0) when Write_Data_ABC, + X(7 downto 0) when Write_Data_X, + Y(7 downto 0) when Write_Data_Y, + std_logic_vector(S(7 downto 0)) when Write_Data_S, + PwithB when Write_Data_P, + std_logic_vector(PC(7 downto 0)) when Write_Data_PCL, + std_logic_vector(PC(15 downto 8)) when Write_Data_PCH, + ABC(7 downto 0) and X(7 downto 0) when Write_Data_AX, + ABC(7 downto 0) and X(7 downto 0) and BusB_r(7 downto 0) when Write_Data_AXB, -- no better way found yet... + X(7 downto 0) and BusB_r(7 downto 0) when Write_Data_XB, -- no better way found yet... + Y(7 downto 0) and BusB_r(7 downto 0) when Write_Data_YB, -- no better way found yet... + (others=>'-') when Write_Data_DONTCARE;--Can probably remove this + + +------------------------------------------------------------------------- +-- +-- Main state machine +-- +------------------------------------------------------------------------- + + process (Res_n_i, Clk) + begin + if Res_n_i = '0' then + MCycle <= "001"; + RstCycle <= '1'; + IRQCycle <= '0'; + NMICycle <= '0'; + NMIAct <= '0'; + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = LCycle or Break = '1' then + MCycle <= "000"; + RstCycle <= '0'; + IRQCycle <= '0'; + NMICycle <= '0'; + if NMIAct = '1' and IR/=x"00" then -- delay NMI further if we just executed a BRK + NMICycle <= '1'; + NMIAct <= '0'; -- reset NMI edge detector if we start processing the NMI + elsif IRQ_n_o = '0' and P(Flag_I) = '0' then + IRQCycle <= '1'; + end if; + else + MCycle <= std_logic_vector(unsigned(MCycle) + 1); + end if; + end if; + --detect NMI even if not rdy + if NMI_n_o = '1' and (NMI_n = '0' and (IR(4 downto 0)/="10000" or Jump/="01")) then -- branches have influence on NMI start (not best way yet, though - but works...) + NMIAct <= '1'; + end if; + -- we entered NMI during BRK instruction + if NMI_entered='1' then + NMIAct <= '0'; + end if; + end if; + end if; + end process; + +end; diff --git a/Acorn - Electron_MiST/rtl/T65/T65_ALU.vhd b/Acorn - Electron_MiST/rtl/T65/T65_ALU.vhd new file mode 100644 index 00000000..b3e083bc --- /dev/null +++ b/Acorn - Electron_MiST/rtl/T65/T65_ALU.vhd @@ -0,0 +1,291 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- See list of changes in T65 top file (T65.vhd)... +-- +-- **** +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65_ALU.vhd 1234 2015-02-28 20:14:50Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author(s), but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- Limitations : +-- See in T65 top file (T65.vhd)... + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T65_Pack.all; + +entity T65_ALU is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + Op : in T_ALU_OP; + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + P_In : in std_logic_vector(7 downto 0); + P_Out : out std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0) + ); +end T65_ALU; + +architecture rtl of T65_ALU is + + -- AddSub variables (temporary signals) + signal ADC_Z : std_logic; + signal ADC_C : std_logic; + signal ADC_V : std_logic; + signal ADC_N : std_logic; + signal ADC_Q : std_logic_vector(7 downto 0); + signal SBC_Z : std_logic; + signal SBC_C : std_logic; + signal SBC_V : std_logic; + signal SBC_N : std_logic; + signal SBC_Q : std_logic_vector(7 downto 0); + signal SBX_Q : std_logic_vector(7 downto 0); + +begin + + process (P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(6 downto 0); + variable C : std_logic; + begin + AL := resize(unsigned(BusA(3 downto 0) & P_In(Flag_C)), 7) + resize(unsigned(BusB(3 downto 0) & "1"), 7); + AH := resize(unsigned(BusA(7 downto 4) & AL(5)), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + +-- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + ADC_Z <= '1'; + else + ADC_Z <= '0'; + end if; + + if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AL(6 downto 1) := AL(6 downto 1) + 6; + end if; + + C := AL(6) or AL(5); + AH := resize(unsigned(BusA(7 downto 4) & C), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + + ADC_N <= AH(4); + ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7)); + +-- pragma translate_off + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AH(6 downto 1) := AH(6 downto 1) + 6; + end if; + + ADC_C <= AH(6) or AH(5); + + ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(5 downto 0); + variable C : std_logic; + variable CT : std_logic; + begin + CT:='0'; + if( Op=ALU_OP_AND or --"0001" These OpCodes used to have LSB set + Op=ALU_OP_ADC or --"0011" + Op=ALU_OP_EQ2 or --"0101" + Op=ALU_OP_SBC or --"0111" + Op=ALU_OP_ROL or --"1001" + Op=ALU_OP_ROR or --"1011" +-- Op=ALU_OP_EQ3 or --"1101" + Op=ALU_OP_INC --"1111" + ) then + CT:='1'; + end if; + + C := P_In(Flag_C) or not CT;--was: or not Op(0); + AL := resize(unsigned(BusA(3 downto 0) & C), 7) - resize(unsigned(BusB(3 downto 0) & "1"), 6); + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(5)), 6); + + -- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "000000"; end if; + -- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + SBC_Z <= '1'; + else + SBC_Z <= '0'; + end if; + + SBC_C <= not AH(5); + SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7)); + SBC_N <= AH(4); + + SBX_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + + if P_In(Flag_D) = '1' then + if AL(5) = '1' then + AL(5 downto 1) := AL(5 downto 1) - 6; + end if; + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(6)), 6); + if AH(5) = '1' then + AH(5 downto 1) := AH(5 downto 1) - 6; + end if; + end if; + + SBC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB, + ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q, + SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q) + variable Q_t : std_logic_vector(7 downto 0); + variable Q2_t : std_logic_vector(7 downto 0); + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + P_Out <= P_In; + Q_t := BusA; + case Op is + when ALU_OP_OR=> + Q_t := BusA or BusB; + when ALU_OP_AND=> + Q_t := BusA and BusB; + when ALU_OP_EOR=> + Q_t := BusA xor BusB; + when ALU_OP_ADC=> + P_Out(Flag_V) <= ADC_V; + P_Out(Flag_C) <= ADC_C; + Q_t := ADC_Q; + when ALU_OP_CMP=> + P_Out(Flag_C) <= SBC_C; + when ALU_OP_SAX=> + P_Out(Flag_C) <= SBC_C; + Q_t := SBX_Q; -- undoc: subtract (A & X) - (immediate) + when ALU_OP_SBC=> + P_Out(Flag_V) <= SBC_V; + P_Out(Flag_C) <= SBC_C; + Q_t := SBC_Q; -- undoc: subtract (A & X) - (immediate), then decimal correction + when ALU_OP_ASL=> + Q_t := BusA(6 downto 0) & "0"; + P_Out(Flag_C) <= BusA(7); + when ALU_OP_ROL=> + Q_t := BusA(6 downto 0) & P_In(Flag_C); + P_Out(Flag_C) <= BusA(7); + when ALU_OP_LSR=> + Q_t := "0" & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when ALU_OP_ROR=> + Q_t := P_In(Flag_C) & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when ALU_OP_ARR=> + Q_t := P_In(Flag_C) & (BusA(7 downto 1) and BusB(7 downto 1)); + P_Out(Flag_V) <= Q_t(5) xor Q_t(6); + Q2_t := Q_t; + if P_In(Flag_D)='1' then + if (BusA(3 downto 0) and BusB(3 downto 0)) > "0100" then + Q2_t(3 downto 0) := std_logic_vector(unsigned(Q_t(3 downto 0)) + x"6"); + end if; + if (BusA(7 downto 4) and BusB(7 downto 4)) > "0100" then + Q2_t(7 downto 4) := std_logic_vector(unsigned(Q_t(7 downto 4)) + x"6"); + P_Out(Flag_C) <= '1'; + else + P_Out(Flag_C) <= '0'; + end if; + else + P_Out(Flag_C) <= Q_t(6); + end if; + when ALU_OP_BIT=> + P_Out(Flag_V) <= BusB(6); + when ALU_OP_DEC=> + Q_t := std_logic_vector(unsigned(BusA) - 1); + when ALU_OP_INC=> + Q_t := std_logic_vector(unsigned(BusA) + 1); + when others => + null; + --EQ1,EQ2,EQ3 passes BusA to Q_t and P_in to P_out + end case; + + case Op is + when ALU_OP_ADC=> + P_Out(Flag_N) <= ADC_N; + P_Out(Flag_Z) <= ADC_Z; + when ALU_OP_CMP|ALU_OP_SBC|ALU_OP_SAX=> + P_Out(Flag_N) <= SBC_N; + P_Out(Flag_Z) <= SBC_Z; + when ALU_OP_EQ1=>--dont touch P + when ALU_OP_BIT=> + P_Out(Flag_N) <= BusB(7); + if (BusA and BusB) = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + when ALU_OP_ANC=> + P_Out(Flag_N) <= Q_t(7); + P_Out(Flag_C) <= Q_t(7); + if Q_t = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + when others => + P_Out(Flag_N) <= Q_t(7); + if Q_t = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + end case; + + if Op=ALU_OP_ARR then + -- handled above in ARR code + Q <= Q2_t; + else + Q <= Q_t; + end if; + end process; + +end; diff --git a/Acorn - Electron_MiST/rtl/T65/T65_MCode.vhd b/Acorn - Electron_MiST/rtl/T65/T65_MCode.vhd new file mode 100644 index 00000000..7af12a31 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/T65/T65_MCode.vhd @@ -0,0 +1,1239 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- See list of changes in T65 top file (T65.vhd)... +-- +-- **** +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65_MCode.vhd 1234 2015-02-28 20:14:50Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author(s), but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- Limitations : +-- See in T65 top file (T65.vhd)... + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use ieee.std_logic_unsigned.all; +use work.T65_Pack.all; + +entity T65_MCode is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + IR : in std_logic_vector(7 downto 0); + MCycle : in T_Lcycle; + P : in std_logic_vector(7 downto 0); + LCycle : out T_Lcycle; + ALU_Op : out T_ALU_Op; + Set_BusA_To : out T_Set_BusA_To; -- DI,A,X,Y,S,P,DA,DAO,DAX,AAX + Set_Addr_To : out T_Set_Addr_To; -- PC Adder,S,AD,BA + Write_Data : out T_Write_Data; -- DL,A,X,Y,S,P,PCL,PCH,AX,AXB,XB,YB + Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel + BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj + BreakAtNA : out std_logic; + ADAdd : out std_logic; + AddY : out std_logic; + PCAdd : out std_logic; + Inc_S : out std_logic; + Dec_S : out std_logic; + LDA : out std_logic; + LDP : out std_logic; + LDX : out std_logic; + LDY : out std_logic; + LDS : out std_logic; + LDDI : out std_logic; + LDALU : out std_logic; + LDAD : out std_logic; + LDBAL : out std_logic; + LDBAH : out std_logic; + SaveP : out std_logic; + Write : out std_logic + ); +end T65_MCode; + +architecture rtl of T65_MCode is + + signal Branch : std_logic; + signal ALUmore:std_logic; + +begin + + with IR(7 downto 5) select + Branch <= not P(Flag_N) when "000", + P(Flag_N) when "001", + not P(Flag_V) when "010", + P(Flag_V) when "011", + not P(Flag_C) when "100", + P(Flag_C) when "101", + not P(Flag_Z) when "110", + P(Flag_Z) when others; + + process (IR, MCycle, P, Branch, Mode) + begin + lCycle <= Cycle_1; + Set_BusA_To <= Set_BusA_To_ABC; + Set_Addr_To <= Set_Addr_To_PBR; + Write_Data <= Write_Data_DL; + Jump <= (others => '0'); + BAAdd <= "00"; + BreakAtNA <= '0'; + ADAdd <= '0'; + PCAdd <= '0'; + Inc_S <= '0'; + Dec_S <= '0'; + LDA <= '0'; + LDP <= '0'; + LDX <= '0'; + LDY <= '0'; + LDS <= '0'; + LDDI <= '0'; + LDALU <= '0'; + LDAD <= '0'; + LDBAL <= '0'; + LDBAH <= '0'; + SaveP <= '0'; + Write <= '0'; + AddY <= '0'; + ALUmore <= '0'; + + case IR(7 downto 5) is + when "100" => -- covers $8x,$9x + case IR(1 downto 0) is + when "00" => -- IR: $80,$84,$88,$8C,$90,$94,$98,$9C + Set_BusA_To <= Set_BusA_To_Y; + if IR(4 downto 2)="111" then -- SYA ($9C) + Write_Data <= Write_Data_YB; + else + Write_Data <= Write_Data_Y; + end if; + when "10" => -- IR: $82,$86,$8A,$8E,$92,$96,$9A,$9E + Set_BusA_To <= Set_BusA_To_X; + if IR(4 downto 2)="111" then -- SXA ($9E) + Write_Data <= Write_Data_XB; + else + Write_Data <= Write_Data_X; + end if; + when "11" => -- IR: $83,$87,$8B,$8F,$93,$97,$9B,$9F + if IR(4 downto 2)="110" then -- SHS ($9B) + Set_BusA_To <= Set_BusA_To_AAX; + LDS <= '1'; + else + Set_BusA_To <= Set_BusA_To_ABC; + end if; + if IR(4 downto 2)="111" or IR(4 downto 2)="110" or IR(4 downto 2)="100" then -- SHA ($9F, $93), SHS ($9B) + Write_Data <= Write_Data_AXB; + else + Write_Data <= Write_Data_AX; + end if; + when others => -- IR: $81,$85,$89,$8D,$91,$95,$99,$9D + Write_Data <= Write_Data_ABC; + end case; + when "101" => -- covers $Ax,$Bx + Set_BusA_To <= Set_BusA_To_DI; + case IR(1 downto 0) is + when "00" => -- IR: $A0,$A4,$A8,$AC,$B0,$B4,$B8,$BC + if IR(4) /= '1' or IR(2) /= '0' then--only for $A0,$A4,$A8,$AC or $B4,$BC + LDY <= '1'; + end if; + when "01" => -- IR: $A1,$A5,$A9,$AD,$B1,$B5,$B9,$BD + LDA <= '1'; + when "10" => -- IR: $A2,$A6,$AA,$AE,$B2,$B6,$BA,$BE + LDX <= '1'; + when others => -- IR: $A3,$A7,$AB,$AF,$B3,$B7,$BB,$BF (undoc) + LDX <= '1'; + LDA <= '1'; + if IR(4 downto 2)="110" then -- LAS (BB) + Set_BusA_To <= Set_BusA_To_S; + LDS <= '1'; + end if; + end case; + when "110" => -- covers $Cx,$Dx + case IR(1 downto 0) is + when "00" => -- IR: $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC + if IR(4) = '0' then--only for $Cx + LDY <= '1'; + end if; + Set_BusA_To <= Set_BusA_To_Y; + when others => -- IR: $C1,$C5,$C9,$CD,$D1,$D5,$D9,$DD, $C2,$C6,$CA,$CE,$D2,$D6,$DA,$DE, $C3,$C7,$CB,$CF,$D3,$D7,$DB,$DF + Set_BusA_To <= Set_BusA_To_ABC; + end case; + when "111" => -- covers $Ex,$Fx + case IR(1 downto 0) is + when "00" => -- IR: $E0,$E4,$E8,$EC,$F0,$F4,$F8,$FC + if IR(4) = '0' then -- only $Ex + LDX <= '1'; + end if; + Set_BusA_To <= Set_BusA_To_X; + when others => -- IR: $E1,$E5,$E9,$ED,$F1,$F5,$F9,$FD, $E2,$E6,$EA,$EE,$F2,$F6,$FA,$FE, $E3,$E7,$EB,$EF,$F3,$F7,$FB,$FF + Set_BusA_To <= Set_BusA_To_ABC; + end case; + when others => + end case; + + if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then--covers $0x-$7x, $Cx-$Fx x=2,3,6,7,A,B,E,F, for 6502 undocs + if IR=x"eb" then + Set_BusA_To <= Set_BusA_To_ABC; -- alternate SBC ($EB) + else + Set_BusA_To <= Set_BusA_To_DI; + end if; + end if; + + case IR(4 downto 0) is + -- IR: $00,$20,$40,$60,$80,$A0,$C0,$E0 + -- $08,$28,$48,$68,$88,$A8,$C8,$E8 + -- $0A,$2A,$4A,$6A,$8A,$AA,$CA,$EA + -- $18,$38,$58,$78,$98,$B8,$D8,$F8 + -- $1A,$3A,$5A,$7A,$9A,$BA,$DA,$FA + when "00000" | "01000" | "01010" | "11000" | "11010" => + -- Implied + case IR is + when x"00" => + -- BRK ($00) + lCycle <= Cycle_6; + case MCycle is + when Cycle_1 => + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCH; + Write <= '1'; + when Cycle_2 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCL; + Write <= '1'; + when Cycle_3 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_P; + Write <= '1'; + when Cycle_4 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_6 => + Jump <= "10"; + when others => + end case; + when x"20" => -- JSR ($20) + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_2 => + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCH; + Write <= '1'; + when Cycle_3 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCL; + Write <= '1'; + when Cycle_4 => + Dec_S <= '1'; + when Cycle_5 => + Jump <= "10"; + when others => + end case; + when x"40" => -- RTI ($40) + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_2 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_3 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Set_BusA_To <= Set_BusA_To_DI; + when Cycle_4 => + LDP <= '1'; + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_5 => + Jump <= "10"; + when others => + end case; + when x"60" => -- RTS ($60) + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_2 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_3 => + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_4 => + Jump <= "10"; + when Cycle_5 => + Jump <= "01"; + when others => + end case; + when x"08" | x"48" | x"5a" | x"da" => -- PHP, PHA, PHY*, PHX* ($08,$48,$5A,$DA) + lCycle <= Cycle_2; + if Mode = "00" and IR(1) = '1' then--2 cycle nop + lCycle <= Cycle_1; + end if; + case MCycle is + when Cycle_1 => + if mode/="00" or IR(1)='0' then --wrong on 6502 + Write <= '1'; + case IR(7 downto 4) is + when "0000" => + Write_Data <= Write_Data_P; + when "0100" => + Write_Data <= Write_Data_ABC; + when "0101" => + if Mode /= "00" then + Write_Data <= Write_Data_Y; + else + Write <= '0'; + end if; + when "1101" => + if Mode /= "00" then + Write_Data <= Write_Data_X; + else + Write <= '0'; + end if; + when others => + end case; + Set_Addr_To <= Set_Addr_To_SP; + end if; + when Cycle_2 => + Dec_S <= '1'; + when others => + end case; + when x"28" | x"68" | x"7a" | x"fa" => -- PLP, PLA, PLY*, PLX* ($28,$68,$7A,$FA) + lCycle <= Cycle_3; + if Mode = "00" and IR(1) = '1' then--2 cycle nop + lCycle <= Cycle_1; + end if; + case IR(7 downto 4) is + when "0010" =>--plp + LDP <= '1'; + when "0110" =>--pla + LDA <= '1'; + when "0111" =>--ply not for 6502 + if Mode /= "00" then + LDY <= '1'; + end if; + when "1111" =>--plx not for 6502 + if Mode /= "00" then + LDX <= '1'; + end if; + when others => + end case; + case MCycle is + when Cycle_sync => + if Mode /= "00" or IR(1) = '0' then--wrong on 6502 + SaveP <= '1'; + end if; + when Cycle_1 => + if Mode /= "00" or IR(1) = '0' then--wrong on 6502 + Set_Addr_To <= Set_Addr_To_SP; + LDP <= '0'; + end if; + when Cycle_2 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + LDP <= '0'; + when Cycle_3 => + Set_BusA_To <= Set_BusA_To_DI; + when others => + end case; + when x"a0" | x"c0" | x"e0" => -- LDY, CPY, CPX ($A0,$C0,$E0) + -- Immediate + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + when others => + end case; + when x"88" => -- DEY ($88) + LDY <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_Y; + when others => + end case; + when x"ca" => -- DEX ($CA) + LDX <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_X; + when others => + end case; + when x"1a" | x"3a" => -- INC*, DEC* ($1A,$3A) + if Mode /= "00" then + LDA <= '1'; -- A + else + lCycle <= Cycle_1;--undoc 2 cycle nop + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_S; + when others => + end case; + when x"0a" | x"2a" | x"4a" | x"6a" => -- ASL, ROL, LSR, ROR ($0A,$2A,$4A,$6A) + LDA <= '1'; -- A + Set_BusA_To <= Set_BusA_To_ABC; + case MCycle is + when Cycle_sync => + when Cycle_1 => + when others => + end case; + when x"8a" | x"98" => -- TYA, TXA ($8A,$98) + LDA <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + when others => + end case; + when x"aa" | x"a8" => -- TAX, TAY ($AA,$A8) + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_ABC; + when others => + end case; + when x"9a" => -- TXS ($9A) + LDS <= '1'; -- will be set only in Cycle_sync + when x"ba" => -- TSX ($BA) + LDX <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_S; + when others => + end case; + when x"80" => -- undoc: NOP imm2 ($80) + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + when others => + end case; + when others => -- others ($0A,$EA, $18,$38,$58,$78,$B8,$C8,$D8,$E8,$F8) + case MCycle is + when Cycle_sync => + when others => + end case; + end case; + + -- IR: $01,$21,$41,$61,$81,$A1,$C1,$E1 + -- $03,$23,$43,$63,$83,$A3,$C3,$E3 + when "00001" | "00011" => + -- Zero Page Indexed Indirect (d,x) + lCycle <= Cycle_5; + if IR(7 downto 6) /= "10" then -- ($01,$21,$41,$61,$C1,$E1,$03,$23,$43,$63,$C3,$E3) + LDA <= '1'; + if Mode="00" and IR(1)='1' then + lCycle <= Cycle_7; + end if; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + ADAdd <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + BAAdd <= "01"; + LDBAL <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_4 => + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5=> + if Mode="00" and IR(1)='1' and IR(7 downto 6)/="10" then + Set_Addr_To <= Set_Addr_To_BA; + Write <= '1'; + LDDI<='1'; + end if; + when Cycle_6=> + Write <= '1'; + LDALU<='1'; + SaveP<='1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_7 => + ALUmore <= '1'; + Set_BusA_To <= Set_BusA_To_ABC; + when others => + end case; + + -- IR: $09,$29,$49,$69,$89,$A9,$C9,$E9 + when "01001" => + -- Immediate + if IR(7 downto 5)/="100" then -- all except undoc. NOP imm2 (not $89) + LDA <= '1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + when others => + end case; + + -- IR: $0B,$2B,$4B,$6B,$8B,$AB,$CB,$EB + when "01011" => + if Mode="00" then + -- Immediate undoc for 6500 + case IR(7 downto 5) is + when "010"|"011"|"000"|"001" =>--ALR,ARR + Set_BusA_To<=Set_BusA_To_DA; + LDA <= '1'; + when "100" =>--XAA + Set_BusA_To<=Set_BusA_To_DAX; + LDA <= '1'; + when "110" =>--SAX (SBX) + Set_BusA_To<=Set_BusA_To_AAX; + LDX <= '1'; + when "101" =>--OAL + Set_BusA_To<=Set_BusA_To_DAO; + LDA <= '1'; + when others=> + LDA <= '1'; + end case; + case MCycle is + when Cycle_1 => + Jump <= "01"; + when others => + end case; + end if; + + -- IR: $02,$22,$42,$62,$82,$A2,$C2,$E2 + -- $12,$32,$52,$72,$92,$B2,$D2,$F2 + when "00010" | "10010" => + -- Immediate, SKB, KIL + case MCycle is + when Cycle_sync => + when Cycle_1 => + if IR = "10100010" then + -- LDX ($A2) + Jump <= "01"; + LDX <= '1'; -- Moved, Lorenz test showed X changing on SKB (NOPx) + elsif IR(7 downto 4)="1000" or IR(7 downto 4)="1100" or IR(7 downto 4)="1110" then + -- undoc: NOP imm2 + Jump <= "01"; + else + -- KIL !!! + end if; + when others => + end case; + + -- IR: $04,$24,$44,$64,$84,$A4,$C4,$E4 + when "00100" => + -- Zero Page + lCycle <= Cycle_2; + case MCycle is + when Cycle_sync => + if IR(7 downto 5) = "001" then--24=BIT zpg + SaveP <= '1'; + end if; + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then--84=sty zpg (the only write in this group) + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + when others => + end case; + + -- IR: $05,$25,$45,$65,$85,$A5,$C5,$E5 + -- $06,$26,$46,$66,$86,$A6,$C6,$E6 + -- $07,$27,$47,$67,$87,$A7,$C7,$E7 + when "00101" | "00110" | "00111" => + -- Zero Page + if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then--covers 0x-7x,cx-fx x=2,3,6,7,a,b,e,f, for 6502 undocs + -- Read-Modify-Write + lCycle <= Cycle_4; + if Mode="00" and IR(0)='1' then + LDA<='1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + LDDI <= '1'; + if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_4 => + if Mode="00" and IR(0)='1' then + Set_BusA_To<=Set_BusA_To_ABC; + ALUmore <= '1'; -- For undoc DCP/DCM support + LDDI <= '1'; -- requires DIN to reflect DOUT! + end if; + when others => + end case; + else + lCycle <= Cycle_2; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + when others => + end case; + end if; + + -- IR: $0C,$2C,$4C,$6C,$8C,$AC,$CC,$EC + when "01100" => + -- Absolute + if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then -- JMP ($4C,$6C) + if IR(5) = '0' then + lCycle <= Cycle_2; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDDI <= '1'; + when Cycle_2 => + Jump <= "10"; + when others => + end case; + else + lCycle <= Cycle_4; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDDI <= '1'; + LDBAL <= '1'; + when Cycle_2 => + LDBAH <= '1'; + if Mode /= "00" then + Jump <= "10"; + end if; + if Mode = "00" then + Set_Addr_To <= Set_Addr_To_BA; + end if; + when Cycle_3 => + LDDI <= '1'; + if Mode = "00" then + Set_Addr_To <= Set_Addr_To_BA; + BAAdd <= "01"; -- DB Inc + else + Jump <= "01"; + end if; + when Cycle_4 => + Jump <= "10"; + when others => + end case; + end if; + else + lCycle <= Cycle_3; + case MCycle is + when Cycle_sync => + if IR(7 downto 5) = "001" then--2c-BIT + SaveP <= '1'; + end if; + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then--80, sty, the only write in this group + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + when others => + end case; + end if; + + -- IR: $0D,$2D,$4D,$6D,$8D,$AD,$CD,$ED + -- $0E,$2E,$4E,$6E,$8E,$AE,$CE,$EE + -- $0F,$2F,$4F,$6F,$8F,$AF,$CF,$EF + when "01101" | "01110" | "01111" => + -- Absolute + if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then -- ($0E,$2E,$4E,$6E,$CE,$EE, $0F,$2F,$4F,$6F,$CF,$EF) + -- Read-Modify-Write + lCycle <= Cycle_5; + if Mode="00" and IR(0) = '1' then + LDA <= '1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + LDDI <= '1'; + if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + Write <= '1'; + LDALU <= '1'; + SaveP <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + if Mode="00" and IR(0)='1' then + ALUmore <= '1'; -- For undoc DCP/DCM support + Set_BusA_To<=Set_BusA_To_ABC; + end if; + when others => + end case; + else + lCycle <= Cycle_3; + if IR(7 downto 6) /= "10" then -- all but $8D, $8E, $8F, $AD, $AE, $AF ($AD does set LDA in an earlier case statement) + LDA <= '1'; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then--8d + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + when others => + end case; + end if; + + -- IR: $10,$30,$50,$70,$90,$B0,$D0,$F0 + when "10000" => + -- Relative + -- This circuit dictates when the last + -- microcycle occurs for the branch depending on + -- whether or not the branch is taken and if a page + -- is crossed... + if (Branch = '1') then + lCycle <= Cycle_3; -- We're done @ T3 if branching...upper + -- level logic will stop at T2 if no page cross + -- (See the Break signal) + else + lCycle <= Cycle_1; + end if; + -- This decodes the current microcycle and takes the + -- proper course of action... + case MCycle is + -- On the T1 microcycle, increment the program counter + -- and instruct the upper level logic to fetch the offset + -- from the Din bus and store it in the data latches. This + -- will be the last microcycle if the branch isn't taken. + when Cycle_1 => + Jump <= "01"; -- Increments the PC by one (PC will now be PC+2) + -- from microcycle T0. + LDDI <= '1'; -- Tells logic in top level (T65.vhd) to route + -- the Din bus to the memory data latch (DL) + -- so that the branch offset is fetched. + -- In microcycle T2, tell the logic in the top level to + -- add the offset. If the most significant byte of the + -- program counter (i.e. the current "page") does not need + -- updating, we are done here...the Break signal at the + -- T65.vhd level takes care of that... + when Cycle_2 => + Jump <= "11"; -- Tell the PC Jump logic to use relative mode. + PCAdd <= '1'; -- This tells the PC adder to update itself with + -- the current offset recently fetched from + -- memory. + -- The following is microcycle T3 : + -- The program counter should be completely updated + -- on this cycle after the page cross is detected. + -- We don't need to do anything here... + when Cycle_3 => + when others => null; -- Do nothing. + end case; + + -- IR: $11,$31,$51,$71,$91,$B1,$D1,$F1 + -- $13,$33,$53,$73,$93,$B3,$D3,$F3 + when "10001" | "10011" => + lCycle <= Cycle_5; + if IR(7 downto 6) /= "10" then -- ($11,$31,$51,$71,$D1,$F1,$13,$33,$53,$73,$D3,$F3) + LDA <= '1'; + if Mode="00" and IR(1)='1' then + lCycle <= Cycle_7; + end if; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + LDBAL <= '1'; + BAAdd <= "01"; -- DB Inc + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + Set_BusA_To <= Set_BusA_To_Y; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + BAAdd <= "11"; -- BA Adj + if IR(7 downto 5) = "100" then + Write <= '1'; + elsif IR(1)='0' or IR=x"B3" then -- Dont do this on $x3, except undoc LAXiy $B3 (says real CPU and Lorenz tests) + BreakAtNA <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + if Mode="00" and IR(1)='1' and IR(7 downto 6)/="10" then + Set_Addr_To <= Set_Addr_To_BA; + LDDI<='1'; + Write <= '1'; + end if; + when Cycle_6 => + LDALU<='1'; + SaveP<='1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_7 => + ALUmore <= '1'; + Set_BusA_To<=Set_BusA_To_ABC; + when others => + end case; + + -- IR: $14,$34,$54,$74,$94,$B4,$D4,$F4 + -- $15,$35,$55,$75,$95,$B5,$D5,$F5 + -- $16,$36,$56,$76,$96,$B6,$D6,$F6 + -- $17,$37,$57,$77,$97,$B7,$D7,$F7 + when "10100" | "10101" | "10110" | "10111" => + -- Zero Page, X + if IR(7 downto 6) /= "10" and IR(1) = '1' and (Mode="00" or IR(0)='0') then -- ($16,$36,$56,$76,$D6,$F6, $17,$37,$57,$77,$D7,$F7) + -- Read-Modify-Write + if Mode="00" and IR(0)='1' then + LDA<='1'; + end if; + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + ADAdd <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + LDDI <= '1'; + if Mode="00" then -- The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_4 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + if Mode="00" and IR(0)='1' then + LDDI<='1'; + end if; + when Cycle_5 => + if Mode="00" and IR(0)='1' then + ALUmore <= '1'; -- For undoc DCP/DCM support + Set_BusA_To<=Set_BusA_To_ABC; + end if; + when others => + end case; + else + lCycle <= Cycle_3; + if IR(7 downto 6) /= "10" and IR(0)='1' then -- dont LDA on undoc skip + LDA <= '1'; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + ADAdd <= '1'; + -- Added this check for Y reg. use, added undocs + if (IR(3 downto 1) = "011") then -- ($16,$36,$56,$76,$96,$B6,$D6,$F6,$17,$37,$57,$77,$97,$B7,$D7,$F7) + AddY <= '1'; + end if; + if IR(7 downto 5) = "100" then -- ($14,$34,$15,$35,$16,$36,$17,$37) the only write instruction + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => null; + when others => + end case; + end if; + + -- IR: $19,$39,$59,$79,$99,$B9,$D9,$F9 + -- $1B,$3B,$5B,$7B,$9B,$BB,$DB,$FB + when "11001" | "11011" => + -- Absolute Y + lCycle <= Cycle_4; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + if Mode="00" and IR(1)='1' then + lCycle <= Cycle_6; + end if; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + Set_BusA_To <= Set_BusA_To_Y; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then--99/9b + Write <= '1'; + elsif IR(1)='0' or IR=x"BB" then -- Dont do this on $xB, except undoc $BB (says real CPU and Lorenz tests) + BreakAtNA <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => -- just for undoc + if Mode="00" and IR(1)='1' and IR(7 downto 6)/="10" then + Set_Addr_To <= Set_Addr_To_BA; + LDDI<='1'; + Write <= '1'; + end if; + when Cycle_5 => + Write <= '1'; + LDALU<='1'; + Set_Addr_To <= Set_Addr_To_BA; + SaveP<='1'; + when Cycle_6 => + ALUmore <= '1'; + Set_BusA_To <= Set_BusA_To_ABC; + when others => + end case; + + -- IR: $1C,$3C,$5C,$7C,$9C,$BC,$DC,$FC + -- $1D,$3D,$5D,$7D,$9D,$BD,$DD,$FD + -- $1E,$3E,$5E,$7E,$9E,$BE,$DE,$FE + -- $1F,$3F,$5F,$7F,$9F,$BF,$DF,$FF + when "11100" | "11101" | "11110" | "11111" => + -- Absolute X + if IR(7 downto 6) /= "10" and IR(1) = '1' and (Mode="00" or IR(0)='0') then -- ($1E,$3E,$5E,$7E,$DE,$FE, $1F,$3F,$5F,$7F,$DF,$FF) + -- Read-Modify-Write + lCycle <= Cycle_6; + if Mode="00" and IR(0)='1' then + LDA <= '1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + Set_BusA_To <= Set_BusA_To_X; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + BAAdd <= "11"; -- BA adj + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + LDDI <= '1'; + if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_6 => + if Mode="00" and IR(0)='1' then + ALUmore <= '1'; + Set_BusA_To <= Set_BusA_To_ABC; + end if; + when others => + end case; + else -- ($1C,$3C,$5C,$7C,$9C,$BC,$DC,$FC, $1D,$3D,$5D,$7D,$9D,$BD,$DD,$FD, $9E,$BE,$9F,$BF) + lCycle <= Cycle_4;--Or 3 if not page crossing + if IR(7 downto 6) /= "10" then + if Mode/="00" or IR(4)='0' or IR(1 downto 0)/="00" then + LDA <= '1'; + end if; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + -- special case $BE which uses Y reg as index!! + if(IR(7 downto 6)="10" and IR(4 downto 1)="1111") then + Set_BusA_To <= Set_BusA_To_Y; + else + Set_BusA_To <= Set_BusA_To_X; + end if; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then -- ($9E,$9F) + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + when others => + end case; + end if; + when others => + end case; + end process; + + process (IR, MCycle, Mode,ALUmore) + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + case IR(1 downto 0) is + when "00" => + case IR(4 downto 2) is + -- IR: $00,$20,$40,$60,$80,$A0,$C0,$E0 + -- $04,$24,$44,$64,$84,$A4,$C4,$E4 + -- $0C,$2C,$4C,$6C,$8C,$AC,$CC,$EC + when "000" | "001" | "011" => + case IR(7 downto 5) is + when "110" | "111" => -- CP ($C0,$C4,$CC,$E0,$E4,$EC) + ALU_Op <= ALU_OP_CMP; + when "101" => -- LD ($A0,$A4,$AC) + ALU_Op <= ALU_OP_EQ2; + when "001" => -- BIT ($20,$24,$2C - $20 is ignored, as its a jmp) + ALU_Op <= ALU_OP_BIT; + when others => -- other, NOP/ST ($x0,$x4,$xC) + ALU_Op <= ALU_OP_EQ1; + end case; + + -- IR: $08,$28,$48,$68,$88,$A8,$C8,$E8 + when "010" => + case IR(7 downto 5) is + when "111" | "110" => -- IN ($C8,$E8) + ALU_Op <= ALU_OP_INC; + when "100" => -- DEY ($88) + ALU_Op <= ALU_OP_DEC; + when others => -- LD + ALU_Op <= ALU_OP_EQ2; + end case; + + -- IR: $18,$38,$58,$78,$98,$B8,$D8,$F8 + when "110" => + case IR(7 downto 5) is + when "100" => -- TYA ($98) + ALU_Op <= ALU_OP_EQ2; + when others => + ALU_Op <= ALU_OP_EQ1; + end case; + + -- IR: $10,$30,$50,$70,$90,$B0,$D0,$F0 + -- $14,$34,$54,$74,$94,$B4,$D4,$F4 + -- $1C,$3C,$5C,$7C,$9C,$BC,$DC,$FC + when others => + case IR(7 downto 5) is + when "101" => -- LD ($B0,$B4,$BC) + ALU_Op <= ALU_OP_EQ2; + when others => + ALU_Op <= ALU_OP_EQ1; + end case; + end case; + + when "01" => -- OR + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> -- IR: $01,$05,$09,$0D,$11,$15,$19,$1D + ALU_Op<=ALU_OP_OR; + when 1=> -- IR: $21,$25,$29,$2D,$31,$35,$39,$3D + ALU_Op<=ALU_OP_AND; + when 2=> -- IR: $41,$45,$49,$4D,$51,$55,$59,$5D + ALU_Op<=ALU_OP_EOR; + when 3=> -- IR: $61,$65,$69,$6D,$71,$75,$79,$7D + ALU_Op<=ALU_OP_ADC; + when 4=>-- IR: $81,$85,$89,$8D,$91,$95,$99,$9D + ALU_Op<=ALU_OP_EQ1; -- STA + when 5=> -- IR: $A1,$A5,$A9,$AD,$B1,$B5,$B9,$BD + ALU_Op<=ALU_OP_EQ2; -- LDA + when 6=> -- IR: $C1,$C5,$C9,$CD,$D1,$D5,$D9,$DD + ALU_Op<=ALU_OP_CMP; + when others=> -- IR: $E1,$E5,$E9,$ED,$F1,$F5,$F9,$FD + ALU_Op<=ALU_OP_SBC; + end case; + + when "10" => + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> -- IR: $02,$06,$0A,$0E,$12,$16,$1A,$1E + ALU_Op<=ALU_OP_ASL; + if IR(4 downto 2) = "110" and Mode/="00" then -- 00011010,$1A -> INC acc, not on 6502 + ALU_Op <= ALU_OP_INC; + end if; + when 1=> -- IR: $22,$26,$2A,$2E,$32,$36,$3A,$3E + ALU_Op<=ALU_OP_ROL; + if IR(4 downto 2) = "110" and Mode/="00" then -- 00111010,$3A -> DEC acc, not on 6502 + ALU_Op <= ALU_OP_DEC; + end if; + when 2=> -- IR: $42,$46,$4A,$4E,$52,$56,$5A,$5E + ALU_Op<=ALU_OP_LSR; + when 3=> -- IR: $62,$66,$6A,$6E,$72,$76,$7A,$7E + ALU_Op<=ALU_OP_ROR; + when 4=> -- IR: $82,$86,$8A,$8E,$92,$96,$9A,$9E + ALU_Op<=ALU_OP_BIT; + if IR(4 downto 2) = "010" then -- 10001010, $8A -> TXA + ALU_Op <= ALU_OP_EQ2; + else -- 100xxx10, $82,$86,$8E,$92,$96,$9A,$9E + ALU_Op <= ALU_OP_EQ1; + end if; + when 5=> -- IR: $A2,$A6,$AA,$AE,$B2,$B6,$BA,$BE + ALU_Op<=ALU_OP_EQ2; -- LDX + when 6=> -- IR: $C2,$C6,$CA,$CE,$D2,$D6,$DA,$DE + ALU_Op<=ALU_OP_DEC; + when others=> -- IR: $E2,$E6,$EA,$EE,$F2,$F6,$FA,$FE + ALU_Op<=ALU_OP_INC; + end case; + + when others => -- "11" undoc double alu ops + case(to_integer(unsigned(IR(7 downto 5)))) is + -- IR: $A3,$A7,$AB,$AF,$B3,$B7,$BB,$BF + when 5 => + if IR=x"bb" then--LAS + ALU_Op <= ALU_OP_AND; + else + ALU_Op <= ALU_OP_EQ2; + end if; + + -- IR: $03,$07,$0B,$0F,$13,$17,$1B,$1F + -- $23,$27,$2B,$2F,$33,$37,$3B,$3F + -- $43,$47,$4B,$4F,$53,$57,$5B,$5F + -- $63,$67,$6B,$6F,$73,$77,$7B,$7F + -- $83,$87,$8B,$8F,$93,$97,$9B,$9F + -- $C3,$C7,$CB,$CF,$D3,$D7,$DB,$DF + -- $E3,$E7,$EB,$EF,$F3,$F7,$FB,$FF + when others => + if IR=x"6b" then -- ARR + ALU_Op<=ALU_OP_ARR; + elsif IR=x"8b" then -- ARR + ALU_Op<=ALU_OP_XAA; -- we can't use the bit operation as we don't set all flags... + elsif IR=x"0b" or IR=x"2b" then -- ANC + ALU_Op<=ALU_OP_ANC; + elsif IR=x"eb" then -- alternate SBC + ALU_Op<=ALU_OP_SBC; + elsif ALUmore='1' then + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> + ALU_Op<=ALU_OP_OR; + when 1=> + ALU_Op<=ALU_OP_AND; + when 2=> + ALU_Op<=ALU_OP_EOR; + when 3=> + ALU_Op<=ALU_OP_ADC; + when 4=> + ALU_Op<=ALU_OP_EQ1; -- STA + when 5=> + ALU_Op<=ALU_OP_EQ2; -- LDA + when 6=> + ALU_Op<=ALU_OP_CMP; + when others=> + ALU_Op<=ALU_OP_SBC; + end case; + else + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> + ALU_Op<=ALU_OP_ASL; + when 1=> + ALU_Op<=ALU_OP_ROL; + when 2=> + ALU_Op<=ALU_OP_LSR; + when 3=> + ALU_Op<=ALU_OP_ROR; + when 4=> + ALU_Op<=ALU_OP_BIT; + when 5=> + ALU_Op<=ALU_OP_EQ2; -- LDX + when 6=> + ALU_Op<=ALU_OP_DEC; + if IR(4 downto 2)="010" then -- $6B + ALU_Op<=ALU_OP_SAX; -- special SAX (SBX) case + end if; + when others=> + ALU_Op<=ALU_OP_INC; + end case; + end if; + end case; + end case; + end process; + +end; diff --git a/Acorn - Electron_MiST/rtl/T65/T65_Pack.vhd b/Acorn - Electron_MiST/rtl/T65/T65_Pack.vhd new file mode 100644 index 00000000..c3977396 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/T65/T65_Pack.vhd @@ -0,0 +1,180 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- See list of changes in T65 top file (T65.vhd)... +-- +-- **** +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65_Pack.vhd 1234 2015-02-28 20:14:50Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author(s), but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +-- Limitations : +-- See in T65 top file (T65.vhd)... + +library IEEE; +use IEEE.std_logic_1164.all; + +package T65_Pack is + + constant Flag_C : integer := 0; + constant Flag_Z : integer := 1; + constant Flag_I : integer := 2; + constant Flag_D : integer := 3; + constant Flag_B : integer := 4; + constant Flag_1 : integer := 5; + constant Flag_V : integer := 6; + constant Flag_N : integer := 7; + + subtype T_Lcycle is std_logic_vector(2 downto 0); + constant Cycle_sync :T_Lcycle:="000"; + constant Cycle_1 :T_Lcycle:="001"; + constant Cycle_2 :T_Lcycle:="010"; + constant Cycle_3 :T_Lcycle:="011"; + constant Cycle_4 :T_Lcycle:="100"; + constant Cycle_5 :T_Lcycle:="101"; + constant Cycle_6 :T_Lcycle:="110"; + constant Cycle_7 :T_Lcycle:="111"; + + function CycleNext(c:T_Lcycle) return T_Lcycle; + + type T_Set_BusA_To is + ( + Set_BusA_To_DI, + Set_BusA_To_ABC, + Set_BusA_To_X, + Set_BusA_To_Y, + Set_BusA_To_S, + Set_BusA_To_P, + Set_BusA_To_DA, + Set_BusA_To_DAO, + Set_BusA_To_DAX, + Set_BusA_To_AAX, + Set_BusA_To_DONTCARE + ); + + type T_Set_Addr_To is + ( + Set_Addr_To_SP, + Set_Addr_To_ZPG, + Set_Addr_To_PBR, + Set_Addr_To_BA + ); + + type T_Write_Data is + ( + Write_Data_DL, + Write_Data_ABC, + Write_Data_X, + Write_Data_Y, + Write_Data_S, + Write_Data_P, + Write_Data_PCL, + Write_Data_PCH, + Write_Data_AX, + Write_Data_AXB, + Write_Data_XB, + Write_Data_YB, + Write_Data_DONTCARE + ); + + type T_ALU_OP is + ( + ALU_OP_OR, --"0000" + ALU_OP_AND, --"0001" + ALU_OP_EOR, --"0010" + ALU_OP_ADC, --"0011" + ALU_OP_EQ1, --"0100" EQ1 does not change N,Z flags, EQ2/3 does. + ALU_OP_EQ2, --"0101" Not sure yet whats the difference between EQ2&3. They seem to do the same ALU op + ALU_OP_CMP, --"0110" + ALU_OP_SBC, --"0111" + ALU_OP_ASL, --"1000" + ALU_OP_ROL, --"1001" + ALU_OP_LSR, --"1010" + ALU_OP_ROR, --"1011" + ALU_OP_BIT, --"1100" +-- ALU_OP_EQ3, --"1101" + ALU_OP_DEC, --"1110" + ALU_OP_INC, --"1111" + ALU_OP_ARR, + ALU_OP_ANC, + ALU_OP_SAX, + ALU_OP_XAA +-- ALU_OP_UNDEF--"----"--may be replaced with any? + ); + + type T_t65_dbg is record + I : std_logic_vector(7 downto 0); -- instruction + A : std_logic_vector(7 downto 0); -- A reg + X : std_logic_vector(7 downto 0); -- X reg + Y : std_logic_vector(7 downto 0); -- Y reg + S : std_logic_vector(7 downto 0); -- stack pointer + P : std_logic_vector(7 downto 0); -- processor flags + end record; + +end; + +package body T65_Pack is + + function CycleNext(c:T_Lcycle) return T_Lcycle is + begin + case(c) is + when Cycle_sync=> + return Cycle_1; + when Cycle_1=> + return Cycle_2; + when Cycle_2=> + return Cycle_3; + when Cycle_3=> + return Cycle_4; + when Cycle_4=> + return Cycle_5; + when Cycle_5=> + return Cycle_6; + when Cycle_6=> + return Cycle_7; + when Cycle_7=> + return Cycle_sync; + when others=> + return Cycle_sync; + end case; + end CycleNext; + +end T65_Pack; \ No newline at end of file diff --git a/Acorn - Electron_MiST/rtl/build_id.tcl b/Acorn - Electron_MiST/rtl/build_id.tcl new file mode 100644 index 00000000..938515d8 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/build_id.tcl @@ -0,0 +1,35 @@ +# ================================================================================ +# +# Build ID Verilog Module Script +# Jeff Wiencrot - 8/1/2011 +# +# Generates a Verilog module that contains a timestamp, +# from the current build. These values are available from the build_date, build_time, +# physical_address, and host_name output ports of the build_id module in the build_id.v +# Verilog source file. +# +# ================================================================================ + +proc generateBuildID_Verilog {} { + + # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) + set buildDate [ clock format [ clock seconds ] -format %y%m%d ] + set buildTime [ clock format [ clock seconds ] -format %H%M%S ] + + # Create a Verilog file for output + set outputFileName "rtl/build_id.v" + set outputFile [open $outputFileName "w"] + + # Output the Verilog source + puts $outputFile "`define BUILD_DATE \"$buildDate\"" + puts $outputFile "`define BUILD_TIME \"$buildTime\"" + close $outputFile + + # Send confirmation message to the Messages window + post_message "Generated build identification Verilog module: [pwd]/$outputFileName" + post_message "Date: $buildDate" + post_message "Time: $buildTime" +} + +# Comment out this line to prevent the process from automatically executing when the file is sourced: +generateBuildID_Verilog \ No newline at end of file diff --git a/Acorn - Electron_MiST/rtl/build_id.v b/Acorn - Electron_MiST/rtl/build_id.v new file mode 100644 index 00000000..565cec23 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/build_id.v @@ -0,0 +1,2 @@ +`define BUILD_DATE "180123" +`define BUILD_TIME "014157" diff --git a/Acorn - Electron_MiST/rtl/hq2x.sv b/Acorn - Electron_MiST/rtl/hq2x.sv new file mode 100644 index 00000000..f17732b6 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/hq2x.sv @@ -0,0 +1,454 @@ +// +// +// Copyright (c) 2012-2013 Ludvig Strigeus +// Copyright (c) 2017 Sorgelig +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on + +`define BITS_TO_FIT(N) ( \ + N <= 2 ? 0 : \ + N <= 4 ? 1 : \ + N <= 8 ? 2 : \ + N <= 16 ? 3 : \ + N <= 32 ? 4 : \ + N <= 64 ? 5 : \ + N <= 128 ? 6 : \ + N <= 256 ? 7 : \ + N <= 512 ? 8 : \ + N <=1024 ? 9 : 10 ) + +module hq2x_in #(parameter LENGTH, parameter DWIDTH) +( + input clk, + + input [AWIDTH:0] rdaddr, + input rdbuf, + output[DWIDTH:0] q, + + input [AWIDTH:0] wraddr, + input wrbuf, + input [DWIDTH:0] data, + input wren +); + + localparam AWIDTH = `BITS_TO_FIT(LENGTH); + wire [DWIDTH:0] out[2]; + assign q = out[rdbuf]; + + hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]); + hq2x_buf #(.NUMWORDS(LENGTH), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]); +endmodule + + +module hq2x_out #(parameter LENGTH, parameter DWIDTH) +( + input clk, + + input [AWIDTH:0] rdaddr, + input [1:0] rdbuf, + output[DWIDTH:0] q, + + input [AWIDTH:0] wraddr, + input [1:0] wrbuf, + input [DWIDTH:0] data, + input wren +); + + localparam AWIDTH = `BITS_TO_FIT(LENGTH*2); + wire [DWIDTH:0] out[4]; + assign q = out[rdbuf]; + + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf0(clk,data,rdaddr,wraddr,wren && (wrbuf == 0),out[0]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf1(clk,data,rdaddr,wraddr,wren && (wrbuf == 1),out[1]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf2(clk,data,rdaddr,wraddr,wren && (wrbuf == 2),out[2]); + hq2x_buf #(.NUMWORDS(LENGTH*2), .AWIDTH(AWIDTH), .DWIDTH(DWIDTH)) buf3(clk,data,rdaddr,wraddr,wren && (wrbuf == 3),out[3]); +endmodule + + +module hq2x_buf #(parameter NUMWORDS, parameter AWIDTH, parameter DWIDTH) +( + input clock, + input [DWIDTH:0] data, + input [AWIDTH:0] rdaddress, + input [AWIDTH:0] wraddress, + input wren, + output [DWIDTH:0] q +); + + altsyncram altsyncram_component ( + .address_a (wraddress), + .clock0 (clock), + .data_a (data), + .wren_a (wren), + .address_b (rdaddress), + .q_b(q), + .aclr0 (1'b0), + .aclr1 (1'b0), + .addressstall_a (1'b0), + .addressstall_b (1'b0), + .byteena_a (1'b1), + .byteena_b (1'b1), + .clock1 (1'b1), + .clocken0 (1'b1), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .data_b ({(DWIDTH+1){1'b1}}), + .eccstatus (), + .q_a (), + .rden_a (1'b1), + .rden_b (1'b1), + .wren_b (1'b0)); + defparam + altsyncram_component.address_aclr_b = "NONE", + altsyncram_component.address_reg_b = "CLOCK0", + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_input_b = "BYPASS", + altsyncram_component.clock_enable_output_b = "BYPASS", + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = NUMWORDS, + altsyncram_component.numwords_b = NUMWORDS, + altsyncram_component.operation_mode = "DUAL_PORT", + altsyncram_component.outdata_aclr_b = "NONE", + altsyncram_component.outdata_reg_b = "UNREGISTERED", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE", + altsyncram_component.widthad_a = AWIDTH+1, + altsyncram_component.widthad_b = AWIDTH+1, + altsyncram_component.width_a = DWIDTH+1, + altsyncram_component.width_b = DWIDTH+1, + altsyncram_component.width_byteena_a = 1; + +endmodule + +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +module DiffCheck +( + input [17:0] rgb1, + input [17:0] rgb2, + output result +); + + wire [5:0] r = rgb1[5:1] - rgb2[5:1]; + wire [5:0] g = rgb1[11:7] - rgb2[11:7]; + wire [5:0] b = rgb1[17:13] - rgb2[17:13]; + wire [6:0] t = $signed(r) + $signed(b); + wire [6:0] gx = {g[5], g}; + wire [7:0] y = $signed(t) + $signed(gx); + wire [6:0] u = $signed(r) - $signed(b); + wire [7:0] v = $signed({g, 1'b0}) - $signed(t); + + // if y is inside (-24..24) + wire y_inside = (y < 8'h18 || y >= 8'he8); + + // if u is inside (-4, 4) + wire u_inside = (u < 7'h4 || u >= 7'h7c); + + // if v is inside (-6, 6) + wire v_inside = (v < 8'h6 || v >= 8'hfA); + assign result = !(y_inside && u_inside && v_inside); +endmodule + +module InnerBlend +( + input [8:0] Op, + input [5:0] A, + input [5:0] B, + input [5:0] C, + output [5:0] O +); + + function [8:0] mul6x3; + input [5:0] op1; + input [2:0] op2; + begin + mul6x3 = 9'd0; + if(op2[0]) mul6x3 = mul6x3 + op1; + if(op2[1]) mul6x3 = mul6x3 + {op1, 1'b0}; + if(op2[2]) mul6x3 = mul6x3 + {op1, 2'b00}; + end + endfunction + + wire OpOnes = Op[4]; + wire [8:0] Amul = mul6x3(A, Op[7:5]); + wire [8:0] Bmul = mul6x3(B, {Op[3:2], 1'b0}); + wire [8:0] Cmul = mul6x3(C, {Op[1:0], 1'b0}); + wire [8:0] At = Amul; + wire [8:0] Bt = (OpOnes == 0) ? Bmul : {3'b0, B}; + wire [8:0] Ct = (OpOnes == 0) ? Cmul : {3'b0, C}; + wire [9:0] Res = {At, 1'b0} + Bt + Ct; + assign O = Op[8] ? A : Res[9:4]; +endmodule + +module Blend +( + input [5:0] rule, + input disable_hq2x, + input [17:0] E, + input [17:0] A, + input [17:0] B, + input [17:0] D, + input [17:0] F, + input [17:0] H, + output [17:0] Result +); + + reg [1:0] input_ctrl; + reg [8:0] op; + localparam BLEND0 = 9'b1_xxx_x_xx_xx; // 0: A + localparam BLEND1 = 9'b0_110_0_10_00; // 1: (A * 12 + B * 4) >> 4 + localparam BLEND2 = 9'b0_100_0_10_10; // 2: (A * 8 + B * 4 + C * 4) >> 4 + localparam BLEND3 = 9'b0_101_0_10_01; // 3: (A * 10 + B * 4 + C * 2) >> 4 + localparam BLEND4 = 9'b0_110_0_01_01; // 4: (A * 12 + B * 2 + C * 2) >> 4 + localparam BLEND5 = 9'b0_010_0_11_11; // 5: (A * 4 + (B + C) * 6) >> 4 + localparam BLEND6 = 9'b0_111_1_xx_xx; // 6: (A * 14 + B + C) >> 4 + localparam AB = 2'b00; + localparam AD = 2'b01; + localparam DB = 2'b10; + localparam BD = 2'b11; + wire is_diff; + DiffCheck diff_checker(rule[1] ? B : H, rule[0] ? D : F, is_diff); + + always @* begin + case({!is_diff, rule[5:2]}) + 1,17: {op, input_ctrl} = {BLEND1, AB}; + 2,18: {op, input_ctrl} = {BLEND1, DB}; + 3,19: {op, input_ctrl} = {BLEND1, BD}; + 4,20: {op, input_ctrl} = {BLEND2, DB}; + 5,21: {op, input_ctrl} = {BLEND2, AB}; + 6,22: {op, input_ctrl} = {BLEND2, AD}; + + 8: {op, input_ctrl} = {BLEND0, 2'bxx}; + 9: {op, input_ctrl} = {BLEND0, 2'bxx}; + 10: {op, input_ctrl} = {BLEND0, 2'bxx}; + 11: {op, input_ctrl} = {BLEND1, AB}; + 12: {op, input_ctrl} = {BLEND1, AB}; + 13: {op, input_ctrl} = {BLEND1, AB}; + 14: {op, input_ctrl} = {BLEND1, DB}; + 15: {op, input_ctrl} = {BLEND1, BD}; + + 24: {op, input_ctrl} = {BLEND2, DB}; + 25: {op, input_ctrl} = {BLEND5, DB}; + 26: {op, input_ctrl} = {BLEND6, DB}; + 27: {op, input_ctrl} = {BLEND2, DB}; + 28: {op, input_ctrl} = {BLEND4, DB}; + 29: {op, input_ctrl} = {BLEND5, DB}; + 30: {op, input_ctrl} = {BLEND3, BD}; + 31: {op, input_ctrl} = {BLEND3, DB}; + default: {op, input_ctrl} = 11'bx; + endcase + + // Setting op[8] effectively disables HQ2X because blend will always return E. + if (disable_hq2x) op[8] = 1; + end + + // Generate inputs to the inner blender. Valid combinations. + // 00: E A B + // 01: E A D + // 10: E D B + // 11: E B D + wire [17:0] Input1 = E; + wire [17:0] Input2 = !input_ctrl[1] ? A : + !input_ctrl[0] ? D : B; + + wire [17:0] Input3 = !input_ctrl[0] ? B : D; + InnerBlend inner_blend1(op, Input1[5:0], Input2[5:0], Input3[5:0], Result[5:0]); + InnerBlend inner_blend2(op, Input1[11:6], Input2[11:6], Input3[11:6], Result[11:6]); + InnerBlend inner_blend3(op, Input1[17:12], Input2[17:12], Input3[17:12], Result[17:12]); +endmodule + + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +module Hq2x #(parameter LENGTH, parameter HALF_DEPTH) +( + input clk, + input ce_x4, + input [DWIDTH:0] inputpixel, + input mono, + input disable_hq2x, + input reset_frame, + input reset_line, + input [1:0] read_y, + input [AWIDTH+1:0] read_x, + output [DWIDTH:0] outpixel +); + + +localparam AWIDTH = `BITS_TO_FIT(LENGTH); +localparam DWIDTH = HALF_DEPTH ? 8 : 17; + +wire [5:0] hqTable[256] = '{ + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39, + 19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 35, 35, 23, 15, 7, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43, + 19, 19, 26, 58, 19, 19, 26, 58, 23, 15, 51, 35, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 35, 35, 23, 61, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 61, 7, 35, 23, 61, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 58, 23, 15, 51, 35, 23, 61, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 47, 35, 23, 15, 55, 39, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 55, 39, 23, 15, 51, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 39, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 51, 39, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 35, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 51, 35, 23, 15, 7, 43, + 19, 19, 26, 11, 19, 19, 26, 11, 23, 15, 7, 35, 23, 15, 7, 43 +}; + +reg [17:0] Prev0, Prev1, Prev2, Curr0, Curr1, Next0, Next1, Next2; +reg [17:0] A, B, D, F, G, H; +reg [7:0] pattern, nextpatt; +reg [1:0] i; +reg [7:0] y; + +wire curbuf = y[0]; +reg prevbuf = 0; +wire iobuf = !curbuf; + +wire diff0, diff1; +DiffCheck diffcheck0(Curr1, (i == 0) ? Prev0 : (i == 1) ? Curr0 : (i == 2) ? Prev2 : Next1, diff0); +DiffCheck diffcheck1(Curr1, (i == 0) ? Prev1 : (i == 1) ? Next0 : (i == 2) ? Curr2 : Next2, diff1); + +wire [7:0] new_pattern = {diff1, diff0, pattern[7:2]}; + +wire [17:0] X = (i == 0) ? A : (i == 1) ? Prev1 : (i == 2) ? Next1 : G; +wire [17:0] blend_result; +Blend blender(hqTable[nextpatt], disable_hq2x, Curr0, X, B, D, F, H, blend_result); + +reg Curr2_addr1; +reg [AWIDTH:0] Curr2_addr2; +wire [17:0] Curr2 = HALF_DEPTH ? h2rgb(Curr2tmp) : Curr2tmp; +wire [DWIDTH:0] Curr2tmp; + +reg [AWIDTH:0] wrin_addr2; +reg [DWIDTH:0] wrpix; +reg wrin_en; + +function [17:0] h2rgb; + input [8:0] v; +begin + h2rgb = mono ? {v[5:3],v[2:0], v[5:3],v[2:0], v[5:3],v[2:0]} : {v[8:6],v[8:6],v[5:3],v[5:3],v[2:0],v[2:0]}; +end +endfunction + +function [8:0] rgb2h; + input [17:0] v; +begin + rgb2h = mono ? {3'b000, v[17:15], v[14:12]} : {v[17:15], v[11:9], v[5:3]}; +end +endfunction + +hq2x_in #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_in +( + .clk(clk), + + .rdaddr(Curr2_addr2), + .rdbuf(Curr2_addr1), + .q(Curr2tmp), + + .wraddr(wrin_addr2), + .wrbuf(iobuf), + .data(wrpix), + .wren(wrin_en) +); + +reg [1:0] wrout_addr1; +reg [AWIDTH+1:0] wrout_addr2; +reg wrout_en; +reg [DWIDTH:0] wrdata; + +hq2x_out #(.LENGTH(LENGTH), .DWIDTH(DWIDTH)) hq2x_out +( + .clk(clk), + + .rdaddr(read_x), + .rdbuf(read_y), + .q(outpixel), + + .wraddr(wrout_addr2), + .wrbuf(wrout_addr1), + .data(wrdata), + .wren(wrout_en) +); + +always @(posedge clk) begin + reg [AWIDTH:0] offs; + reg old_reset_line; + reg old_reset_frame; + + wrout_en <= 0; + wrin_en <= 0; + + if(ce_x4) begin + + pattern <= new_pattern; + + if(~&offs) begin + if (i == 0) begin + Curr2_addr1 <= prevbuf; + Curr2_addr2 <= offs; + end + if (i == 1) begin + Prev2 <= Curr2; + Curr2_addr1 <= curbuf; + Curr2_addr2 <= offs; + end + if (i == 2) begin + Next2 <= HALF_DEPTH ? h2rgb(inputpixel) : inputpixel; + wrpix <= inputpixel; + wrin_addr2 <= offs; + wrin_en <= 1; + end + if (i == 3) begin + offs <= offs + 1'd1; + end + + if(HALF_DEPTH) wrdata <= rgb2h(blend_result); + else wrdata <= blend_result; + + wrout_addr1 <= {curbuf, i[1]}; + wrout_addr2 <= {offs, i[1]^i[0]}; + wrout_en <= 1; + end + + if(i==3) begin + nextpatt <= {new_pattern[7:6], new_pattern[3], new_pattern[5], new_pattern[2], new_pattern[4], new_pattern[1:0]}; + {A, G} <= {Prev0, Next0}; + {B, F, H, D} <= {Prev1, Curr2, Next1, Curr0}; + {Prev0, Prev1} <= {Prev1, Prev2}; + {Curr0, Curr1} <= {Curr1, Curr2}; + {Next0, Next1} <= {Next1, Next2}; + end else begin + nextpatt <= {nextpatt[5], nextpatt[3], nextpatt[0], nextpatt[6], nextpatt[1], nextpatt[7], nextpatt[4], nextpatt[2]}; + {B, F, H, D} <= {F, H, D, B}; + end + + i <= i + 1'b1; + if(old_reset_line && ~reset_line) begin + old_reset_frame <= reset_frame; + offs <= 0; + i <= 0; + y <= y + 1'd1; + prevbuf <= curbuf; + if(old_reset_frame & ~reset_frame) begin + y <= 0; + prevbuf <= 0; + end + end + + old_reset_line <= reset_line; + end +end + +endmodule // Hq2x diff --git a/Acorn - Electron_MiST/rtl/keyboard.vhd b/Acorn - Electron_MiST/rtl/keyboard.vhd new file mode 100644 index 00000000..6af77034 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/keyboard.vhd @@ -0,0 +1,186 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use ieee.std_logic_unsigned.all; + +entity keyboard is + port ( + clk : in std_logic; + rst_n : in std_logic; + ps2_clk : in std_logic; + ps2_data : in std_logic; + col : out std_logic_vector(3 downto 0); + row : in std_logic_vector(13 downto 0); + break : out std_logic; + turbo : out std_logic_vector(1 downto 0) + ;scanSW : buffer std_logic --q + ); +end entity; + +architecture rtl of keyboard is + + type key_matrix is array(0 to 13) of std_logic_vector(3 downto 0); + signal keys : key_matrix; + signal release : std_logic; + signal extended : std_logic; + + signal keyb_data : std_logic_vector(7 downto 0); + signal keyb_valid : std_logic; + signal keyb_error : std_logic; + +begin + + ps2 : entity work.ps2_intf port map ( + CLK => clk, + nRESET => rst_n, + PS2_CLK => ps2_clk, + PS2_DATA => ps2_data, + DATA => keyb_data, + VALID => keyb_valid, + error => keyb_error + ); + + process(keys, row) + variable i : integer; + variable tmp : std_logic_vector(3 downto 0); + begin + tmp := "1111"; + for i in 0 to 13 loop + if (row(i) = '0') then + tmp := tmp and keys(i); + end if; + end loop; + col <= tmp xor "1111"; + end process; + + process(clk, rst_n) + begin + if rst_n = '0' then + + release <= '0'; + extended <= '0'; + turbo <= "00"; -- 1MHz + break <= '1'; + keys( 0) <= (others => '1'); + keys( 1) <= (others => '1'); + keys( 2) <= (others => '1'); + keys( 3) <= (others => '1'); + keys( 4) <= (others => '1'); + keys( 5) <= (others => '1'); + keys( 6) <= (others => '1'); + keys( 7) <= (others => '1'); + keys( 8) <= (others => '1'); + keys( 9) <= (others => '1'); + keys(10) <= (others => '1'); + keys(11) <= (others => '1'); + keys(12) <= (others => '1'); + keys(13) <= (others => '1'); + + elsif rising_edge(clk) then + + if keyb_valid = '1' then + if keyb_data = X"e0" then + extended <= '1'; + elsif keyb_data = X"f0" then + release <= '1'; + else + release <= '0'; + extended <= '0'; + + case keyb_data is + -- Special keys + when X"05" => turbo <= "00"; -- F1 (1MHz) + when X"06" => turbo <= "01"; -- F2 (2MMz) + when X"04" => turbo <= "10"; -- F3 (4MHz) + when X"0C" => turbo <= "11"; -- F4 (8MHz) + when X"09" => break <= release; -- F10 (BREAK) + -- Key Matrix + when X"74" => keys( 0)(0) <= release; -- RIGHT + when X"69" => keys( 0)(1) <= release; -- END (COPY) + -- keys( 0)(2) -- NC + when X"29" => keys( 0)(3) <= release; -- SPACE + + when X"6B" => keys( 1)(0) <= release; -- LEFT + when X"72" => keys( 1)(1) <= release; -- DOWN + when X"5B" => keys( 1)(1) <= release; -- ] + when X"5A" => keys( 1)(2) <= release; -- RETURN + when X"66" => keys( 1)(3) <= release; -- BACKSPACE (DELETE) + + when X"4E" => keys( 2)(0) <= release; -- - + when X"75" => keys( 2)(1) <= release; -- UP + when X"54" => keys( 2)(1) <= release; -- [ + when X"52" => keys( 2)(2) <= release; -- ' full colon substitute + -- keys( 2)(3) -- NC + + when X"45" => keys( 3)(0) <= release; -- 0 + when X"4D" => keys( 3)(1) <= release; -- P + when X"4C" => keys( 3)(2) <= release; -- ; + when X"4A" => keys( 3)(3) <= release; -- / + + when X"46" => keys( 4)(0) <= release; -- 9 + when X"44" => keys( 4)(1) <= release; -- O + when X"4B" => keys( 4)(2) <= release; -- L + when X"49" => keys( 4)(3) <= release; -- . + + when X"3E" => keys( 5)(0) <= release; -- 8 + when X"43" => keys( 5)(1) <= release; -- I + when X"42" => keys( 5)(2) <= release; -- K + when X"41" => keys( 5)(3) <= release; -- , + + when X"3D" => keys( 6)(0) <= release; -- 7 + when X"3C" => keys( 6)(1) <= release; -- U + when X"3B" => keys( 6)(2) <= release; -- J + when X"3A" => keys( 6)(3) <= release; -- M + + when X"36" => keys( 7)(0) <= release; -- 6 + when X"35" => keys( 7)(1) <= release; -- Y + when X"33" => keys( 7)(2) <= release; -- H + when X"31" => keys( 7)(3) <= release; -- N + + when X"2E" => keys( 8)(0) <= release; -- 5 + when X"2C" => keys( 8)(1) <= release; -- T + when X"34" => keys( 8)(2) <= release; -- G + when X"32" => keys( 8)(3) <= release; -- B + + when X"25" => keys( 9)(0) <= release; -- 4 + when X"2D" => keys( 9)(1) <= release; -- R + when X"2B" => keys( 9)(2) <= release; -- F + when X"2A" => keys( 9)(3) <= release; -- V + + when X"26" => keys(10)(0) <= release; -- 3 + when X"24" => keys(10)(1) <= release; -- E + when X"23" => keys(10)(2) <= release; -- D + when X"21" => keys(10)(3) <= release; -- C + + when X"1E" => keys(11)(0) <= release; -- 2 + when X"1D" => keys(11)(1) <= release; -- W + when X"1B" => keys(11)(2) <= release; -- S + when X"22" => keys(11)(3) <= release; -- X + + when X"16" => keys(12)(0) <= release; -- 1 + when X"15" => keys(12)(1) <= release; -- Q + when X"1C" => keys(12)(2) <= release; -- A + when X"1A" => keys(12)(3) <= release; -- Z + + when X"76" => keys(13)(0) <= release; -- ESCAPE + when X"58" => keys(13)(1) <= release; -- CAPS LOCK + when X"14" => keys(13)(2) <= release; -- LEFT/RIGHT CTRL (CTRL) + + when X"7D" => scanSW <= '1'; -- pgUP (VGA) + when X"7A" => scanSW <= '0'; -- pgDN (RGB) + + when X"12" | X"59" => + if (extended = '0') then -- Ignore fake shifts + keys(13)(3) <= release; -- Left SHIFT -- Right SHIFT + end if; + when others => null; + end case; + + end if; + end if; + end if; + end process; + +end architecture; + + diff --git a/Acorn - Electron_MiST/rtl/m6522.vhd b/Acorn - Electron_MiST/rtl/m6522.vhd new file mode 100644 index 00000000..20d9b941 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/m6522.vhd @@ -0,0 +1,920 @@ +-- +-- A simulation model of VIC20 hardware +-- Copyright (c) MikeJ - March 2003 +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- You are responsible for any legal issues arising from your use of this code. +-- +-- The latest version of this file can be found at: www.fpgaarcade.com +-- +-- Email vic20@fpgaarcade.com +-- +-- +-- Revision list +-- +-- version 004 fixes to PB7 T1 control and Mode 0 Shift Register operation +-- version 003 fix reset of T1/T2 IFR flags if T1/T2 is reload via reg5/reg9 from wolfgang (WoS) +-- Ported to numeric_std and simulation fix for signal initializations from arnim laeuger +-- version 002 fix from Mark McDougall, untested +-- version 001 initial release +-- not very sure about the shift register, documentation is a bit light. + +library ieee ; + use ieee.std_logic_1164.all ; + use ieee.std_logic_unsigned.all; + use ieee.numeric_std.all; + +entity M6522 is + port ( + + I_RS : in std_logic_vector(3 downto 0); + I_DATA : in std_logic_vector(7 downto 0); + O_DATA : out std_logic_vector(7 downto 0); + O_DATA_OE_L : out std_logic; + + I_RW_L : in std_logic; + I_CS1 : in std_logic; + I_CS2_L : in std_logic; + + O_IRQ_L : out std_logic; -- note, not open drain + -- port a + I_CA1 : in std_logic; + I_CA2 : in std_logic; + O_CA2 : out std_logic; + O_CA2_OE_L : out std_logic; + + I_PA : in std_logic_vector(7 downto 0); + O_PA : out std_logic_vector(7 downto 0); + O_PA_OE_L : out std_logic_vector(7 downto 0); + + -- port b + I_CB1 : in std_logic; + O_CB1 : out std_logic; + O_CB1_OE_L : out std_logic; + + I_CB2 : in std_logic; + O_CB2 : out std_logic; + O_CB2_OE_L : out std_logic; + + I_PB : in std_logic_vector(7 downto 0); + O_PB : out std_logic_vector(7 downto 0); + O_PB_OE_L : out std_logic_vector(7 downto 0); + + I_P2_H : in std_logic; -- high for phase 2 clock ____----__ + RESET_L : in std_logic; + ENA_4 : in std_logic; -- clk enable + CLK : in std_logic + ); +end; + +architecture RTL of M6522 is + + signal phase : std_logic_vector(1 downto 0):="00"; + signal p2_h_t1 : std_logic; + signal cs : std_logic; + + -- registers + signal r_ddra : std_logic_vector(7 downto 0); + signal r_ora : std_logic_vector(7 downto 0); + signal r_ira : std_logic_vector(7 downto 0); + + signal r_ddrb : std_logic_vector(7 downto 0); + signal r_orb : std_logic_vector(7 downto 0); + signal r_irb : std_logic_vector(7 downto 0); + + signal r_t1l_l : std_logic_vector(7 downto 0); + signal r_t1l_h : std_logic_vector(7 downto 0); + signal r_t2l_l : std_logic_vector(7 downto 0); + signal r_t2l_h : std_logic_vector(7 downto 0); -- not in real chip + signal r_sr : std_logic_vector(7 downto 0); + signal r_acr : std_logic_vector(7 downto 0); + signal r_pcr : std_logic_vector(7 downto 0); + signal r_ifr : std_logic_vector(7 downto 0); + signal r_ier : std_logic_vector(6 downto 0); + + signal sr_write_ena : boolean; + signal sr_read_ena : boolean; + signal ifr_write_ena : boolean; + signal ier_write_ena : boolean; + signal clear_irq : std_logic_vector(7 downto 0); + signal load_data : std_logic_vector(7 downto 0); + + -- timer 1 + signal t1c : std_logic_vector(15 downto 0) := (others => '1'); -- simulators may not catch up w/o init here... + signal t1c_active : boolean; + signal t1c_done : boolean; + signal t1_w_reset_int : boolean; + signal t1_r_reset_int : boolean; + signal t1_load_counter : boolean; + signal t1_reload_counter : boolean; + signal t1_toggle : std_logic; + signal t1_irq : std_logic := '0'; + + -- timer 2 + signal t2c : std_logic_vector(15 downto 0) := (others => '1'); -- simulators may not catch up w/o init here... + signal t2c_active : boolean; + signal t2c_done : boolean; + signal t2_pb6 : std_logic; + signal t2_pb6_t1 : std_logic; + signal t2_w_reset_int : boolean; + signal t2_r_reset_int : boolean; + signal t2_load_counter : boolean; + signal t2_reload_counter : boolean; + signal t2_irq : std_logic := '0'; + signal t2_sr_ena : boolean; + + -- shift reg + signal sr_cnt : std_logic_vector(3 downto 0); + signal sr_cb1_oe_l : std_logic; + signal sr_cb1_out : std_logic; + signal sr_drive_cb2 : std_logic; + signal sr_strobe : std_logic; + signal sr_strobe_t1 : std_logic; + signal sr_strobe_falling : boolean; + signal sr_strobe_rising : boolean; + signal sr_irq : std_logic; + signal sr_out : std_logic; + signal sr_off_delay : std_logic; + + -- io + signal w_orb_hs : std_logic; + signal w_ora_hs : std_logic; + signal r_irb_hs : std_logic; + signal r_ira_hs : std_logic; + + signal ca_hs_sr : std_logic; + signal ca_hs_pulse : std_logic; + signal cb_hs_sr : std_logic; + signal cb_hs_pulse : std_logic; + + signal cb1_in_mux : std_logic; + signal ca1_ip_reg : std_logic; + signal cb1_ip_reg : std_logic; + signal ca1_int : boolean; + signal cb1_int : boolean; + signal ca1_irq : std_logic; + signal cb1_irq : std_logic; + + signal ca2_ip_reg : std_logic; + signal cb2_ip_reg : std_logic; + signal ca2_int : boolean; + signal cb2_int : boolean; + signal ca2_irq : std_logic; + signal cb2_irq : std_logic; + + signal final_irq : std_logic; +begin + + p_phase : process + begin + -- internal clock phase + wait until rising_edge(CLK); + if (ENA_4 = '1') then + p2_h_t1 <= I_P2_H; + if (p2_h_t1 = '0') and (I_P2_H = '1') then + phase <= "11"; + else + phase <= phase + "1"; + end if; + end if; + end process; + + p_cs : process(I_CS1, I_CS2_L, I_P2_H) + begin + cs <= '0'; + if (I_CS1 = '1') and (I_CS2_L = '0') and (I_P2_H = '1') then + cs <= '1'; + end if; + end process; + + -- peripheral control reg (pcr) + -- 0 ca1 interrupt control (0 +ve edge, 1 -ve edge) + -- 3..1 ca2 operation + -- 000 input -ve edge + -- 001 independend interrupt input -ve edge + -- 010 input +ve edge + -- 011 independend interrupt input +ve edge + -- 100 handshake output + -- 101 pulse output + -- 110 low output + -- 111 high output + -- 7..4 as 3..0 for cb1,cb2 + + -- auxiliary control reg (acr) + -- 0 input latch PA (0 disable, 1 enable) + -- 1 input latch PB (0 disable, 1 enable) + -- 4..2 shift reg control + -- 000 disable + -- 001 shift in using t2 + -- 010 shift in using o2 + -- 011 shift in using ext clk + -- 100 shift out free running t2 rate + -- 101 shift out using t2 + -- 101 shift out using o2 + -- 101 shift out using ext clk + -- 5 t2 timer control (0 timed interrupt, 1 count down with pulses on pb6) + -- 7..6 t1 timer control + -- 00 timed interrupt each time t1 is loaded pb7 disable + -- 01 continuous interrupts pb7 disable + -- 00 timed interrupt each time t1 is loaded pb7 one shot output + -- 01 continuous interrupts pb7 square wave output + -- + + p_write_reg_reset : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + r_ora <= x"00"; r_orb <= x"00"; + r_ddra <= x"00"; r_ddrb <= x"00"; + r_acr <= x"00"; r_pcr <= x"00"; + + w_orb_hs <= '0'; + w_ora_hs <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + w_orb_hs <= '0'; + w_ora_hs <= '0'; + if (cs = '1') and (I_RW_L = '0') then + case I_RS is + when x"0" => r_orb <= I_DATA; w_orb_hs <= '1'; + when x"1" => r_ora <= I_DATA; w_ora_hs <= '1'; + when x"2" => r_ddrb <= I_DATA; + when x"3" => r_ddra <= I_DATA; + + when x"B" => r_acr <= I_DATA; + when x"C" => r_pcr <= I_DATA; + when x"F" => r_ora <= I_DATA; + + when others => null; + end case; + end if; + + if r_acr(7) = '1' then + -- DMB: Forgetting to clear B7 broke Acornsoft Planetoid + if t1_load_counter then + r_orb(7) <= '0'; -- writing T1C-H resets bit 7 + elsif t1_toggle = '1' then + r_orb(7) <= not r_orb(7); -- toggle + end if; + end if; + end if; + end if; + end process; + + p_write_reg : process (RESET_L, CLK) is + begin + if (RESET_L = '0') then + -- The spec says, this is not reset. + -- Fact is that the 1541 VIA1 timer won't work, + -- as the firmware ONLY sets the r_t1l_h latch!!!! + r_t1l_l <= (others => '0'); + r_t1l_h <= (others => '0'); + r_t2l_l <= (others => '0'); + r_t2l_h <= (others => '0'); + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + t1_w_reset_int <= false; + t1_load_counter <= false; + + t2_w_reset_int <= false; + t2_load_counter <= false; + + load_data <= x"00"; + sr_write_ena <= false; + ifr_write_ena <= false; + ier_write_ena <= false; + + if (cs = '1') and (I_RW_L = '0') then + load_data <= I_DATA; + case I_RS is + when x"4" => r_t1l_l <= I_DATA; + when x"5" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; + t1_load_counter <= true; + + when x"6" => r_t1l_l <= I_DATA; + when x"7" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; + + when x"8" => r_t2l_l <= I_DATA; + when x"9" => r_t2l_h <= I_DATA; t2_w_reset_int <= true; + t2_load_counter <= true; + + when x"A" => sr_write_ena <= true; + when x"D" => ifr_write_ena <= true; + when x"E" => ier_write_ena <= true; + + when others => null; + end case; + end if; + end if; + end if; + end process; + + p_oe : process(cs, I_RW_L) + begin + O_DATA_OE_L <= '1'; + if (cs = '1') and (I_RW_L = '1') then + O_DATA_OE_L <= '0'; + end if; + end process; + + p_read : process(cs, I_RW_L, I_RS, r_irb, r_ira, r_ddrb, r_ddra, t1c, r_t1l_l, + r_t1l_h, t2c, r_sr, r_acr, r_pcr, r_ifr, r_ier, r_orb) + begin + t1_r_reset_int <= false; + t2_r_reset_int <= false; + sr_read_ena <= false; + r_irb_hs <= '0'; + r_ira_hs <= '0'; + O_DATA <= x"00"; -- default + if (cs = '1') and (I_RW_L = '1') then + case I_RS is + --when x"0" => O_DATA <= r_irb; r_irb_hs <= '1'; + -- fix from Mark McDougall, untested + when x"0" => O_DATA <= (r_irb and not r_ddrb) or (r_orb and r_ddrb); r_irb_hs <= '1'; + when x"1" => O_DATA <= r_ira; r_ira_hs <= '1'; + when x"2" => O_DATA <= r_ddrb; + when x"3" => O_DATA <= r_ddra; + when x"4" => O_DATA <= t1c( 7 downto 0); t1_r_reset_int <= true; + when x"5" => O_DATA <= t1c(15 downto 8); + when x"6" => O_DATA <= r_t1l_l; + when x"7" => O_DATA <= r_t1l_h; + when x"8" => O_DATA <= t2c( 7 downto 0); t2_r_reset_int <= true; + when x"9" => O_DATA <= t2c(15 downto 8); + when x"A" => O_DATA <= r_sr; sr_read_ena <= true; + when x"B" => O_DATA <= r_acr; + when x"C" => O_DATA <= r_pcr; + when x"D" => O_DATA <= r_ifr; + when x"E" => O_DATA <= ('0' & r_ier); + when x"F" => O_DATA <= r_ira; + when others => null; + end case; + end if; + + end process; + -- + -- IO + -- + p_ca1_cb1_sel : process(sr_cb1_oe_l, sr_cb1_out, I_CB1) + begin + -- if the shift register is enabled, cb1 may be an output + -- in this case, we should listen to the CB1_OUT for the interrupt + if (sr_cb1_oe_l = '1') then + cb1_in_mux <= I_CB1; + else + cb1_in_mux <= sr_cb1_out; + end if; + end process; + + p_ca1_cb1_int : process(r_pcr, ca1_ip_reg, I_CA1, cb1_ip_reg, cb1_in_mux) + begin + if (r_pcr(0) = '0') then -- ca1 control + -- negative edge + ca1_int <= (ca1_ip_reg = '1') and (I_CA1 = '0'); + else + -- positive edge + ca1_int <= (ca1_ip_reg = '0') and (I_CA1 = '1'); + end if; + + if (r_pcr(4) = '0') then -- cb1 control + -- negative edge + cb1_int <= (cb1_ip_reg = '1') and (cb1_in_mux = '0'); + else + -- positive edge + cb1_int <= (cb1_ip_reg = '0') and (cb1_in_mux = '1'); + end if; + end process; + + p_ca2_cb2_int : process(r_pcr, ca2_ip_reg, I_CA2, cb2_ip_reg, I_CB2) + begin + ca2_int <= false; + if (r_pcr(3) = '0') then -- ca2 input + if (r_pcr(2) = '0') then -- ca2 edge + -- negative edge + ca2_int <= (ca2_ip_reg = '1') and (I_CA2 = '0'); + else + -- positive edge + ca2_int <= (ca2_ip_reg = '0') and (I_CA2 = '1'); + end if; + end if; + + cb2_int <= false; + if (r_pcr(7) = '0') then -- cb2 input + if (r_pcr(6) = '0') then -- cb2 edge + -- negative edge + cb2_int <= (cb2_ip_reg = '1') and (I_CB2 = '0'); + else + -- positive edge + cb2_int <= (cb2_ip_reg = '0') and (I_CB2 = '1'); + end if; + end if; + end process; + + p_ca2_cb2 : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + O_CA2 <= '0'; + O_CA2_OE_L <= '1'; + O_CB2 <= '0'; + O_CB2_OE_L <= '1'; + + ca_hs_sr <= '0'; + ca_hs_pulse <= '0'; + cb_hs_sr <= '0'; + cb_hs_pulse <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- ca + if (phase = "00") and ((w_ora_hs = '1') or (r_ira_hs = '1')) then + ca_hs_sr <= '1'; + elsif ca1_int then + ca_hs_sr <= '0'; + end if; + + if (phase = "00") then + ca_hs_pulse <= w_ora_hs or r_ira_hs; + end if; + + O_CA2_OE_L <= not r_pcr(3); -- ca2 output + case r_pcr(3 downto 1) is + when "000" => O_CA2 <= '0'; -- input + when "001" => O_CA2 <= '0'; -- input + when "010" => O_CA2 <= '0'; -- input + when "011" => O_CA2 <= '0'; -- input + when "100" => O_CA2 <= not (ca_hs_sr); -- handshake + when "101" => O_CA2 <= not (ca_hs_pulse); -- pulse + when "110" => O_CA2 <= '0'; -- low + when "111" => O_CA2 <= '1'; -- high + when others => null; + end case; + + -- cb + if (phase = "00") and (w_orb_hs = '1') then + cb_hs_sr <= '1'; + elsif cb1_int then + cb_hs_sr <= '0'; + end if; + + if (phase = "00") then + cb_hs_pulse <= w_orb_hs; + end if; + + O_CB2_OE_L <= not (r_pcr(7) or sr_drive_cb2); -- cb2 output or serial + if (sr_drive_cb2 = '1') then -- serial output + O_CB2 <= sr_out; + else + case r_pcr(7 downto 5) is + when "000" => O_CB2 <= '0'; -- input + when "001" => O_CB2 <= '0'; -- input + when "010" => O_CB2 <= '0'; -- input + when "011" => O_CB2 <= '0'; -- input + when "100" => O_CB2 <= not (cb_hs_sr); -- handshake + when "101" => O_CB2 <= not (cb_hs_pulse); -- pulse + when "110" => O_CB2 <= '0'; -- low + when "111" => O_CB2 <= '1'; -- high + when others => null; + end case; + end if; + end if; + end if; + end process; + O_CB1 <= sr_cb1_out; + O_CB1_OE_L <= sr_cb1_oe_l; + + p_ca_cb_irq : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + ca1_irq <= '0'; + ca2_irq <= '0'; + cb1_irq <= '0'; + cb2_irq <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- not pretty + if ca1_int then + ca1_irq <= '1'; + elsif (r_ira_hs = '1') or (w_ora_hs = '1') or (clear_irq(1) = '1') then + ca1_irq <= '0'; + end if; + + if ca2_int then + ca2_irq <= '1'; + else + if (((r_ira_hs = '1') or (w_ora_hs = '1')) and (r_pcr(1) = '0')) or + (clear_irq(0) = '1') then + ca2_irq <= '0'; + end if; + end if; + + if cb1_int then + cb1_irq <= '1'; + elsif (r_irb_hs = '1') or (w_orb_hs = '1') or (clear_irq(4) = '1') then + cb1_irq <= '0'; + end if; + + if cb2_int then + cb2_irq <= '1'; + else + if (((r_irb_hs = '1') or (w_orb_hs = '1')) and (r_pcr(5) = '0')) or + (clear_irq(3) = '1') then + cb2_irq <= '0'; + end if; + end if; + end if; + end if; + end process; + + p_input_reg : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + ca1_ip_reg <= '0'; + cb1_ip_reg <= '0'; + + ca2_ip_reg <= '0'; + cb2_ip_reg <= '0'; + + r_ira <= x"00"; + r_irb <= x"00"; + + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- we have a fast clock, so we can have input registers + ca1_ip_reg <= I_CA1; + cb1_ip_reg <= cb1_in_mux; + + ca2_ip_reg <= I_CA2; + cb2_ip_reg <= I_CB2; + + if (r_acr(0) = '0') then + r_ira <= I_PA; + else -- enable latching + if ca1_int then + r_ira <= I_PA; + end if; + end if; + + if (r_acr(1) = '0') then + r_irb <= I_PB; + else -- enable latching + if cb1_int then + r_irb <= I_PB; + end if; + end if; + end if; + end if; + end process; + + + p_buffers : process(r_ddra, r_ora, r_ddrb, r_acr, r_orb) + begin + -- data direction reg (ddr) 0 = input, 1 = output + O_PA <= r_ora; + O_PA_OE_L <= not r_ddra; + + if (r_acr(7) = '1') then -- not clear if r_ddrb(7) must be 1 as well + O_PB_OE_L(7) <= '0'; -- an output if under t1 control + else + O_PB_OE_L(7) <= not (r_ddrb(7)); + end if; + + O_PB_OE_L(6 downto 0) <= not r_ddrb(6 downto 0); + O_PB(7 downto 0) <= r_orb(7 downto 0); + + end process; + -- + -- Timer 1 + -- + p_timer1_done : process + variable done : boolean; + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + done := (t1c = x"0000"); + t1c_done <= done and (phase = "11"); + if (phase = "11") then + t1_reload_counter <= done and (r_acr(6) = '1'); + end if; + if t1_load_counter then -- done reset on load! + t1c_done <= false; + end if; + end if; + end process; + + p_timer1 : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if t1_load_counter or (t1_reload_counter and phase = "11") then + t1c( 7 downto 0) <= r_t1l_l; + t1c(15 downto 8) <= r_t1l_h; + elsif (phase="11") then + t1c <= t1c - "1"; + end if; + + if t1_load_counter or t1_reload_counter then + t1c_active <= true; + elsif t1c_done then + t1c_active <= false; + end if; + + t1_toggle <= '0'; + if t1c_active and t1c_done then + t1_toggle <= '1'; + t1_irq <= '1'; + elsif t1_w_reset_int or t1_r_reset_int or (clear_irq(6) = '1') then + t1_irq <= '0'; + end if; + if t1_load_counter then -- irq reset on load! + t1_irq <= '0'; + end if; + end if; + end process; + -- + -- Timer2 + -- + p_timer2_pb6_input : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if (phase = "01") then -- leading edge p2_h + t2_pb6 <= I_PB(6); + t2_pb6_t1 <= t2_pb6; + end if; + end if; + end process; + + p_timer2_done : process + variable done : boolean; + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + done := (t2c = x"0000"); + t2c_done <= done and (phase = "11"); + if (phase = "11") then + t2_reload_counter <= done; + end if; + if t2_load_counter then -- done reset on load! + t2c_done <= false; + end if; + end if; + end process; + + p_timer2 : process + variable ena : boolean; + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if (r_acr(5) = '0') then + ena := true; + else + ena := (t2_pb6_t1 = '1') and (t2_pb6 = '0'); -- falling edge + end if; + + if t2_load_counter or (t2_reload_counter and phase = "11") then + -- not sure if t2c_reload should be here. Does timer2 just continue to + -- count down, or is it reloaded ? Reloaded makes more sense if using + -- it to generate a clock for the shift register. + t2c( 7 downto 0) <= r_t2l_l; + t2c(15 downto 8) <= r_t2l_h; + else + if (phase="11") and ena then -- or count mode + t2c <= t2c - "1"; + end if; + end if; + + t2_sr_ena <= (t2c(7 downto 0) = x"00") and (phase = "11"); + + if t2_load_counter then + t2c_active <= true; + elsif t2c_done then + t2c_active <= false; + end if; + + if t2c_active and t2c_done then + t2_irq <= '1'; + elsif t2_w_reset_int or t2_r_reset_int or (clear_irq(5) = '1') then + t2_irq <= '0'; + end if; + if t2_load_counter then -- irq reset on load! + t2_irq <= '0'; + end if; + end if; + end process; + -- + -- Shift Register + -- + p_sr : process(RESET_L, CLK) + variable dir_out : std_logic; + variable ena : std_logic; + variable cb1_op : std_logic; + variable cb1_ip : std_logic; + variable use_t2 : std_logic; + variable free_run : std_logic; + variable sr_count_ena : boolean; + begin + if (RESET_L = '0') then + r_sr <= x"00"; + sr_drive_cb2 <= '0'; + sr_cb1_oe_l <= '1'; + sr_cb1_out <= '0'; + sr_strobe <= '1'; + sr_cnt <= "0000"; + sr_irq <= '0'; + sr_out <= '1'; + sr_off_delay <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- decode mode + dir_out := r_acr(4); -- output on cb2 + cb1_op := '0'; + cb1_ip := '0'; + use_t2 := '0'; + free_run := '0'; + + -- DMB: SR still runs even in disabled mode (on rising edge of CB1). + -- It just doesn't generate any interrupts. + -- Ref BBC micro advanced user guide p409 + + case r_acr(4 downto 2) is + -- DMB: in disabled mode, configure cb1 as an input + when "000" => ena := '0'; cb1_ip := '1'; + when "001" => ena := '1'; cb1_op := '1'; use_t2 := '1'; + when "010" => ena := '1'; cb1_op := '1'; + when "011" => ena := '1'; cb1_ip := '1'; + when "100" => ena := '1'; use_t2 := '1'; free_run := '1'; + when "101" => ena := '1'; cb1_op := '1'; use_t2 := '1'; + when "110" => ena := '1'; + when "111" => ena := '1'; cb1_ip := '1'; + when others => null; + end case; + + -- clock select + -- DMB: in disabled mode, strobe from cb1 + if (cb1_ip = '1') then + sr_strobe <= I_CB1; + else + if (sr_cnt(3) = '0') and (free_run = '0') then + sr_strobe <= '1'; + else + if ((use_t2 = '1') and t2_sr_ena) or + ((use_t2 = '0') and (phase = "00")) then + sr_strobe <= not sr_strobe; + end if; + end if; + end if; + + -- latch on rising edge, shift on falling edge + if sr_write_ena then + r_sr <= load_data; + + else + -- DMB: allow shifting in all modes + if (dir_out = '0') then + -- input + if (sr_cnt(3) = '1') or (cb1_ip = '1') then + if sr_strobe_rising then + r_sr(0) <= I_CB2; + elsif sr_strobe_falling then + r_sr(7 downto 1) <= r_sr(6 downto 0); + end if; + end if; + sr_out <= '1'; + else + -- output + if (sr_cnt(3) = '1') or (sr_off_delay = '1') or (cb1_ip = '1') or (free_run = '1') then + if sr_strobe_falling then + r_sr(7 downto 1) <= r_sr(6 downto 0); + r_sr(0) <= r_sr(7); + sr_out <= r_sr(7); + end if; + else + sr_out <= '1'; + end if; + end if; + end if; + + sr_count_ena := sr_strobe_rising; + + -- DMB: reseting sr_count when not enabled cause the sr to + -- start running immediately it was enabled, which is incorrect + -- and broke the latest SmartSPI ROM on the BBC Micro + if ena = '1' and (sr_write_ena or sr_read_ena) then + -- some documentation says sr bit in IFR must be set as well ? + sr_cnt <= "1000"; + elsif sr_count_ena and (sr_cnt(3) = '1') then + sr_cnt <= sr_cnt + "1"; + end if; + + if (phase = "00") then + sr_off_delay <= sr_cnt(3); -- give some hold time when shifting out + end if; + + if sr_count_ena and (sr_cnt = "1111") and (ena = '1') and (free_run = '0') then + sr_irq <= '1'; + elsif sr_write_ena or sr_read_ena or (clear_irq(2) = '1') then + sr_irq <= '0'; + end if; + + -- assign ops + sr_drive_cb2 <= dir_out; + sr_cb1_oe_l <= not cb1_op; + sr_cb1_out <= sr_strobe; + end if; + end if; + end process; + + p_sr_strobe_rise_fall : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + sr_strobe_t1 <= sr_strobe; + sr_strobe_rising <= (sr_strobe_t1 = '0') and (sr_strobe = '1'); + sr_strobe_falling <= (sr_strobe_t1 = '1') and (sr_strobe = '0'); + end if; + end process; + -- + -- Interrupts + -- + p_ier : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + r_ier <= "0000000"; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + if ier_write_ena then + if (load_data(7) = '1') then + -- set + r_ier <= r_ier or load_data(6 downto 0); + else + -- clear + r_ier <= r_ier and not load_data(6 downto 0); + end if; + end if; + end if; + end if; + end process; + + p_ifr : process(t1_irq, t2_irq, final_irq, ca1_irq, ca2_irq, sr_irq, + cb1_irq, cb2_irq) + begin + r_ifr(7) <= final_irq; + r_ifr(6) <= t1_irq; + r_ifr(5) <= t2_irq; + r_ifr(4) <= cb1_irq; + r_ifr(3) <= cb2_irq; + r_ifr(2) <= sr_irq; + r_ifr(1) <= ca1_irq; + r_ifr(0) <= ca2_irq; + + O_IRQ_L <= not final_irq; + end process; + + p_irq : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + final_irq <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + if ((r_ifr(6 downto 0) and r_ier(6 downto 0)) = "0000000") then + final_irq <= '0'; -- no interrupts + else + final_irq <= '1'; + end if; + end if; + end if; + end process; + + p_clear_irq : process(ifr_write_ena, load_data) + begin + clear_irq <= x"00"; + if ifr_write_ena then + clear_irq <= load_data; + end if; + end process; + +end architecture RTL; diff --git a/Acorn - Electron_MiST/rtl/mist_io.v b/Acorn - Electron_MiST/rtl/mist_io.v new file mode 100644 index 00000000..ad233a3b --- /dev/null +++ b/Acorn - Electron_MiST/rtl/mist_io.v @@ -0,0 +1,491 @@ +// +// mist_io.v +// +// mist_io for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +/////////////////////////////////////////////////////////////////////// + +// +// Use buffer to access SD card. It's time-critical part. +// Made module synchroneous with 2 clock domains: clk_sys and SPI_SCK +// (Sorgelig) +// +// for synchronous projects default value for PS2DIV is fine for any frequency of system clock. +// clk_ps2 = clk_sys/(PS2DIV*2) +// + +module mist_io #(parameter STRLEN=0, parameter PS2DIV=100) +( + + // parameter STRLEN and the actual length of conf_str have to match + input [(8*STRLEN)-1:0] conf_str, + + // Global clock. It should be around 100MHz (higher is better). + input clk_sys, + + // Global SPI clock from ARM. 24MHz + input SPI_SCK, + + input CONF_DATA0, + input SPI_SS2, + output SPI_DO, + input SPI_DI, + + output reg [7:0] joystick_0, + output reg [7:0] joystick_1, + output reg [15:0] joystick_analog_0, + output reg [15:0] joystick_analog_1, + output [1:0] buttons, + output [1:0] switches, + output scandoubler_disable, + output ypbpr, + + output reg [31:0] status, + + // SD config + input sd_conf, + input sd_sdhc, + output img_mounted, // signaling that new image has been mounted + output reg [31:0] img_size, // size of image in bytes + + // SD block level access + input [31:0] sd_lba, + input sd_rd, + input sd_wr, + output reg sd_ack, + output reg sd_ack_conf, + + // SD byte level access. Signals for 2-PORT altsyncram. + output reg [8:0] sd_buff_addr, + output reg [7:0] sd_buff_dout, + input [7:0] sd_buff_din, + output reg sd_buff_wr, + + // ps2 keyboard emulation + output ps2_kbd_clk, + output reg ps2_kbd_data, + output ps2_mouse_clk, + output reg ps2_mouse_data, + input ps2_caps_led, + + // ARM -> FPGA download + output reg ioctl_download = 0, // signal indicating an active download + output reg [7:0] ioctl_index, // menu index used to upload the file + output ioctl_wr, + output reg [24:0] ioctl_addr, + output reg [7:0] ioctl_dout +); + +reg [7:0] b_data; +reg [6:0] sbuf; +reg [7:0] cmd; +reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... +reg [9:0] byte_cnt; // counts bytes +reg [7:0] but_sw; +reg [2:0] stick_idx; + +reg mount_strobe = 0; +assign img_mounted = mount_strobe; + +assign buttons = but_sw[1:0]; +assign switches = but_sw[3:2]; +assign scandoubler_disable = but_sw[4]; +assign ypbpr = but_sw[5]; + +wire [7:0] spi_dout = { sbuf, SPI_DI}; + +// this variant of user_io is for 8 bit cores (type == a4) only +wire [7:0] core_type = 8'ha4; + +// command byte read by the io controller +wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd }; + +reg spi_do; +assign SPI_DO = CONF_DATA0 ? 1'bZ : spi_do; + +wire [7:0] kbd_led = { 2'b01, 4'b0000, ps2_caps_led, 1'b1}; + +// drive MISO only when transmitting core id +always@(negedge SPI_SCK) begin + if(!CONF_DATA0) begin + // first byte returned is always core type, further bytes are + // command dependent + if(byte_cnt == 0) begin + spi_do <= core_type[~bit_cnt]; + + end else begin + case(cmd) + // reading config string + 8'h14: begin + // returning a byte from string + if(byte_cnt < STRLEN + 1) spi_do <= conf_str[{STRLEN - byte_cnt,~bit_cnt}]; + else spi_do <= 0; + end + + // reading sd card status + 8'h16: begin + if(byte_cnt == 1) spi_do <= sd_cmd[~bit_cnt]; + else if((byte_cnt >= 2) && (byte_cnt < 6)) spi_do <= sd_lba[{5-byte_cnt, ~bit_cnt}]; + else spi_do <= 0; + end + + // reading sd card write data + 8'h18: + spi_do <= b_data[~bit_cnt]; + + // reading keyboard LED status + 8'h1f: + spi_do <= kbd_led[~bit_cnt]; + + default: + spi_do <= 0; + endcase + end + end +end + +reg b_wr2,b_wr3; +always @(negedge clk_sys) begin + b_wr3 <= b_wr2; + sd_buff_wr <= b_wr3; +end + +// SPI receiver +always@(posedge SPI_SCK or posedge CONF_DATA0) begin + + if(CONF_DATA0) begin + b_wr2 <= 0; + bit_cnt <= 0; + byte_cnt <= 0; + sd_ack <= 0; + sd_ack_conf <= 0; + end else begin + b_wr2 <= 0; + + sbuf <= spi_dout[6:0]; + bit_cnt <= bit_cnt + 1'd1; + if(bit_cnt == 5) begin + if (byte_cnt == 0) sd_buff_addr <= 0; + if((byte_cnt != 0) & (sd_buff_addr != 511)) sd_buff_addr <= sd_buff_addr + 1'b1; + if((byte_cnt == 1) & ((cmd == 8'h17) | (cmd == 8'h19))) sd_buff_addr <= 0; + end + + // finished reading command byte + if(bit_cnt == 7) begin + if(~&byte_cnt) byte_cnt <= byte_cnt + 8'd1; + if(byte_cnt == 0) begin + cmd <= spi_dout; + + if(spi_dout == 8'h19) begin + sd_ack_conf <= 1; + sd_buff_addr <= 0; + end + if((spi_dout == 8'h17) || (spi_dout == 8'h18)) begin + sd_ack <= 1; + sd_buff_addr <= 0; + end + if(spi_dout == 8'h18) b_data <= sd_buff_din; + + mount_strobe <= 0; + + end else begin + + case(cmd) + // buttons and switches + 8'h01: but_sw <= spi_dout; + 8'h02: joystick_0 <= spi_dout; + 8'h03: joystick_1 <= spi_dout; + + // store incoming ps2 mouse bytes + 8'h04: begin + ps2_mouse_fifo[ps2_mouse_wptr] <= spi_dout; + ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; + end + + // store incoming ps2 keyboard bytes + 8'h05: begin + ps2_kbd_fifo[ps2_kbd_wptr] <= spi_dout; + ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; + end + + 8'h15: status[7:0] <= spi_dout; + + // send SD config IO -> FPGA + // flag that download begins + // sd card knows data is config if sd_dout_strobe is asserted + // with sd_ack still being inactive (low) + 8'h19, + // send sector IO -> FPGA + // flag that download begins + 8'h17: begin + sd_buff_dout <= spi_dout; + b_wr2 <= 1; + end + + 8'h18: b_data <= sd_buff_din; + + // joystick analog + 8'h1a: begin + // first byte is joystick index + if(byte_cnt == 1) stick_idx <= spi_dout[2:0]; + else if(byte_cnt == 2) begin + // second byte is x axis + if(stick_idx == 0) joystick_analog_0[15:8] <= spi_dout; + else if(stick_idx == 1) joystick_analog_1[15:8] <= spi_dout; + end else if(byte_cnt == 3) begin + // third byte is y axis + if(stick_idx == 0) joystick_analog_0[7:0] <= spi_dout; + else if(stick_idx == 1) joystick_analog_1[7:0] <= spi_dout; + end + end + + // notify image selection + 8'h1c: mount_strobe <= 1; + + // send image info + 8'h1d: if(byte_cnt<5) img_size[(byte_cnt-1)<<3 +:8] <= spi_dout; + + // status, 32bit version + 8'h1e: if(byte_cnt<5) status[(byte_cnt-1)<<3 +:8] <= spi_dout; + default: ; + endcase + end + end + end +end + + +/////////////////////////////// PS2 /////////////////////////////// +// 8 byte fifos to store ps2 bytes +localparam PS2_FIFO_BITS = 3; + +reg clk_ps2; +always @(negedge clk_sys) begin + integer cnt; + cnt <= cnt + 1'd1; + if(cnt == PS2DIV) begin + clk_ps2 <= ~clk_ps2; + cnt <= 0; + end +end + +// keyboard +reg [7:0] ps2_kbd_fifo[1<= 1)&&(ps2_kbd_tx_state < 9)) begin + ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits + ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down + if(ps2_kbd_tx_byte[0]) + ps2_kbd_parity <= !ps2_kbd_parity; + end + + // transmission of parity + if(ps2_kbd_tx_state == 9) ps2_kbd_data <= ps2_kbd_parity; + + // transmission of stop bit + if(ps2_kbd_tx_state == 10) ps2_kbd_data <= 1; // stop bit is 1 + + // advance state machine + if(ps2_kbd_tx_state < 11) ps2_kbd_tx_state <= ps2_kbd_tx_state + 1'd1; + else ps2_kbd_tx_state <= 0; + end + end +end + +// mouse +reg [7:0] ps2_mouse_fifo[1<= 1)&&(ps2_mouse_tx_state < 9)) begin + ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits + ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down + if(ps2_mouse_tx_byte[0]) + ps2_mouse_parity <= !ps2_mouse_parity; + end + + // transmission of parity + if(ps2_mouse_tx_state == 9) ps2_mouse_data <= ps2_mouse_parity; + + // transmission of stop bit + if(ps2_mouse_tx_state == 10) ps2_mouse_data <= 1; // stop bit is 1 + + // advance state machine + if(ps2_mouse_tx_state < 11) ps2_mouse_tx_state <= ps2_mouse_tx_state + 1'd1; + else ps2_mouse_tx_state <= 0; + end + end +end + + +/////////////////////////////// DOWNLOADING /////////////////////////////// + +reg [7:0] data_w; +reg [24:0] addr_w; +reg rclk = 0; + +localparam UIO_FILE_TX = 8'h53; +localparam UIO_FILE_TX_DAT = 8'h54; +localparam UIO_FILE_INDEX = 8'h55; + +// data_io has its own SPI interface to the io controller +always@(posedge SPI_SCK, posedge SPI_SS2) begin + reg [6:0] sbuf; + reg [7:0] cmd; + reg [4:0] cnt; + reg [24:0] addr; + + if(SPI_SS2) cnt <= 0; + else begin + rclk <= 0; + + // don't shift in last bit. It is evaluated directly + // when writing to ram + if(cnt != 15) sbuf <= { sbuf[5:0], SPI_DI}; + + // increase target address after write + if(rclk) addr <= addr + 1'd1; + + // count 0-7 8-15 8-15 ... + if(cnt < 15) cnt <= cnt + 1'd1; + else cnt <= 8; + + // finished command byte + if(cnt == 7) cmd <= {sbuf, SPI_DI}; + + // prepare/end transmission + if((cmd == UIO_FILE_TX) && (cnt == 15)) begin + // prepare + if(SPI_DI) begin + addr <= 0; + ioctl_download <= 1; + end else begin + addr_w <= addr; + ioctl_download <= 0; + end + end + + // command 0x54: UIO_FILE_TX + if((cmd == UIO_FILE_TX_DAT) && (cnt == 15)) begin + addr_w <= addr; + data_w <= {sbuf, SPI_DI}; + rclk <= 1; + end + + // expose file (menu) index + if((cmd == UIO_FILE_INDEX) && (cnt == 15)) ioctl_index <= {sbuf, SPI_DI}; + end +end + +assign ioctl_wr = |ioctl_wrd; +reg [1:0] ioctl_wrd; + +always@(negedge clk_sys) begin + reg rclkD, rclkD2; + + rclkD <= rclk; + rclkD2 <= rclkD; + ioctl_wrd<= {ioctl_wrd[0],1'b0}; + + if(rclkD & ~rclkD2) begin + ioctl_dout <= data_w; + ioctl_addr <= addr_w; + ioctl_wrd <= 2'b11; + end +end + +endmodule diff --git a/Acorn - Electron_MiST/rtl/osd.v b/Acorn - Electron_MiST/rtl/osd.v new file mode 100644 index 00000000..c62c10af --- /dev/null +++ b/Acorn - Electron_MiST/rtl/osd.v @@ -0,0 +1,179 @@ +// A simple OSD implementation. Can be hooked up between a cores +// VGA output and the physical VGA pins + +module osd ( + // OSDs pixel clock, should be synchronous to cores pixel clock to + // avoid jitter. + input clk_sys, + + // SPI interface + input SPI_SCK, + input SPI_SS3, + input SPI_DI, + + // VGA signals coming from core + input [5:0] R_in, + input [5:0] G_in, + input [5:0] B_in, + input HSync, + input VSync, + + // VGA signals going to video connector + output [5:0] R_out, + output [5:0] G_out, + output [5:0] B_out +); + +parameter OSD_X_OFFSET = 10'd0; +parameter OSD_Y_OFFSET = 10'd0; +parameter OSD_COLOR = 3'd0; + +localparam OSD_WIDTH = 10'd256; +localparam OSD_HEIGHT = 10'd128; + +// ********************************************************************************* +// spi client +// ********************************************************************************* + +// this core supports only the display related OSD commands +// of the minimig +reg osd_enable; +(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[2047:0]; // the OSD buffer itself + +// the OSD has its own SPI interface to the io controller +always@(posedge SPI_SCK, posedge SPI_SS3) begin + reg [4:0] cnt; + reg [10:0] bcnt; + reg [7:0] sbuf; + reg [7:0] cmd; + + if(SPI_SS3) begin + cnt <= 0; + bcnt <= 0; + end else begin + sbuf <= {sbuf[6:0], SPI_DI}; + + // 0:7 is command, rest payload + if(cnt < 15) cnt <= cnt + 1'd1; + else cnt <= 8; + + if(cnt == 7) begin + cmd <= {sbuf[6:0], SPI_DI}; + + // lower three command bits are line address + bcnt <= {sbuf[1:0], SPI_DI, 8'h00}; + + // command 0x40: OSDCMDENABLE, OSDCMDDISABLE + if(sbuf[6:3] == 4'b0100) osd_enable <= SPI_DI; + end + + // command 0x20: OSDCMDWRITE + if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin + osd_buffer[bcnt] <= {sbuf[6:0], SPI_DI}; + bcnt <= bcnt + 1'd1; + end + end +end + +// ********************************************************************************* +// video timing and sync polarity anaylsis +// ********************************************************************************* + +// horizontal counter +reg [9:0] h_cnt; +reg [9:0] hs_low, hs_high; +wire hs_pol = hs_high < hs_low; +wire [9:0] dsp_width = hs_pol ? hs_low : hs_high; + +// vertical counter +reg [9:0] v_cnt; +reg [9:0] vs_low, vs_high; +wire vs_pol = vs_high < vs_low; +wire [9:0] dsp_height = vs_pol ? vs_low : vs_high; + +wire doublescan = (dsp_height>350); + +reg ce_pix; +always @(negedge clk_sys) begin + integer cnt = 0; + integer pixsz, pixcnt; + reg hs; + + cnt <= cnt + 1; + hs <= HSync; + + pixcnt <= pixcnt + 1; + if(pixcnt == pixsz) pixcnt <= 0; + ce_pix <= !pixcnt; + + if(hs && ~HSync) begin + cnt <= 0; + pixsz <= (cnt >> 9) - 1; + pixcnt <= 0; + ce_pix <= 1; + end +end + +always @(posedge clk_sys) begin + reg hsD, hsD2; + reg vsD, vsD2; + + if(ce_pix) begin + // bring hsync into local clock domain + hsD <= HSync; + hsD2 <= hsD; + + // falling edge of HSync + if(!hsD && hsD2) begin + h_cnt <= 0; + hs_high <= h_cnt; + end + + // rising edge of HSync + else if(hsD && !hsD2) begin + h_cnt <= 0; + hs_low <= h_cnt; + v_cnt <= v_cnt + 1'd1; + end else begin + h_cnt <= h_cnt + 1'd1; + end + + vsD <= VSync; + vsD2 <= vsD; + + // falling edge of VSync + if(!vsD && vsD2) begin + v_cnt <= 0; + vs_high <= v_cnt; + end + + // rising edge of VSync + else if(vsD && !vsD2) begin + v_cnt <= 0; + vs_low <= v_cnt; + end + end +end + +// area in which OSD is being displayed +wire [9:0] h_osd_start = ((dsp_width - OSD_WIDTH)>> 1) + OSD_X_OFFSET; +wire [9:0] h_osd_end = h_osd_start + OSD_WIDTH; +wire [9:0] v_osd_start = ((dsp_height- (OSD_HEIGHT<> 1) + OSD_Y_OFFSET; +wire [9:0] v_osd_end = v_osd_start + (OSD_HEIGHT<= h_osd_start) && (h_cnt < h_osd_end) && + (VSync != vs_pol) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end); + +reg [7:0] osd_byte; +always @(posedge clk_sys) if(ce_pix) osd_byte <= osd_buffer[{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt[7:0]}]; + +wire osd_pixel = osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]]; + +assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[5:3]}; +assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[5:3]}; +assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[5:3]}; + +endmodule diff --git a/Acorn - Electron_MiST/rtl/pll.vhd b/Acorn - Electron_MiST/rtl/pll.vhd new file mode 100644 index 00000000..d6b3ceb3 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/pll.vhd @@ -0,0 +1,446 @@ +-- megafunction wizard: %ALTPLL% +-- GENERATION: STANDARD +-- VERSION: WM1.0 +-- MODULE: altpll + +-- ============================================================ +-- File Name: pll.vhd +-- Megafunction Name(s): +-- altpll +-- +-- Simulation Library Files(s): +-- altera_mf +-- ============================================================ +-- ************************************************************ +-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +-- +-- 13.0.1 Build 232 06/12/2013 SP 1 SJ Full Version +-- ************************************************************ + + +--Copyright (C) 1991-2013 Altera Corporation +--Your use of Altera Corporation's design tools, logic functions +--and other software and tools, and its AMPP partner logic +--functions, and any output files from any of the foregoing +--(including device programming or simulation files), and any +--associated documentation or information are expressly subject +--to the terms and conditions of the Altera Program License +--Subscription Agreement, Altera MegaCore Function License +--Agreement, or other applicable license agreement, including, +--without limitation, that your use is for the sole purpose of +--programming logic devices manufactured by Altera and sold by +--Altera or its authorized distributors. Please refer to the +--applicable agreement for further details. + + +LIBRARY ieee; +USE ieee.std_logic_1164.all; + +LIBRARY altera_mf; +USE altera_mf.all; + +ENTITY pll IS + PORT + ( + inclk0 : IN STD_LOGIC := '0'; + c0 : OUT STD_LOGIC ; + c1 : OUT STD_LOGIC ; + c2 : OUT STD_LOGIC ; + c3 : OUT STD_LOGIC + ); +END pll; + + +ARCHITECTURE SYN OF pll IS + + SIGNAL sub_wire0 : STD_LOGIC_VECTOR (4 DOWNTO 0); + SIGNAL sub_wire1 : STD_LOGIC ; + SIGNAL sub_wire2 : STD_LOGIC ; + SIGNAL sub_wire3 : STD_LOGIC ; + SIGNAL sub_wire4 : STD_LOGIC ; + SIGNAL sub_wire5 : STD_LOGIC ; + SIGNAL sub_wire6 : STD_LOGIC_VECTOR (1 DOWNTO 0); + SIGNAL sub_wire7_bv : BIT_VECTOR (0 DOWNTO 0); + SIGNAL sub_wire7 : STD_LOGIC_VECTOR (0 DOWNTO 0); + + + + COMPONENT altpll + GENERIC ( + bandwidth_type : STRING; + clk0_divide_by : NATURAL; + clk0_duty_cycle : NATURAL; + clk0_multiply_by : NATURAL; + clk0_phase_shift : STRING; + clk1_divide_by : NATURAL; + clk1_duty_cycle : NATURAL; + clk1_multiply_by : NATURAL; + clk1_phase_shift : STRING; + clk2_divide_by : NATURAL; + clk2_duty_cycle : NATURAL; + clk2_multiply_by : NATURAL; + clk2_phase_shift : STRING; + clk3_divide_by : NATURAL; + clk3_duty_cycle : NATURAL; + clk3_multiply_by : NATURAL; + clk3_phase_shift : STRING; + compensate_clock : STRING; + inclk0_input_frequency : NATURAL; + intended_device_family : STRING; + lpm_hint : STRING; + lpm_type : STRING; + operation_mode : STRING; + pll_type : STRING; + port_activeclock : STRING; + port_areset : STRING; + port_clkbad0 : STRING; + port_clkbad1 : STRING; + port_clkloss : STRING; + port_clkswitch : STRING; + port_configupdate : STRING; + port_fbin : STRING; + port_inclk0 : STRING; + port_inclk1 : STRING; + port_locked : STRING; + port_pfdena : STRING; + port_phasecounterselect : STRING; + port_phasedone : STRING; + port_phasestep : STRING; + port_phaseupdown : STRING; + port_pllena : STRING; + port_scanaclr : STRING; + port_scanclk : STRING; + port_scanclkena : STRING; + port_scandata : STRING; + port_scandataout : STRING; + port_scandone : STRING; + port_scanread : STRING; + port_scanwrite : STRING; + port_clk0 : STRING; + port_clk1 : STRING; + port_clk2 : STRING; + port_clk3 : STRING; + port_clk4 : STRING; + port_clk5 : STRING; + port_clkena0 : STRING; + port_clkena1 : STRING; + port_clkena2 : STRING; + port_clkena3 : STRING; + port_clkena4 : STRING; + port_clkena5 : STRING; + port_extclk0 : STRING; + port_extclk1 : STRING; + port_extclk2 : STRING; + port_extclk3 : STRING; + width_clock : NATURAL + ); + PORT ( + clk : OUT STD_LOGIC_VECTOR (4 DOWNTO 0); + inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0) + ); + END COMPONENT; + +BEGIN + sub_wire7_bv(0 DOWNTO 0) <= "0"; + sub_wire7 <= To_stdlogicvector(sub_wire7_bv); + sub_wire4 <= sub_wire0(2); + sub_wire3 <= sub_wire0(0); + sub_wire2 <= sub_wire0(3); + sub_wire1 <= sub_wire0(1); + c1 <= sub_wire1; + c3 <= sub_wire2; + c0 <= sub_wire3; + c2 <= sub_wire4; + sub_wire5 <= inclk0; + sub_wire6 <= sub_wire7(0 DOWNTO 0) & sub_wire5; + + altpll_component : altpll + GENERIC MAP ( + bandwidth_type => "AUTO", + clk0_divide_by => 25, + clk0_duty_cycle => 50, + clk0_multiply_by => 37, + clk0_phase_shift => "0", + clk1_divide_by => 125, + clk1_duty_cycle => 50, + clk1_multiply_by => 74, + clk1_phase_shift => "0", + clk2_divide_by => 30, + clk2_duty_cycle => 50, + clk2_multiply_by => 37, + clk2_phase_shift => "0", + clk3_divide_by => 120, + clk3_duty_cycle => 50, + clk3_multiply_by => 37, + clk3_phase_shift => "0", + compensate_clock => "CLK0", + inclk0_input_frequency => 37037, + intended_device_family => "Cyclone III", + lpm_hint => "CBX_MODULE_PREFIX=pll", + lpm_type => "altpll", + operation_mode => "NORMAL", + pll_type => "AUTO", + port_activeclock => "PORT_UNUSED", + port_areset => "PORT_UNUSED", + port_clkbad0 => "PORT_UNUSED", + port_clkbad1 => "PORT_UNUSED", + port_clkloss => "PORT_UNUSED", + port_clkswitch => "PORT_UNUSED", + port_configupdate => "PORT_UNUSED", + port_fbin => "PORT_UNUSED", + port_inclk0 => "PORT_USED", + port_inclk1 => "PORT_UNUSED", + port_locked => "PORT_UNUSED", + port_pfdena => "PORT_UNUSED", + port_phasecounterselect => "PORT_UNUSED", + port_phasedone => "PORT_UNUSED", + port_phasestep => "PORT_UNUSED", + port_phaseupdown => "PORT_UNUSED", + port_pllena => "PORT_UNUSED", + port_scanaclr => "PORT_UNUSED", + port_scanclk => "PORT_UNUSED", + port_scanclkena => "PORT_UNUSED", + port_scandata => "PORT_UNUSED", + port_scandataout => "PORT_UNUSED", + port_scandone => "PORT_UNUSED", + port_scanread => "PORT_UNUSED", + port_scanwrite => "PORT_UNUSED", + port_clk0 => "PORT_USED", + port_clk1 => "PORT_USED", + port_clk2 => "PORT_USED", + port_clk3 => "PORT_USED", + port_clk4 => "PORT_UNUSED", + port_clk5 => "PORT_UNUSED", + port_clkena0 => "PORT_UNUSED", + port_clkena1 => "PORT_UNUSED", + port_clkena2 => "PORT_UNUSED", + port_clkena3 => "PORT_UNUSED", + port_clkena4 => "PORT_UNUSED", + port_clkena5 => "PORT_UNUSED", + port_extclk0 => "PORT_UNUSED", + port_extclk1 => "PORT_UNUSED", + port_extclk2 => "PORT_UNUSED", + port_extclk3 => "PORT_UNUSED", + width_clock => 5 + ) + PORT MAP ( + inclk => sub_wire6, + clk => sub_wire0 + ); + + + +END SYN; + +-- ============================================================ +-- CNX file retrieval info +-- ============================================================ +-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "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 "25" +-- Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "125" +-- Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "30" +-- Retrieval info: PRIVATE: DIV_FACTOR3 NUMERIC "120" +-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000" +-- Retrieval info: PRIVATE: DUTY_CYCLE3 STRING "50.00000000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "39.959999" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "15.984000" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "33.299999" +-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE3 STRING "8.325000" +-- 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 "0" +-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "ps" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps" +-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT3 STRING "ps" +-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0" +-- Retrieval info: PRIVATE: MIRROR_CLK3 STRING "0" +-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "37" +-- Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "74" +-- Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "37" +-- Retrieval info: PRIVATE: MULT_FACTOR3 NUMERIC "37" +-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "40.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "16.00000000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "33.33333300" +-- Retrieval info: PRIVATE: OUTPUT_FREQ3 STRING "8.33250000" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE3 STRING "0" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz" +-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT3 STRING "MHz" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT3 STRING "0.00000000" +-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "deg" +-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT3 STRING "deg" +-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0" +-- 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: STICKY_CLK3 STRING "1" +-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +-- Retrieval info: PRIVATE: USE_CLK0 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK1 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK2 STRING "1" +-- Retrieval info: PRIVATE: USE_CLK3 STRING "1" +-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA2 STRING "0" +-- Retrieval info: PRIVATE: USE_CLKENA3 STRING "0" +-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +-- Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "25" +-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "37" +-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "125" +-- Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "74" +-- Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "30" +-- Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "37" +-- Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: CLK3_DIVIDE_BY NUMERIC "120" +-- Retrieval info: CONSTANT: CLK3_DUTY_CYCLE NUMERIC "50" +-- Retrieval info: CONSTANT: CLK3_MULTIPLY_BY NUMERIC "37" +-- Retrieval info: CONSTANT: CLK3_PHASE_SHIFT STRING "0" +-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" +-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +-- Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_USED" +-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +-- Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +-- Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" +-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +-- Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +-- Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2" +-- Retrieval info: USED_PORT: c3 0 0 0 0 OUTPUT_CLK_EXT VCC "c3" +-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +-- Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +-- Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2 +-- Retrieval info: CONNECT: c3 0 0 0 0 @clk 0 0 1 3 +-- Retrieval info: GEN_FILE: TYPE_NORMAL pll.vhd 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.vhd FALSE +-- Retrieval info: LIB_FILE: altera_mf +-- Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/Acorn - Electron_MiST/rtl/pll_inst.vhd b/Acorn - Electron_MiST/rtl/pll_inst.vhd new file mode 100644 index 00000000..3b82d097 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/pll_inst.vhd @@ -0,0 +1,6 @@ +pll_inst : pll PORT MAP ( + inclk0 => inclk0_sig, + c0 => c0_sig, + c1 => c1_sig, + c2 => c2_sig + ); diff --git a/Acorn - Electron_MiST/rtl/ps2_intf.vhd b/Acorn - Electron_MiST/rtl/ps2_intf.vhd new file mode 100644 index 00000000..7080c264 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/ps2_intf.vhd @@ -0,0 +1,119 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.NUMERIC_STD.all; + +-- This is input-only for the time being +entity ps2_intf is + generic (filter_length : positive := 8); + port( + CLK : in std_logic; + nRESET : in std_logic; + + -- PS/2 interface (could be bi-dir) + PS2_CLK : in std_logic; + PS2_DATA : in std_logic; + + -- Byte-wide data interface - only valid for one clock + -- so must be latched externally if required + DATA : out std_logic_vector(7 downto 0); + VALID : out std_logic; + error : out std_logic + ); +end ps2_intf; + +architecture ps2_intf_arch of ps2_intf is +--subtype filter_t is std_logic_vector(filter_length-1 downto 0); +--signal clk_filter : filter_t; + signal clk_filter : std_logic_vector(7 downto 0); + + signal ps2_clk_in : std_logic; + signal ps2_dat_in : std_logic; +-- Goes high when a clock falling edge is detected + signal clk_edge : std_logic; + signal bit_count : unsigned (3 downto 0); + signal shiftreg : std_logic_vector(8 downto 0); + signal parity : std_logic; +begin + -- Register input signals + process(nRESET, CLK) + begin + if nRESET = '0' then + ps2_clk_in <= '1'; + ps2_dat_in <= '1'; + clk_filter <= (others => '1'); + clk_edge <= '0'; + elsif rising_edge(CLK) then + -- Register inputs (and filter clock) + ps2_dat_in <= PS2_DATA; + clk_filter <= PS2_CLK & clk_filter(7 downto 1); + clk_edge <= '0'; + + if clk_filter = x"ff" then + -- Filtered clock is high + ps2_clk_in <= '1'; + elsif clk_filter = x"00" then + -- Filter clock is low, check for edge + if ps2_clk_in = '1' then + clk_edge <= '1'; + end if; + ps2_clk_in <= '0'; + end if; + end if; + end process; + + -- Shift in keyboard data + process(nRESET, CLK) + begin + if nRESET = '0' then + bit_count <= (others => '0'); + shiftreg <= (others => '0'); + parity <= '0'; + DATA <= (others => '0'); + VALID <= '0'; + error <= '0'; + elsif rising_edge(CLK) then + -- Clear flags + VALID <= '0'; + error <= '0'; + + if clk_edge = '1' then + -- We have a new bit from the keyboard for processing + if bit_count = 0 then + -- Idle state, check for start bit (0) only and don't + -- start counting bits until we get it + + parity <= '0'; + + if ps2_dat_in = '0' then + -- This is a start bit + bit_count <= bit_count + 1; + end if; + else + -- Running. 8-bit data comes in LSb first followed by + -- a single stop bit (1) + if bit_count < 10 then + -- Shift in data and parity (9 bits) + bit_count <= bit_count + 1; + shiftreg <= ps2_dat_in & shiftreg(shiftreg'high downto 1); + parity <= parity xor ps2_dat_in; -- Calculate parity + elsif ps2_dat_in = '1' then + -- Valid stop bit received + bit_count <= (others => '0'); -- back to idle + if parity = '1' then + -- Parity correct, submit data to host + DATA <= shiftreg(7 downto 0); + VALID <= '1'; + else + -- Error + error <= '1'; + end if; + else + -- Invalid stop bit + bit_count <= (others => '0'); -- back to idle + error <= '1'; + end if; + end if; + end if; + end if; + end process; +end ps2_intf_arch; diff --git a/Acorn - Electron_MiST/rtl/roms/basic2.hex b/Acorn - Electron_MiST/rtl/roms/basic2.hex new file mode 100644 index 00000000..11831382 --- /dev/null +++ b/Acorn - Electron_MiST/rtl/roms/basic2.hex @@ -0,0 +1,514 @@ +:020000040000FA +:20000000C901F01F60EA600E01424153494300284329313938322041636F726E0A0D00005A +:20002000800000A98420F4FF86068407A98320F4FF8418A200861F8E02048E0304CA86232B +:20004000A20A8E0004CA8E0104A9012511050D050E050F0510D00CA941850DA952850EA948 +:2000600057850FA9028D0202A9B48D0302584CDD8A414E4480004142539400414353950036 +:20008000414456414C9600415343970041534E980041544E99004155544FC61042474554CD +:2000A0009A0142505554D503434F4C4F5552FB0243414C4CD602434841494ED702434852B4 +:2000C00024BD00434C454152D801434C4F5345D903434C47DA01434C53DB01434F539B00BE +:2000E000434F554E549C0144415441DC204445479D00444546DD0044454C455445C71044DD +:200100004956810044494DDE0244524157DF02454E4450524F43E101454E44E001454E5668 +:20012000454C4F5045E202454C53458B144556414CA00045524C9E014552524F52850445FC +:200140004F46C501454F5282004552529F01455850A100455854A201464F52E30246414C92 +:200160005345A301464EA408474F544FE51247455424BE00474554A500474F535542E41216 +:2001800047434F4CE60248494D454D9343494E505554E8024946E702494E4B455924BF00B7 +:2001A000494E4B4559A600494E54A800494E53545228A7004C495354C9104C494E45860064 +:2001C0004C4F4144C8024C4F4D454D92434C4F43414CEA024C4546542428C0004C454EA9D0 +:2001E000004C4554E9044C4F47AB004C4EAA004D49442428C1004D4F4445EB024D4F448300 +:20020000004D4F5645EC024E455854ED024E4557CA014E4F54AC004F4C44CB014F4EEE0201 +:200220004F464687004F5284004F50454E494E8E004F50454E4F5554AE004F50454E555031 +:20024000AD004F53434C49FF025052494E54F1025041474590435054528F435049AF0150A5 +:200260004C4F54F002504F494E5428B00050524F43F20A504F53B10152455455524EF8018E +:20028000524550454154F5005245504F5254F60152454144F30252454DF42052554EF901DD +:2002A000524144B200524553544F5245F71252494748542428C200524E44B30152454E552A +:2002C0004D424552CC1053544550880053415645CD0253474EB40053494EB500535152B673 +:2002E00000535043890053545224C300535452494E472428C400534F554E44D40253544F73 +:2003000050FA0154414EB7005448454E8C14544FB800544142288A005452414345FC125474 +:20032000494D45914354525545B901554E54494CFD02555352BA00564455EF0256414CBB57 +:200340000056504F53BC015749445448FE0250414745D000505452CF0054494D45D1004C1A +:200360004F4D454DD20048494D454DD3007847C0B4FC036AD4339EDA076F8DF7C29FA6E935 +:200380009146CA95B9ADE278D1FEA8D1807CCB416DB1498898B4BEDCC4D22F76BDBF26CC99 +:2003A00039EE94C2B8AC31249CDAB6A3F32A3083C96F5D4C58D22A8D99BDC47D7D2FE8C8B3 +:2003C0005672C488CC7AC244E4239AE495152FF19A041F7DE4E4E6B611D08E95B1A0C2BFFA +:2003E000BFAEAEAEAFADA8ABACA8A9BFA9AEABAFAFABAABFAEB1AFACACACAEA7ABACBFBF19 +:20040000ABABABABAFABA9A7A6AEACABACABB3AFB0AFB0AFB0B0AC908FBFB58A8A8FBE98CC +:20042000BF92929292B4BF8EBF92BF8E8E8B8B91938A93B4B7B8B89398BA8B939393B6B9BE +:2004400094938D93BB8BBBBFBAB8BD8A9392BBB4BE4B83848996B8B9D8D9F001108190895C +:2004600093A3A4A93839780113216373B1A9C50CC3D3C4F24183B081436C72ECF2A3C3181C +:200480001934B072989981989914350A0D0D0D0D1010252539414141414A4A4C4C4C5050C4 +:2004A0005253535308080809090A0A0A05153E040D304C0632494910250E0E09292A3030ED +:2004C0004E4E4E3E160018D858B8CA88E8C8EA48086828406038F878AAA8BA8A9A9890B0C2 +:2004E000F030D010507021410161C1A1E106462666C6E6E0C0204C20A2A0818684A9FF858B +:20050000284CA38BA903852820978AC95DF0EE206D98C60A20BA85C60AA5284A9060A51EAD +:200520006904853FA5382045B5A5372062B5A2FCA4391002A4368438F01CA000E8D00D20CC +:2005400025BCA63F2065B5CAD0FAA2FDB13A2062B5C8C638D0E6E8100C2065B52058B5203F +:2005600058B54C5685A000B10BC93AF00AC90DF00A200EB5C8D0F0C40A90F62025BCA40AB0 +:2005800088C8B10BC93AF004C90DD0F520599888B10BC93AF00CA50CC907D0034CF68A2029 +:2005A00090984C0885208295F05AB0582094BD203AAE852720B4B4202788A20320978AA0AF +:2005C00000843DC93AF064C90DF060C95CF05CC92EF0D2C60AA40AE60AB10B302AC920F056 +:2005E00010A0050A0A0A0A263D263E88D0F8CAD0E4A23AA53DDD5084D007BC8A84C43EF087 +:200600001FCAD0F14C2A98A222C980F013E8C982F00EE8C984D0EDE60AC8B10BC941D0E4BD +:20062000BDC4848529A001E01AB048AD400485378439A628E004AE410486389006AD3C0424 +:20064000AE3D04853A863B98F0281004A436F02288B9290024391003B90006913AEE4004E5 +:20066000D003EE41049008EE3C04D003EE3D0498D0DE60E022B04020218818A52AED400433 +:20068000A8A52BED4104C00188E900F025C9FFF01CA5284AF00F00014F7574206F662072BF +:2006A000616E676500A8842AA0024C2B869830F610DF9810F130DAE029B01820978AC9235C +:2006C000D018202F88202188A52BF0DC00024279746500E036D06820978AC928D037202198 +:2006E0008820978AC929D01320978AC92CD01E202C8820978AC959D014F0CDC92CD00E206D +:20070000978AC958D00720978AC929F0BB0003496E64657800C60A20218820978AC92CD048 +:2007200014202C8820978AC958F00AC959D0DE202F884C9A87203288A52BD0F34CA886E09A +:200740002FB02BE02DB00920978AC941F019C60A20218820978AC92CD0DE202C8820978AE3 +:20076000C958F0D44C0D87203288A001D02EE032B016E031F00C20978AC923D0034CC586BF +:20078000C60A2021884C3587E033F00BB02420978AC928F00AC60A202188A0034C2B862051 +:2007A0002C88202C8820218820978AC929F0EB4C0D87E039B05DA53D4901291F48E037B051 +:2007C0002F20978AC923D004684CC586C60A20218868853720978AC92CF0034C3587209745 +:2007E0008A291FC537D006202C884C35874C0D8720218868853720978AC92CD01320978A52 +:20080000291FC537D0E7202C88A52BF0034CCC864C3887D025202188A52A8528A0004C2B4C +:2008200086201D9B20F092A41B840A60202F88203288A529186904852960A201A40AE60AB8 +:20084000B10BC942F012E8C957F00DA204C944F007C953F0154C2A988A48202188A229206B +:2008600044BE68A84C2B864C0E8CA52848201D9BD0F5688528202788A0FFD0E84818986539 +:20088000378539A000986538853A689137C8B1399137C90DD0F760290F853D843EC8B137BC +:2008A000C93AB036C9309032290F48A63EA53D0A263E30210A263E301C653D853D8A653E44 +:2008C000063D2A3010B00E853E68653D853D90CDE63E10C94868A000386088A98D207C88FA +:2008E000A53769028539A5386900853AB137913988D0F9A003A53E0940913788A53D293F82 +:200900000940913788A53D29C0853DA53E29C04A4A053D4A4A49549137204489204489201C +:200920004489A0001860C97BB0FAC95FB00EC95BB0F2C941B006C93AB0EAC93060C92ED0BB +:20094000F560B137E637D002E63860204489B13760A000843B843CB137C90DF0EDC920D045 +:2009600005204489D0F1C926D012204B89203689B0F8C94190E1C94790F0B0DBC922D00C1B +:20098000204B89C922F0DAC90DD0F560C93AD006843B843CF0CBC92CF0C7C92AD005A53B4C +:2009A000D04160C92EF00E2036899033A63CF0052097889034B137203D8990062044894CB8 +:2009C000B589A2FF863B843C4C57892026899013A000B13720268990E92044894CD289C9EC +:2009E00041B009A2FF863B843C4C6189C958B0DBA2718639A280863AD13990D6D00FC8B17D +:200A0000393034D137F0F7B137C92EF00BC8B13910FBC9FED00FB0B8C8B139301AE639D0BA +:200A2000F8E63AD0F438C898653985399002E63AA000B1374CF889AAC8B139853D884A905F +:200A400007B137202689B0888A243D5007A63BD00318694088207C88A000A2FFA53D4A4A86 +:200A60009004863B843C4A9004843B843C4A901148C8B13720268990062044894C728A88FF +:200A8000684A9002863C4AB00D4C6189A41BE61BB119C920F0F660A40AE60AB10BC920F027 +:200AA000F66000054D697373696E67202C00208C8AC92CD0ED60205798A5188538A90085B6 +:200AC000379137206FBED02B205798206FBED026205798000053544F5000205798A90DA4BF +:200AE000188413A000841284209112A9FFC89112C884122020BDA007840CA000840BA9331A +:200B00008516A9B48517A93E2002BCA9338516A9B48517A2FF8628863C9A203ABDA8A50BF2 +:200B20008537A50C8538843B840A20578920DF979006208DBC4CF38A20978AC9C6B072905E +:200B40007E4CF68A4C0485BAE0FCB00DADFF01C9A4D006201D9B4C4C9800074E6F20A400A3 +:200B6000A40A88B10BC93DF0DEC92AF006C95BF0D3D023206D98A60BA40C20F7FFA90DA4F6 +:200B80000A88C8D10BD0FBC98BF0F2A50CC907F0B0209098D00DC60A205798A000B10BC9D4 +:200BA0003AD0E4A40AE60AB10BC920F0F6C9CF900EAABDDF828537BD518385386C3700A6CD +:200BC0000B8619A60C861A841B20DD95D01BB090861B20419820FC94A205E42CD001E820E3 +:200BE0003195C60A208295F02290102094BD201398A527D019201E8C4C9B8B2094BD2013A5 +:200C000098A527F00920B4B44C9B8B4C2A98000654797065206D69736D617463680020EA47 +:200C2000BDA52CC980F07BA002B12AC536B055A502852CA503852DA536C908900669079001 +:200C400002A9FF1848AAB12AA000712A4502D00FC8712A4503D008852D8AC838F12AAA8A96 +:200C6000186502A8A5036900C404AAE505B0488402860368A002912A88A52DF007912A8880 +:200C8000A52C912AA003A536912AF0158888B12A852D88B12A852CB90006912CC8C436D0CB +:200CA000F66020BABEC000F00BB90006912A88D0F8AD0006912A6000004E6F20726F6F6D59 +:200CC00000A539C980F027903AA000B104AAF015B137E9018539C8B137E900853AB10491DA +:200CE00039C8CAD0F8A104A00391374CDCBDA000B104AAF00AC8B104889137C8CAD0F6A9A5 +:200D00000DD0E6A000B1049137C8C439B018B1049137C8B1049137C8B1049137C8C439B0EA +:200D200005B1049137C898184CE1BDC60A20A9BF9848208C8AC92CD03E20299B2085A368CA +:200D4000A8A52720D4FFAAF01B300CA203B52A20D4FFCA10F830D9A204BD6C0420D4FFCA59 +:200D600010F730CCA53620D4FFAAF0C4BDFF0520D4FFCAD0F7F0B968840A4C988B2025BCF0 +:200D80004C968BA9008514851520978AC93AF0F0C90DF0ECC98BF0E8D03820978AC923F0E3 +:200DA0008AC60A4CBB8DAD0004F010A51EF00CED0004B0F9A82065B5C8D0FA18AD00048579 +:200DC00014661520978AC93AF0B3C90DF0AFC98BF0ABC97EF0EBC92CF0CCC93BF0A520703D +:200DE0008E90E0A51448A51548C61B20299B688515688514A51B850A98F01320DF9EA514EA +:200E000038E5369009F007A82065B588D0FAA536F0B1A000B900062058B5C8C436D0F5F03C +:200E2000A24CA28AC92CD0F9A52A482056AE20F092A91F20EEFF6820EEFF2056944C6A8E65 +:200E400020DD92208C8AC929D0DAA52AE51EF01AA8B00C2025BCF00320E392A42AF00B207F +:200E600065B588D0FAF0032025BC18A41B840A60A60B8619A60C861AA60A861BC927F0E793 +:200E8000C98AF0BCC989F0D0386020978A20708E90F7C922F011386000094D697373696EC3 +:200EA000672022002058B5C8B119C90DF0EAC922D0F2C8841BB119C922D0AFF0E7205798EC +:200EC000A910D0082057982028BCA90C20EEFF4C9B8B201D9B20EE922094BDA0008C00061F +:200EE0008CFF06208C8AC92CD022A41B20D595F02AACFF06C8A52A990006C8A52B990006C3 +:200F0000C8A52C990006EE00064CE08EC61B20529820EABD201E8FD84C9B8B4C43AEAD0C2C +:200F2000044AAD0404AE6004AC64046C2A004C2A9820DF9790F82094BD20978AC92CD0EE61 +:200F400020DF9790E9205798A52A8539A52B853A20EABD202DBC207B98202292A539C52AB3 +:200F6000A53AE52BB0ED4CF38AA90A20D8AE20DF972094BDA90A20D8AE20978AC92CD00D50 +:200F800020DF97A52BD058A52AF054E60AC60A4C5798A512853BA513853CA5188538A901A1 +:200FA00085376020698FA239200DBE206FBE20928FA000B1373030913BC8B137913B3898A9 +:200FC000653B853BAAA53C6900853CE406E507B005209F9090DB0000CC20737061636500BF +:200FE0000053696C6C7900209A8FA000B137301DA53A9137A539C8913718A52A653985396E +:20100000A900653A297F853A209F9090DDA518850CA000840BC8B10B3020A004B10BC98D5E +:20102000F01BC8C90DD0F5B10B300FA003B10B18650B850B90E4E60CB0E04CF38A20EB976F +:2010400020928FA000B1373037B13BC8C52BD021B13BC52AD01BB137853D88B137853EA484 +:201060000A88A50B8537A50C853820F588A40AD0AB209F90A53B6902853B90C7E63CB0C3F8 +:2010800020CFBF4661696C656420617420C8B10B852BC8B10B852A201F992025BCF0CEC882 +:2010A000B137653785379003E638186020698FA52A4820EABD2094BD202399A9202002BCDD +:2010C00020EABD205189208DBC2020BD684818652A852A90E0E62B10DC4CF38A4C1892C6F1 +:2010E0000A208295F041B03F2094BD20DD92202292A52D052CD03018A52A6502A8A52B658D +:2011000003AAC404E505B0D4A502852AA503852B84028603A900852C852DA940852720B4BA +:20112000B42027884C0B92000A42616420DE0020978A9818650BA60C9002E818E9008537EA +:201140008AE9008538A205863FA60A205995C001F0D5C928F015C924F004C925D00AC63F0B +:20116000C8E8B137C928F0034CDF908439860A206994D0B320FC94A201203195A53F48A93D +:20118000014820D8AE2094BD202188A52B29C0052C052DD09220229268A8A52A9102C8A5F5 +:2011A0002B9102C8984820319220978AC92CF0D5C929F0034C279168851568853FA90085A6 +:2011C00040203692A000A5159102652A852A9002E62BA5038538A502853718652AA8A52B32 +:2011E0006503B034AAC404E505B02D84028603A5376515A8A90085379002E6389137C8D0E8 +:2012000002E638C402D0F5E438D0F120978AC92CF0034C968B4C2F91000BDE2073706163F4 +:201220006500E62AD00AE62BD006E62CD002E62D60A23F200DBEA200A0004640663F900B4D +:201240001898652AA88A652BAAB00F062A262BA53F0540D0E5842A862B604C279120EB9265 +:20126000A52A85068504A52B850785054C9B8B20EB92A52A85008502A52B85018503202F8E +:20128000BDF00720EB92A52B85184C9B8B2057982020BDF0F520DF97B00BC9EEF019C987CC +:2012A000F01E202188205798A52A8521A52B8522A9FF85204C9B8BE60A205798A9FFD0EE38 +:2012C000E60A205798A900F0E920EB92A22AA000842EA90220F1FF4C9B8B20AE8A20299B69 +:2012E0004CF09220ECADF00F300A60200798A527F00510F64CE4A34C0E8C20ECADF0F830BE +:20130000E94CBEA2A50B8519A50C851AA50A851BA9F22097B12052984C9B8BA003A90091EF +:201320002AF01EBAE0FCB043208295F026200DB3A42C30E72094BDA90020D8AE852720B498 +:20134000B4BAFE0601A41B840A20978AC92CF0D34C968B4C988BBAE0FCB00AADFF01C9F240 +:20136000D0034C5798000D4E6F20F2000C4E6F7420EA001942616420EB00202188A52A4831 +:2013800020DA92205298A91220EEFF4CDA93A911482021882057984CDA93A91648202188D3 +:2013A00020579820E7BEE0FFD02DC0FFD029A504C506D0BEA505C507D0B8A62AA98520F4B3 +:2013C000FFE40298E50390AAE41298E51390A386068604840784052028BC6820EEFF20569C +:2013E000944C9B8BA904D002A90548201D9B4CFD93202188A52A4820AE8A20299B20EE9202 +:201400002094BD20DA92205298A91920EEFF6820EEFF200BBEA53720EEFFA53820EEFF20A5 +:201420005694A52B20EEFF4C9B8BA52B20EEFF20978AC93AF01DC90DF019C98BF015C60A3D +:2014400020218820569420978AC92CF0E2C93BD0E1F0D74C968BA52A6C0E02A001B137A054 +:20146000F6C9F2F00AA0F8D006A001B1370AA8B90004853AB90104853BA53BF035A000B1C8 +:201480003A853CC8B13A853DC8B13AD00D88C439D021C8B012C8B13AF019D137D015C439A6 +:2014A000D0F3C8B13AD00C98653A852AA53B6900852B60A53DF0FBA000B13C853AC8B13CCD +:2014C000853BC8B13CD00D88C439D0ADC8B012C8B13CF0A5D137D0A1C439D0F3C8B13CD026 +:2014E0009898653C852AA53D6900852B60A001B137AAA9F6E0F2F009A9F8D005A001B13775 +:201500000A853AA904853BB13AF00BAA88B13A853A863BC810F1A503913AA50288913A9844 +:20152000C89102C439F031C8B1379102C439D0F760A900C89102CAD0FA389865029002E684 +:2015400003A403C405900FD004C5049009A900A001913A4CB78C850260A001B137C93090A6 +:2015600018C940B00CC93AB010C001F00CE8C8D0EAC95FB005C95B90F460C97B90EF60207C +:20158000319520C995D01DB01B20FC94A205E42CD0EDE8D0EAC921F00CC924F013493FF03B +:2015A00006A9003860A90448E61B20E3924C9F96E61B20E392A52BF006A980852C3860000A +:2015C00008242072616E676500A50B8519A50C851AA40A88C8841BB119C920F0F7C9409044 +:2015E000B4C95BB01A0A0A852AA904852BC8B119C8C925D00AA204862CB119C928D066A21C +:2016000005862CA51B186519A61A9002E818E9008537B001CA8638A61BA001B137C941B089 +:201620000CC930901CC93AB018E8C8D0EEC95BB004E8C8D0E6C95F9008C97BB004E8C8D04A +:20164000DA88F02FC924F067C925D008C62CC8E8C8B137888439C928F04C206994F0188690 +:201660001BA41BB119C921F016C93FF00E18841BA9FF60A9003860A9001860A900F002A96B +:201680000448C8841B202CB320F092A52B48A52A4820E3921868652A852A68652B852B6864 +:2016A000852C18A9FF60E8E63920DF964C6196E8C88439C8C62CB137C928F00D206994F070 +:2016C000B6861BA981852C3860E88439C62C20DF96A981852C3860000E4172726179002074 +:2016E0006994F0F3861BA52C48A52A48A52B48A000B12AC90490759820D8AEA901852D201A +:2017000094BD20DD92E61BE02CD0CCA239200DBEA43C68853868853748A5384820BA9784EF +:201720002DB137853FC8B1378540A52A6539852AA52B653A852B203692A00038B137E52D66 +:20174000C903B0BB2094BD2056AE20F092688538688537A239200DBEA43C20BA9718A539C5 +:20176000652A852AA53A652B852B90112056AE20F092688538688537A00120BA9768852C31 +:20178000C905D017A62BA52A062A262B062A262B652A852A8A652B852B9008062A262B06CB +:2017A0002A262B98652A852A9003E62B18A537652A852AA538652B852B60A52B29C0052C9B +:2017C000052DD00DA52AD137C8A52BF137B002C860000F53756273637269707400E60AA427 +:2017E0000AB10BC920F0F6C98DD01AC8B10B0A0AAA29C0C8510B852A8A0A0AC8510B852BA4 +:20180000C8840A38601860A50B8519A50C851AA50A851BA41BE61BB119C920F0F6C93DF026 +:201820002800044D697374616B65001053796E746178206572726F7200114573636170656B +:2018400000208C8AC93DD0D96020299B8AA41B4C6198A41B4C5998A40A88C8B10BC920F042 +:20186000F9C93AF008C90DF004C98BD0BD1898650B850B9002E60CA001840A24FF30B960FA +:2018800020579888B10BC93AF0F5A50CC907F02CC8B10B3027A520F0139848C8B10B488899 +:2018A000B10BA86820EAAE20059968A8C83898650B850B9002E60CA001840A604CF68A4C13 +:2018C0000E8C201D9BF0F8100320E4A3A41B840AA52A052B052C052DF017E08CF0034CA3F0 +:2018E0008BE60A20DF9790F620AFB92077984CD2B8A40AB10BC90DF009C8C98BD0F5840A1C +:20190000F0E14C878BA52AC521A52BE522B0ACA95B2058B5201F99A95D2058B54C65B5A965 +:2019200000F002A9058514A204A900953F38A52AFD6B99A8A52BFDB9999008852B842AF690 +:201940003FD0EBCA10E3A205CAF004B53FF0F98637A514F00BE537F007A82065B588D0FAD6 +:20196000B53F09302058B5CA10F660010A64E810A000843DA518853EA001B13DC52BB00E58 +:20198000A003B13D653D853D90EEE63EB0EAD014A002B13DC52A90E8D00A98653D853D90D5 +:2019A00003E63E18A0026000124469766973696F6E206279207A65726F0000000327A820C2 +:2019C000F092A52D482071AD201D9E8627A820F092688538452D85372071ADA239200DBE04 +:2019E000843D843E843F8440A52D052A052B052CF0B5A02088F0410639263A263B263C10EB +:201A0000F32639263A263B263C263D263E263F264038A53DE52A48A53EE52B48A53FE52C1E +:201A2000AAA540E52D900C8540863F68853E68853DB002686888D0C960862720EABD2051A2 +:201A4000BD20BEA2201EA2207EBD20B5A34C629A2051BD20429C8627A820FD92207EBD20A3 +:201A60004EA3A627A000A53B2980853BA52E2980C53BD01EA53DC530D019A53EC531D013D9 +:201A8000A53FC532D00DA540C533D007A541C534D001606A453B2AA901604C0E8C8AF04705 +:201AA00030AE2094BD20429CA8F0EF308CA52D4980852D38A000B104E52A852AC8B104E59C +:201AC0002B852BC8B104E52C852CC8B104A0004980E52D052A052B052C0818A904650485A9 +:201AE000049002E605286020B2BD20429CA8D0AA8637A636A000B1048539C536B001AA86A6 +:201B00003AA000C43AF00AC8B104D9FF05F0F4D004A539C5360820DCBDA6372860A50B85AD +:201B200019A50C851AA50A851B20729BE084F00AE082F021C61BA8852760206B9BA820F07C +:201B400092A003B104192A00992A008810F520FFBDA940D0D7206B9BA820F092A003B104D4 +:201B6000592A00992A008810F530E3A820F0922094BD209C9BE080F00160A820F0922094BE +:201B8000BD209C9BA820F092A003B104392A00992A008810F520FFBDA940D0D920429CE090 +:201BA0003FB004E03CB00160F016E03EF03AAA209E9AD00188842A842B842C842DA9406055 +:201BC000AAA41BB119C93DF00BC93EF012209D9A90E2B0E1E61B209D9AF0D990D7B0D6E67A +:201BE0001B209D9AD0CEF0CDAAA41BB119C93DF009209D9AF0BFB0BC90BBE61B209D9AB021 +:201C0000B390B20013537472696E6720746F6F206C6F6E670020B2BD20209EA8D06A188616 +:201C200037A000B1046536B0DAAA48A436B9FF059DFF05CA88D0F620CBBD688536A6379871 +:201C4000F00320D19DE02BF005E02DF06860A8F0C4303820CE9DA8F02F304CA00018B1043F +:201C6000652A852AC8B104652B852BC8B104652C852CC8B104652D852D18A5046904850432 +:201C8000A94090C1E605B0BD4C0E8C2051BD20D19DA8F0F48627300320BEA2207EBD2000A9 +:201CA000A5A627A9FFD09E862720EABD2051BD20BEA24C9B9CA8F0D0302720CE9DA8F0C84D +:201CC000303838A000B104E52A852AC8B104E52B852BC8B104E52C852CC8B104E52D4C7783 +:201CE0009C2051BD20D19DA8F09E8627300320BEA2207EBD20FDA44CA19C862720EABD20BD +:201D000051BD20BEA2207EBD20D0A44CA19C20BEA220EABD2051BD20BEA24C2C9D20BEA233 +:201D20002051BD20209E8627A820FD92207EBD2056A6A9FFA6274CD49D4C0E8CA8F0FA3042 +:201D4000DFA52DC52CD0D6A8F004C9FFD0CF452B30CB201D9E8627A8F0DF30B5A52DC52C26 +:201D6000D0ACA8F004C9FFD0A5452B30A1A52D482071ADA2392044BE20EABD68452D85371B +:201D80002071ADA000A200843F8440463A663990151898652AA88A652BAAA53F652C853F94 +:201DA000A540652D8540062A262B262C262DA539053AD0D7843D863EA53708A23D2056AF90 +:201DC0002810032093ADA6274CD49D4C3C9D2094BD20209EE02AF0F3E02FF009E083F02101 +:201DE000E081F02660A820FD922051BD20209E8627A820FD92207EBD20ADA6A627A9FFD092 +:201E0000D320BE99A538084CBB9D20BE992639263A263B263C243708A2394CBD9D2094BDA1 +:201E200020ECAD48A41BE61BB119C920F0F6AA68E05EF00160A820FD922051BD20FA92A5D1 +:201E400030C987B0432086A4D00F207EBD20B5A3A54A2012ABA9FFD0CA2081A3A504854B48 +:201E6000A505854C20B5A3A54A2012AB207DA3207EBD20B5A32001A820D1AA2094AA20EDC1 +:201E8000A72056A6A9FFD09B2081A32099A6D0DC98100320E4A3A200A000B92A0048290F26 +:201EA000953F684A4A4A4AE8953FE8C8C004D0EACAF004B53FF0F9B53FC90A900269066908 +:201EC000302066A0CA10F0601007A92D852E2066A0A530C981B04E20F4A1C6494CD19EAE72 +:201EE0000204E0039002A2008637AD0104F006C90AB0069006E002F002A90A8538854EA981 +:201F000000853685492415308798300320BEA220DAA1D0B4A537D005A9304C66A04C9C9F7B +:201F20002099A6D00FC9849010D006A531C9A09008204DA2E6494CD19EA53585272085A302 +:201F4000A54E8538A637E002D012654930528538C90B9008A90A8538A90085372086A6A90D +:201F6000A08531A9838530A638F006204DA2CAD0FA20F5A7204EA3A5278542200BA5A530AE +:201F8000C984B00E66316632663366346635E630D0ECA531C9A0B088A538D011C901F04632 +:201FA0002086A6A9008549A54E8538E638A901C537F033A449300CC438B02BA9008549C888 +:201FC00098D023A537C902F006A901C0FFD017A9302066A0A92E2066A0A930E649F0052070 +:201FE00066A0D0F7A980854E2040A0C64ED005A92E2066A0C638D0F0A43788F01888F01180 +:20200000A43688B90006C930F0F8C92EF001C88436A549F02AA9452066A0A549100AA92D5A +:202020002066A038A900E5492052A0A537F010A920A44930032066A0E000D0034C66A06009 +:20204000A5314A4A4A4A2064A0A531290F85314C97A1A2FF38E8E90AB0FB690A488AF0037F +:202060002064A0680930863BA6369D0006A63BE6366018863520DAA1A9FF60A200863186A9 +:202080003286338634863586488649C92EF011C93AB0DFE92F30DB8535C8B119C92ED0087B +:2020A000A548D044E648D0F1C945F035C93AB038E92F9034A631E0189008A648D0DBE64907 +:2020C000B0D7A648F002C6492097A16535853590C8E634D0C4E633D0C0E632D0BCE631D0A4 +:2020E000B82040A165498549841BA5490548F02F20DAA1F026A9A88530A900852F852E20CB +:2021000003A3A549300BF01020F4A1C649D0F9F007204DA2E649D0F9205CA638A9FF60A55E +:2021200032852D29800531D0CCA535852AA534852BA533852CA9403860204BA149FF386038 +:20214000C8B119C92DF0F2C92BD003C8B119C93AB022E92F901E854AC8B119C93AB011E913 +:202160002F900DC88543A54A0A0A654A0A654360A54A1860A9001860A53565428535A534A3 +:2021800065418534A53365408533A532653F8532A531653E85316048A634A53148A532488B +:2021A000A53348A5350A26342633263226310A2634263326322631653585358A653485341D +:2021C0006865338533686532853268653106352634263326322A85316860A5310532053360 +:2021E00005340535F007A52ED009A90160852E8530852F6018A530690385309002E62F206E +:202200001EA22042A22042A22078A1901066316632663366346635E630D002E62F60A52EF0 +:20222000853BA52F853CA530853DA531853EA532853FA5338540A5348541A5358542602021 +:202240001EA2463E663F6640664166426038A530E9048530B002C62F203FA22008A2203FC0 +:20226000A22042A22042A22042A22008A2A900853EA531853FA5328540A5338541A5348548 +:2022800042A5352A2008A2A900853E853FA5318540A5328541A5338542A5342A2008A2A5B5 +:2022A000322AA531653585359013E634D00FE633D00BE632D007E631D0034C0BA260A20034 +:2022C0008635862FA52D10052093ADA2FF862EA52A8534A52B8533A52C8532A52D8531A929 +:2022E000A085304C03A3852E8530852F60482086A668F0F81007852EA90038E52E8531A91A +:20230000888530A53130E50532053305340535F0D5A530A43130D5D021A6328631A6338660 +:2023200032A6348633A6358634843538E9088530B0E1C62F90DDA43130B206352634263314 +:2023400026322631E9008530B0ECC62F90E8A004B14B854188B14B854088B14B853F88B1F7 +:202360004B853B888442843CB14B853D053B053F05400541F004A53B0980853E60A971D00D +:2023800006A976D002A96C854BA904854CA000A530914BC8A52E2980852EA531297F052EEA +:2023A000914BA532C8914BA533C8914BA534C8914B6020F5A7A004B14B853488B14B85331C +:2023C00088B14B853288B14B852E88B14B85308435842F052E053205330534F004A52E093B +:2023E0008085316020FEA3A531852DA532852CA533852BA534852A60201EA24C86A6A530D9 +:2024000010F62053A420DAA1D032F05CA530C9A0B054C999B02669088530A5408541A53F87 +:202420008540A53E853FA534853EA5338534A5328533A5318532A9008531F0D046316632B9 +:2024400066336634663E663F66406641E630D0BC4C6CA6A900853B853C853D853E853F85BB +:20246000408541854260D0E8A52E101938A900E5348534A900E5338533A900E5328532A92F +:2024800000E531853160A5303007A900854A4CDAA120FEA3A534854A20E8A4A9808530A62C +:2024A000311010452E852E1005E64A4CB0A4C64A206CA44C03A3E634D00CE633D008E6328F +:2024C000D004E631F08A60206CA420B6A44C6CA420FDA44C7EAD204EA3208DA3A53B852E05 +:2024E000A53C852FA53D8530A53E8531A53F8532A5408533A5418534A542853560207EADF4 +:20250000204EA3F0F7200BA54C5CA620DAA1F0CCA00038A530E53DF0779037C925B0DD488E +:202520002938F0194A4A4AAAA5418542A5408541A53F8540A53E853F843ECAD0EB68290722 +:20254000F04EAA463E663F664066416642CAD0F3F03E38A53DE530C925B081482938F019BA +:202560004A4A4AAAA5348535A5338534A5328533A53185328431CAD0EB682907F00EAA46D3 +:20258000316632663366346635CAD0F3A53D8530A52E453B1049A531C53ED01BA532C53F35 +:2025A000D015A533C540D00FA534C541D009A535C542D0034C86A6B02A38A542E5358535C9 +:2025C000A541E5348534A540E5338533A53FE5328532A53EE5318531A53B852E4C03A31890 +:2025E0004C08A238A535E5428535A534E5418534A533E5408533A532E53F8532A531E53EDA +:2026000085314C03A36020DAA1F0FA204EA3D0034C86A618A530653D9003E62F18E97F8595 +:2026200030B002C62FA205A000B53095429430CAD0F7A52E453B852EA020463E663F6640D6 +:202640006641664206462645264426439004182078A188D0E5602006A62003A3A535C9806A +:20266000901AF012A9FF20A4A24C7CA60014546F6F2062696700A53409018534A90085359B +:20268000A52FF01410E6A900852E852F853085318532853385348535602086A6A08084318E +:2026A000C8843098602085A32099A6D03A20DAA1F009201EA220B5A3D037604CA79920FAFC +:2026C0009220D3A9A54A4820E9A7208DA3E64A209EA920E9A720D6A468854A209EA920E90D +:2026E000A720E7A6A9FF6020DAA1F0AC204EA3F0CAA52E453B852E38A530E53DB003C62F9F +:2027000038698085309003E62F18A220B018A531C53ED010A532C53FD00AA533C540D0047A +:20272000A534C5419019A534E5418534A533E5408533A532E53F8532A531E53E85313826E5 +:20274000462645264426430634263326322631CAD0BAA207B018A531C53ED010A532C53F5A +:20276000D00AA533C540D004A534C5419019A534E5418534A533E5408533A532E53F853227 +:20278000A531E53E85313826350634263326322631CAD0C00635A5468534A5458533A544F1 +:2027A0008532A54385314C59A600152D766520726F6F740020FA9220DAA1F02A30EB208557 +:2027C000A3A5304A69408530A905854A20EDA7208DA3A96C854B20ADA6A971854B2000A551 +:2027E000C630C64AD0E9A9FF60A97BD00AA971D006A976D002A96C854BA904854C6020FA56 +:202800009220DAA1F002100C00164C6F672072616E6765002053A4A080843B843EC8843DD7 +:20282000A630F006A531C9B59002E8888A4884302005A5A97B2087A3A973A0A82097A820D5 +:20284000E9A72056A62056A62000A52085A36838E98120EDA2A96E854BA9A8854C2056A6C5 +:2028600020F5A72000A5A9FF607F5E5BD8AA80317217F8067A1238A50B88790E9FF37C2A22 +:20288000AC3FB5863401A27A7F638E37EC823FFFFFC17FFFFFFFFF854D844E2085A3A000A7 +:2028A000B14D8548E64DD002E64EA54D854BA54E854C20B5A320F5A720ADA618A54D69056F +:2028C000854D854BA54E6900854E854C2000A5C648D0E26020DAA84C27A920FA9220DAA16C +:2028E0001008462E20EAA84C16A92081A320B1A920DAA1F00920F1A720ADA64C0AA920559E +:20290000AA20B5A3A9FF6020FA9220DAA1F0F5100A462E201BA9A980852E60A530C9819004 +:202920001520A5A62036A92048AA2000A5204CAA2000A54C7EADA530C97390C82081A32022 +:2029400053A4A980853D853E853B2005A5A95AA0A92097A820D1AAA9FF600985A359E86721 +:20296000801C9D07368057BB78DF80CA9A0E83848CBBCA6E81959606DE810AC76C527F7DE4 +:20298000AD90A182FB62572F806D63382C20FA9220D3A9E64A4C9EA920FA9220D3A9A54AFE +:2029A0002902F00620AAA94C7EAD464A901520C3A92085A32056A6208DA32099A620D0A4A4 +:2029C0004CB7A72081A32056A6A972A0AA2097A84CD1AAA530C998B05F2085A32055AA2096 +:2029E0004EA3A52E853BC63D2005A520E7A620FEA3A534854A053305320531F038A9A085D5 +:202A000030A0008435A531852E1003206CA42003A3207DA32048AA2056A620F5A72000A5AC +:202A2000208DA320EDA720B5A3204CAA2056A620F5A74C00A54CB2A3001741636375726134 +:202A40006379206C6F737400A959D002A95E854BA9AA854C60A963D0F581C91000006F15DA +:202A6000777A6181490FDAA27B0EFA351286652EE0D305848AEA0C1B841ABEBB2B843745B3 +:202A800055AB82D555577C83C0000005810000000020FA92A530C987901ED006A431C0B351 +:202AA0009016A52E10062086A6A9FF6000184578702072616E6765002086A420DAAA208132 +:202AC000A3A9E4854BA9AA854C20B5A3A54A2012AB20F1A72056A6A9FF60A9E9A0AA20971F +:202AE000A8A9FF60822DF854580783E020865B82805393B883200006A1820000216382C036 +:202B0000000002828000000C81000000008100000000AA1009CA8A49FF4820A5A6684820C1 +:202B200085A32099A668F00A38E901482056A64C25AB6020E392A62AA98020F4FF8A4CEA49 +:202B4000AE20DD922094BD20AE8A2056AE20F092A52A48A52B4820EABD68852D68852CA2DE +:202B60002AA90920F1FFA52E30334CD8AEA98620F4FF8A4CD8AEA98620F4FF984CD8AE20F7 +:202B8000DAA1F01E101A301520ECADF05930F0A52D052C052B052AF00CA52D10034CC4AC1C +:202BA000A9014CD8AEA9406020FEA7A069A9A8D00720FA92A068A9AA844B854C2056A6A9EE +:202BC000FF6020FA92A06DA9AAD0ED20FEA8E630A86020E392201E8F852A862B842C086807 +:202BE000852DD8A940604C0E8C20ECADD0F8E636A436A90D99FF0520B2BDA51948A51A48B6 +:202C0000A51B48A404A605C884198437D001E8861A8638A0FF843BC8841B20558920299B7B +:202C200020DCBD68851B68851A688519A5276020ECADD067A436A900990006A51948A51AC3 +:202C400048A51B48A900851BA9008519A906851A208C8AC92DF00FC92BD003208C8AC61B3D +:202C6000207BA04C73AC208C8AC61B207BA09003208FAD85274C23AC20ECADF01E101BA50F +:202C80002E0820FEA328100DA53E053F05400541F00320C7A420E7A3A940604C0E8C20ECE3 +:202CA000ADD0F8A536F01DAD00064CD8AE20ADAFC000D0108A4CEAAE20B5BFAAA97F20F42E +:202CC000FF8AF0E6A9FF852A852B852C852DA9406020E392A203B52A49FF952ACA10F7A948 +:202CE000406020299BD0B4E02CD018E61B20B2BD20299BD0A6A901852AE61BE029F013E0A8 +:202D00002CF0034CA28A20B2BD2056AE20F09220CBBDA000A62AD002A201862A8ACA862D83 +:202D200018650485379865058538B10438E52D9021E536901D6900852B20DCBDA000A636D1 +:202D4000F00BB137D90006D010C8CAD0F5A52A4CD8AE20DCBDA900F0F6E62AC62BF0F6E6C4 +:202D600037D0D9E638D0D54C0E8C20ECADF0F83006242D301E103320DAA1100D300520DA2A +:202D8000A1F006A52E4980852EA9FF602002AEF0D630EB38A900A8E52A852A98E52B852BF5 +:202DA00098E52C852C98E52D852DA94060208C8AC922F015A200B1199D0006C8E8C90DF069 +:202DC00004C92CD0F1884CE1ADA200C8B119C90DF017C89D0006E8C922D0F1B119C922F022 +:202DE000EACA8636841BA900604C988EA41BE61BB119C920F0F6C92DF092C922F0CBC92BDE +:202E0000D003208C8AC98E9007C9C6B0364CB18BC93FB00CC92EB012C926F051C928F036FA +:202E2000C61B20DD95F0094C2CB3207BA0901460A5282902D00DB00B861BAD4004AC4104A9 +:202E40004CEAAE001A4E6F2073756368207661726961626C650020299BE61BE029D002A816 +:202E600060001B4D697373696E67202900A200862A862B862C862DA41BB119C9309023C94E +:202E80003A900AE937C90A9019C910B0150A0A0A0AA2030A262A262B262C262DCA10F4C871 +:202EA000D0D78A1005841BA94060001C4261642048455800A22AA000A90120F1FFA940604D +:202EC000A900A4184CEAAE4C43AEA900F00A4C0E8C20ECADD0F8A536A000F00EA41BB11960 +:202EE000C950D0E3E61BA512A413852A842BA900852C852DA94060A51E4CD8AEA500A40105 +:202F00004CEAAEA506A4074CEAAEE61B2056AE20F092A52D3029052C052BD008A52AF04C5D +:202F2000C901F04520BEA22051BD2069AF207EBD2006A62003A320E4A3202292A94060A259 +:202F40000D2044BEA940851160A41BB119C928F0B92087AFA20DB500852AB501852BB502BA +:202F6000852CB503852DA940602087AFA200862E862F8635A9808530B50D9531E8E004D0CF +:202F8000F72059A6A9FF60A020A50F4A4A4A45116A260D260E260F2610261188D0EB60A4B1 +:202FA00009A5084CEAAEA000B1FD4CEAAE20E392A981A62AA42B4CF4FF20E0FF4CD8AE20B7 +:202FC000E0FF8D0006A9018536A9006020299BD062E02CD061E61B20B2BD2056AE20F09268 +:202FE00020CBBDA52AC536B0028536A9006020299BD040E02CD03FE61B20B2BD2056AE2006 +:20300000F09220CBBDA53638E52A9017F017AAA52A8536F010A000BD0006990006E8C8C60A +:203020002AD0F4A9006020ADAF8AC000F094A9008536604C0E8C4CA28A20299BD0F5E02C78 +:20304000D0F420B2BDE61B20DD92A52A48A9FF852AE61BE029F00AE02CD0DB2056AE20F030 +:203060009220CBBD68A818F006E536B0C18898852CAAA000A53638E52CC52AB002852AA538 +:203080002AF0ABBD0006990006C8E8C42AD0F48436A90060208C8AA0FFC97EF004A000C66E +:2030A0001B984820ECADF017A8688515AD0304D008853720F99EA9006020DF9EA900604CB1 +:2030C0000E8C20DD922094BD20AE8A2056AED0EF20EABDA436F01EA52AF01DC62AF016A2F8 +:2030E00000BD0006990006E8C8F010E43690F2C62AD0EC8436A900608536604C039C6885C0 +:203100000C68850B001D4E6F207375636820A42FF200A518850CA900850BA001B10B30DE27 +:20312000A003C8B10BC920F0F9C9DDF00FA003B10B18650B850B90E2E60CB0DEC8840A2012 +:20314000978A98AA18650BA40C9002C818E900853C98E900853DA000C8E8B13CD137D0CD93 +:20316000C439D0F4C8B13C202689B0C18AA8206D9820ED94A201203195A000A50B9102C86D +:20318000A50C91022039954CF4B1001E4261642063616C6C00A9A48527BA8A186504202E1F +:2031A000BEA0008A9104E8C8BD00019104E0FFD0F59AA52748A50A48A50B48A50C48A51B95 +:2031C000AA186519A41A9002C818E901853798E9008538A002205B95C002F0AE861B8884DC +:2031E00039205B94D0034C12B1A000B12A850BC8B12A850CA90048850A20978AC928F04D77 +:20320000C60AA51B48A51948A51A4820A38B68851A68851968851B68F00C853F200BBE2035 +:20322000C18CC63FD0F668850C68850B68850A68A000B104AA9AC8E8B1049D0001E0FFD0DB +:20324000F598650485049002E605A52760A51B48A51948A51A48208295F05AA51B850A68F9 +:20326000851A68851968851B68AAA52C48A52B48A52A48E88A48200DB320978AC92CF0CDBA +:20328000C929D031A90048208C8AC928D02720299B2090BDA527852D2094BD68AAE88A4820 +:2032A000208C8AC92CF0E7C929D00A6868854D854EE44DF015A2FB9A68850C68850B001F4E +:2032C000417267756D656E74730020EABD68852A68852B68852C3021A52DF0D98527A237B8 +:2032E0002044BEA5271009207EBD20B5A34CF3B220EABD20B7B44C03B3A52DD0B820CBBDAD +:2033000020218CC64DD0C3A54E484C02B2A42CC004D005A2372044BE202CB3082090BD28FF +:20332000F0073005A2372056AF4C94BDA42C3054F01DC005F01EA003B12A852D88B12A857A +:203340002C88B12AAA88B12A852A862BA94060B12A4CEAAE88B12A853488B12A853388B1F9 +:203360002A853288B12A852E88B12A85308435842F052E053205330534F004A52E09808522 +:2033800031A9FF60C080F01FA003B12A8536F016A001B12A853888B12A8537A43688B137C4 +:2033A00099000698D0F760A52BF015A000B12A990006490DF004C8D0F49884366020E392A3 +:2033C000A52A4CC2AFA00084088409A61886388437A60CE007F02AA60B204289C90DD01963 +:2033E000E437A50CE53890192042890900301285092042898508204289E437A50CE538B07B +:20340000D86020C5B38420B1FDD008A9338516A9B48517A516850BA517850C203ABDAA8663 +:203420000AA9DA20F4FFA97E20F4FFA2FF86289A4CA38BF63AE79EF122206174206C696E2F +:203440006520223B9E3AE08BF13AE00D202188A203A52A48A52B488A4820DA9268AACAD088 +:20346000F0205298A52A853DA52B853EA007A205D01D202188A20DA52A488A4820DA92689E +:20348000AACAD0F3205298A52A8544A20CA008689537CA10FA98A237A00020F1FF4C9B8B62 +:2034A000202188205298A42A8884234C9B8B4C0E8C20299B200BBEA539C905F023A527F09C +:2034C000ED100320E4A3A000A52A9137A539F00FA52BC89137A52CC89137A52DC8913760AE +:2034E000A527F0CA300320BEA2A000A5309137C8A52E2980852EA531297F052E9137C8A579 +:20350000329137C8A5339137C8A5349137608537C9809044A9718538A9808539843AA0008B +:20352000C8B13810FBC537F00DC898386538853890ECE639B0E8A000B13830062058B5C8FD +:20354000D0F6A43A60484A4A4A4A2050B568290FC90A900269066930C90DD00B20EEFF4CBB +:2035600028BC2045B5A92048A523C51EB0032025BC68E61E6C0E02251FF00E8AF00B30E519 +:203580002065B52058B5CAD0F760E60A201D9B204C9820EE92A52A851F4CF68AC8B10BC9DB +:2035A0004FF0E7A900853B853C20D8AE20DF97082094BDA9FF852AA97F852B289011209757 +:2035C0008AC92CF01320EABD2094BDC60A100C20978AC92CF002C60A20DF97A52A8531A58D +:2035E0002B8532205798206FBE20EABD207099A53D850BA53E850C901688B0062025BC20B2 +:203600006D98B10B852BC8B10B852AC8C8840AA52A18E531A52BE53290034CF68A202399C9 +:20362000A2FF864DA9012077B5A63BA9022077B5A63CA9042077B5A40AB10BC90DF0BDC9B7 +:2036400022D00EA9FF454D854DA9222058B5C8D0E8244D10F6C98DD00F20EB97840AA90061 +:203660008514201F994C37B6C9E3D002E63BC9EDD006A63BF002C63BC9F5D002E63CC9FD29 +:20368000D006A63CF002C63C200EB5C8D0AB00204E6F20E30020C995D009A626F0F0B0378E +:2036A0004C2A98B0FBA626F0E5A52ADDF104D00EA52BDDF204D007A52CDDF304F0198A3847 +:2036C000E90FAA8626D0E2002143616E2774204D6174636820E300BDF104852ABDF2048573 +:2036E0002BBCF304C005F07EA000B12A7DF404912A8537C8B12A7DF504912A8538C8B12A1E +:203700007DF604912A8539C8B12A7DF704912AA8A53738FDF9048537A538FDFA048538A537 +:2037200039FDFB04853998FDFC04053705380539F00F985DF7045DFC041004B0049012B0E4 +:2037400010BCFE04BDFF04840B850C2077984CA38BA52638E90F8526A41B840A20978AC915 +:203760002CD03E4C95B62054B3A5261869F4854BA905854C2000A5A52A8537A52B853820C5 +:20378000E9B4A52685271869F9854BA905854C205F9AF0ADBDF5043004B0A690B490A2B030 +:2037A000B04C968B0022E3207661726961626C650023546F6F206D616E7920E37300244E6F +:2037C0006F20B800208295F0DBB0D92094BD20419820B1B4A426C096B0D6A537990005A563 +:2037E00038990105A539990205AA208C8AC9B8D0CCE005F05A20DD92A426A52A990805A5D5 +:203800002B990905A52C990A05A52D990B05A90120D8AE208C8AC988D00520DD92A41B8464 +:203820000AA426A52A990305A52B990405A52C990505A52D990605208098A426A50B990D90 +:2038400005A50C990E051898690F85264CA38B20299B20FD92A526186908854BA905854C83 +:20386000208DA32099A6208C8AC988D00820299B20FD92A41B840AA526186903854BA9058D +:20388000854C208DA34C37B8209AB9205798A425C01AB00EA50B99CC05A50C99E605E6258F +:2038A00090300025546F6F206D616E7920E47300264E6F20E400205798A625F0F2C625BC5B +:2038C000CB05BDE505840B850C4C9B8B209AB9205798A520F003200599A43DA53E840B850F +:2038E0000C4CA38B205798A9338516A9B485174C9B8B20978AC987F0EBA40A88206D98A5E5 +:203900000B8516A50C85174C7D8B0027EE2073796E7461780020978AC985F0D6C60A201D22 +:203920009B20F092A41BC8840AE0E5F004E0E4D0D98A48A52B052C052DD042A62AF03ECA30 +:20394000F01AA40AB10BC8C90DF032C93AF02EC98BF02AC92CD0EDCAD0EA840A209AB96805 +:20396000C9E4F0062077984CD2B8A40AB10BC8C90DF004C93AD0F588840A4C8BB8A40A6820 +:20398000B10BC8C98BF00EC90DD0F50028EE2072616E676500840A4CE39820DF97B01020A8 +:2039A0001D9B20F092A51B850AA52B297F852B207099B0016000294E6F2073756368206CB7 +:2039C000696E65004C0E8C4C2A98840A4C988BC60A20A9BFA51B850A844D20978AC92CD03C +:2039E000E9A54D48208295F0DEA51B850A68854D082094BDA44D20D7FF852728901BA5276B +:203A0000D0C220D7FF8536AAF00920D7FF9DFF05CAD0F7201E8C4CDAB9A527F0A7300CA2AE +:203A20000320D7FF952ACA10F8300EA20420D7FF9D6C04CA10F720B2A320B4B44CDAB96800 +:203A4000684C988B20978AC923F084C986F003C60A18664D464DA9FF854E208A8EB00A20F1 +:203A60008A8E90FBA2FF864E1808064D28664DC92CF0E7C93BF0E3C60AA54D48A54E4820D8 +:203A80008295F0BB68854E68854DA51B850A08244D7006A54EC9FFD017244D1005A93F2081 +:203AA00058B520FCBB8436064D18664D244D701D851BA9008519A906851A20ADAD208C8A67 +:203AC000C92CF006C90DD0F5A0FEC8844E28B00C2094BD2034AC20B4B44C5ABAA900852796 +:203AE00020218C4C5ABAA000843DA418843E20978AC60AC93AF010C90DF00CC98BF0082068 +:203B00009AB9A0012055BE205798A53D851CA53E851D4C9B8B20978AC92CF0034C968B203F +:203B20008295F0F1B00C2050BB2094BD20B1B44C40BB2050BB2094BD20ADAD8527201E8CDD +:203B400018A51B6519851CA51A6900851D4C15BBA51B850AA51C8519A51D851AA000841B3A +:203B6000208C8AC92CF049C9DCF045C90DF00B208C8AC92CF03AC90DD0F5A41BB119301C71 +:203B8000C8C8B119AAC8B119C920F0F9C9DCF01D8A186519851990E2E61AB0DE002A4F755F +:203BA00074206F6620DC002B4E6F20F500C8841B60201D9B204C9820EE92A624F0E8A52AEF +:203BC000052B052C052DF005C6244C9B8BBCA305BDB7054CDDB8002C546F6F206D616E7910 +:203BE00020F57300A624E014B0EC206D98A50B9DA405A50C9DB805E6244CA38BA000A906EA +:203C0000D0072058B5A000A90784378538A9EE8539A920853AA0FF843BC8A2379820F1FF54 +:203C200090064C389820E7FFA900851E60207099B04EA53DE9028537853D8512A53EE9004B +:203C400085388513853EA003B13718653785379002E638A000B1379112C90DF009C8D0F51A +:203C6000E638E613D0EFC8D004E638E613B137911230092081BC2081BC4C5DBC2092BE1850 +:203C800060C8D004E613E638B137911260843B202DBCA007843CA000A90DD13BF072C8D19A +:203CA0003BD0FBC8C8C8843FE63FA5128539A513853A2092BE8537A513853888A506C51227 +:203CC000A507E513B010206FBE2020BD00008620737061636500B139913798D004C63AC6A0 +:203CE0003888986539A63A9001E8C53D8AE53EB0E538A001A52B913DC8A52A913DC8A53FA9 +:203D0000913D2056BEA0FFC8B13B913DC90DD0F7602057982020BDA518850C860B4C0B8BB6 +:203D2000A51285008502A51385018503203ABDA280A9009D7F04CAD0FA60A518851DA506FA +:203D40008504A5078505A900852485268525851C60A50438E905202EBEA000A5309104C84F +:203D6000A52E2980852EA531297F052E9104C8A5329104C8A5339104C8A534910460A50426 +:203D800018854B69058504A505854C6900850560F02030BDA50438E904202EBEA003A52D2A +:203DA000910488A52C910488A52B910488A52A91046018A504E536202EBEA436F008B9FFD5 +:203DC00005910488D0F8A536910460A000B1048536F009A8B10499FF0588D0F8A000B10481 +:203DE00038650485049023E60560A003B104852D88B104852C88B104852B88B104852A18B2 +:203E0000A504690485049002E60560A237A003B104950388B104950288B104950188B10479 +:203E2000950018A5046904850490DFE605608504B002C605A405C4039007D004C502900143 +:203E4000604CB78CA52A9500A52B9501A52C9502A52D9503601898653D853D9002E63EA00D +:203E6000016020DDBEA8A9FF843DA23720DDFFA5188513A0008412C888B112C90DD01FC815 +:203E8000B112300CA003B112F014182093BED0E8C81898651285129002E613A0016020CF77 +:203EA000BF0D4261642070726F6772616D0DEA4CF68AA9008537A9068538A436A90D99005A +:203EC000066020D2BEA200A00620F7FF4C9B8B4C0E8C201D9BD0F820B2BE4C4C9820D2BE06 +:203EE000888439A518853AA98220F4FF863B843CA90060206FBEA5128545A5138546A9231C +:203F0000853DA980853EA518854220DDBE863F844086438444864784488541A8A23720DDBD +:203F2000FF4C9B8B2062BE4CF38A2062BE4C14BD20A9BF4820139820EE9268A8A22AA901E9 +:203F400020DAFF4C9B8B38A9002A2A4820B5BFA22A6820DAFFA9406020A9BF4820AE8A2027 +:203F6000499820EE9268A8A52A20D4FF4C9B8B20B5BF20D7FF4CD8AEA940D006A980D00266 +:203F8000A9C04820ECADD00E20BABEA200A0066820CEFF4CD8AE4C0E8C20A9BF205298A4B6 +:203FA0002AA90020CEFF4C9B8BA50A851BA50B8519A50C851A208C8AC923D00720E392A4B0 +:203FC0002A9860002D4D697373696E67202300688537688538A000F00320E3FF204B891093 +:203FE000F86C37002057982025BCA001B1FDF006200EB5C8D0F64C9B8B00526F67657200EF +:00000001FF diff --git a/Acorn - Electron_MiST/rtl/roms/os100.hex b/Acorn - Electron_MiST/rtl/roms/os100.hex new file mode 100644 index 00000000..670b711e --- /dev/null +++ b/Acorn - Electron_MiST/rtl/roms/os100.hex @@ -0,0 +1,514 @@ +:020000040000FA +:20000000000000000000000018181818180018006C6C6C000000000036367F367F36360000 +:200020000C3F683E0B7E180060660C1830660600386C6C386D663B000C18300000000000FE +:200040000C18303030180C0030180C0C0C18300000187E3C7E1800000018187E18180000CE +:2000600000000000001818300000007E00000000000000000018180000060C1830600000B8 +:200080003C666E7E76663C001838181818187E003C66060C18307E003C66061C06663C00A6 +:2000A0000C1C3C6C7E0C0C007E607C0606663C001C30607C66663C007E060C18303030006A +:2000C0003C66663C66663C003C66663E060C38000000181800181800000018180018183054 +:2000E0000C18306030180C0000007E007E00000030180C060C1830003C660C181800180058 +:200100003C666E6A6E603C003C66667E666666007C66667C66667C003C66606060663C0033 +:20012000786C6666666C78007E60607C60607E007E60607C606060003C66606E66663C007B +:200140006666667E666666007E18181818187E003E0C0C0C0C6C3800666C7870786C660033 +:200160006060606060607E0063777F6B6B6363006666767E6E6666003C66666666663C005C +:200180007C66667C606060003C6666666A6C36007C66667C6C6666003C66603C06663C001F +:2001A0007E181818181818006666666666663C0066666666663C180063636B6B7F7763004A +:2001C00066663C183C6666006666663C181818007E060C1830607E007C60606060607C00B3 +:2001E000006030180C0600003E06060606063E00183C66420000000000000000000000FFB0 +:200200001C36307C30307E0000003C063E663E0060607C6666667C0000003C6660663C0050 +:2002200006063E6666663E0000003C667E603C001C30307C3030300000003E66663E063C36 +:2002400060607C66666666001800381818183C0018003818181818706060666C786C6600FA +:200260003818181818183C000000367F6B6B630000007C666666660000003C6666663C00E6 +:2002800000007C66667C606000003E66663E060700006C766060600000003E603C067C0027 +:2002A00030307C3030301C000000666666663E0000006666663C18000000636B6B7F36006C +:2002C0000000663C183C660000006666663E063C00007E0C18307E000C18187018180C00D8 +:2002E00018181800181818003018180E18183000316B460000000000FFFFFFFFFFFFFFFFC6 +:200300004C12CB0D41636F726E20456C656374726F6E2000080D0D001122334455667788B2 +:2003200099AABBCCDDEEFF0055AAFF8BB51C272E358B4B3EE26AD9F65E132C6CA5C441F66D +:2003400021ECF23886028B74A11625ABC41FC5C5C5C5C4E6C5C5C6C5C6C7C5C5C74F4E5BCC +:20036000C7C55F57786BCAC43C7CC74ECA00000280050007800A000C800F001180140016C5 +:200380008019001B801E0020802300258028002A802D002F8032003480370039803C003EA5 +:2003A0008041004380460048804B004D801F1F1F181F1F184F27134F271327081020080847 +:2003C0001008AA55884422118040201008040201030F0101030100FF0000FFFFFFFF0000F5 +:2003E000FF000FF0FF00030C0F30333C3FC0C3CCCFF0F3FCFF0703010007030000000102F0 +:2004000002030304000602504028203040586040809DD295D2818B5962D2D2D2D204050614 +:20042000000102FFF00F0011224488183C3C7E7E007E3CAE6A02D05424D0501620E2C420F8 +:20044000C1CC300EC90DD00AA9BD2030C54E5F03A90DC97FF011C920900F24D0300620DF46 +:20046000CE20E2C54CD8C4A920A8B92BC38D5D03B94CC3304AAA09F08D6A028A4A4A4A4A6A +:200480001869C38D5E0324D0701F18609D2402E88E6A02D01724D030157005205FD218602C +:2004A00020E2C420C1CC205FD220DFC41860AC5E03C0C4D0F7AAA5D04A90D08A4CAEDE8D2D +:2004C0005E0398C908900649FFC9F249FF24D0302608205FD2289003A5D04A24D050AC2044 +:2004E000C1CC0848A218A064201ACD2042CEA5D0490285D06828604906D004A97F90319089 +:2005000003A5D04A60A5D029206020DED620FBDE4CDED6A0008C6902A904D007200AC5A91B +:2005200094499505D0D00B200AC5A90A492F49DB25D085D060AD6103F0FAA920D0E5200513 +:20054000C5D05ACE1803AE1803EC0803301EA5D638ED4F03AAA5D7E900CD4E03B0036D5422 +:200560000386D6100438ED540385D760AD0A038D1803CE69021003EE6902AE1903EC0B0305 +:20058000F006CE19034C42CE182096CCA90824D0D00520D1C9D00320DDCC4C28C6A2008653 +:2005A000D9201ED0A6D938BD2403E9089D2403B003DE2503A5D8D01E201ED0F019A6D9BD8D +:2005C0000403E001B002E9069D2403BD0503E9009D25038AF0084CC9D02005C5F094A202E2 +:2005E000D04EA5D02920D046AE1803EC0A03B010EE1803A5D66D4F03AAA5D769004C61C543 +:20060000AD08038D18031820D8CAAE1903EC0903B005EE190390142096CCA90824D0D0057F +:2006200020E1C9D003203BCD20E8CD4C42CEA20086D9201ED0A6D918BD240369089D240305 +:200640009003FE2503A5D8D01E201ED0F019A6D9BD0003E001900269069D2403BD01036950 +:20066000009D25038AF0084CC9D02005C5F097A2024C9FC5AE5503AD2103CD23039076DDDC +:20068000ADC3F002B06FAD2203A8DDB4C3F002B06438ED2003305EA82087CAA9082023C55D +:2006A000A220A00820A1D32024CEB06F60A003B1F09928038810F820DED6A228205AD0A289 +:2006C000282075D7D01BB1D40A26D806D108B00246D828D0F3A5D82D600320DED6A004D01F +:2006E0000CA9FFD0F52D6003AABD6F03C891F0A900C004D0F7602005C5D06EA5D02908D09D +:20070000034C9DCBAE0B038E190320E8CDAE1903EC0903E890F12005C5D032A9008D230374 +:200720008D2203F0052005C5D0CB2046C718AD22036D08038D1803AD2303186D0B038D194A +:20074000032024CE90AFA218A0284C1ACDA206A0262099D3A200A0242099D34CC9D020059A +:20076000C5D0F120AACD4C42CE204DC7AD6103F033AE5A03AC5C0320C4CFA200A0282093B2 +:20078000D338AD0603ED0203A8C88C3003A22CA02820BCD5AD2E03D003CE2F03CE2E03CEB2 +:2007A0003003D0E960A810132D6003087885D8AD4B0329F005D88D4B032898A000F007484A +:2007C00020A5C768A002AA1001C82D600385D8AD600329071865D8AABDDEC3995703C002C1 +:2007E000B00DAD570349FF85D34D580385D260AD220399590360A9008D2203AD6003290774 +:2008000020BFC7A98020BFC7AE60038E1F03E003F01190208E20032041C8CE2003CE1F0353 +:2008200010F560A2078E20032041C84E2003CE1F0310F560A207203EC8A2008E1F038E203B +:2008400003AD2003AE1F03180878290F85FB8A2D6003A8A5FBB003996F03C90890054D488A +:200860000285FB98AE6003E003F01F901C4A4A084A282AAA982CCDC3F001382A0A2906A845 +:20088000C90490094902A8B0040AAAA00086FAA5FB4A20C5C8A5FBC820C5C82860AAC8B120 +:2008A000F0B0A4A5D848AE6003BC6F03C008900E8A489829074D4802382048C868AACA1005 +:2008C000E86885D8602903AABD23C4A6FA3D27C485FCBD27C449FF39040805FC990408AAC3 +:2008E000AD4B032930D0048A9908FE60AD23034C30CBAD1B03C9209045484A4A4A4A4AAA40 +:20090000BDC8C32C6703D0200D67038D67038A29031869BF85DDBD670385DBA00084DA843A +:20092000DCB1DC91DA88D0F968204FCFA007B91C0391DC8810F860AD1F03186C2602C901CB +:20094000F029B0F738AD1C03490AD0EFAD1D0349202960F008207AC9A9EF4C30C5A9104CC9 +:2009600023C5207AC9A0008C5F0360AC1C03F0EDC002F0EE90DFA00AD0ED0878AD4B03099C +:20098000408D4B032860AE6103F0AC4C71CF18AD5F036D4A038D4A03AD4B03303390054983 +:2009A000408D4B032940F007AD6003E904093F85FBA5D02930D019AAAD600385FAA0073828 +:2009C000BD0C0845FB91D6986907A8E846FAD0F060AE5003AD5103204FCCB0146D54039052 +:2009E0000FAE5003AD510320C9CA100438ED54038D51038E5003484A8D03FE8A6A8D02FE40 +:200A00006860A900A22C9D0003CA10FAAE5503BCB4C38C0A032087CABCADC38C0903A00379 +:200A20008C2303C88C2103CE2203CE20032042CE2038CAA9F74C30C52080CAA21CA02C2061 +:200A400028D30D2D033039A220205AD0A21C205AD0AD1F030D1D033027AD2303D022AE55C6 +:200A600003AD210385D8AD200346D86A46D8D0106A4ADDB4C3F0021007A000A21C2093D3FA +:200A8000A210A0284C22CDC898A0008C4D038D4C03AD4F034AF0090E4C032E4D034A90F7FB +:200AA00060A220A00C20A1D34CC9D0203EC52005C5D00985DCA9C085DD4CE2CEA97F204F4A +:200AC000CFAE5A03A0004C94CE488A186D5203AA686D5303602009CB20D1E7900230F6A5E4 +:200AE000D049042946D02AAD69023022AD1903CD0903901A4A4A386D69026D0B03CD0903C2 +:200B0000900C1820D1E73810FAA9FF8D6902EE69026048A27FA90085D09DFF02CAD0FAA273 +:200B2000049D0B08CAD0FA205ECC68A27F8E660320DADA8E550308788DF402AD820229C7C5 +:200B40000DF4028D82028D07FE28BDCFC38D6003BDBBC38D4F03BDF5C38D6103D002A90786 +:200B60000AA8B9C1C38D63030A10FD8D6203BCFBC38C5603B907C48D5403B90BC48D4E035D +:200B8000984A4901AABD0FC48D5203E88E5303A9432030C520F6C72002CA2076C9A200ADC9 +:200BA0004E0320F0C92061C52003CCA9008D69028D18038D1903A206AC4E0394D995D8C89D +:200BC000CACA10F7A8AD580391D891DA91DC91DE88D0F5A20618B5D9690495D93006CACADA +:200BE00010F430E1A9DFD002A9EF08782D4B038D4B032930D00BA007B904089908FE881041 +:200C0000F72860A920D00BF0DFAD55032904D02FA91008780D4B038D4B0328290FAABD6F0C +:200C200003C90890034D480248A0072032CC684AA0062903AABD23C49908FE888810F960BF +:200C4000204FCFA000B1DCC891F0C008D0F760488A38ED5203AA68ED5303CD4E0360A90F1A +:200C60008D6703A90CA0069968038810FAE0079002A2068E4602AD4302A200EC4602B00B12 +:200C8000BC1DC49968036901E8D0F08D4402A8F0CCA2114CA8F0A90224D0D002503EAD091E +:200CA000039003AD0B0370088D190368684C2BC608CD6503F025289004CE650360EE6503BB +:200CC000600848AC4F0388A9FFC01FD002A93F85D8B1D645D891D68810F76828602097CD32 +:200CE000AD09038D19032042CE204FCCB0036D540385D986D885DAB00620AFCD4C0ACD2000 +:200D0000C9CA20C9CA30F22074CDA5DAA6D885D786D6C6DCD0D3A228A018A902D006A22447 +:200D2000A014A90485D8BD000348B900039D000368990003E8C8C6D8D0EC602097CDAC0BE8 +:200D4000038C19032042CE20C9CA100438ED540385D986D885DA900620AFCD4C66CD20C9C0 +:200D6000CA30F52074CDA5DAA6D885D786D6C6DCD0D5F0A2AE4D03F010A000B1D891D6C83F +:200D8000D0F9E6D7E6D9CAD0F2AC4C03F00888B1D891D698D0F8602016CD38AD0903ED0B6B +:200DA0000385DCD00568684C16CDAD08031070A5D84838AD0A03ED080385DDAC4F0388B17B +:200DC000D891D68810F9A20218B5D66D4F0395D6B5D76900100438ED540395D7CACAF0E875 +:200DE000C6DD10D76885D860AD18034820AACD2042CE38AD0A03ED080385DAAD5803AC4F21 +:200E0000038891D6D0FB8A186D4F03AAA5D76900100438ED540386D685D7C6DA10DD688D5B +:200E200018033860AE1803EC080330F6EC0A03F00210EFAE1903EC0B0330E7EC0903F0026A +:200E400010E0AD19030AA8B96DC385D7B96EC3AC530388D00346D76A6D500385D6A5D76D10 +:200E60005103A8AD1803AE4F03E010F00390020A0A0A0A9002C8C80A9002C81865D685D6DD +:200E8000AA986900100438ED540385D71860AE5903AC5B0320C4CF209DD3A00084DAB1DC61 +:200EA000F01385DB100320F4CFEE2403D003EE250306DBD0EFA228A0242099D3AC2603D07C +:200EC00003CE2703CE2603A4DAC8C008D0CEA228A0244CA1D3A22B86DCA2C486DDD003203B +:200EE0004FCFAE6003A5D02920D0A3A007E003F00EB03CB1DC05D245D391D68810F560B19D +:200F0000DC484A4A4A4AAABD17C305D245D391D698186908A868290FAABD17C305D245D355 +:200F200091D698E908A810D76098E92130FAA8B1DC85DA38A90026DAF0EF2A06DA2AAABD17 +:200F400027C305D245D391D618986908A890E50A2A2A85DC29032AAA290369BFA8BDC8C310 +:200F60002C6703F003BC670384DDA5DC29F885DC60A220205ED0AD1F03C904F06DA0052927 +:200F800003F00E4AB00388D008AABC5B03BD5903AA20C4CFAD1F0330230A103B29F00AF02F +:200FA000464940F0144820EDCF684960F011C940D00AA90285DA4C1DD44C00D54C37C9850C +:200FC000DA4CD6D38A19D7C359D8C385DE8A19D6C359DBC385DF600A30E20A0A100320FC58 +:200FE000CF20FED04CEACF20FCCF201ECDA024A2204CA1D3A2242075D7F006602073D7D031 +:2010000013AC1A03A5D125DE11D485D8A5DF25D145D891D460B1D405DE45DF91D460A224C6 +:20102000A00084D8A0022039D006D806D8CACAA0002039D0E8E8A5D860BD0203D90003BDC8 +:201040000303F901033010B90403DD0203B90503FD03031004E6D8E6D860A9FFD003AD1FB0 +:201060000385D8A0022087D020BED0A000CACA2087D0AC6103C003F005B00620BED020BE94 +:20108000D0AD5603D0386018A5D82904F009BD020348BD0303900EBD020379100348BD0396 +:2010A0000379110318991103790D039D03036899100318790C039D02039003FE0303BD0302 +:2010C000030A7E03037E020360A010209FD3A202A00220E6D0A200A004AD6103884AD0FC49 +:2010E000AD5603F001C81E10033E110388D0F73820F4D0E8BD1003FD0C039D10036020242B +:20110000D3AD2B034D2903300FAD2A03CD2803AD2B03ED29034C2BD1AD2803186D2A03AA27 +:20112000AD29036D2B03D0038AF00A6AA2004D2B031002A20286DCBD11C48D5D03BD12C433 +:201140008D5E03BD29031004A224D002A22086DDA02C20A1D3A5DD490485DB05DCAA209716 +:20116000D3AD1F0329100A0A0A85D9A22C2020D085DAF006A94005D985D9A6DB2020D0240B +:20118000DAF00160A6DCF0024A4A2902F0078A0904AA2097D32043D3A5DC4902AAA8AD2905 +:2011A000034D2B031001E8BD15C48D3203BD19C48D3303A97F8D340324D97029BD03C4AA53 +:2011C00038BD0003F92C0385D8BD0103F92D03A4D8AA100320B2D3AAC8D001E88AF002A083 +:2011E0000084DDF0098A4A6A090245DC85DCA22C207AD7A6DAD002C6DBCAA5D9F01F101021 +:201200002C34031005CE3403D023EE34030A100D86DAA22C2075D7A6DA0900D010A5D12574 +:20122000DE11D485D8A5DF25D145D891D438AD3503ED37038D3503AD3603ED3803B0118535 +:20124000D8AD35036D39038D3503A5D86D3A03188D360308B0096C320388100320EAD26C19 +:201260005D03C8C008D0F818A5D46D520385D4A5D56D5303100438ED540385D5A0006C5D7A +:201280000346D190DA2004D36C5D0306D190D02014D36C5D0388100C20EAD2D00746D190FF +:2012A000032004D328E8D004E6DBF00A24D97007B035C6DDD03160A5DC86DA2902AAB019B9 +:2012C00024DC300AFE2C03D010FE2D03900BBD2C03D003DE2D03DE2C038A4902AAFE2C0378 +:2012E000D003FE2D03A6DA4CFAD138A5D4ED520385D4A5D5ED5303CD4E03B0036D54038533 +:20130000D5A00760AD620385D1A5D4690785D49002E6D560AD630385D1A5D4D002C6D5E962 +:201320000885D460A028A220202FD3E8E8C8C838BD0403FD0003990003BD0503FD010399E9 +:20134000010360A5DCD007A228A02A201ACDA228A03720A1D338A6DCAD3003FD2C03A8ADE6 +:201360003103FD2D03300320B2D385DB84DAA235207ED34A9D0103986A9D0003CACABC044D +:2013800003BD0503100C20B2D39D050348989D04036860A908D00CA030A902D006A028A28B +:2013A00024A90485D8BD0003990003E8C8C6D8D0F460489849FFA86849FFC8D00318690194 +:2013C000602073D7D008B1D44D5A0385D8606868EE26034C5CD420C1D325D1D0F3A20020ED +:2013E000A8D4F02DAC1A0306D1B005208AD490212014D3B1D44D5A0385D8D012388A6D61CB +:20140000039004E6D91007AA2015D038B0E2208AD4A00020C2D4A020A2242022CD20C1D3C9 +:20142000A20420A8D48AD002C6D9CA2062D490272004D3B1D44D5A0385D8A5DAD0EDA5D85C +:20144000D012388A6D61039004E6D91007AA2015D038B0DC2062D4A00420C2D420EACF4C65 +:20146000C9D0A5D118900E68E8D004E6D9101646D1B01205D148A5D124D8086845DA482836 +:20148000F0E56845D185D14C01D0A90018900AE8D004E6D910EF0AB00B05D124D8F0F045F5 +:2014A000D14A90E16A38B0DDBD000338ED2003A8BD0103ED2103300320B2D385D998AA0572 +:2014C000D96084D88AA8A5D93002A900A6D8D00320B2D34818987D00038D2003687D0103E5 +:2014E0008D210360A90320EBD4A90748201ECD20C9D0A20368A8BD100391F088CA10F760D5 +:20150000A220A03E2093D32048D5A214A024204CD52048D5A220A02A2028D3AD2B038D322F +:2015200003A2282070D3A02E20EFCF201ECD18206ED5201ECDA2202020CD38206ED5A23EF4 +:20154000A0202093D34CEACFA220A014BD0203D90203BD0303F9030330134C22CDAD180322 +:2015600038ED0803AAAD190338ED0B03A86008A220A0352028D3AD36038D3D03A2332070BB +:20158000D3A03920EFCF38AD2203ED26038D1B03AD2303ED27038D1C030D1B03F01720B856 +:2015A000D5A233208AD6A228208AD6EE1B03D0EEEE1C03D0E92890B5A239A02E86DCBD00F2 +:2015C00003D90003BD0103F90103300698A4DCAA86DC84DDB9000348B9010348A6DD2020E7 +:2015E000D0F00DC902D03DA204A4DD2099D3A6DD207AD7A6DC2020D04AD0299002A200A4F2 +:20160000DD38B90003FD000385DAB90103FD010385DBA9000A05D1A4DAD014C6DB1010854B +:20162000D12001D0A6DD689D0103689D000360C6DAAA10E085D12001D0A6DAE8D002E6DB78 +:201640008A4846DB6AAC6103C003F005900646DB6A46DB4AAC1A03AAF00F9838E908A8B04E +:2016600002C6D52015D0CAD0F1682D6103F0B5AAA9000A0D6303CAD0F985D19838E908A87D +:20168000B002C6D52004D04C24D6FE0803D003FE090338BD0003FD02039D0003BD0103FD85 +:2016A00003039D01031030BD0A03300BFE0603D011FE07034CC2D6BD0603D003DE0703DE0B +:2016C000060318BD00037D04039D0003BD01037D05039D010330D06020DED62033C4087853 +:2016E00048A5D02930D027AD600385D8AD4B0349808D4B03A200A00738B1D648BD0C08911F +:20170000D6689D0C08E8986907A846D8D0EB68286020DED6A00784D8A90185D9AD62038503 +:20172000DAB1D64D58031824DAF0013826D9B00A46DA90F3986907A890E2A4D8A5D9992828 +:20174000038810D2A2208A48204FCF68AAA007B92803D1DCD0088810F68AE07FD00DE8A547 +:20176000DC18690885DCD0E58AD0DB20DED6AC5503AA60A2202020D0D06ABD020349FFA819 +:2017800029078D1A03984A4A4A0AA8B96DC385D8B96EC3AC5603F00346D86A6D500385D47E +:2017A000A5D86D510385D5BD010385D8BD0003482D61036D6103A8B9C1C385D168AC610356 +:2017C000C003F005B0060A26D80A26D829F81865D485D4A5D865D5100438ED540385D5AC73 +:2017E0001A03A9006048A9A0AE6A02D04524D0D04120DED67012A218A0642099D320C1CCB1 +:20180000A9022023C50E5F03A9BF2030C568297F2033C4A9402023C54CDED6A92024D05003 +:20182000C1D0BF2011D7F00B4820DED620E2C520DED66860AE55038A2907A8BEFBC3BD0B2A +:20184000C4A200A8607EE033DB47DB89DB14DD44E5BCE52DDE50DCD6F1CCF020F480F4A289 +:20186000FF20F3E8F0A2FFA2FFA2FFA2FFDFEA21E2D2E141DFA2FFA2FFA2FF90019F0DA09B +:2018800002D3ED00030000FF0000000000000000FF040400FF0019191932080000000000F9 +:2018A000FF000000000050000390640681000000001B01D0E0F0010101000000FFFFFF009F +:2018C000000000000000000005FF000A0000000000FFA9408D000D78D8A2FF9AE88E00FE79 +:2018E0008E8D02A9F88D05FEAD00FE2902490248F009AD58024AC901D0184AA20486018539 +:2019000000A89100C8D0FBC8E60110F68D8E028E8402A23A201EEC08680AA29BA08D68F0D3 +:2019200009A07E900FA087EE8D02EE8D02A9FF8D8F02A290A900E0C39002A9FF9D0002E8BB +:20194000D0F48EF7028AA2E29500E8D0FBB944D899FF0188D0F7A90785ED84FC5878A5FC16 +:20196000F00320C2EEAD8F0220DADA09848D82028D07FE8D04FEA20C8E5B028E00FE207618 +:20198000E9AE8402F00320C0E7A200209FE3A203AC0780B90080DD97DCD034C8CA10F4A68B +:2019A000F48AA8C8C010B02B9849FF85FAA97F85FB20A9E38C05FEB1FA20A9E38E05FED193 +:2019C000FAD0E0E6FAD0EAE6FBA5FBC98490E2A6F4100DAD06809DA002298FD0038E4B02F4 +:2019E000E8E01090A6AD8F022000C3A0CA205FE2207BE8208BF0A9818DE0FCADE0FC6A90B9 +:201A000015A9018DE0FCADE0FC6AB00AA2FF20A8F0D003CE7A02A00EA20120A8F0A20220AE +:201A2000A8F08C43028C4402A2FEAC7A0220A8F02D6702101DA0022034DCAD8D02F00EA973 +:201A40000720EEFF20DED620D5CE20DED6A0132034DC38207BE820D1E708684A4A4A4A4DAC +:201A60008F022908A8A20320A8F0F01C98D014A98D20A5E7A209A0F0CE670220F7FFEE6758 +:201A800002D005A90020A7E7AD8D02D005AE8C02101EA20FBDA0022A3016CA10F7A9002C77 +:201AA0007A02303300F94C616E67756167653F0018088E8C02209FE3A980A0082036DC8486 +:201AC000FD20E7FF20E7FFA9008D5D0228A9012C7A0230034C00804C00042907C90790020D +:201AE000A906AA0A0A0A6085FC68482910D0176C0402A6F484F420A9E38C05FEA000B1F6B8 +:201B000048209FE368608A48BABD0301D838E90185FDBD0401E90085FE86F0A20620A8F046 +:201B2000A5F48D4A02AE8C022000DB68AAA5FC586C0202A000203CDCAD67026AB0FE20E774 +:201B4000FF20E7FF4C83DAD8A5FC488A489848A9DB48A98148AC00FE984A9013982D5B02D5 +:201B600029FEAA290C24258A2970F0204CDFF4A20520A8F0F08F686868A868AA6885FC6C9F +:201B8000060268A868AA6885FCA5FC408AA0202908D0328A2904F0D7208EC9AD5102F01BD4 +:201BA000CE5102D016AE5202AD4802F003AE530249078D48028E510220A3C8A0042002E2F4 +:201BC000CE4002A0108C05FEAD8302AA490F48A838BD90026900999002CAF00388D0F26808 +:201BE0008D8302A205FE9A02D008CAD0F8A0052002E2ADB002D008ADB102F006CEB102CEA3 +:201C0000B0022C7802100BEE7802582093E878CE7802AD4202F00BA5EC05ED18F001382066 +:201C200049ECAC4902F005A21520A8F02CC60230144CF9DEA9C385FEA90085FDC8B1FD2009 +:201C4000E3FFAAD0F7608EB0028CB102A9FFD002A90085E68A489848AC5602F0143866EB81 +:201C600020D7FF0846EB289025A9008D560220CEFF24FF3016AE4102202EE3901124E65057 +:201C8000F0ADB0020DB102D0E8B00538A91B85E668A868AAA5E660294328002EDDBA0546B0 +:201CA00058E0B0FF4241534943DDA100434154DDBA05434F4445E0B68845584543F5EA00AC +:201CC00048454C50EED5FF4B4559E095FF4C4F4144DFAA004C494E45E461014D4F544F5214 +:201CE000E0B6894F5054E0B68B52554EDDBA04524F4DE0B68D53415645DFAC0053504F4F15 +:201D00004CDFEF0054415045E0B68C5456E0B690DDBA030086F284F3A90820BADDA000B14B +:201D2000F2C90DF004C8D0F760A0FF20C2DDF070C92AF0F720C3DDF067C97CF063C92FD0E9 +:201D400008C82092DDA902D07184E6A200F0135D9BDC29DFD017C818B023E8B1F22051E2D5 +:201D600090EDBD9BDC3018B1F2C92EF00418A4E688C8E8E8BD99DCF03110F830DBCACA48D8 +:201D8000BD9CDC4820C3DD1808208DDD40BD9DDC300E98BC9DDC1865F2AA98A4F39001C83A +:201DA00060AE4B023004384CB1DAA4E6A20420A8F0F0EDA5E62096DDA9036C1E020A290136 +:201DC00010F8C8B1F2C920F0F9C90D6090F520C3DDC92CD0F4C86020C3DD2006DE90378552 +:201DE000E62005DE9019AAA5E60AB02A0AB02765E6B0230AB02085E68A65E6B01990E0A640 +:201E0000E6C90D3860C8B1F2C93AB00AC9309006290F6020CEDD18602006DEB00E29DFC949 +:201E200047B0F0C94190EC08E93728C860488A489848BABD0301482C60021008A8A90420E5 +:201E400095E3B05918A9022C7C02D005684820D8D6A9082C7C02D0029005684820A4DEAD80 +:201E60007C026A9022A4EA88101D684808782C4F0208A2022068DF28100CA21320A8F0F024 +:201E800005A2022009DF28A9102C7C02D00FAC5702F00A68483866EB20D4FF46EB6868A853 +:201EA00068AA68602C7C027020CD8602F01B0878AAA9042C7C02D0108AA2032068DFB008FF +:201EC0002CC602100320CADE2860AD8502F03AC903B00BA21420A8F0F0EFA203D02B18A918 +:201EE0000120FBDE6EC60260D01CA208587820F4DECA10F8E009901160A900A203AC8502BD +:201F00002095E36C2202AE410218480878B0198A2904F014AD6B02F00C8A48A8A21720A833 +:201F2000F068AAD0032083E9387EC302E002B00BA9008D68028D5D028D6A02200BE5286803 +:201F4000605007BDCC029DD5026008780838BDD502FDCC02B00438FDB5E1289006187DB5C5 +:201F6000E149FFA000AA286078201EE2900D20E5E73008482050E96858B0ED6048A9009D21 +:201F8000E2029DE3029DE4029DE502686084E62A2A2A2AA0042A3EE2023EE3023EE4023E85 +:201FA000E502B03188D0EEA4E660A9FF86F284F38EE2028CE30248A202207CDFA0FF8CE835 +:201FC00002C820FCE7200EE890FB6848F062201BE0B03BF03E00FC4261642061646472653A +:201FE000737300A21020A8F0F02320E8F5A9000884E6AC57028D5702F00320CEFFA4E628E9 +:20200000F00BA98020CEFFA8F0748D570260D06EEEE802A2E2A002684CDDFF20C3DD201899 +:20202000DE900C207CDF208DDF2018DEB0F83860A20A201BE09047B8B1F2C92BD0042CBC20 +:20204000D8C8A20E201BE0903508500FA2FC18BDF0017DF4019DF401E8D0F4A203BDEC0285 +:202060009DE8029DE402CA10F428F0A7A206201BE0900BF09EA202201BE09002F09500FE09 +:2020800042616420636F6D6D616E6400FB426164206B65790020D7DD90F1E010B0ED20CEFF +:2020A000DD08AE100B9848203FE168A828D0366020D7DD90C98A48A90085E585E420CCDD70 +:2020C000F01820D7DD90B786E520CEDDF00C20D7DD90AB86E420C3DDD0A4A4E4A6E5682063 +:2020E000F4FF709A603820FDE7200EE8B008E8F09A9D000B90F3D0930878203FE1A210E423 +:20210000E6F00EBD000BD9000BD006AD100B9D000BCA10EB28600878AD100B38F9000B8593 +:20212000FB8A48A210BD000B38F9000B9008F006C5FBB00285FBCA10EC68AAA5FB28600894 +:20214000788A48A4E62016E1B9000BA81865FBAA85FAAD6802F00D00FA4B657920696E2039 +:2021600075736500CE84026838E5FA85FAF00CBD010B99010BC8E8C6FAD0F49848A4E6A216 +:2021800010BD000BD9000B9007F005E5FB9D000BCA10EEAD100B99000B688D100BAAEE840F +:2021A000022860030A080707070707090000C0C05060708000E00040C0F0F0F0F0C0BDAC6B +:2021C000E185FABDA3E185FB602CBCD87001B86C2C020878BDCC02DDD502F072A820BEE173 +:2021E000B1FA701A48C898D003BDB5E19DCC02E002900ADDD502D005A0002002E268A82890 +:20220000186008784885FAB9B502F04198A4FA20E2E76828186098A0022002E2A8986C2A23 +:2022200002087848BCD502C8D003BCB5E198DDCC02F00FBCD5029DD50220BEE16891FA2831 +:20224000186068E002B007A0012002E248682838604829DFC9419004C95B9001386860A2AB +:20226000008A2D4502D0B6984D6C020D7502D0A6AD58026A98B00AA0062002E290032080ED +:20228000E41860C9A09005AD7302B003AD7202F0214AD031A5F448AD8C02301920A0E3ADDD +:2022A00006802910F00FA9032000808C5D026820A0E34C33E3B989EE8D5C02B9A9EEA8B0F9 +:2022C000EA6A68B0BC98484A4A4A4A4904A8B96502C901F07E68900D290F187965021860D4 +:2022E000204BE668AA20CEE1B066E001D005AC4502D05CA81059C9909004C9B09085290FFD +:20230000C90B90C1697B48AD7D02D0B5AD7C026A6A68B0D1C987D00D8A48201BD8A8F0C069 +:2023200068AA981860A88A489820E5D768AA2C5F0230608A2D4502D0ACAD5D02D027AD68CC +:2023400002F0A2AC7902B9010BEE7902CE680218B0466068290FA82016E18D6802B9000BD4 +:202360008D7902D0C9AAA5F448AD8C02301920A0E3AD06802910F00FA902200080CE5D0227 +:202380006820A0E3981860AC5C02B959EFA8EE5C02D0EAA9066C2402482050E96838608AFD +:2023A00085F420A9E38D05FE6048A90C8D05FE6860F2E580E732E58FE78FE767E780E73885 +:2023C000E538E59CE49EE48DE784E7C2E4C3E4E8DE38E538E5C0E7AEE75ECCF4DE64E41439 +:2023E000EF38E507CC76E948E6D1E7E3DF10F051EC4FECE4DE7FE480E468E4BEDD11E5D049 +:20240000E4EBE4DDEF34D837D85DD511D75FE48AE41DE2BDDDA5E7A5E7B1DAA8F089E8CE44 +:20242000E18FE88AE8A8FFA3FF32F085E8C9E161E2E8EEA2FF38E5B3FF38E538E5B8E7945A +:20244000E761E4F3E6C6E6D9E6C2E6D5E6D4E5DCE5FEE57FE6ADC640CCE5C69DC8E4D4A9F7 +:20246000006C0002EE490260A20024FF1011AD7602D00A588D690220EAF520EADEA2FF1880 +:2024800066FF2C7A0210E04C0304AD820229BFE000F00209408D82028D07FE60C818B952CA +:2024A00002488A99520268A8AD5102D0138E5102A9009002A9078D4802984820A3C868A84A +:2024C000500B98E00AB007BCB5029DB50298AA6098300B582046DCB003AAA900A8608A29D1 +:2024E0000FF0118A497FAA204CEC2AA2FFA0FFB002E8C8608AF0072038E518D0EE60A201B5 +:20250000D0D88A49FFAAE002B850032CBCD86C2E0230EFF00D2038E5F007BCFB02BDF7028F +:20252000AA602038E5F002A200ACF702A9008DF702608A0D4102F0BBA20720A8F0A6F0A46C +:20254000F149006048087885EF86F084F1A207C9739040C9A19009C9A6903E18A9A16900FA +:20256000E9590A3884F1A82C5E0210078AB82095E3701AB9B2E385FBB9B1E385FAA5EFA4E1 +:20258000F1B004A000B1F038A6F020BFEE6A282A68B860A000C91990C90808686820A8F00B +:2025A000D005A6F04C8DE528682CBCD860A5EB3032A90825E2D004A98825BB604808788506 +:2025C000EF86F084F1A208C9E0B091C90EB0CA69490A909020E6E5A1FA91F06020E6E5B15D +:2025E000F081FAA9006085FAC8B1F085FBA004A20060D0FB00F74F5320312E303000AD6207 +:2026000002D047AD6B02D005C8B1F0C920A208B08A88B1F020A4E620BAE60904AA9005207D +:202620000ADFA00120BAE685FA08A006B1F048A004B1F048A002B1F02A38E9020A0A05FA0A +:202640002068DF902C686828A6D060AD6202D0FAAD6B02F005A2164CA8F00878AD63022051 +:20266000A4E6AAAD6402201EE2AD660248AD650248386E140868201EE268201EE22860AE32 +:202680006202D0C6AE6B02D084E9010A0A0A0A090FAAA900A010C00EB002B1F09DC008CA54 +:2026A00088D0F36029030904CD2508F00C4818AE25088D2508200ADF6860B1F0C9102903D4 +:2026C000C860A20FD003AE8302A004BD8C0291F0E88810F760A90FD006AD8302490F18485C +:2026E000AAA004B1F09D8C02E88810F768B0E58D830260A004B1F099B00288C002B0F6B1A9 +:20270000F085E9888C6902B1F085E8589007A90788C820EEFF20E0FFB049AAAD7C026A6A31 +:202720008AB005AE6A02D0EAC97FD007C000F0E588B0DFC915D00D98F0DBA97F20EEFF88E0 +:20274000D0FAF0D191E8C90DF013CCB202B0BFCDB30290BECDB402F0B890B6B0B520E7FF01 +:202760002095E3A5FF2A60587824FF30372CC60210F520FDDEA00084F186F02038E5A905CF +:2027800009F0D00ED007A2328E5402A20869CF1869E986F0A8B99001AA25F145F099900100 +:2027A000B99101A860498C0A8D47024C94F0AD40025878CD4002F0F9BC0103BD0003AA6000 +:2027C000A9108D8402A2009D000BE8D0FA8E8402600878A94020E5E7300518B8204CEC28E3 +:2027E0002A606C2002901248AD820209808D07FE297F8D82028D07FE6824FF601866E420D3 +:20280000C3DDC8C922F002881866E4C90D60A90085E5B1F2C90DD00624E43052101BC92053 +:20282000904CD00624E43040500FC922D01024E41036C8B1F2C922F02F20C3DD3860C97CE4 +:20284000D026C8B1F2C97CF01FC922F01BC921D005C8A980D0BAC9209014C93FF00820F3F3 +:20286000EF2CBCD87003A97FB8C805E5186000FD42616420737472696E6700AD8702494CA6 +:20288000D0074C8702989D00FE60989D00FC60BC00FC60AD6B02D005AD1408D00160AE2594 +:2028A00008BDC3023005AD1B08D0032093E9AD1B08F011C9FFF010CE1C08D00B2001EACEDB +:2028C0001B08D0032093E9AC1D08C0FFF05FAD1E08F005CE1E08D055AD1908C903F04EB915 +:2028E000C008297F8D1E08AD1A08D02AEE1908AD1908C903D010AC1D08B9C008302FA90009 +:202900008D1908201FEAAD1908186D1D08A8B9C4088D1A08F017CE1A08AD1D08186D19081D +:20292000A8B9C108F007186D1F08201FEAA5EA0D6202D0410878AD820229F90D2008CD8239 +:2029400002F0068D82028D07FE28AD21088D06FEAD2208F020A5EAD01C8A48EE2408AE242D +:2029600008BD93E8AE92025D9AE82D22080D23088D06FE68AA60A2048E25082083E9E8E0AF +:2029800007D0F8A9008D1B089DC3028D14082014EAF09AAE25082014EABDC302F008A90040 +:2029A0009DC3028D1B0820C9E1B05C087820CEE1482904F00E682014EA20CEE120CEE12821 +:2029C0004CFEE9A9028D20086829F80A900BC9F0D005A9008D2008A9FF8D1D08A0018C1EA5 +:2029E00008888C1A088C1F08888C190820CEE18D180820CEE12848AD18082026EA688D1BE9 +:202A000008A9058D1C0860087820C9E19005A9008D140828A9008D2008A9008D2208608DEB +:202A20001F08186D1808482903AAAD2508C904D018682904F00BBD8AEA8D2308BD2DEDD0FD +:202A4000DABD8EEA8D2108D0D0E8A9008D2108684A4AC90C9007EE2108E90CD0F5A8AD211B +:202A60000848B97EEAC007E902CAD0F98D210868A8F0064E210888D0FACE2108D09B00F0C9 +:202A8000E3D6CBBFB5AAA0978F874080C0803B76F076A9EF85F560E6F5A4F5A20D0820A8CB +:202AA000F028C9019860A20EA0FF4C9DEAADCB0385F6ADCC0385F7A5F560A2FF8E420208B7 +:202AC000AD8202297F48A9102C5A02D0046809804868CD8202F0068D82028D07FE6860501D +:202AE00008EE4202B0084C06EC90034C53ECAD5A02291FA23B201EEC8E7702B810052CBC74 +:202B0000D80940CA201EEC90B610020980CA201EEC100209208D5A02A6ECF012201EEC30B9 +:202B200010E4EC86ECD007A20086EC2013EC4CDDEBE4ECD0EEA5E7F026C6E7D022ADBF02E8 +:202B400085E7AD55028DBF02AD5A02A6ECE0B9D0112C7702100249308D5A02A90085E74C28 +:202B6000DDEBBD4FEDAE5A028E7702AAC9219054C926B011A9C02C7702F004A4EDF00618BA +:202B80008A696AD03EAD77024910F0382E77029009A4EDD096BD99EEB0292E7702900AA4EA +:202BA000EDD088BDB7EFAAB00A2E77029008BD0BF0B0102E77022E7702B0088A2051E2B0BF +:202BC000024920AA8ACD6C02D007AE7502D00286E7A82034EDAD5902D003205FE2A6EDF038 +:202BE0000B201EEC86ED3004A20086EDA6EDD016A0EC2076ED300C2050E9A5EC85ED86EC52 +:202C00002013EC4CBAEAA5ECD0F9A0ED2076ED30F210EBA20186E7AE54028EBF0260F02843 +:202C2000488A293F4820F8EC85FCA6F4A90820A0E3082038ED2825FCF002A98085FC209FAE +:202C4000E36805FCAA68A4FC602CBCD86C2802A201B0F98A103F297FA82050E9BE40EE20E6 +:202C60001EEC8A60500F2082EC900A2CC002F0054DC002F00CA2FF4AE890FCA9002ACA10DF +:202C8000FC601848A5FA4DC102D008A5FB4DC202D001386860E88A297FAA78A5F448A908A1 +:202CA00020A0E3A9FFA88DC0028EC102AD0080290FF03684FAA29F86FBA2002038ED290F97 +:202CC000F030A0044A901248BD08EECDC1029008CDC002B0038DC00268E888D0E7A5FB4918 +:202CE000C0386A66FA85FBB0D2AEC0026820A0E38A60E8E8E8E810E50848293F4A4AAABD63 +:202D000017ED85FB8DC202BD25ED85FA8DC102682903AABD86F02860BFBFBFBFBFBFBFBF4F +:202D2000BEBDBBB7AF9FFEFDFBF7EFDFBF7FFFFFFFFFFFFF58788A60A4FAC8F00588B9000F +:202D4000BF60A5FBC9BBB016C9AF900CF004ADFFB760A5FFADFFAF60A5FFADFF9F60A5FB51 +:202D6000C9BD9006F00AADFFBE60A5FFADFFBB60A5FFADFFBD60B8B90000F0092CBCD82051 +:202D8000F8EC8DC002A5F448A90885F48D05FEA0FF84FAA2AF86FBAD00A0290FF018203891 +:202DA000ED290FF0052064ECD020A5FB49C0386A66FA85FBB0E8A99F85FBADFF9F2903F0A7 +:202DC000052064ECD004A28030032047F06820A0E38A602321002022240D7F2D253A003017 +:202DE000703B2F396F6C2E38696B2C37756A6D3679686E35746762347266763365646332F2 +:202E00007773783171617A1B704001003010416131215142112232521233436313235364B1 +:202E20003444545524354565152546662636566727375768173948FF192949597969FF6294 +:202E40003B3A0000000000000000000000000000352C28240018000C08080000000000001C +:202E600000312D251C191410090900000000000034302E29201D1511050D00000000000034 +:202E80003936332A211E1A100E0A00000000000000322F2622231612050B000000000000E1 +:202EA0000037072B271F1B171305000000000000380000000000000004045D7E5C7D7B6C3E +:202EC000FA006CFEFD1C1D1E1F003132333435363738393A3BA20920A8F020BAF90D4F53E4 +:202EE00020312E30300D00600878A2008E4802AD53028D510220A3C8286001020304050682 +:202F00000708090A0B0C0D0E0F101112131415161718191ACE4902607F00040C12161A1D00 +:202F20002124292C3135393D41454A4E52565B5E65696F72727276767A0408060404030482 +:202F4000030503050404040404050404040503070406030000040004054155544F52454EF5 +:202F6000554D424552434F4C4F555244524157454C5345464F52474F544F444547494E50D4 +:202F80005554524144434841494E4C4953544D4F44454E4558544F4C440D504C4F544C4FE8 +:202FA00043414C52554E0D535445505448454E554E54494C564455524553544F5245505293 +:202FC0004F43524550454154454E444C4F4144534156455052494E545B5E7C5F60AC440205 +:202FE000A200603C3D3E3F402122232425262728292A2BC97FF0119003492060C960D00257 +:20300000A95FC9409002291F602F21424F4F540D84ECBD40EE85ED60414243444546474883 +:20302000494A4B4C4D4E4F505152535455565758595ABC00FE607FACADAEAF8081828384FC +:203040008586878889AAABA2FFE84A90FC86FCA5FA49FFF00DA200E84A90FC8A0A0A05FCB4 +:20306000AA60A5FB293F493FA208D0EB909192939495969798999A9B9C9D9E9FA0A1A2A353 +:20308000A4A5A6A7A8A9010204087FA9A185E3A9198DD103A90620BADDA20EBD56D89D1137 +:2030A00002CAD0F786C2A20FA5F4488AA20FFEA002DEA002100D48209FE368200380AAF09C +:2030C00005A6F4CA10E86820A0E38A60C000D0090900D005AD4702090160A3F477F55AF274 +:2030E0007DE05AF280F2E2DFC907B0ED86BC0AAABDDBF048BDDAF048A6BC6008482082FA44 +:20310000ADC20348208BF568F01AA203A9FF48BDBE0395B06835B0CA10F4C9FFD006205959 +:20312000FA4CD5DFADCA034A68F00E90132063FA00D54C6F636B6564009005A9038D5802FC +:20314000A93025BBF004A5C1D00A9848205CFB68A82035F72024F9D05320FAFA2CCA033032 +:203160000820DAF820DBF6D0D7A002B9BC0391C8C8C00AD0F6ADC80391C8C8ADC903186D5B +:20318000C60391C8C8A9006DC70391C8C8A90091C8C8B9BD0391C8C8C012D0F6282059FAAD +:2031A00024BA30070820B6F90D0028602091F5D08F7886F284F3A00020FCE7A200200EE8C7 +:2031C000B00DF0089DD203E8E00BD0F14C6EE8A9009DD20358604886C884C9A000B1C8AA19 +:2031E000C8B1C8A820B1F1A002B1C899BC0399AE00C8C00AD0F368F007C9FFD0D84CFBF00F +:203200008DC6038DC703B1C899A600C8C012D0F68AF0B92082FA2093F8A900205EFB38A273 +:20322000FDBDB7FFFDB3FF9DCB02E8D0F4A8D00EECC803A901EDC9039004A280D008A90181 +:203240008DC9038EC8038ECA03204CF7308720DAF8EEC603D0C8EEC703D0C320B1F1A2FF58 +:203260008EC20320FBF02C7A02100AADC4032DC503C9FFD0036CC203A2C2A003A9044C6891 +:20328000FBA908209AF22082FAA900209EF2206DFAA9F725E285E260A94005E2D0F748AD60 +:2032A0004702F00B2092EA2097EA9003B8504120DBF6ADC60385B4ADC70385B5A2FF8EDF52 +:2032C00003E886BAF00620FAFA20DBF6AD4702F002501D6848F02D20E2F9D016A93025BB0C +:2032E000F00EADC603C5B6D009ADC703C5B7D0026860AD4702F00D20ADEAA9FF8DC6038D44 +:20330000C703D0C25005A9FF2037F7A2002049F9AD4702F00424BB50DE2CCA0330DC10A650 +:2033200085BC8A489848A5BCD01E98D00C20E3DF20CEF346E206E2900C4AB0F74AB0034C2E +:2033400043FB20CEF34CC7F320B1F124BC503DA9008D9E038DDD038DDE03A93E2093F220BB +:2033600075FA08208BF52011F628A2FFE8BDB2039DA703D0F7A901209AF2ADDE020DDF020D +:20338000D0032098F2A9010D4702D0398AD0034C6EE8A2FFE8BDD2039D8003D0F7A9FFA25C +:2033A000089D8B03CAD0FA8AA2149D8003E8E01ED0F82E97032082FA2093F82063FAA90201 +:2033C000209AF2A90285BC68A868AAA5BC60A90225E2F0F9A9008D9703A980AE9D038E966C +:2033E000038D980320ECF3A9FD4C93F22075FA20C9F8A211BD8C039DBE03CA10F786B286D0 +:20340000B3A90085B0A90985B1A27F2012FB8DDF03201FFB204CF7EE9403D003EE9503609B +:203420008A489848A901202DFBA5E20AB04C0A9009A980209AF2A9FEB038AE9E03E8ECDE53 +:2034400002D02A2CE0023022ADE102482075FA082009F6286885BC182CE0021017ADDE02D7 +:203460000DDF02D00F2098F2D00A2098F2CA18BD000A85BCEE9E034CC7F300DF454F460019 +:2034800085C48A489848A902202DFBAE9D03A5C49D0009E8D00620ECF32063FAEE9D03A574 +:2034A000C44CC5F38AF02EE003F01FC003B006CAF006CAF00A4C7EE0A933C8C8C8D002A954 +:2034C000CCC825E319D8F485E360983002D002A9198DD10360A8F0ECA10022110088CCAA2E +:2034E000C6C0AD4702F00720A6EAA818901C8A482920F00BA4CAF00768A5BD8D04FE60AC5D +:2035000004FEA9408D05FE680A0AA6C2F069CAD0069064A002D05ECAD013B05B982009FB1B +:20352000A003C92AF04F20CDFAA001D048CAD00CB00484BDF041A98085C0D03BCAD029B05E +:203540002F982010F7A4BCE6BC24BD300D204DFBF0058EE5FCD0038A91B0C8CCC803D017AD +:20356000A90185BCA005D00D982010F7C6BC100720B0FAA00084C2604898488AA8A9032050 +:203580002DFBA5E22940AA68A86860A90085B485B5A5B44885B6A5B54885B720B6F9536534 +:2035A00061726368696E670D00A9FF209EF26885B56885B4A5B605B7D02885B485B5AD4711 +:2035C00002F0167014206DFA00D646696C65206E6F7420666F756E6400A5C1D005A2B12027 +:2035E00012FBA0FF8CDF0360A9000884E6AC56028D5602F00320CEFFA4E628F00BA94020B7 +:20360000CEFFA8F0C08D560260A2A62012FB20DBF6ADCA034A90034C2DF1ADDD0385B4ADA6 +:20362000DE0385B5A90085B0A90A85B1A9FF85B285B32035F72024F9D025ADFF0A8DE102ED +:2036400020FAFA8EDD038CDE03A202BDC8039DDE02CA10F72CE002100320A0F14C63FA2066 +:2036600091F5D0ADA9F72093F2206DFA00D742616420524F4D00C92AF028C923D0E6EEC62E +:2036800003D003EEC703A2FF2CBCD8D046A0FF2021FBA90185C220CDFA2005F9A903C5C221 +:2036A000D0F7A000200DFB20F7F6501A99B203F006C8C00BD0F188A20C20F7F650089DB282 +:2036C00003E8E01FD0F398AAA90099B203A5BE05BF85C12009FB84C28AD059AD4702F0ADE7 +:2036E00020A6EAC92BD08FA90825E2F00320A4F12097EA90EBB860AD4702F0118A4898488A +:2037000020A6EA85BDA9FF85C068A868AA20E5F708483866CB45BF85BFA5BF2A900C6A49CE +:203720000885BFA5BE491085BE3826BE26BF46CBD0E7682860A90085BDA20086BC500AADAF +:20374000C8030DC903F002A20486C26008A203A9009DCB03CA10FAADC6030DC703D00520AE +:20376000F3F7F00320F7F7A92A85BD2009FB20BFFA20E5F7A0FFC8B9D20399B20320D6F720 +:20378000D0F4A20CBDB20320D6F7E8E01DD0F520DCF7ADC8030DC903F01CA000200DFBB1E5 +:2037A000B0204DFBF003AEE5FC8A20D6F7C8CCC803D0EC20DCF72CE5F72CE5F720B0FAA967 +:2037C0000120F9F728201AF82CCA0310080820F3F7209DF1286020E3F74C10F7A5BF20E371 +:2037E000F7A5BE85BD2005F924C010F9A90085C0A5BD60A932D002A5C7A2058D40022005BE +:20380000F92C400210F8CAD0F260ADC6030DC703F0052CDF03100320A0F1A20086BAADCAE0 +:20382000038DDF0320ADE5F069A90D20EEFFA000B9B203F010C9209004C97F9002A93F20DB +:20384000EEFFC8D0EBAD4702F00424BB50442001F9C8C00B90EFADC603AA20EAF82CCA0354 +:2038600010308A186DC90320E5F8ADC80320EAF824BB501EA2042001F9CAD0FAA20F2086BE +:20388000F82001F9A213A004BDB20320EAF8CA88D0F660AD4702F0034C7EE020C9F8201F1E +:2038A000FB20ADE5F0EC20B6F95245434F5244207468656E2052455455524E002005F920E4 +:2038C000E0FFC90DD0F64CE7FF0878AD820229F909048D82028D07FE2860E6B1D002E6B22F +:2038E000D002E6B360482001F968484A4A4A4A20F3F86818290F6930C93A900269064CEE29 +:20390000FFA920D0F90824EB300424FF300228602091F22063FAA97E20F4FF001145736368 +:203920006170650098F00D20B6F90D4C6F6164696E670D0085BAA2FFA5C1D00D20E2F908EF +:20394000A2FFA009A9FA28D01CA0FEA5C1F004A9F9D012ADC603C5B4D007ADC703C5B5F043 +:2039600013A014A9FA4898488A482017F868AA68A868D0148A48200AF82047FA68AAA5BE7C +:2039800005BFF079A0FEA9F9C6BA4824EB300D8A2D4702D0078A291125BBF0106885B98401 +:2039A000B820E8F546EB2059FA6CB80068C8D00318690148984820ADE5A86885B86885B938 +:2039C0009808E6B8D002E6B9A000B1B8F00A2808F0F020E3FF4CC2F928E6B8D002E6B96C79 +:2039E000B800A2FFE8BDD203D0078AF003BDB203602051E25DB203B00229DFF0E76000D8A0 +:203A00000D446174613F00D01500DB0D46696C653F00D00A00DA0D426C6F636B3F00A5BA0A +:203A2000F0228AF01FA92224BBF01920B0FAA0FF20BAF90D07526577696E642074617065A5 +:203A40000D0D006020A4F1A5C2F0F82005F9AD4702F0F420DFF44C47FA20ADE5F005A90719 +:203A600020EEFFA980205EFBA2002026FB20B0FAA90085EA60A5E30A0A0A0A85BBADD10301 +:203A8000D008A5E329F085BBA90685C75808782C4F02101624EA3012A90185EAAD82022934 +:203AA000F98D82028D07FE2838602824FF10DD600878AD5B02298F8D5B028D00FE2860AD26 +:203AC0005B0229AF0920A8A90485CAD010A2008E06FE86CAAD5B0229DF0950A88A09408D0D +:203AE000F4020878AD820229F90DF4028D8202288D07FE8C5B028C00FE60AEC603ACC7036F +:203B0000E886B4D001C884B560A00084C084BE84BF60A0FFC8E8BD000399D203D0F660A045 +:203B20000058A20184C3A989A4C34CF4FF85BC984D4702A8A5E225BC4A88F0044A88D00381 +:203B400090016000DE4368616E6E656C00AAA5B225B3C9FFF005AD7A02298060A901204DFE +:203B6000FBF0DF8AA2B0A00048A9C020060490FB684C0604000000000000000000000000DB +:203B8000000000000000000000000000000000000000000000000000000000000000000025 +:203BA000000000000000000000000000000000000000000000000000000000000000000005 +:203BC0000000000000000000000000000000000000000000000000000000000000000000E5 +:203BE00000000000000000000000000000000000000000000000000000000000000020EDB8 +:203C000028432920313938332041636F726E20436F6D707574657273204C74642E54686197 +:203C20006E6B73206172652064756520746F2074686520666F6C6C6F77696E6720636F6ECD +:203C40007472696275746F727320746F2074686520646576656C6F706D656E74206F66203A +:203C600074686520456C656374726F6E2028616D6F6E67206F746865727320746F6F206E98 +:203C8000756D65726F757320746F206D656E74696F6E293A2D20426F622041757374696EA0 +:203CA0002C41737465632C4861727279204261726D616E2C5061756C20426F6E642C416C0B +:203CC000FFFFFFFF00100E00FFFFFFFF00100E006E2042726964676577617465722C4361E2 +:203CE0006D6272696467652C4A6F686E20436F782C43687269732043757272792C363530C4 +:203D0000322064657369676E6572732C4A6572656D792044696F6E2C54696D20446F62734D +:203D20006F6E2C4A6F652044756E6E2C46657272616E74692C5374657665204675726265F9 +:203D4000722C44617669642047616C652C416E6472657720476F72646F6E2C4D61727479F5 +:203D60006E2047696C626572742C4C617772656E636520486172647769636B2C4865726D8A +:203D8000616E6E204861757365722C4A6F686E20486572626572742C486974616368692CA5 +:203DA000416E647920486F707065722C5061756C204A657068636F742C427269616E204ABC +:203DC0006F6E65732C4368726973204A6F7264616E2C436F6D7075746572204C61626F7200 +:203DE00061746F72792C546F6E79204D616E6E2C5065746572204D696C6C65722C5472650C +:203E0000BD6F7220A46F727269732C5374657665BD506172D26F6E732C526F62696E205046 +:203E2000AD696E2CD26C796E205068696C6C6970AD2C4272D2616E20526F62657274736F1D +:203E4000AD2C5065D2657220526F62696E736F6EAD446176D264205365616C2C4B696D20B1 +:203E6000AD70656ED2652D4A6F6E65732C477261AD616D20D2656262792C4A6F6E2054686B +:203E8000AD636B7269792C546F70657870726573AD2C4368696973205475726E65722C4880 +:203EA000AD676F206979736F6E2C4A6F686E2055AD6E657969416C65782076616E20536FCA +:203EC000AD657265692C47656F66662056696E63AD6E742C34647269616E205761726E65B3 +:203EE000AD2C526F34696E2057696C6C69616D73AD6E2C52346765722057696C736F6E2EE6 +:203F00002051FF2051FF2051FF2051FF2051FF2051FF2051FF2051FF2051FF2051FF2051D0 +:203F2000FF2051FF2051FF2051FF2051FF2051FF2051FF2051FF2051FF2051FF2051FF2002 +:203F400051FF2051FF2051FF2051FF2051FF2051FF484848484808488A489848BAA9FF9D78 +:203F60000801A9869D0701BC0A01B99D0D9D0501B99E0D9D0601A5F49D0901B99F0D20A02A +:203F8000E368A868AA684008488A48BABD02019D0501BD03019D060168AA68686820A0E3E3 +:203FA000682860989D00FD60BC00FD600E05FE2C2CFC408AB01E3645D84CF2DA4CD8D64CB8 +:203FC00002E24CFDE74C0EE84C50DC4C2DDE6C1C026C1A026C18026C16026C14026C12029E +:203FE0006C1002C90DD007A90A20EEFFA90D6C0E026C0C026C0A026C0802000DD2D8E7DAC4 +:00000001FF diff --git a/Acorn - Electron_MiST/rtl/scandoubler.v b/Acorn - Electron_MiST/rtl/scandoubler.v new file mode 100644 index 00000000..0213d20c --- /dev/null +++ b/Acorn - Electron_MiST/rtl/scandoubler.v @@ -0,0 +1,195 @@ +// +// scandoubler.v +// +// Copyright (c) 2015 Till Harbaum +// Copyright (c) 2017 Sorgelig +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +// TODO: Delay vsync one line + +module scandoubler #(parameter LENGTH, parameter HALF_DEPTH) +( + // system interface + input clk_sys, + input ce_pix, + input ce_pix_actual, + + input hq2x, + + // shifter video interface + input hs_in, + input vs_in, + input line_start, + + input [DWIDTH:0] r_in, + input [DWIDTH:0] g_in, + input [DWIDTH:0] b_in, + input mono, + + // output interface + output reg hs_out, + output vs_out, + output [DWIDTH:0] r_out, + output [DWIDTH:0] g_out, + output [DWIDTH:0] b_out +); + + +localparam DWIDTH = HALF_DEPTH ? 2 : 5; + +assign vs_out = vs_in; + +reg [2:0] phase; +reg [2:0] ce_div; +reg [7:0] pix_len = 0; +wire [7:0] pl = pix_len + 1'b1; + +reg ce_x1, ce_x4; +reg req_line_reset; +wire ls_in = hs_in | line_start; +always @(negedge clk_sys) begin + reg old_ce; + reg [2:0] ce_cnt; + + reg [7:0] pixsz2, pixsz4 = 0; + + old_ce <= ce_pix; + if(~&pix_len) pix_len <= pix_len + 1'd1; + + ce_x4 <= 0; + ce_x1 <= 0; + + // use such odd comparison to place c_x4 evenly if master clock isn't multiple 4. + if((pl == pixsz4) || (pl == pixsz2) || (pl == (pixsz2+pixsz4))) begin + phase <= phase + 1'd1; + ce_x4 <= 1; + end + + if(~old_ce & ce_pix) begin + pixsz2 <= {1'b0, pl[7:1]}; + pixsz4 <= {2'b00, pl[7:2]}; + ce_x1 <= 1; + ce_x4 <= 1; + pix_len <= 0; + phase <= phase + 1'd1; + + ce_cnt <= ce_cnt + 1'd1; + if(ce_pix_actual) begin + phase <= 0; + ce_div <= ce_cnt + 1'd1; + ce_cnt <= 0; + req_line_reset <= 0; + end + + if(ls_in) req_line_reset <= 1; + end +end + +reg ce_sd; +always @(*) begin + case(ce_div) + 2: ce_sd = !phase[0]; + 4: ce_sd = !phase[1:0]; + default: ce_sd <= 1; + endcase +end + +`define BITS_TO_FIT(N) ( \ + N <= 2 ? 0 : \ + N <= 4 ? 1 : \ + N <= 8 ? 2 : \ + N <= 16 ? 3 : \ + N <= 32 ? 4 : \ + N <= 64 ? 5 : \ + N <= 128 ? 6 : \ + N <= 256 ? 7 : \ + N <= 512 ? 8 : \ + N <=1024 ? 9 : 10 ) + +localparam AWIDTH = `BITS_TO_FIT(LENGTH); +Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x +( + .clk(clk_sys), + .ce_x4(ce_x4 & ce_sd), + .inputpixel({b_in,g_in,r_in}), + .mono(mono), + .disable_hq2x(~hq2x), + .reset_frame(vs_in), + .reset_line(req_line_reset), + .read_y(sd_line), + .read_x(sd_h_actual), + .outpixel({b_out,g_out,r_out}) +); + +reg [10:0] sd_h_actual; +always @(*) begin + case(ce_div) + 2: sd_h_actual = sd_h[10:1]; + 4: sd_h_actual = sd_h[10:2]; + default: sd_h_actual = sd_h; + endcase +end + +reg [10:0] sd_h; +reg [1:0] sd_line; +always @(posedge clk_sys) begin + + reg [11:0] hs_max,hs_rise,hs_ls; + reg [10:0] hcnt; + reg [11:0] sd_hcnt; + + reg hs, hs2, vs, ls; + + if(ce_x1) begin + hs <= hs_in; + ls <= ls_in; + + if(ls && !ls_in) hs_ls <= {hcnt,1'b1}; + + // falling edge of hsync indicates start of line + if(hs && !hs_in) begin + hs_max <= {hcnt,1'b1}; + hcnt <= 0; + if(ls && !ls_in) hs_ls <= {10'd0,1'b1}; + end else begin + hcnt <= hcnt + 1'd1; + end + + // save position of rising edge + if(!hs && hs_in) hs_rise <= {hcnt,1'b1}; + + vs <= vs_in; + if(vs && ~vs_in) sd_line <= 0; + end + + if(ce_x4) begin + hs2 <= hs_in; + + // output counter synchronous to input and at twice the rate + sd_hcnt <= sd_hcnt + 1'd1; + sd_h <= sd_h + 1'd1; + if(hs2 && !hs_in) sd_hcnt <= hs_max; + if(sd_hcnt == hs_max) sd_hcnt <= 0; + + // replicate horizontal sync at twice the speed + if(sd_hcnt == hs_max) hs_out <= 0; + if(sd_hcnt == hs_rise) hs_out <= 1; + + if(sd_hcnt == hs_ls) sd_h <= 0; + if(sd_hcnt == hs_ls) sd_line <= sd_line + 1'd1; + end +end + +endmodule diff --git a/Acorn - Electron_MiST/rtl/video_mixer.sv b/Acorn - Electron_MiST/rtl/video_mixer.sv new file mode 100644 index 00000000..04cfd4ba --- /dev/null +++ b/Acorn - Electron_MiST/rtl/video_mixer.sv @@ -0,0 +1,242 @@ +// +// +// Copyright (c) 2017 Sorgelig +// +// This program is GPL Licensed. See COPYING for the full license. +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +`timescale 1ns / 1ps + +// +// LINE_LENGTH: Length of display line in pixels +// Usually it's length from HSync to HSync. +// May be less if line_start is used. +// +// HALF_DEPTH: If =1 then color dept is 3 bits per component +// For half depth 6 bits monochrome is available with +// mono signal enabled and color = {G, R} + +module video_mixer +#( + parameter LINE_LENGTH = 768, + parameter HALF_DEPTH = 0, + + parameter OSD_COLOR = 3'd4, + parameter OSD_X_OFFSET = 10'd0, + parameter OSD_Y_OFFSET = 10'd0 +) +( + // master clock + // it should be multiple by (ce_pix*4). + input clk_sys, + + // Pixel clock or clock_enable (both are accepted). + input ce_pix, + + // Some systems have multiple resolutions. + // ce_pix_actual should match ce_pix where every second or fourth pulse is enabled, + // thus half or qurter resolutions can be used without brake video sync while switching resolutions. + // For fixed single resolution (or when video sync stability isn't required) ce_pix_actual = ce_pix. + input ce_pix_actual, + + // OSD SPI interface + input SPI_SCK, + input SPI_SS3, + input SPI_DI, + + // scanlines (00-none 01-25% 10-50% 11-75%) + input [1:0] scanlines, + + // 0 = HVSync 31KHz, 1 = CSync 15KHz + input scandoubler_disable, + + // High quality 2x scaling + input hq2x, + + // YPbPr always uses composite sync + input ypbpr, + + // 0 = 16-240 range. 1 = 0-255 range. (only for YPbPr color space) + input ypbpr_full, + + // color + input [DWIDTH:0] R, + input [DWIDTH:0] G, + input [DWIDTH:0] B, + + // Monochrome mode (for HALF_DEPTH only) + input mono, + + // interlace sync. Positive pulses. + input HSync, + input VSync, + + // Falling of this signal means start of informative part of line. + // It can be horizontal blank signal. + // This signal can be used to reduce amount of required FPGA RAM for HQ2x scan doubler + // If FPGA RAM is not an issue, then simply set it to 0 for whole line processing. + // Keep in mind: due to algo first and last pixels of line should be black to avoid side artefacts. + // Thus, if blank signal is used to reduce the line, make sure to feed at least one black (or paper) pixel + // before first informative pixel. + input line_start, + + // MiST video output signals + output [5:0] VGA_R, + output [5:0] VGA_G, + output [5:0] VGA_B, + output VGA_VS, + output VGA_HS +); + +localparam DWIDTH = HALF_DEPTH ? 2 : 5; + +wire [DWIDTH:0] R_sd; +wire [DWIDTH:0] G_sd; +wire [DWIDTH:0] B_sd; +wire hs_sd, vs_sd; + +scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH)) scandoubler +( + .*, + .hs_in(HSync), + .vs_in(VSync), + .r_in(R), + .g_in(G), + .b_in(B), + + .hs_out(hs_sd), + .vs_out(vs_sd), + .r_out(R_sd), + .g_out(G_sd), + .b_out(B_sd) +); + +wire [DWIDTH:0] rt = (scandoubler_disable ? R : R_sd); +wire [DWIDTH:0] gt = (scandoubler_disable ? G : G_sd); +wire [DWIDTH:0] bt = (scandoubler_disable ? B : B_sd); + +generate + if(HALF_DEPTH) begin + wire [5:0] r = mono ? {gt,rt} : {rt,rt}; + wire [5:0] g = mono ? {gt,rt} : {gt,gt}; + wire [5:0] b = mono ? {gt,rt} : {bt,bt}; + end else begin + wire [5:0] r = rt; + wire [5:0] g = gt; + wire [5:0] b = bt; + end +endgenerate + +wire hs = (scandoubler_disable ? HSync : hs_sd); +wire vs = (scandoubler_disable ? VSync : vs_sd); + +reg scanline = 0; +always @(posedge clk_sys) begin + reg old_hs, old_vs; + + old_hs <= hs; + old_vs <= vs; + + if(old_hs && ~hs) scanline <= ~scanline; + if(old_vs && ~vs) scanline <= 0; +end + +wire [5:0] r_out, g_out, b_out; +always @(*) begin + case(scanlines & {scanline, scanline}) + 1: begin // reduce 25% = 1/2 + 1/4 + r_out = {1'b0, r[5:1]} + {2'b00, r[5:2]}; + g_out = {1'b0, g[5:1]} + {2'b00, g[5:2]}; + b_out = {1'b0, b[5:1]} + {2'b00, b[5:2]}; + end + + 2: begin // reduce 50% = 1/2 + r_out = {1'b0, r[5:1]}; + g_out = {1'b0, g[5:1]}; + b_out = {1'b0, b[5:1]}; + end + + 3: begin // reduce 75% = 1/4 + r_out = {2'b00, r[5:2]}; + g_out = {2'b00, g[5:2]}; + b_out = {2'b00, b[5:2]}; + end + + default: begin + r_out = r; + g_out = g; + b_out = b; + end + endcase +end + +wire [5:0] red, green, blue; +osd #(OSD_X_OFFSET, OSD_Y_OFFSET, OSD_COLOR) osd +( + .*, + + .R_in(r_out), + .G_in(g_out), + .B_in(b_out), + .HSync(hs), + .VSync(vs), + + .R_out(red), + .G_out(green), + .B_out(blue) +); + +wire [5:0] yuv_full[225] = '{ + 6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1, + 6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4, + 6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6, + 6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8, + 6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11, + 6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13, + 6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15, + 6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17, + 6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20, + 6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22, + 6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24, + 6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27, + 6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29, + 6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31, + 6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33, + 6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36, + 6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38, + 6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40, + 6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42, + 6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45, + 6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47, + 6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49, + 6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52, + 6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54, + 6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56, + 6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58, + 6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61, + 6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63, + 6'd63 +}; + +// http://marsee101.blog19.fc2.com/blog-entry-2311.html +// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B) +// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) +// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) + +wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); +wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); +wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); + +wire [7:0] y = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8]; +wire [7:0] pb = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8]; +wire [7:0] pr = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8]; + +assign VGA_R = ypbpr ? (ypbpr_full ? yuv_full[pr-8'd16] : pr[7:2]) : red; +assign VGA_G = ypbpr ? (ypbpr_full ? yuv_full[y -8'd16] : y[7:2]) : green; +assign VGA_B = ypbpr ? (ypbpr_full ? yuv_full[pb-8'd16] : pb[7:2]) : blue; +assign VGA_VS = (scandoubler_disable | ypbpr) ? 1'b1 : ~vs_sd; +assign VGA_HS = scandoubler_disable ? ~(HSync ^ VSync) : ypbpr ? ~(hs_sd ^ vs_sd) : ~hs_sd; + +endmodule