diff --git a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/SpyHunter.qsf b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/SpyHunter.qsf index 7a1839be..ec7e9dbf 100644 --- a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/SpyHunter.qsf +++ b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/SpyHunter.qsf @@ -41,7 +41,7 @@ # ======================== set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL -set_global_assignment -name LAST_QUARTUS_VERSION 13.1 +set_global_assignment -name LAST_QUARTUS_VERSION "13.1 SP4.26" set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl" # Pin & Location Assignments @@ -214,7 +214,7 @@ 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 ENABLE_SIGNALTAP OFF -set_global_assignment -name USE_SIGNALTAP_FILE output_files/reset.stp +set_global_assignment -name USE_SIGNALTAP_FILE output_files/csd.stp set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE SPEED set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS ON set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS" @@ -222,7 +222,7 @@ set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON set_global_assignment -name FITTER_EFFORT "STANDARD FIT" set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON set_global_assignment -name SMART_RECOMPILE ON -set_global_assignment -name ALLOW_SYNCH_CTRL_USAGE ON +set_global_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF set_global_assignment -name SYSTEMVERILOG_FILE rtl/SpyHunter_MiST.sv set_global_assignment -name VHDL_FILE rtl/spy_hunter.vhd set_global_assignment -name VHDL_FILE rtl/ctc_counter.vhd @@ -235,10 +235,13 @@ set_global_assignment -name VHDL_FILE rtl/cmos_ram.vhd set_global_assignment -name VHDL_FILE rtl/rom/spy_hunter_bg_bits_2.vhd set_global_assignment -name VHDL_FILE rtl/rom/spy_hunter_bg_bits_1.vhd set_global_assignment -name VHDL_FILE rtl/rom/spy_hunter_ch_bits.vhd -set_global_assignment -name VHDL_FILE rtl/rom/spy_hunter_sound_cpu.vhd set_global_assignment -name VHDL_FILE rtl/rom/midssio_82s123.vhd set_global_assignment -name SYSTEMVERILOG_FILE rtl/sdram.sv set_global_assignment -name VHDL_FILE rtl/pll_mist.vhd +set_global_assignment -name VHDL_FILE rtl/cheap_squeak_deluxe.vhd +set_global_assignment -name VHDL_FILE ../../../common/IO/pia6821.vhd +set_global_assignment -name QIP_FILE ../../../common/CPU/68000/FX68k/fx68k.qip set_global_assignment -name QIP_FILE ../../../common/CPU/T80/T80.qip set_global_assignment -name QIP_FILE ../../../common/mist/mist.qip +set_global_assignment -name SIGNALTAP_FILE output_files/csd.stp set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/SpyHunter_MiST.sv b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/SpyHunter_MiST.sv index 8caa38db..7383d4d3 100644 --- a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/SpyHunter_MiST.sv +++ b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/SpyHunter_MiST.sv @@ -82,6 +82,7 @@ wire [7:0] joy_1; wire scandoublerD; wire ypbpr; wire [15:0] audio_l, audio_r; +wire [9:0] csd_audio; wire hs, vs, cs; wire blankn; wire [2:0] g, r, b; @@ -89,6 +90,8 @@ wire [15:0] rom_addr; wire [15:0] rom_do; wire [12:0] snd_addr; wire [15:0] snd_do; +wire [14:1] csd_addr; +wire [15:0] csd_do; wire [14:0] sp_addr; wire [31:0] sp_do; wire ioctl_downl; @@ -111,7 +114,21 @@ data_io data_io( .ioctl_dout ( ioctl_dout ) ); -wire [24:0] sp_ioctl_addr = ioctl_addr - 17'h10000;//Wrong for CSD roms !!! +// ROM structure: + +// 0000 - DFFF - Main ROM (8 bit) +// E000 - FFFF - Super Sound board ROM (8 bit) +// 10000 - 17FFF - CSD ROM (16 bit) +// 18000 - Sprite ROMs (32 bit) + +// spy-hunter_cpu_pg0_2-9-84.6d spy-hunter_cpu_pg1_2-9-84.7d spy-hunter_cpu_pg2_2-9-84.8d spy-hunter_cpu_pg3_2-9-84.9d spy-hunter_cpu_pg4_2-9-84.10d spy-hunter_cpu_pg5_2-9-84.11d +// spy-hunter_snd_0_sd_11-18-83.a7 spy-hunter_snd_1_sd_11-18-83.a8 +// spy-hunter_cs_deluxe_u17_b_11-18-83.u17 spy-hunter_cs_deluxe_u18_d_11-18-83.u18 spy-hunter_cs_deluxe_u7_a_11-18-83.u7 spy-hunter_cs_deluxe_u8_c_11-18-83.u8 +// spy-hunter_video_1fg_11-18-83.a7 spy-hunter_video_0fg_11-18-83.a8 spy-hunter_video_3fg_11-18-83.a5 spy-hunter_video_2fg_11-18-83.a6 spy-hunter_video_5fg_11-18-83.a3 spy-hunter_video_4fg_11-18-83.a4 spy-hunter_video_7fg_11-18-83.a1 spy-hunter_video_6fg_11-18-83.a2 + +wire [24:0] rom_ioctl_addr = ~ioctl_addr[16] ? ioctl_addr : // 8 bit ROMs + {ioctl_addr[24:16], ioctl_addr[15], ioctl_addr[13:0], ioctl_addr[14]}; // 16 bit ROM +wire [24:0] sp_ioctl_addr = ioctl_addr - 17'h18000; reg port1_req, port2_req; sdram sdram( @@ -119,19 +136,22 @@ sdram sdram( .init_n ( pll_locked ), .clk ( clk_mem ), - // port1 used for main + sound CPU + // port1 used for main + sound CPUs .port1_req ( port1_req ), .port1_ack ( ), - .port1_a ( ioctl_addr[23:1] ), - .port1_ds ( {ioctl_addr[0], ~ioctl_addr[0]} ), + .port1_a ( rom_ioctl_addr[23:1] ), + .port1_ds ( {rom_ioctl_addr[0], ~rom_ioctl_addr[0]} ), .port1_we ( ioctl_downl ), .port1_d ( {ioctl_dout, ioctl_dout} ), .port1_q ( ), .cpu1_addr ( ioctl_downl ? 16'hffff : {1'b0, rom_addr[15:1]} ), .cpu1_q ( rom_do ), - .cpu2_addr ( 16'hffff ),// CSD Roms - Change Rom File for this - .cpu2_q ( ),//snd_do ), + // need higher priority for CSD + .cpu2_addr ( ioctl_downl ? 16'hffff : (16'h8000 + csd_addr[14:1]) ), + .cpu2_q ( csd_do ), + .cpu3_addr ( ioctl_downl ? 16'hffff : (16'h7000 + snd_addr[12:1]) ), + .cpu3_q ( snd_do ), // port2 for sprite graphics .port2_req ( port2_req ), @@ -202,6 +222,7 @@ spy_hunter spy_hunter( .separate_audio(1'b0), .audio_out_l(audio_l), .audio_out_r(audio_r), + .csd_audio_out(csd_audio), .coin1(btn_coin), .coin2(1'b0), .shift(m_shift), @@ -220,6 +241,8 @@ spy_hunter spy_hunter( .cpu_rom_do ( rom_addr[0] ? rom_do[15:8] : rom_do[7:0] ), .snd_rom_addr ( snd_addr ), .snd_rom_do ( snd_addr[0] ? snd_do[15:8] : snd_do[7:0] ), + .csd_rom_addr ( csd_addr ), + .csd_rom_do ( csd_do ), .sp_addr ( sp_addr ), .sp_graphx32_do ( sp_do ) ); @@ -279,16 +302,16 @@ dac #( dac_l( .clk_i(clk_sys), .res_n_i(1), - .dac_i(audio_l), + .dac_i(audio_l + { csd_audio, 5'd0 }), .dac_o(AUDIO_L) ); - + dac #( .C_bits(16)) dac_r( .clk_i(clk_sys), .res_n_i(1), - .dac_i(audio_r), + .dac_i(audio_r + { csd_audio, 5'd0 }), .dac_o(AUDIO_R) ); diff --git a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/cheap_squeak_deluxe.vhd b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/cheap_squeak_deluxe.vhd new file mode 100644 index 00000000..6e9dc8f1 --- /dev/null +++ b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/cheap_squeak_deluxe.vhd @@ -0,0 +1,219 @@ +-- Midway Cheap Squeak Deluxe sound board + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; +use ieee.numeric_std.all; +use work.fx68k.all; + +entity cheap_squeak_deluxe is +port( + clock_40 : in std_logic; + reset : in std_logic; + input : in std_logic_vector(7 downto 0); + rom_addr : out std_logic_vector(14 downto 1); + rom_do : in std_logic_vector(15 downto 0); + audio_out : out std_logic_vector(9 downto 0) +); +end cheap_squeak_deluxe; + +architecture rtl of cheap_squeak_deluxe is + +signal cpu_ce1 : std_logic; +signal cpu_ce2 : std_logic; +signal cpu_ce_count : std_logic_vector( 4 downto 0); +signal cpu_addr : std_logic_vector(23 downto 1); +signal cpu_rw : std_logic; +signal cpu_irq : std_logic; +signal cpu_data_in : std_logic_vector(15 downto 0); +signal cpu_data_out : std_logic_vector(15 downto 0); +signal cpu_as_n : std_logic; +signal cpu_lds_n : std_logic; +signal cpu_uds_n : std_logic; +signal cpu_dtack_n : std_logic; +signal cpu_vpa_n : std_logic; +signal cpu_fc : std_logic_vector( 2 downto 0); +signal cpu_ipl2_N : std_logic; +signal cpu_sel : std_logic; + +signal pia_data_out : std_logic_vector( 7 downto 0); +signal pia_pa_in : std_logic_vector( 7 downto 0); +signal pia_pa_out : std_logic_vector( 7 downto 0); +signal pia_pa_oe : std_logic_vector( 7 downto 0); +signal pia_pb_in : std_logic_vector( 7 downto 0); +signal pia_pb_out : std_logic_vector( 7 downto 0); +signal pia_pb_oe : std_logic_vector( 7 downto 0); +signal pia_ca1_in : std_logic; +signal pia_ca2_out : std_logic; +signal pia_cb1_in : std_logic; +signal pia_cb2_out : std_logic; +signal pia_irqa : std_logic; +signal pia_irqb : std_logic; + +signal cs_rom : std_logic; +signal cs_ram : std_logic; +signal cs_pia : std_logic; + +signal ram_we : std_logic; +signal ram_data_out : std_logic_vector(15 downto 0); + +signal romd1 : std_logic; +signal romd : std_logic; +signal rom_addr_out : std_logic_vector(14 downto 1); +signal rom_addr_old : std_logic_vector(14 downto 1); + +begin + +fx68k_inst: fx68k +port map ( + clk => clock_40, + extReset => reset, + pwrUp => reset, + enPhi1 => cpu_ce1, + enPhi2 => cpu_ce2, + + eRWn => cpu_rw, + ASn => cpu_as_n, + LDSn => cpu_lds_n, + UDSn => cpu_uds_n, + E => open, + VMAn => open, + FC0 => cpu_fc(0), + FC1 => cpu_fc(1), + FC2 => cpu_fc(2), + BGn => open, + oRESETn => open, + oHALTEDn => open, + DTACKn => cpu_dtack_n, + VPAn => cpu_vpa_n, + BERRn => '1', + BRn => '1', + BGACKn => '1', + IPL0n => '1', + IPL1n => '1', + IPL2n => cpu_ipl2_n, + iEdb => cpu_data_in, + oEdb => cpu_data_out, + eab => cpu_addr +); + +-- U6 +u_wram : entity work.gen_ram +generic map( dWidth => 8, aWidth => 11) +port map( + clk => clock_40, + we => ram_we and not cpu_uds_n, + addr => cpu_addr(11 downto 1), + d => cpu_data_out(15 downto 8), + q => ram_data_out(15 downto 8) +); + +-- U16 +l_wram : entity work.gen_ram +generic map( dWidth => 8, aWidth => 11) +port map( + clk => clock_40, + we => ram_we and not cpu_lds_n, + addr => cpu_addr(11 downto 1), + d => cpu_data_out(7 downto 0), + q => ram_data_out(7 downto 0) +); + +-- U9 +pia6821 : entity work.pia6821 +port map ( + clk => clock_40, + rst => reset, + cs => cs_pia, + rw => cpu_rw, + addr => cpu_addr(1)&cpu_addr(2), -- wired in reverse order + data_in => cpu_data_out(15 downto 8), + data_out => pia_data_out, + irqa => pia_irqa, + irqb => pia_irqb, + pa_i => pia_pa_in, + pa_o => pia_pa_out, + pa_oe => open, + ca1 => pia_ca1_in, + ca2_i => '0', + ca2_o => open, + ca2_oe => open, + pb_i => pia_pb_in, + pb_o => pia_pb_out, + pb_oe => open, + cb1 => pia_cb1_in, + cb2_i => '0', + cb2_o => open, + cb2_oe => open +); + +-- clock enable generation: 40/5 = 8 MHz effective clock (original: 7.5 MHz) +process (clock_40, reset) +begin + if reset = '1' then + cpu_ce1 <= '0'; + cpu_ce2 <= '0'; + cpu_ce_count <= (others => '0'); + elsif rising_edge(clock_40) then + cpu_ce1 <= '0'; + cpu_ce2 <= '0'; + cpu_ce_count <= cpu_ce_count + 1; + if cpu_ce_count = 2 then + cpu_ce1 <= '1'; + end if; + if cpu_ce_count = 4 then + cpu_ce2 <= '1'; + cpu_ce_count <= (others => '0'); + end if; + end if; +end process; + +process (clock_40, reset) +begin + if reset = '1' then + rom_addr_old <= (others => '1'); + elsif rising_edge(clock_40) then + + rom_addr_old <= rom_addr_out; + + -- ROMD signal - DTACK_N delay for ROM access + if cpu_as_n = '1' then + romd1 <= '0'; + romd <= '0'; + elsif cpu_ce1 = '1' then + romd1 <= '1'; + romd <= romd1; + end if; + end if; +end process; + +cpu_sel <= '1' when cpu_as_n = '0' and (cpu_uds_n = '0' or cpu_lds_n = '0') else '0'; +cpu_dtack_n <= not ((cs_rom and romd) or cs_ram or cs_pia); + +-- auto-vectored interrupt handling +cpu_vpa_n <= '0' when cpu_fc = "111" else '1'; +cpu_ipl2_n <= not (pia_irqa or pia_irqb); + +cs_rom <= '1' when cpu_sel = '1' and cpu_addr(16 downto 15) = "00" else '0'; +cs_ram <= '1' when cpu_sel = '1' and cpu_addr(16 downto 14) = "111" else '0'; +-- PIA uses 6800 bus cycle originally with VMA, VPA and E clock +cs_pia <= '1' when cpu_sel = '1' and cpu_addr(16 downto 14) = "110" else '0'; + +ram_we <= '1' when cs_ram = '1' and cpu_rw = '0' else '0'; + +cpu_data_in <= rom_do when cs_rom = '1' else + ram_data_out when cs_ram = '1' else + pia_data_out&x"FF" when cs_pia = '1' else + (others => '1'); + +rom_addr_out <= cpu_addr(14 downto 1) when cs_rom = '1' else rom_addr_old; +rom_addr <= rom_addr_out; + +audio_out <= pia_pa_out(7 downto 0)&pia_pb_out(7 downto 6); +pia_pb_in(5 downto 0) <= "00"&input(3 downto 0); -- stat1-stat0, sr3-sr0 +pia_ca1_in <= not input(4); -- sirq +pia_pa_in <= (others => '0'); +pia_cb1_in <= '0'; -- spare + + +end rtl; diff --git a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/rom/spy_hunter_sound_cpu.vhd b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/rom/spy_hunter_sound_cpu.vhd deleted file mode 100644 index 6e402ca2..00000000 --- a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/rom/spy_hunter_sound_cpu.vhd +++ /dev/null @@ -1,534 +0,0 @@ -library ieee; -use ieee.std_logic_1164.all,ieee.numeric_std.all; - -entity spy_hunter_sound_cpu is -port ( - clk : in std_logic; - addr : in std_logic_vector(12 downto 0); - data : out std_logic_vector(7 downto 0) -); -end entity; - -architecture prom of spy_hunter_sound_cpu is - type rom is array(0 to 8191) of std_logic_vector(7 downto 0); - signal rom_data: rom := ( - X"F3",X"00",X"00",X"00",X"31",X"FF",X"83",X"ED",X"56",X"18",X"55",X"06",X"06",X"11",X"09",X"00", - X"DD",X"21",X"BC",X"82",X"DD",X"7E",X"01",X"FE",X"FF",X"28",X"13",X"DD",X"4E",X"02",X"21",X"27", - X"00",X"E5",X"DD",X"6E",X"00",X"67",X"E9",X"11",X"09",X"00",X"DD",X"36",X"02",X"00",X"DD",X"19", - X"10",X"E2",X"C9",X"85",X"6F",X"D0",X"24",X"C9",X"F5",X"3A",X"00",X"E0",X"3A",X"75",X"83",X"3D", - X"28",X"06",X"32",X"75",X"83",X"F1",X"FB",X"C9",X"3C",X"32",X"74",X"83",X"3E",X"06",X"32",X"75", - X"83",X"F1",X"FB",X"C9",X"C5",X"42",X"21",X"00",X"00",X"54",X"78",X"B7",X"C3",X"E7",X"00",X"FF", - X"21",X"00",X"B0",X"36",X"0F",X"21",X"02",X"B0",X"36",X"F0",X"3A",X"00",X"F0",X"CB",X"47",X"20", - X"4F",X"CB",X"4F",X"20",X"2E",X"AF",X"32",X"77",X"83",X"CD",X"29",X"05",X"CD",X"E1",X"05",X"3A", - X"77",X"83",X"FE",X"00",X"28",X"1D",X"CB",X"67",X"20",X"05",X"01",X"00",X"10",X"18",X"03",X"01", - X"00",X"80",X"11",X"01",X"00",X"60",X"69",X"32",X"00",X"D0",X"37",X"3F",X"ED",X"52",X"20",X"FC", - X"2F",X"18",X"F2",X"3E",X"FF",X"32",X"00",X"D0",X"3A",X"00",X"F0",X"CB",X"57",X"20",X"08",X"CD", - X"55",X"06",X"18",X"EF",X"3A",X"00",X"F0",X"CB",X"5F",X"20",X"F9",X"CD",X"7C",X"06",X"18",X"F4", - X"06",X"00",X"CD",X"38",X"06",X"06",X"FF",X"CD",X"38",X"06",X"06",X"55",X"CD",X"38",X"06",X"06", - X"AA",X"CD",X"38",X"06",X"AF",X"32",X"77",X"83",X"CD",X"29",X"05",X"CD",X"E1",X"05",X"3A",X"77", - X"83",X"32",X"00",X"C0",X"CD",X"EE",X"00",X"28",X"03",X"19",X"10",X"FD",X"C1",X"C9",X"31",X"FF", - X"83",X"F3",X"ED",X"56",X"CD",X"13",X"01",X"CD",X"AD",X"07",X"FB",X"AF",X"32",X"74",X"83",X"CD", - X"82",X"01",X"CD",X"0B",X"00",X"CD",X"AD",X"07",X"00",X"00",X"00",X"3A",X"74",X"83",X"B7",X"28", - X"FA",X"18",X"E8",X"21",X"3C",X"1E",X"06",X"20",X"11",X"20",X"80",X"DD",X"21",X"00",X"80",X"7E", - X"DD",X"77",X"00",X"2F",X"12",X"13",X"23",X"DD",X"23",X"10",X"F4",X"06",X"06",X"11",X"09",X"00", - X"DD",X"21",X"BC",X"82",X"DD",X"36",X"00",X"FF",X"DD",X"36",X"01",X"FF",X"DD",X"36",X"02",X"00", - X"DD",X"36",X"03",X"00",X"DD",X"36",X"04",X"00",X"DD",X"36",X"05",X"00",X"DD",X"36",X"06",X"00", - X"DD",X"19",X"10",X"E0",X"06",X"03",X"21",X"6B",X"83",X"36",X"00",X"23",X"10",X"FB",X"3E",X"01", - X"32",X"0C",X"83",X"32",X"20",X"83",X"3D",X"32",X"1F",X"83",X"3A",X"00",X"90",X"E6",X"80",X"32", - X"6E",X"83",X"3E",X"55",X"32",X"71",X"83",X"3E",X"06",X"32",X"75",X"83",X"3E",X"52",X"32",X"76", - X"83",X"C9",X"3A",X"6E",X"83",X"47",X"3A",X"00",X"90",X"A8",X"CB",X"7F",X"20",X"31",X"CB",X"40", - X"28",X"1E",X"CB",X"80",X"78",X"32",X"6E",X"83",X"CD",X"E0",X"01",X"3A",X"70",X"83",X"CB",X"47", - X"28",X"0E",X"CD",X"95",X"02",X"CD",X"A3",X"03",X"CD",X"06",X"04",X"CD",X"02",X"19",X"18",X"23", - X"CD",X"A3",X"03",X"3A",X"6F",X"83",X"CB",X"47",X"28",X"19",X"CD",X"02",X"19",X"18",X"14",X"78", - X"2F",X"CB",X"C7",X"32",X"6E",X"83",X"CD",X"A3",X"03",X"3A",X"6F",X"83",X"CB",X"47",X"28",X"03", - X"CD",X"02",X"19",X"3E",X"01",X"32",X"20",X"83",X"32",X"0C",X"83",X"3D",X"32",X"1F",X"83",X"C9", - X"3E",X"01",X"32",X"70",X"83",X"DD",X"21",X"00",X"90",X"DD",X"46",X"00",X"CB",X"70",X"28",X"23", - X"FD",X"21",X"00",X"80",X"FD",X"7E",X"0F",X"E6",X"8F",X"4F",X"78",X"17",X"E6",X"70",X"B1",X"FD", - X"77",X"0F",X"FD",X"7E",X"1F",X"E6",X"8F",X"4F",X"78",X"17",X"17",X"17",X"17",X"E6",X"70",X"B1", - X"FD",X"77",X"1F",X"DD",X"7E",X"01",X"4F",X"FE",X"00",X"28",X"23",X"CB",X"7F",X"28",X"6E",X"DD", - X"7E",X"02",X"CB",X"7F",X"20",X"67",X"79",X"E6",X"7F",X"4F",X"06",X"06",X"FD",X"21",X"BC",X"82", - X"11",X"09",X"00",X"FD",X"7E",X"06",X"B9",X"CC",X"61",X"02",X"FD",X"19",X"10",X"F5",X"FD",X"21", - X"6B",X"83",X"DD",X"46",X"02",X"78",X"E6",X"7F",X"28",X"24",X"CB",X"77",X"20",X"20",X"FD",X"77", - X"01",X"DD",X"7E",X"01",X"CB",X"7F",X"C0",X"DD",X"7E",X"03",X"FE",X"00",X"C8",X"FD",X"77",X"02", - X"C9",X"DD",X"7E",X"03",X"E5",X"FD",X"6E",X"07",X"FD",X"66",X"08",X"77",X"E1",X"C9",X"DD",X"4E", - X"01",X"79",X"FE",X"00",X"20",X"09",X"DD",X"7E",X"03",X"FE",X"00",X"20",X"D4",X"18",X"09",X"CB", - X"79",X"28",X"CE",X"CB",X"78",X"20",X"CA",X"AF",X"32",X"70",X"83",X"18",X"C4",X"79",X"E6",X"7F", - X"32",X"6B",X"83",X"18",X"A9",X"06",X"03",X"21",X"6B",X"83",X"C5",X"7E",X"4F",X"FE",X"00",X"CA", - X"66",X"03",X"3A",X"76",X"83",X"91",X"DA",X"66",X"03",X"79",X"FE",X"06",X"20",X"04",X"F3",X"C3", - X"00",X"00",X"79",X"FE",X"01",X"20",X"0C",X"DD",X"21",X"00",X"80",X"DD",X"7E",X"1F",X"F6",X"80", - X"DD",X"77",X"1F",X"79",X"FE",X"02",X"20",X"0F",X"DD",X"21",X"00",X"80",X"DD",X"7E",X"1F",X"E6", - X"7F",X"DD",X"77",X"1F",X"CD",X"6D",X"03",X"79",X"FE",X"03",X"20",X"03",X"CD",X"6D",X"03",X"79", - X"FE",X"04",X"20",X"07",X"3E",X"52",X"32",X"76",X"83",X"18",X"0A",X"79",X"FE",X"05",X"20",X"05", - X"3E",X"52",X"32",X"76",X"83",X"79",X"D9",X"6F",X"26",X"00",X"54",X"5D",X"29",X"29",X"19",X"19", - X"19",X"11",X"01",X"08",X"19",X"EB",X"1A",X"FE",X"00",X"20",X"1F",X"01",X"0C",X"83",X"60",X"69", - X"3E",X"06",X"08",X"13",X"1A",X"FE",X"00",X"28",X"4A",X"7E",X"CD",X"33",X"00",X"1A",X"77",X"60", - X"69",X"34",X"08",X"3D",X"FE",X"00",X"20",X"EA",X"18",X"39",X"3E",X"06",X"21",X"20",X"83",X"08", - X"13",X"1A",X"FE",X"00",X"28",X"2D",X"7E",X"CD",X"33",X"00",X"1A",X"77",X"26",X"00",X"6F",X"29", - X"01",X"46",X"0A",X"09",X"01",X"20",X"83",X"0A",X"CB",X"27",X"E5",X"21",X"33",X"83",X"CD",X"33", - X"00",X"EB",X"E3",X"7E",X"12",X"23",X"13",X"7E",X"12",X"0A",X"3C",X"02",X"D1",X"60",X"69",X"08", - X"3D",X"20",X"CC",X"D9",X"AF",X"77",X"23",X"C1",X"05",X"C2",X"9A",X"02",X"C9",X"D9",X"DD",X"21", - X"BC",X"82",X"01",X"09",X"00",X"11",X"0C",X"83",X"3E",X"01",X"12",X"62",X"6B",X"3E",X"06",X"08", - X"DD",X"7E",X"03",X"FE",X"00",X"28",X"0B",X"1A",X"CD",X"33",X"00",X"DD",X"7E",X"03",X"77",X"62", - X"6B",X"34",X"DD",X"09",X"08",X"3D",X"20",X"E7",X"3E",X"00",X"32",X"1F",X"83",X"3C",X"32",X"20", - X"83",X"D9",X"C9",X"AF",X"32",X"6F",X"83",X"21",X"0C",X"83",X"7E",X"D6",X"01",X"28",X"2A",X"11", - X"09",X"00",X"4F",X"DD",X"21",X"BC",X"82",X"06",X"06",X"23",X"7E",X"DD",X"BE",X"04",X"20",X"13", - X"AF",X"DD",X"77",X"06",X"DD",X"77",X"04",X"DD",X"77",X"05",X"3C",X"32",X"6F",X"83",X"0D",X"20", - X"E2",X"18",X"06",X"DD",X"19",X"10",X"E4",X"18",X"F5",X"21",X"1F",X"83",X"7E",X"4F",X"FE",X"00", - X"C8",X"3E",X"01",X"32",X"6F",X"83",X"06",X"06",X"21",X"5C",X"1E",X"DD",X"21",X"BC",X"82",X"11", - X"09",X"00",X"79",X"A6",X"28",X"0A",X"AF",X"DD",X"77",X"06",X"DD",X"77",X"04",X"DD",X"77",X"05", - X"DD",X"19",X"23",X"10",X"ED",X"C9",X"3A",X"20",X"83",X"D6",X"01",X"C8",X"08",X"CD",X"38",X"04", - X"CD",X"54",X"04",X"79",X"CB",X"27",X"21",X"33",X"83",X"CD",X"33",X"00",X"7A",X"FE",X"00",X"20", - X"11",X"CB",X"7E",X"20",X"0A",X"E5",X"CD",X"95",X"04",X"E1",X"7A",X"FE",X"00",X"20",X"03",X"CD", - X"CE",X"04",X"23",X"36",X"00",X"08",X"18",X"D1",X"06",X"00",X"0E",X"01",X"16",X"01",X"3A",X"20", - X"83",X"5F",X"21",X"33",X"83",X"23",X"7A",X"BB",X"C8",X"23",X"23",X"78",X"BE",X"30",X"02",X"46", - X"4A",X"14",X"18",X"F2",X"79",X"CB",X"27",X"21",X"33",X"83",X"CD",X"33",X"00",X"C5",X"06",X"06", - X"4E",X"11",X"09",X"00",X"21",X"5C",X"1E",X"DD",X"21",X"BC",X"82",X"7E",X"A1",X"28",X"1D",X"DD", - X"7E",X"04",X"FE",X"00",X"20",X"16",X"21",X"20",X"83",X"C1",X"79",X"CD",X"33",X"00",X"7E",X"DD", - X"77",X"04",X"DD",X"70",X"05",X"AF",X"DD",X"77",X"03",X"16",X"01",X"C9",X"DD",X"19",X"23",X"10", - X"DA",X"16",X"00",X"C1",X"C9",X"26",X"06",X"11",X"09",X"00",X"DD",X"21",X"BC",X"82",X"DD",X"7E", - X"04",X"FE",X"00",X"20",X"15",X"79",X"21",X"20",X"83",X"CD",X"33",X"00",X"7E",X"DD",X"77",X"04", - X"DD",X"70",X"05",X"AF",X"DD",X"77",X"03",X"16",X"01",X"C9",X"DD",X"19",X"25",X"20",X"DF",X"16", - X"00",X"21",X"33",X"83",X"79",X"CB",X"27",X"CD",X"33",X"00",X"F6",X"3F",X"77",X"C9",X"16",X"FF", - X"1E",X"00",X"E5",X"C5",X"4E",X"06",X"00",X"DD",X"21",X"BC",X"82",X"21",X"5C",X"1E",X"7E",X"A1", - X"28",X"08",X"DD",X"7E",X"05",X"BA",X"30",X"02",X"57",X"58",X"D5",X"11",X"09",X"00",X"DD",X"19", - X"D1",X"23",X"04",X"78",X"FE",X"06",X"20",X"E6",X"C1",X"7A",X"B8",X"30",X"24",X"21",X"20",X"83", - X"79",X"CD",X"33",X"00",X"4E",X"6B",X"26",X"00",X"54",X"5D",X"29",X"29",X"29",X"19",X"EB",X"DD", - X"21",X"BC",X"82",X"DD",X"19",X"DD",X"71",X"04",X"DD",X"70",X"05",X"AF",X"DD",X"77",X"03",X"E1", - X"C9",X"E1",X"C0",X"CB",X"76",X"C8",X"E5",X"18",X"D4",X"DD",X"21",X"D1",X"05",X"AF",X"F5",X"DD", - X"6E",X"00",X"DD",X"66",X"01",X"7C",X"B5",X"20",X"0A",X"F1",X"47",X"3A",X"77",X"83",X"B0",X"32", - X"77",X"83",X"C9",X"DD",X"5E",X"04",X"DD",X"56",X"05",X"DD",X"4E",X"02",X"DD",X"46",X"03",X"ED", - X"B0",X"DD",X"6E",X"00",X"DD",X"66",X"01",X"DD",X"5E",X"02",X"DD",X"56",X"03",X"7A",X"B3",X"28", - X"11",X"06",X"02",X"3E",X"00",X"77",X"BE",X"C2",X"CC",X"05",X"F6",X"FF",X"10",X"F7",X"23",X"1B", - X"18",X"EB",X"DD",X"66",X"01",X"DD",X"6E",X"00",X"DD",X"5E",X"02",X"DD",X"56",X"03",X"7A",X"B3", - X"28",X"06",X"36",X"00",X"23",X"1B",X"18",X"F6",X"DD",X"6E",X"00",X"DD",X"66",X"01",X"DD",X"5E", - X"02",X"DD",X"56",X"03",X"7A",X"B3",X"28",X"14",X"7E",X"FE",X"00",X"20",X"2F",X"3E",X"01",X"77", - X"BE",X"C2",X"CC",X"05",X"CB",X"27",X"30",X"F7",X"23",X"1B",X"18",X"E8",X"AF",X"DD",X"66",X"05", - X"DD",X"6E",X"04",X"DD",X"56",X"01",X"DD",X"5E",X"00",X"DD",X"4E",X"02",X"DD",X"46",X"03",X"ED", - X"B0",X"47",X"F1",X"B0",X"11",X"07",X"00",X"DD",X"19",X"C3",X"2E",X"05",X"DD",X"7E",X"06",X"18", - X"DC",X"00",X"80",X"00",X"02",X"00",X"80",X"10",X"00",X"82",X"00",X"02",X"00",X"80",X"10",X"00", - X"00",X"DD",X"21",X"1D",X"06",X"16",X"00",X"DD",X"6E",X"02",X"DD",X"66",X"03",X"DD",X"4E",X"00", - X"DD",X"46",X"01",X"78",X"B1",X"28",X"1A",X"AF",X"86",X"23",X"0D",X"20",X"FB",X"05",X"20",X"F8", - X"DD",X"BE",X"04",X"28",X"05",X"7A",X"DD",X"B6",X"05",X"57",X"01",X"06",X"00",X"DD",X"09",X"18", - X"D6",X"7A",X"B7",X"C8",X"47",X"3A",X"77",X"83",X"B0",X"32",X"77",X"83",X"C9",X"00",X"10",X"00", - X"00",X"D7",X"01",X"00",X"10",X"00",X"10",X"BD",X"02",X"00",X"00",X"00",X"20",X"00",X"04",X"00", - X"00",X"00",X"30",X"00",X"08",X"00",X"00",X"29",X"3A",X"00",X"90",X"B8",X"20",X"FA",X"3A",X"01", - X"90",X"B8",X"20",X"F4",X"3A",X"02",X"90",X"B8",X"20",X"EE",X"3A",X"03",X"90",X"B8",X"20",X"E8", - X"78",X"32",X"00",X"C0",X"C9",X"06",X"00",X"CD",X"B5",X"06",X"0E",X"00",X"3E",X"AD",X"CD",X"F5", - X"06",X"0E",X"01",X"3E",X"07",X"CD",X"F5",X"06",X"06",X"01",X"CD",X"B5",X"06",X"0E",X"00",X"3E", - X"AD",X"CD",X"F5",X"06",X"0E",X"01",X"3E",X"77",X"CD",X"F5",X"06",X"C9",X"CD",X"55",X"06",X"16", - X"10",X"3E",X"00",X"1E",X"FF",X"06",X"00",X"0E",X"00",X"CD",X"F5",X"06",X"2F",X"0E",X"01",X"CD", - X"F5",X"06",X"06",X"01",X"32",X"78",X"83",X"E6",X"7F",X"CD",X"F5",X"06",X"3A",X"78",X"83",X"2F", - X"0E",X"00",X"CD",X"F5",X"06",X"3C",X"E6",X"0F",X"47",X"07",X"07",X"07",X"07",X"B0",X"1D",X"20", - X"FD",X"15",X"20",X"CF",X"C9",X"CD",X"0C",X"07",X"36",X"00",X"DD",X"36",X"00",X"F4",X"36",X"01", - X"DD",X"36",X"00",X"01",X"36",X"02",X"DD",X"36",X"00",X"FA",X"36",X"03",X"DD",X"36",X"00",X"00", - X"36",X"04",X"DD",X"36",X"00",X"7D",X"36",X"05",X"DD",X"36",X"00",X"00",X"36",X"08",X"DD",X"36", - X"00",X"0B",X"36",X"09",X"DD",X"36",X"00",X"0B",X"36",X"0A",X"DD",X"36",X"00",X"0B",X"36",X"07", - X"DD",X"36",X"00",X"F8",X"C9",X"CD",X"0C",X"07",X"32",X"72",X"83",X"AF",X"A9",X"28",X"09",X"36", - X"0F",X"3A",X"72",X"83",X"DD",X"77",X"00",X"C9",X"36",X"0E",X"18",X"F5",X"32",X"72",X"83",X"AF", - X"A8",X"3A",X"72",X"83",X"20",X"08",X"21",X"00",X"A0",X"DD",X"21",X"02",X"A0",X"C9",X"21",X"00", - X"B0",X"DD",X"21",X"02",X"B0",X"C9",X"21",X"F4",X"07",X"16",X"00",X"19",X"56",X"21",X"E8",X"07", - X"79",X"CB",X"27",X"5F",X"7A",X"16",X"00",X"19",X"5E",X"23",X"56",X"6F",X"26",X"00",X"19",X"11", - X"40",X"80",X"19",X"C9",X"21",X"62",X"1E",X"CB",X"27",X"D2",X"53",X"07",X"24",X"CD",X"33",X"00", - X"C3",X"56",X"07",X"CD",X"33",X"00",X"E5",X"1E",X"38",X"51",X"CD",X"54",X"00",X"11",X"EC",X"1C", - X"19",X"C5",X"4E",X"23",X"46",X"60",X"69",X"C1",X"D1",X"1A",X"77",X"23",X"13",X"1A",X"77",X"C9", - X"C5",X"3E",X"06",X"90",X"47",X"57",X"1E",X"38",X"CD",X"54",X"00",X"EB",X"FD",X"21",X"EC",X"1C", - X"FD",X"19",X"16",X"00",X"58",X"21",X"3E",X"82",X"19",X"FD",X"7E",X"14",X"4F",X"FE",X"0F",X"7E", - X"20",X"17",X"CB",X"27",X"CB",X"27",X"CB",X"27",X"CB",X"27",X"E6",X"F0",X"47",X"FD",X"6E",X"12", - X"FD",X"66",X"13",X"7E",X"A1",X"B0",X"77",X"C1",X"C9",X"E6",X"0F",X"18",X"EF",X"01",X"1F",X"00", - X"21",X"00",X"80",X"11",X"20",X"80",X"09",X"EB",X"09",X"06",X"0F",X"DD",X"21",X"00",X"B0",X"1A", - X"BE",X"28",X"07",X"77",X"DD",X"70",X"00",X"32",X"02",X"B0",X"1B",X"2B",X"05",X"F2",X"BF",X"07", - X"06",X"0F",X"DD",X"21",X"00",X"A0",X"1A",X"BE",X"28",X"07",X"77",X"DD",X"70",X"00",X"32",X"02", - X"A0",X"1B",X"2B",X"05",X"F2",X"D6",X"07",X"C9",X"00",X"00",X"55",X"00",X"AA",X"00",X"FF",X"00", - X"54",X"01",X"A9",X"01",X"00",X"11",X"22",X"33",X"44",X"4D",X"49",X"44",X"57",X"41",X"59",X"00", - X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"01",X"01",X"02",X"03",X"04",X"05",X"06",X"00",X"01",X"02",X"03",X"04",X"05",X"06", - X"01",X"07",X"07",X"07",X"07",X"07",X"07",X"00",X"07",X"07",X"07",X"07",X"07",X"07",X"01",X"08", - X"00",X"00",X"00",X"00",X"00",X"01",X"09",X"0A",X"0B",X"0C",X"00",X"00",X"01",X"47",X"00",X"00", - X"00",X"00",X"00",X"00",X"47",X"00",X"00",X"00",X"00",X"00",X"01",X"40",X"00",X"00",X"00",X"00", - X"00",X"00",X"26",X"00",X"00",X"00",X"00",X"00",X"01",X"10",X"00",X"00",X"00",X"00",X"00",X"01", - X"11",X"00",X"00",X"00",X"00",X"00",X"01",X"12",X"13",X"14",X"15",X"16",X"17",X"00",X"12",X"13", - X"14",X"15",X"16",X"17",X"01",X"18",X"19",X"1A",X"1B",X"1C",X"00",X"00",X"18",X"19",X"1A",X"1B", - X"1C",X"00",X"01",X"1D",X"1E",X"1F",X"20",X"00",X"00",X"00",X"1D",X"1E",X"1F",X"20",X"00",X"00", - X"01",X"21",X"22",X"23",X"00",X"00",X"00",X"00",X"21",X"22",X"23",X"00",X"00",X"00",X"01",X"24", - X"25",X"00",X"00",X"00",X"00",X"00",X"24",X"25",X"00",X"00",X"00",X"00",X"01",X"26",X"00",X"00", - X"00",X"00",X"00",X"00",X"2B",X"00",X"00",X"00",X"00",X"00",X"01",X"27",X"00",X"00",X"00",X"00", - X"00",X"00",X"27",X"00",X"00",X"00",X"00",X"00",X"00",X"2A",X"00",X"00",X"00",X"00",X"00",X"01", - X"29",X"00",X"00",X"00",X"00",X"00",X"00",X"29",X"00",X"00",X"00",X"00",X"00",X"01",X"2A",X"00", - X"00",X"00",X"00",X"00",X"01",X"2B",X"00",X"00",X"00",X"00",X"00",X"01",X"2C",X"00",X"00",X"00", - X"00",X"00",X"01",X"2D",X"00",X"00",X"00",X"00",X"00",X"00",X"2D",X"00",X"00",X"00",X"00",X"00", - X"01",X"2E",X"2F",X"00",X"00",X"00",X"00",X"00",X"2E",X"2F",X"35",X"36",X"41",X"42",X"01",X"35", - X"36",X"00",X"00",X"00",X"00",X"01",X"41",X"42",X"00",X"00",X"00",X"00",X"01",X"30",X"00",X"00", - X"00",X"00",X"00",X"00",X"30",X"00",X"00",X"00",X"00",X"00",X"01",X"31",X"00",X"00",X"00",X"00", - X"00",X"01",X"32",X"00",X"00",X"00",X"00",X"00",X"01",X"33",X"00",X"00",X"00",X"00",X"00",X"00", - X"33",X"00",X"00",X"00",X"00",X"00",X"01",X"34",X"00",X"00",X"00",X"00",X"00",X"00",X"34",X"00", - X"00",X"00",X"00",X"00",X"01",X"37",X"28",X"3F",X"00",X"00",X"00",X"00",X"37",X"28",X"3F",X"00", - X"00",X"00",X"01",X"38",X"00",X"00",X"00",X"00",X"00",X"01",X"39",X"00",X"00",X"00",X"00",X"00", - X"00",X"39",X"00",X"00",X"00",X"00",X"00",X"01",X"3A",X"00",X"00",X"00",X"00",X"00",X"00",X"3A", - X"00",X"00",X"00",X"00",X"00",X"01",X"3B",X"00",X"00",X"00",X"00",X"00",X"00",X"3B",X"00",X"00", - X"00",X"00",X"00",X"01",X"3C",X"00",X"00",X"00",X"00",X"00",X"00",X"3C",X"00",X"00",X"00",X"00", - X"00",X"01",X"3D",X"00",X"00",X"00",X"00",X"00",X"00",X"3D",X"00",X"00",X"00",X"00",X"00",X"01", - X"3E",X"00",X"00",X"00",X"00",X"00",X"00",X"3E",X"3D",X"3C",X"3B",X"00",X"00",X"01",X"0F",X"00", - X"00",X"00",X"00",X"00",X"01",X"0D",X"00",X"00",X"00",X"00",X"00",X"01",X"43",X"00",X"00",X"00", - X"00",X"00",X"01",X"44",X"00",X"00",X"00",X"00",X"00",X"01",X"45",X"00",X"00",X"00",X"00",X"00", - X"01",X"46",X"00",X"00",X"00",X"00",X"00",X"00",X"43",X"44",X"45",X"46",X"00",X"00",X"01",X"48", - X"49",X"4A",X"48",X"49",X"4A",X"00",X"31",X"00",X"00",X"00",X"00",X"00",X"01",X"4B",X"00",X"00", - X"00",X"00",X"00",X"00",X"4B",X"00",X"00",X"00",X"00",X"00",X"01",X"4C",X"4D",X"00",X"00",X"00", - X"00",X"00",X"4C",X"4D",X"00",X"00",X"00",X"00",X"01",X"4E",X"00",X"00",X"00",X"00",X"00",X"00", - X"4E",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"01",X"01",X"02",X"02",X"04",X"03",X"08",X"04", - X"10",X"05",X"20",X"06",X"FF",X"90",X"82",X"81",X"C2",X"77",X"C4",X"77",X"C8",X"77",X"D0",X"77", - X"82",X"0D",X"C2",X"1E",X"82",X"0F",X"82",X"29",X"82",X"32",X"81",X"80",X"82",X"80",X"84",X"64", - X"88",X"80",X"90",X"7F",X"A0",X"80",X"81",X"7C",X"82",X"62",X"84",X"80",X"88",X"71",X"90",X"82", - X"81",X"7C",X"82",X"51",X"88",X"50",X"90",X"71",X"81",X"80",X"88",X"80",X"90",X"81",X"82",X"2C", - X"88",X"4D",X"C8",X"2C",X"E0",X"50",X"81",X"7E",X"C1",X"7D",X"88",X"70",X"88",X"70",X"C2",X"31", - X"84",X"66",X"90",X"80",X"84",X"65",X"81",X"7F",X"88",X"57",X"81",X"7E",X"84",X"67",X"C8",X"2C", - X"90",X"81",X"84",X"66",X"A0",X"60",X"C2",X"3F",X"E0",X"50",X"E0",X"50",X"E0",X"50",X"E0",X"50", - X"E0",X"50",X"E0",X"50",X"82",X"70",X"C8",X"2C",X"90",X"82",X"84",X"67",X"E0",X"50",X"E0",X"50", - X"E0",X"50",X"E0",X"50",X"82",X"50",X"89",X"51",X"92",X"51",X"A4",X"51",X"88",X"56",X"E0",X"50", - X"C1",X"50",X"81",X"7C",X"BE",X"0C",X"FF",X"FF",X"FF",X"FF",X"CC",X"0C",X"DA",X"0C",X"6D",X"18", - X"EC",X"0C",X"FA",X"0C",X"6D",X"18",X"0F",X"0D",X"1D",X"0D",X"6D",X"18",X"32",X"0D",X"40",X"0D", - X"6D",X"18",X"55",X"0D",X"63",X"0D",X"6D",X"18",X"78",X"0D",X"86",X"0D",X"6D",X"18",X"9E",X"0D", - X"AC",X"0D",X"7B",X"18",X"BE",X"0D",X"CC",X"0D",X"6D",X"18",X"E1",X"0D",X"ED",X"0D",X"04",X"16", - X"1E",X"0E",X"2A",X"0E",X"04",X"16",X"3C",X"0E",X"48",X"0E",X"04",X"16",X"5D",X"0E",X"69",X"0E", - X"04",X"16",X"BA",X"0E",X"C8",X"0E",X"74",X"18",X"DD",X"0E",X"EB",X"0E",X"88",X"18",X"15",X"0F", - X"21",X"0F",X"6D",X"18",X"2D",X"0F",X"39",X"0F",X"6D",X"18",X"4B",X"0F",X"59",X"0F",X"95",X"18", - X"7D",X"0F",X"D1",X"0F",X"88",X"18",X"8B",X"0F",X"D1",X"0F",X"88",X"18",X"99",X"0F",X"D1",X"0F", - X"88",X"18",X"A7",X"0F",X"D1",X"0F",X"88",X"18",X"B5",X"0F",X"D1",X"0F",X"88",X"18",X"C3",X"0F", - X"D1",X"0F",X"88",X"18",X"FA",X"0F",X"40",X"10",X"88",X"18",X"08",X"10",X"40",X"10",X"88",X"18", - X"16",X"10",X"40",X"10",X"88",X"18",X"24",X"10",X"40",X"10",X"88",X"18",X"32",X"10",X"40",X"10", - X"88",X"18",X"5D",X"10",X"8D",X"10",X"88",X"18",X"69",X"10",X"8D",X"10",X"88",X"18",X"75",X"10", - X"8D",X"10",X"88",X"18",X"81",X"10",X"8D",X"10",X"88",X"18",X"AA",X"10",X"CE",X"10",X"88",X"18", - X"B6",X"10",X"CE",X"10",X"88",X"18",X"C2",X"10",X"CE",X"10",X"88",X"18",X"EB",X"10",X"03",X"11", - X"88",X"18",X"F7",X"10",X"03",X"11",X"88",X"18",X"20",X"11",X"2C",X"11",X"A2",X"18",X"F6",X"15", - X"1C",X"17",X"17",X"16",X"41",X"14",X"88",X"14",X"AF",X"18",X"BA",X"11",X"C8",X"11",X"6D",X"18", - X"D7",X"11",X"E5",X"11",X"74",X"18",X"F4",X"11",X"02",X"12",X"74",X"18",X"11",X"12",X"1D",X"12", - X"88",X"18",X"37",X"12",X"45",X"12",X"88",X"18",X"61",X"12",X"9B",X"12",X"DC",X"18",X"AA",X"12", - X"BA",X"12",X"DC",X"18",X"E7",X"12",X"F5",X"12",X"88",X"18",X"12",X"13",X"20",X"13",X"C9",X"18", - X"4D",X"13",X"70",X"13",X"95",X"18",X"7F",X"13",X"8B",X"13",X"88",X"18",X"96",X"13",X"B1",X"13", - X"A4",X"13",X"61",X"12",X"D5",X"13",X"DC",X"18",X"AA",X"12",X"F3",X"13",X"DC",X"18",X"23",X"14", - X"4F",X"14",X"AF",X"18",X"18",X"15",X"24",X"15",X"88",X"18",X"4D",X"15",X"A8",X"15",X"EF",X"18", - X"5B",X"15",X"A8",X"15",X"EF",X"18",X"C6",X"15",X"46",X"16",X"17",X"16",X"D2",X"15",X"24",X"16", - X"17",X"16",X"DE",X"15",X"46",X"16",X"17",X"16",X"EA",X"15",X"35",X"16",X"17",X"16",X"31",X"14", - X"4F",X"14",X"AF",X"18",X"69",X"15",X"77",X"15",X"BC",X"18",X"61",X"12",X"6D",X"17",X"DC",X"18", - X"AA",X"12",X"7C",X"17",X"DC",X"18",X"57",X"16",X"75",X"16",X"EF",X"18",X"61",X"16",X"86",X"16", - X"EF",X"18",X"61",X"16",X"97",X"16",X"EF",X"18",X"6B",X"16",X"A8",X"16",X"EF",X"18",X"7E",X"0E", - X"8E",X"0E",X"DC",X"18",X"41",X"14",X"D0",X"14",X"AF",X"18",X"23",X"14",X"D0",X"14",X"AF",X"18", - X"31",X"14",X"D0",X"14",X"AF",X"18",X"8B",X"17",X"A5",X"17",X"95",X"18",X"B4",X"17",X"D8",X"17", - X"DC",X"18",X"C6",X"17",X"D8",X"17",X"DC",X"18",X"25",X"18",X"33",X"18",X"C9",X"18",X"CD",X"65", - X"19",X"00",X"00",X"FF",X"0A",X"00",X"FF",X"C9",X"CD",X"70",X"07",X"C9",X"CD",X"65",X"19",X"01", - X"02",X"FF",X"0A",X"01",X"00",X"DE",X"02",X"01",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00", - X"01",X"00",X"04",X"01",X"03",X"01",X"34",X"00",X"04",X"01",X"FD",X"00",X"CD",X"65",X"19",X"01", - X"02",X"FF",X"0A",X"01",X"00",X"AA",X"02",X"01",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00", - X"01",X"00",X"01",X"3C",X"00",X"04",X"01",X"03",X"01",X"34",X"00",X"04",X"01",X"FD",X"00",X"CD", - X"65",X"19",X"01",X"02",X"FF",X"0A",X"01",X"00",X"7B",X"02",X"01",X"FF",X"C9",X"CD",X"6A",X"1A", - X"C7",X"0C",X"00",X"01",X"00",X"01",X"78",X"00",X"04",X"01",X"03",X"01",X"34",X"00",X"04",X"01", - X"FD",X"00",X"CD",X"65",X"19",X"01",X"02",X"FF",X"0A",X"01",X"00",X"52",X"02",X"01",X"FF",X"C9", - X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"00",X"01",X"B4",X"00",X"04",X"01",X"03",X"01",X"34", - X"00",X"04",X"01",X"FD",X"00",X"CD",X"65",X"19",X"01",X"02",X"FF",X"0A",X"01",X"00",X"2D",X"02", - X"01",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"00",X"01",X"F0",X"00",X"04",X"01", - X"03",X"01",X"34",X"00",X"04",X"01",X"FD",X"00",X"CD",X"65",X"19",X"01",X"02",X"FF",X"0A",X"01", - X"00",X"0C",X"02",X"01",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"00",X"01",X"C8", - X"00",X"01",X"64",X"00",X"04",X"01",X"03",X"01",X"34",X"00",X"04",X"01",X"FD",X"00",X"CD",X"65", - X"19",X"01",X"05",X"FF",X"0A",X"0E",X"00",X"50",X"02",X"00",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7", - X"0C",X"00",X"01",X"FF",X"02",X"01",X"07",X"01",X"07",X"00",X"07",X"01",X"FE",X"00",X"CD",X"65", - X"19",X"01",X"01",X"FF",X"0A",X"03",X"00",X"A9",X"02",X"00",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7", - X"0C",X"00",X"01",X"04",X"04",X"01",X"03",X"02",X"02",X"FF",X"01",X"05",X"00",X"05",X"01",X"FE", - X"00",X"CD",X"65",X"19",X"01",X"08",X"FF",X"0A",X"07",X"18",X"1E",X"FF",X"C9",X"CD",X"6A",X"1A", - X"FF",X"0D",X"00",X"01",X"00",X"07",X"02",X"01",X"01",X"14",X"00",X"0E",X"03",X"FF",X"00",X"CD", - X"7B",X"1B",X"0D",X"0E",X"01",X"FF",X"01",X"02",X"01",X"01",X"03",X"FF",X"00",X"CD",X"6A",X"1A", - X"C7",X"0C",X"02",X"02",X"FF",X"05",X"01",X"F0",X"FF",X"05",X"02",X"10",X"00",X"00",X"CD",X"65", - X"19",X"01",X"08",X"FF",X"0A",X"07",X"18",X"19",X"FF",X"C9",X"CD",X"6A",X"1A",X"FF",X"0D",X"00", - X"01",X"00",X"07",X"02",X"01",X"01",X"12",X"00",X"0E",X"03",X"FF",X"00",X"CD",X"65",X"19",X"01", - X"07",X"FF",X"0A",X"00",X"18",X"16",X"FF",X"C9",X"CD",X"6A",X"1A",X"FF",X"0D",X"00",X"01",X"00", - X"01",X"0F",X"00",X"05",X"02",X"03",X"01",X"0A",X"00",X"0F",X"05",X"FF",X"00",X"CD",X"65",X"19", - X"01",X"07",X"FF",X"0A",X"00",X"18",X"11",X"FF",X"C9",X"CD",X"6A",X"1A",X"FF",X"0D",X"00",X"01", - X"00",X"01",X"0F",X"00",X"05",X"02",X"03",X"01",X"08",X"00",X"0F",X"05",X"FF",X"00",X"CD",X"65", - X"19",X"01",X"01",X"FF",X"0A",X"00",X"00",X"81",X"02",X"00",X"2A",X"01",X"FF",X"C9",X"CD",X"6A", - X"1A",X"9A",X"0E",X"01",X"01",X"00",X"07",X"C0",X"01",X"00",X"CD",X"6A",X"1A",X"A9",X"0E",X"00", - X"01",X"00",X"05",X"01",X"02",X"08",X"50",X"FF",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"02",X"02", - X"00",X"90",X"04",X"02",X"00",X"FF",X"03",X"02",X"00",X"00",X"CD",X"65",X"19",X"10",X"07",X"FF", - X"0A",X"0E",X"04",X"10",X"2A",X"0B",X"FF",X"C9",X"CD",X"6A",X"1A",X"C8",X"0C",X"00",X"01",X"00", - X"04",X"06",X"FF",X"02",X"02",X"FF",X"03",X"14",X"01",X"07",X"0B",X"01",X"00",X"CD",X"65",X"19", - X"01",X"04",X"FF",X"0A",X"0C",X"18",X"A8",X"04",X"1F",X"FF",X"C9",X"CD",X"7B",X"1B",X"06",X"0F", - X"01",X"1C",X"01",X"01",X"EA",X"01",X"01",X"13",X"00",X"01",X"01",X"F7",X"01",X"01",X"08",X"01", - X"01",X"F7",X"01",X"01",X"09",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF",X"03",X"02", - X"01",X"01",X"01",X"FD",X"00",X"CD",X"65",X"19",X"10",X"00",X"FF",X"0A",X"0F",X"04",X"0B",X"FF", - X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"00",X"0F",X"01",X"FF",X"00",X"CD",X"65",X"19", - X"10",X"04",X"FF",X"0A",X"0D",X"04",X"04",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01", - X"00",X"01",X"07",X"F3",X"01",X"0D",X"0D",X"01",X"08",X"F3",X"00",X"CD",X"65",X"19",X"10",X"0B", - X"FF",X"2A",X"0B",X"0A",X"0F",X"04",X"1F",X"FF",X"C9",X"CD",X"6A",X"1A",X"6B",X"0F",X"00",X"01", - X"00",X"04",X"04",X"FF",X"01",X"01",X"04",X"0F",X"06",X"FF",X"00",X"CD",X"6A",X"1A",X"C8",X"0C", - X"01",X"01",X"00",X"03",X"05",X"00",X"01",X"02",X"FB",X"1E",X"03",X"00",X"00",X"CD",X"65",X"19", - X"01",X"04",X"FF",X"0A",X"0F",X"18",X"00",X"2A",X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04", - X"FF",X"0A",X"0F",X"18",X"04",X"2A",X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A", - X"0F",X"18",X"08",X"2A",X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A",X"0F",X"18", - X"0C",X"2A",X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A",X"0F",X"18",X"10",X"2A", - X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A",X"0F",X"18",X"14",X"2A",X"04",X"FF", - X"C9",X"CD",X"7B",X"1B",X"DF",X"0F",X"01",X"FF",X"05",X"01",X"02",X"05",X"01",X"FE",X"00",X"CD", - X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"00",X"01",X"08",X"00",X"03",X"01",X"FB",X"01",X"03",X"00", - X"03",X"01",X"05",X"01",X"20",X"00",X"0F",X"0A",X"FF",X"00",X"CD",X"65",X"19",X"01",X"04",X"FF", - X"0A",X"0F",X"18",X"00",X"2A",X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A",X"0F", - X"18",X"04",X"2A",X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A",X"0F",X"18",X"08", - X"2A",X"04",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A",X"0F",X"18",X"0C",X"2A",X"04", - X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"0A",X"0F",X"18",X"10",X"2A",X"04",X"FF",X"C9", - X"CD",X"7B",X"1B",X"4E",X"10",X"01",X"FF",X"06",X"01",X"02",X"06",X"01",X"FE",X"00",X"CD",X"6A", - X"1A",X"C7",X"0C",X"00",X"01",X"00",X"01",X"10",X"00",X"0F",X"09",X"FF",X"00",X"CD",X"65",X"19", - X"01",X"04",X"FF",X"18",X"00",X"0A",X"0F",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"18", - X"02",X"0A",X"0F",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"18",X"04",X"0A",X"0F",X"FF", - X"C9",X"CD",X"65",X"19",X"01",X"04",X"FF",X"18",X"06",X"0A",X"0F",X"FF",X"C9",X"CD",X"7B",X"1B", - X"9B",X"10",X"01",X"FF",X"04",X"01",X"04",X"04",X"01",X"FC",X"00",X"CD",X"6A",X"1A",X"C7",X"0C", - X"00",X"01",X"00",X"01",X"0C",X"00",X"0F",X"08",X"FF",X"00",X"CD",X"65",X"19",X"01",X"02",X"FF", - X"0A",X"0F",X"18",X"10",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"02",X"FF",X"0A",X"0F",X"18",X"15", - X"FF",X"C9",X"CD",X"65",X"19",X"01",X"02",X"FF",X"0A",X"0F",X"18",X"18",X"FF",X"C9",X"CD",X"7B", - X"1B",X"DC",X"10",X"01",X"FF",X"04",X"01",X"02",X"04",X"01",X"FE",X"00",X"CD",X"6A",X"1A",X"C7", - X"0C",X"00",X"01",X"00",X"01",X"18",X"00",X"0F",X"0E",X"FF",X"00",X"CD",X"65",X"19",X"01",X"07", - X"FF",X"0A",X"0F",X"18",X"00",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"07",X"FF",X"0A",X"0F",X"18", - X"02",X"FF",X"C9",X"CD",X"7B",X"1B",X"11",X"11",X"01",X"FF",X"07",X"01",X"02",X"07",X"01",X"FE", - X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"00",X"01",X"0A",X"00",X"0F",X"07",X"FF",X"00", - X"CD",X"65",X"19",X"10",X"06",X"FF",X"0A",X"0C",X"04",X"1E",X"FF",X"C9",X"CD",X"6A",X"1A",X"3E", - X"11",X"00",X"01",X"01",X"03",X"03",X"01",X"01",X"04",X"F1",X"01",X"09",X"0C",X"00",X"CD",X"6A", - X"1A",X"C7",X"0C",X"01",X"01",X"FF",X"01",X"09",X"F1",X"01",X"07",X"F1",X"01",X"05",X"0F",X"01", - X"03",X"0F",X"00",X"CD",X"65",X"19",X"10",X"08",X"FF",X"0A",X"0E",X"04",X"18",X"2C",X"23",X"2A", - X"08",X"FF",X"C9",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"2C",X"2C",X"CD", - X"C9",X"1C",X"20",X"CD",X"33",X"1A",X"02",X"2A",X"2A",X"C9",X"CD",X"6A",X"1A",X"89",X"11",X"00", - X"01",X"FF",X"07",X"01",X"FE",X"01",X"30",X"0E",X"00",X"CD",X"70",X"07",X"CD",X"6A",X"1A",X"9B", - X"11",X"02",X"01",X"FF",X"04",X"21",X"FF",X"04",X"17",X"01",X"00",X"CD",X"6A",X"1A",X"B6",X"11", - X"01",X"01",X"FF",X"06",X"20",X"01",X"07",X"18",X"FF",X"04",X"20",X"02",X"03",X"20",X"FE",X"07", - X"18",X"01",X"08",X"20",X"FF",X"00",X"CD",X"A9",X"1C",X"C9",X"CD",X"65",X"19",X"10",X"03",X"FF", - X"0A",X"0F",X"04",X"1E",X"2A",X"03",X"FF",X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF", - X"01",X"04",X"F1",X"01",X"08",X"0F",X"00",X"CD",X"65",X"19",X"10",X"0F",X"FF",X"0A",X"0F",X"04", - X"00",X"2A",X"0F",X"FF",X"C9",X"CD",X"6A",X"1A",X"C8",X"0C",X"00",X"01",X"07",X"08",X"03",X"FF", - X"07",X"02",X"01",X"00",X"CD",X"65",X"19",X"10",X"0F",X"FF",X"0A",X"0F",X"2A",X"0F",X"04",X"1F", - X"FF",X"C9",X"CD",X"6A",X"1A",X"C8",X"0C",X"00",X"01",X"00",X"0F",X"0F",X"FF",X"0F",X"0F",X"01", - X"00",X"CD",X"65",X"19",X"01",X"03",X"FF",X"0A",X"05",X"18",X"85",X"FF",X"C9",X"CD",X"7B",X"1B", - X"2B",X"12",X"01",X"05",X"03",X"01",X"FD",X"02",X"01",X"02",X"00",X"CD",X"6A",X"1A",X"C7",X"0C", - X"00",X"01",X"00",X"0A",X"03",X"01",X"00",X"CD",X"65",X"19",X"01",X"08",X"FF",X"0A",X"0C",X"18", - X"00",X"04",X"08",X"FF",X"C9",X"CD",X"7B",X"1B",X"52",X"12",X"01",X"00",X"50",X"01",X"02",X"FF", - X"FE",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF",X"01",X"04",X"F4",X"03",X"01",X"04", - X"00",X"CD",X"65",X"19",X"01",X"0F",X"FF",X"0A",X"0F",X"02",X"0F",X"2A",X"0F",X"00",X"FF",X"FF", - X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF",X"01",X"03",X"F1",X"01",X"06",X"0F",X"00", - X"CD",X"70",X"07",X"CD",X"6A",X"1A",X"71",X"12",X"01",X"01",X"00",X"03",X"60",X"FF",X"02",X"50", - X"FF",X"02",X"40",X"FF",X"01",X"40",X"FF",X"FF",X"FF",X"00",X"00",X"CD",X"6A",X"1A",X"80",X"12", - X"02",X"01",X"FF",X"04",X"08",X"F0",X"04",X"08",X"10",X"00",X"CD",X"65",X"19",X"01",X"0F",X"FF", - X"0A",X"0F",X"02",X"00",X"00",X"10",X"2A",X"0F",X"FF",X"C9",X"CD",X"6A",X"1A",X"80",X"12",X"02", - X"01",X"FF",X"03",X"01",X"FF",X"01",X"06",X"03",X"00",X"CD",X"6A",X"1A",X"D8",X"12",X"00",X"01", - X"FF",X"05",X"01",X"01",X"05",X"02",X"FF",X"00",X"CD",X"6A",X"1A",X"C8",X"0C",X"01",X"01",X"FF", - X"05",X"01",X"FF",X"05",X"02",X"01",X"00",X"CD",X"65",X"19",X"11",X"06",X"FF",X"18",X"A0",X"0A", - X"0F",X"04",X"0C",X"FF",X"C9",X"CD",X"7B",X"1B",X"03",X"13",X"01",X"00",X"50",X"01",X"FE",X"FF", - X"FF",X"00",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF",X"01",X"03",X"F1",X"01",X"06", - X"0F",X"00",X"CD",X"65",X"19",X"10",X"04",X"FF",X"0A",X"09",X"2A",X"04",X"04",X"04",X"FF",X"C9", - X"CD",X"6A",X"1A",X"2F",X"13",X"02",X"01",X"FF",X"03",X"0A",X"FF",X"03",X"0F",X"01",X"00",X"CD", - X"6A",X"1A",X"3E",X"13",X"00",X"01",X"FF",X"03",X"0A",X"01",X"03",X"0F",X"FF",X"00",X"CD",X"6A", - X"1A",X"C8",X"0C",X"01",X"01",X"FF",X"03",X"0A",X"FF",X"03",X"0F",X"01",X"00",X"CD",X"65",X"19", - X"10",X"0B",X"FF",X"0A",X"0F",X"04",X"1F",X"2A",X"0B",X"FF",X"C9",X"CD",X"6A",X"1A",X"C8",X"0C", - X"01",X"01",X"00",X"01",X"2C",X"00",X"01",X"01",X"04",X"0F",X"02",X"FF",X"0F",X"06",X"01",X"00", - X"CD",X"6A",X"1A",X"5B",X"13",X"00",X"01",X"00",X"01",X"4B",X"00",X"0F",X"06",X"FF",X"00",X"CD", - X"65",X"19",X"01",X"08",X"FF",X"18",X"A0",X"0A",X"0C",X"FF",X"C9",X"CD",X"7B",X"1B",X"52",X"12", - X"01",X"00",X"FF",X"FF",X"00",X"00",X"CD",X"65",X"19",X"10",X"0F",X"FF",X"04",X"06",X"2A",X"0F", - X"0A",X"04",X"FF",X"C9",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"2A",X"2A", - X"C9",X"CD",X"6A",X"1A",X"C3",X"13",X"00",X"01",X"00",X"0A",X"01",X"01",X"01",X"1C",X"00",X"09", - X"0A",X"FF",X"00",X"CD",X"6A",X"1A",X"C8",X"0C",X"01",X"01",X"00",X"07",X"03",X"FF",X"03",X"09", - X"FF",X"02",X"28",X"01",X"00",X"CD",X"70",X"07",X"CD",X"6A",X"1A",X"05",X"14",X"01",X"01",X"FF", - X"01",X"01",X"F8",X"04",X"B0",X"01",X"03",X"B0",X"FF",X"02",X"B0",X"01",X"03",X"B0",X"FF",X"01", - X"01",X"08",X"00",X"CD",X"70",X"07",X"CD",X"6A",X"1A",X"14",X"14",X"01",X"01",X"00",X"01",X"01", - X"F8",X"FF",X"FF",X"00",X"00",X"CD",X"6A",X"1A",X"71",X"12",X"02",X"01",X"FF",X"04",X"08",X"F0", - X"04",X"08",X"10",X"00",X"CD",X"6A",X"1A",X"71",X"12",X"02",X"01",X"FF",X"03",X"01",X"FF",X"01", - X"06",X"03",X"00",X"CD",X"65",X"19",X"01",X"01",X"FF",X"0A",X"0A",X"02",X"00",X"00",X"59",X"FF", - X"C9",X"CD",X"65",X"19",X"11",X"04",X"FF",X"0A",X"0A",X"02",X"00",X"00",X"6B",X"04",X"1A",X"FF", - X"C9",X"CD",X"65",X"19",X"01",X"01",X"FF",X"0A",X"0A",X"02",X"00",X"00",X"62",X"FF",X"C9",X"CD", - X"6A",X"1A",X"C1",X"14",X"01",X"02",X"02",X"05",X"01",X"03",X"00",X"02",X"02",X"FA",X"FF",X"05", - X"01",X"04",X"00",X"02",X"02",X"F9",X"FF",X"05",X"01",X"05",X"00",X"02",X"02",X"F8",X"FF",X"05", - X"01",X"06",X"00",X"02",X"02",X"F7",X"FF",X"05",X"01",X"07",X"00",X"02",X"02",X"F6",X"FF",X"05", - X"01",X"08",X"00",X"02",X"02",X"F5",X"FF",X"00",X"CD",X"6A",X"1A",X"C1",X"14",X"01",X"02",X"02", - X"02",X"02",X"FA",X"FF",X"05",X"01",X"03",X"00",X"02",X"02",X"F9",X"FF",X"05",X"01",X"04",X"00", - X"02",X"02",X"F8",X"FF",X"05",X"01",X"05",X"00",X"02",X"02",X"F7",X"FF",X"05",X"01",X"07",X"00", - X"02",X"02",X"F6",X"FF",X"05",X"01",X"06",X"00",X"02",X"02",X"F5",X"FF",X"05",X"01",X"08",X"00", - X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF",X"04",X"05",X"01",X"02",X"02",X"FE",X"00", - X"CD",X"6A",X"1A",X"09",X"15",X"01",X"02",X"00",X"06",X"01",X"03",X"00",X"02",X"01",X"FA",X"FF", - X"06",X"01",X"04",X"00",X"02",X"01",X"F9",X"FF",X"06",X"01",X"05",X"00",X"02",X"01",X"F8",X"FF", - X"06",X"01",X"06",X"00",X"02",X"01",X"F7",X"FF",X"06",X"01",X"07",X"00",X"02",X"01",X"F6",X"FF", - X"06",X"01",X"08",X"00",X"02",X"01",X"F5",X"FF",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01", - X"00",X"05",X"0C",X"01",X"0C",X"01",X"FF",X"00",X"CD",X"65",X"19",X"01",X"02",X"FF",X"0A",X"0C", - X"18",X"8C",X"FF",X"C9",X"CD",X"7B",X"1B",X"35",X"15",X"01",X"09",X"03",X"01",X"FE",X"02",X"01", - X"0A",X"01",X"01",X"EA",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"00",X"01",X"04",X"F4", - X"01",X"06",X"0F",X"05",X"06",X"FF",X"05",X"03",X"FF",X"05",X"01",X"FF",X"00",X"CD",X"65",X"19", - X"01",X"09",X"FF",X"0A",X"07",X"02",X"0C",X"00",X"00",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"08", - X"FF",X"0A",X"09",X"02",X"0A",X"00",X"00",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"09",X"FF",X"0A", - X"00",X"00",X"FF",X"02",X"0F",X"FF",X"C9",X"CD",X"6A",X"1A",X"86",X"15",X"00",X"01",X"01",X"01", - X"01",X"0F",X"05",X"05",X"FD",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"01",X"01",X"01",X"01",X"01", - X"F6",X"05",X"05",X"02",X"00",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"00", - X"00",X"CD",X"33",X"1A",X"02",X"00",X"00",X"C9",X"CD",X"6A",X"1A",X"B7",X"15",X"02",X"01",X"FF", - X"02",X"01",X"01",X"01",X"01",X"FE",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF",X"04", - X"10",X"01",X"FF",X"FF",X"00",X"00",X"CD",X"65",X"19",X"01",X"0B",X"00",X"0A",X"0D",X"2A",X"0B", - X"FF",X"C9",X"CD",X"65",X"19",X"01",X"0B",X"00",X"0A",X"0D",X"2A",X"0B",X"FF",X"C9",X"CD",X"65", - X"19",X"01",X"09",X"00",X"0A",X"0D",X"2A",X"09",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"09",X"00", - X"0A",X"0D",X"2A",X"09",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"09",X"FF",X"0A",X"0D",X"02",X"0F", - X"00",X"FF",X"FF",X"C9",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"18",X"18", - X"CD",X"33",X"1A",X"02",X"00",X"00",X"C9",X"CD",X"33",X"1A",X"00",X"02",X"02",X"CD",X"33",X"1A", - X"01",X"0A",X"0A",X"C9",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"02",X"FF",X"02",X"01",X"00",X"FF", - X"01",X"01",X"00",X"02",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"02",X"FF",X"03",X"01",X"00", - X"FF",X"01",X"01",X"00",X"03",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"02",X"FF",X"01",X"01", - X"00",X"03",X"03",X"01",X"00",X"FF",X"00",X"CD",X"65",X"19",X"01",X"0B",X"00",X"0A",X"0F",X"FF", - X"C9",X"CD",X"65",X"19",X"01",X"0A",X"00",X"0A",X"0F",X"FF",X"C9",X"CD",X"65",X"19",X"01",X"09", - X"00",X"0A",X"0F",X"FF",X"C9",X"CD",X"6A",X"1A",X"B9",X"16",X"01",X"02",X"FF",X"03",X"04",X"9D", - X"FF",X"03",X"02",X"63",X"00",X"00",X"CD",X"6A",X"1A",X"C8",X"16",X"01",X"02",X"FF",X"03",X"04", - X"B1",X"FF",X"03",X"02",X"4F",X"00",X"00",X"CD",X"6A",X"1A",X"C8",X"16",X"01",X"02",X"FF",X"03", - X"02",X"C5",X"FF",X"03",X"01",X"3B",X"00",X"00",X"CD",X"6A",X"1A",X"D7",X"16",X"01",X"02",X"FF", - X"03",X"02",X"CF",X"FF",X"03",X"01",X"31",X"00",X"00",X"CD",X"6A",X"1A",X"E6",X"16",X"02",X"01", - X"FF",X"01",X"0C",X"FF",X"01",X"04",X"01",X"00",X"CD",X"6A",X"1A",X"F8",X"16",X"02",X"01",X"FF", - X"01",X"06",X"FF",X"01",X"02",X"01",X"00",X"CD",X"6A",X"1A",X"0A",X"17",X"02",X"01",X"FF",X"01", - X"03",X"FF",X"01",X"01",X"01",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF",X"01",X"0C", - X"00",X"03",X"04",X"FF",X"03",X"02",X"01",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00",X"01",X"FF", - X"01",X"06",X"00",X"03",X"02",X"FF",X"03",X"01",X"01",X"00",X"CD",X"6A",X"1A",X"C7",X"0C",X"00", - X"01",X"FF",X"01",X"03",X"00",X"01",X"03",X"FD",X"01",X"01",X"03",X"00",X"CD",X"6A",X"1A",X"2B", - X"17",X"00",X"01",X"FF",X"05",X"01",X"FF",X"01",X"01",X"05",X"00",X"CD",X"6A",X"1A",X"C7",X"0C", - X"01",X"01",X"FF",X"01",X"28",X"FC",X"01",X"07",X"04",X"01",X"1E",X"FA",X"01",X"05",X"06",X"01", - X"32",X"FD",X"01",X"08",X"03",X"01",X"28",X"FB",X"01",X"0A",X"05",X"01",X"1E",X"FD",X"01",X"0C", - X"03",X"00",X"CD",X"70",X"07",X"CD",X"6A",X"1A",X"71",X"12",X"01",X"01",X"00",X"01",X"01",X"F8", - X"01",X"30",X"01",X"02",X"40",X"01",X"02",X"50",X"01",X"03",X"50",X"01",X"00",X"CD",X"6A",X"1A", - X"52",X"17",X"02",X"01",X"FF",X"04",X"08",X"F0",X"04",X"08",X"10",X"00",X"CD",X"6A",X"1A",X"52", - X"17",X"02",X"01",X"FF",X"03",X"01",X"FF",X"01",X"06",X"03",X"00",X"CD",X"65",X"19",X"10",X"06", - X"FF",X"0A",X"0F",X"04",X"0F",X"2A",X"06",X"FF",X"C9",X"CD",X"6A",X"1A",X"C8",X"0C",X"01",X"01", - X"00",X"06",X"0F",X"FF",X"00",X"CD",X"6A",X"1A",X"99",X"17",X"00",X"01",X"00",X"02",X"09",X"00", - X"08",X"09",X"FF",X"00",X"CD",X"65",X"19",X"11",X"0B",X"FF",X"0A",X"0A",X"2A",X"0B",X"04",X"01", - X"00",X"B8",X"02",X"00",X"FF",X"C9",X"CD",X"65",X"19",X"11",X"0B",X"FF",X"0A",X"0A",X"2A",X"0B", - X"04",X"01",X"00",X"30",X"02",X"02",X"FF",X"C9",X"CD",X"6A",X"1A",X"0F",X"18",X"00",X"01",X"00", - X"05",X"01",X"01",X"01",X"0A",X"00",X"05",X"01",X"FD",X"01",X"0F",X"00",X"05",X"01",X"03",X"01", - X"0F",X"00",X"08",X"0A",X"FF",X"07",X"05",X"FF",X"00",X"CD",X"6A",X"1A",X"0F",X"18",X"02",X"01", - X"00",X"0F",X"02",X"FF",X"FF",X"FF",X"00",X"00",X"01",X"63",X"00",X"08",X"13",X"01",X"00",X"CD", - X"6A",X"1A",X"C8",X"0C",X"01",X"01",X"00",X"05",X"01",X"FF",X"FF",X"FF",X"00",X"00",X"01",X"63", - X"00",X"08",X"13",X"01",X"00",X"CD",X"65",X"19",X"10",X"00",X"FF",X"0A",X"0C",X"04",X"12",X"2A", - X"00",X"FF",X"C9",X"CD",X"6A",X"1A",X"42",X"18",X"00",X"01",X"FF",X"05",X"07",X"FF",X"05",X"0A", - X"01",X"00",X"CD",X"6A",X"1A",X"5A",X"18",X"02",X"01",X"FF",X"01",X"10",X"F8",X"01",X"14",X"04", - X"01",X"20",X"05",X"01",X"15",X"F7",X"01",X"1F",X"08",X"00",X"CD",X"6A",X"1A",X"C8",X"0C",X"01", - X"01",X"FF",X"05",X"01",X"01",X"05",X"03",X"FF",X"00",X"00",X"00",X"00",X"00",X"CD",X"33",X"1A", - X"00",X"0A",X"0A",X"C9",X"CD",X"33",X"1A",X"00",X"2A",X"2A",X"C9",X"CD",X"33",X"1A",X"00",X"0A", - X"0A",X"CD",X"33",X"1A",X"01",X"0A",X"0A",X"C9",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33", - X"1A",X"01",X"18",X"18",X"C9",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"2A", - X"2A",X"C9",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"04",X"04",X"C9",X"CD", - X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"00",X"00",X"C9",X"CD",X"33",X"1A",X"00", - X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"02",X"02",X"C9",X"CD",X"33",X"1A",X"00",X"0A",X"0A",X"CD", - X"33",X"1A",X"01",X"2A",X"2A",X"CD",X"33",X"1A",X"02",X"04",X"04",X"C9",X"CD",X"33",X"1A",X"00", - X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"2A",X"2A",X"CD",X"33",X"1A",X"02",X"00",X"00",X"C9",X"CD", - X"33",X"1A",X"00",X"0A",X"0A",X"CD",X"33",X"1A",X"01",X"00",X"00",X"CD",X"33",X"1A",X"02",X"02", - X"02",X"C9",X"DD",X"21",X"BC",X"82",X"06",X"00",X"DD",X"7E",X"04",X"DD",X"BE",X"03",X"28",X"49", - X"DD",X"77",X"03",X"DD",X"36",X"02",X"01",X"26",X"00",X"DD",X"6E",X"04",X"29",X"54",X"5D",X"19", - X"19",X"11",X"E4",X"0A",X"19",X"5E",X"23",X"56",X"DD",X"E5",X"E5",X"EB",X"11",X"31",X"19",X"D5", - X"E9",X"E1",X"DD",X"E1",X"23",X"7E",X"DD",X"77",X"00",X"23",X"7E",X"DD",X"77",X"01",X"DD",X"7E", - X"04",X"FE",X"00",X"28",X"14",X"23",X"23",X"7E",X"FE",X"FF",X"28",X"0D",X"DD",X"E5",X"57",X"2B", - X"5E",X"EB",X"11",X"57",X"19",X"D5",X"E9",X"DD",X"E1",X"11",X"09",X"00",X"DD",X"19",X"04",X"78", - X"FE",X"06",X"20",X"A4",X"C9",X"50",X"1E",X"38",X"CD",X"54",X"00",X"11",X"EC",X"1C",X"19",X"E5", - X"FD",X"E1",X"DD",X"E3",X"DD",X"CB",X"00",X"46",X"20",X"10",X"FD",X"7E",X"09",X"2F",X"4F",X"FD", - X"5E",X"06",X"FD",X"56",X"07",X"1A",X"B1",X"12",X"18",X"0B",X"FD",X"5E",X"06",X"FD",X"56",X"07", - X"1A",X"FD",X"A6",X"09",X"12",X"DD",X"CB",X"00",X"66",X"20",X"0A",X"FD",X"7E",X"08",X"2F",X"4F", - X"1A",X"B1",X"12",X"18",X"05",X"1A",X"FD",X"A6",X"08",X"12",X"DD",X"4E",X"01",X"FD",X"7E",X"14", - X"FE",X"0F",X"20",X"0A",X"79",X"CB",X"27",X"CB",X"27",X"CB",X"27",X"CB",X"27",X"4F",X"FD",X"5E", - X"12",X"FD",X"56",X"13",X"1A",X"FD",X"A6",X"14",X"B1",X"12",X"DD",X"7E",X"02",X"4F",X"FE",X"FF", - X"28",X"39",X"26",X"00",X"68",X"5D",X"54",X"29",X"29",X"29",X"19",X"11",X"BC",X"82",X"19",X"11", - X"01",X"90",X"3E",X"06",X"CD",X"33",X"00",X"1A",X"E6",X"7F",X"77",X"23",X"FD",X"E5",X"D1",X"EB", - X"79",X"CD",X"33",X"00",X"7E",X"12",X"23",X"13",X"66",X"6F",X"EB",X"72",X"21",X"03",X"90",X"7E", - X"12",X"2B",X"7E",X"CB",X"77",X"28",X"04",X"E6",X"0F",X"13",X"12",X"DD",X"E5",X"E1",X"1E",X"03", - X"16",X"00",X"19",X"D9",X"FD",X"E5",X"D1",X"D9",X"7E",X"FE",X"FF",X"28",X"12",X"D9",X"62",X"6B", - X"CD",X"33",X"00",X"4E",X"23",X"46",X"D9",X"23",X"7E",X"D9",X"02",X"D9",X"23",X"18",X"E9",X"23", - X"D1",X"E5",X"C9",X"DD",X"E1",X"48",X"DD",X"5E",X"00",X"CD",X"26",X"07",X"DD",X"5E",X"01",X"FD", - X"E5",X"16",X"00",X"FD",X"19",X"FD",X"7E",X"00",X"77",X"23",X"FD",X"7E",X"01",X"77",X"FD",X"E1", - X"DD",X"5E",X"02",X"FD",X"E5",X"FD",X"19",X"FD",X"7E",X"00",X"23",X"77",X"23",X"FD",X"7E",X"01", - X"77",X"1E",X"03",X"DD",X"19",X"FD",X"E1",X"DD",X"E5",X"C9",X"FD",X"E1",X"C5",X"3E",X"06",X"90", - X"4F",X"FD",X"5E",X"02",X"CD",X"26",X"07",X"C1",X"C5",X"E5",X"DD",X"E3",X"79",X"FE",X"00",X"28", - X"33",X"DD",X"6E",X"00",X"DD",X"66",X"01",X"DD",X"5E",X"02",X"DD",X"56",X"03",X"7E",X"12",X"FD", - X"CB",X"03",X"4E",X"28",X"04",X"23",X"13",X"7E",X"12",X"FD",X"7E",X"06",X"DD",X"77",X"04",X"FD", - X"7E",X"05",X"DD",X"77",X"05",X"AF",X"DD",X"77",X"06",X"FD",X"7E",X"04",X"DD",X"77",X"07",X"DD", - X"E1",X"C3",X"72",X"1B",X"DD",X"35",X"04",X"28",X"05",X"DD",X"E1",X"C3",X"72",X"1B",X"FD",X"46", - X"03",X"CB",X"48",X"26",X"00",X"DD",X"6E",X"06",X"54",X"5D",X"20",X"04",X"0E",X"03",X"18",X"03", - X"0E",X"04",X"29",X"19",X"19",X"16",X"00",X"1E",X"05",X"19",X"EB",X"FD",X"E5",X"FD",X"19",X"DD", - X"6E",X"00",X"DD",X"66",X"01",X"DD",X"5E",X"02",X"DD",X"56",X"03",X"CB",X"48",X"20",X"07",X"FD", - X"7E",X"02",X"86",X"12",X"18",X"10",X"C5",X"4E",X"23",X"46",X"FD",X"6E",X"02",X"FD",X"66",X"03", - X"09",X"C1",X"EB",X"73",X"23",X"72",X"DD",X"35",X"05",X"20",X"5D",X"DD",X"34",X"06",X"16",X"00", - X"59",X"FD",X"19",X"FD",X"7E",X"00",X"FE",X"00",X"20",X"3C",X"DD",X"7E",X"07",X"FE",X"00",X"28", - X"1D",X"FE",X"FF",X"28",X"03",X"DD",X"35",X"07",X"AF",X"DD",X"77",X"06",X"FD",X"E1",X"FD",X"7E", - X"05",X"DD",X"77",X"05",X"FD",X"7E",X"06",X"DD",X"77",X"04",X"DD",X"E1",X"18",X"34",X"FD",X"E1", - X"DD",X"E1",X"C1",X"3E",X"06",X"90",X"21",X"5C",X"1E",X"16",X"00",X"5F",X"19",X"3A",X"1F",X"83", - X"B6",X"32",X"1F",X"83",X"18",X"1D",X"FD",X"7E",X"01",X"DD",X"77",X"04",X"FD",X"7E",X"00",X"DD", - X"77",X"05",X"FD",X"E1",X"DD",X"E1",X"18",X"0A",X"FD",X"7E",X"01",X"DD",X"77",X"04",X"FD",X"E1", - X"DD",X"E1",X"C1",X"FD",X"6E",X"00",X"FD",X"66",X"01",X"E5",X"C9",X"FD",X"E1",X"C5",X"3E",X"06", - X"90",X"4F",X"FD",X"5E",X"02",X"CD",X"26",X"07",X"59",X"C1",X"C5",X"E5",X"DD",X"E3",X"79",X"FE", - X"00",X"28",X"48",X"C5",X"4B",X"16",X"00",X"1E",X"09",X"19",X"71",X"C1",X"2B",X"DD",X"75",X"00", - X"DD",X"74",X"01",X"DD",X"75",X"02",X"DD",X"74",X"03",X"DD",X"6E",X"00",X"DD",X"66",X"01",X"DD", - X"5E",X"02",X"DD",X"56",X"03",X"7E",X"12",X"FD",X"7E",X"05",X"DD",X"77",X"04",X"FD",X"7E",X"04", - X"DD",X"77",X"05",X"AF",X"DD",X"77",X"06",X"FD",X"7E",X"03",X"DD",X"77",X"07",X"DD",X"7E",X"08", - X"DD",X"4E",X"09",X"CD",X"44",X"07",X"DD",X"E1",X"C3",X"A0",X"1C",X"DD",X"35",X"04",X"28",X"05", - X"DD",X"E1",X"C3",X"A0",X"1C",X"26",X"00",X"DD",X"6E",X"06",X"54",X"5D",X"0E",X"03",X"19",X"19", - X"16",X"00",X"1E",X"04",X"19",X"EB",X"FD",X"E5",X"FD",X"19",X"DD",X"6E",X"00",X"DD",X"66",X"01", - X"DD",X"5E",X"02",X"DD",X"56",X"03",X"FD",X"7E",X"02",X"CB",X"7F",X"CA",X"1E",X"1C",X"86",X"CB", - X"7F",X"CA",X"2B",X"1C",X"CB",X"77",X"CA",X"2B",X"1C",X"C6",X"C0",X"C3",X"2B",X"1C",X"86",X"CB", - X"7F",X"CA",X"2B",X"1C",X"CB",X"77",X"CA",X"2B",X"1C",X"C6",X"40",X"12",X"C5",X"DD",X"4E",X"09", - X"CD",X"44",X"07",X"C1",X"DD",X"35",X"05",X"20",X"5D",X"DD",X"34",X"06",X"16",X"00",X"59",X"FD", - X"19",X"FD",X"7E",X"00",X"FE",X"00",X"20",X"3C",X"DD",X"7E",X"07",X"FE",X"00",X"28",X"1D",X"FE", - X"FF",X"28",X"03",X"DD",X"35",X"07",X"AF",X"DD",X"77",X"06",X"FD",X"E1",X"FD",X"7E",X"04",X"DD", - X"77",X"05",X"FD",X"7E",X"05",X"DD",X"77",X"04",X"DD",X"E1",X"18",X"34",X"FD",X"E1",X"DD",X"E1", - X"C1",X"3E",X"06",X"90",X"21",X"5C",X"1E",X"16",X"00",X"5F",X"19",X"3A",X"1F",X"83",X"B6",X"32", - X"1F",X"83",X"18",X"1D",X"FD",X"7E",X"01",X"DD",X"77",X"04",X"FD",X"7E",X"00",X"DD",X"77",X"05", - X"FD",X"E1",X"DD",X"E1",X"18",X"0A",X"FD",X"7E",X"01",X"DD",X"77",X"04",X"FD",X"E1",X"DD",X"E1", - X"C1",X"FD",X"6E",X"00",X"FD",X"66",X"01",X"E5",X"C9",X"3E",X"06",X"90",X"6F",X"26",X"00",X"54", - X"5D",X"29",X"19",X"FD",X"21",X"F2",X"82",X"EB",X"FD",X"19",X"FD",X"6E",X"00",X"FD",X"66",X"01", - X"FD",X"7E",X"02",X"96",X"D8",X"3E",X"01",X"77",X"C9",X"DD",X"E1",X"FD",X"E5",X"E1",X"DD",X"5E", - X"00",X"16",X"00",X"19",X"E5",X"68",X"26",X"00",X"54",X"5D",X"29",X"19",X"11",X"F2",X"82",X"19", - X"D1",X"1A",X"77",X"13",X"23",X"1A",X"77",X"DD",X"23",X"DD",X"E5",X"C9",X"00",X"80",X"01",X"80", - X"06",X"80",X"07",X"80",X"F7",X"FE",X"08",X"80",X"0B",X"80",X"0C",X"80",X"0D",X"80",X"0E",X"80", - X"F0",X"00",X"48",X"80",X"59",X"80",X"6A",X"80",X"7B",X"80",X"8C",X"80",X"44",X"80",X"55",X"80", - X"66",X"80",X"77",X"80",X"88",X"80",X"3E",X"82",X"F4",X"82",X"49",X"80",X"5A",X"80",X"6B",X"80", - X"7C",X"80",X"8D",X"80",X"02",X"80",X"03",X"80",X"06",X"80",X"07",X"80",X"EF",X"FD",X"09",X"80", - X"0B",X"80",X"0C",X"80",X"0D",X"80",X"0E",X"80",X"0F",X"00",X"9D",X"80",X"AE",X"80",X"BF",X"80", - X"D0",X"80",X"E1",X"80",X"99",X"80",X"AA",X"80",X"BB",X"80",X"CC",X"80",X"DD",X"80",X"3F",X"82", - X"F7",X"82",X"9E",X"80",X"AF",X"80",X"C0",X"80",X"D1",X"80",X"E2",X"80",X"04",X"80",X"05",X"80", - X"06",X"80",X"07",X"80",X"DF",X"FB",X"0A",X"80",X"0B",X"80",X"0C",X"80",X"0D",X"80",X"0F",X"80", - X"F0",X"00",X"F2",X"80",X"03",X"81",X"14",X"81",X"25",X"81",X"36",X"81",X"EE",X"80",X"FF",X"80", - X"10",X"81",X"21",X"81",X"32",X"81",X"40",X"82",X"FA",X"82",X"F3",X"80",X"04",X"81",X"15",X"81", - X"26",X"81",X"37",X"81",X"10",X"80",X"11",X"80",X"16",X"80",X"17",X"80",X"F7",X"FE",X"18",X"80", - X"1B",X"80",X"1C",X"80",X"1D",X"80",X"1E",X"80",X"F0",X"00",X"47",X"81",X"58",X"81",X"69",X"81", - X"7A",X"81",X"8B",X"81",X"43",X"81",X"54",X"81",X"65",X"81",X"76",X"81",X"87",X"81",X"41",X"82", - X"FD",X"82",X"48",X"81",X"59",X"81",X"6A",X"81",X"7B",X"81",X"8C",X"81",X"12",X"80",X"13",X"80", - X"16",X"80",X"17",X"80",X"EF",X"FD",X"19",X"80",X"1B",X"80",X"1C",X"80",X"1D",X"80",X"1E",X"80", - X"0F",X"00",X"9C",X"81",X"AD",X"81",X"BE",X"81",X"CF",X"81",X"E0",X"81",X"98",X"81",X"A9",X"81", - X"BA",X"81",X"CB",X"81",X"DC",X"81",X"42",X"82",X"00",X"83",X"9D",X"81",X"AE",X"81",X"BF",X"81", - X"D0",X"81",X"E1",X"81",X"14",X"80",X"15",X"80",X"16",X"80",X"17",X"80",X"DF",X"FB",X"1A",X"80", - X"1B",X"80",X"1C",X"80",X"1D",X"80",X"1F",X"80",X"F0",X"00",X"F1",X"81",X"02",X"82",X"13",X"82", - X"24",X"82",X"35",X"82",X"ED",X"81",X"FE",X"81",X"0F",X"82",X"20",X"82",X"31",X"82",X"43",X"82", - X"03",X"83",X"F2",X"81",X"03",X"82",X"14",X"82",X"25",X"82",X"36",X"82",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"FF",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"00", - X"00",X"00",X"00",X"FF",X"00",X"00",X"00",X"00",X"00",X"00",X"00",X"70",X"01",X"02",X"04",X"08", - X"10",X"20",X"D1",X"0F",X"60",X"0F",X"EE",X"0E",X"83",X"0E",X"18",X"0E",X"B2",X"0D",X"4D",X"0D", - X"EE",X"0C",X"8E",X"0C",X"34",X"0C",X"DA",X"0B",X"84",X"0B",X"2F",X"0B",X"DF",X"0A",X"8F",X"0A", - X"43",X"0A",X"F7",X"09",X"B0",X"09",X"68",X"09",X"24",X"09",X"E1",X"08",X"A1",X"08",X"61",X"08", - X"25",X"08",X"E9",X"07",X"B0",X"07",X"77",X"07",X"42",X"07",X"0C",X"07",X"D9",X"06",X"A7",X"06", - X"77",X"06",X"47",X"06",X"15",X"06",X"ED",X"05",X"C3",X"05",X"98",X"05",X"6F",X"05",X"47",X"05", - X"21",X"05",X"FB",X"04",X"D8",X"04",X"B4",X"04",X"92",X"04",X"70",X"04",X"50",X"04",X"31",X"04", - X"13",X"04",X"F4",X"03",X"D8",X"03",X"BC",X"03",X"9F",X"03",X"86",X"03",X"6D",X"03",X"53",X"03", - X"3B",X"03",X"24",X"03",X"0D",X"03",X"F6",X"02",X"E1",X"02",X"CC",X"02",X"B8",X"02",X"A4",X"02", - X"91",X"02",X"7E",X"02",X"6C",X"02",X"5A",X"02",X"49",X"02",X"38",X"02",X"28",X"02",X"18",X"02", - X"09",X"02",X"FA",X"01",X"EC",X"01",X"DE",X"01",X"D1",X"01",X"C3",X"01",X"B7",X"01",X"AA",X"01", - X"9E",X"01",X"92",X"01",X"86",X"01",X"7B",X"01",X"71",X"01",X"66",X"01",X"5C",X"01",X"52",X"01", - X"48",X"01",X"3F",X"01",X"36",X"01",X"2D",X"01",X"25",X"01",X"1C",X"01",X"14",X"01",X"0C",X"01", - X"04",X"01",X"FD",X"00",X"F6",X"00",X"EF",X"00",X"E8",X"00",X"E1",X"00",X"DB",X"00",X"D5",X"00", - X"CF",X"00",X"C9",X"00",X"C4",X"00",X"BE",X"00",X"B8",X"00",X"B3",X"00",X"AE",X"00",X"A9",X"00", - X"A4",X"00",X"9F",X"00",X"9B",X"00",X"96",X"00",X"92",X"00",X"8E",X"00",X"8A",X"00",X"86",X"00", - X"82",X"00",X"7F",X"00",X"7B",X"00",X"77",X"00",X"74",X"00",X"71",X"00",X"6D",X"00",X"6A",X"00", - X"67",X"00",X"64",X"00",X"62",X"00",X"5F",X"00",X"5C",X"00",X"59",X"00",X"56",X"00",X"54",X"00", - X"52",X"00",X"50",X"00",X"4E",X"00",X"4B",X"00",X"49",X"00",X"47",X"00",X"45",X"00",X"43",X"00", - X"41",X"00",X"3F",X"00",X"3D",X"00",X"3B",X"00",X"39",X"00",X"38",X"00",X"37",X"00",X"35",X"00", - X"33",X"00",X"32",X"00",X"31",X"00",X"2F",X"00",X"2D",X"00",X"2C",X"00",X"2B",X"00",X"2A",X"00", - X"29",X"00",X"27",X"00",X"26",X"00",X"26",X"00",X"25",X"00",X"24",X"00",X"23",X"00",X"22",X"00", - X"21",X"00",X"20",X"00",X"1F",X"00",X"1E",X"00",X"1D",X"00",X"1C",X"00",X"1B",X"00",X"1B",X"00", - X"1A",X"00",X"19",X"00",X"18",X"00",X"18",X"00",X"17",X"00",X"16",X"00",X"15",X"00",X"15",X"00", - X"14",X"00",X"14",X"00",X"13",X"00",X"13",X"00",X"12",X"00",X"12",X"00",X"11",X"00",X"11",X"00", - X"10",X"00",X"52",X"6F",X"62",X"65",X"72",X"74",X"20",X"4D",X"20",X"4C",X"69",X"62",X"62",X"65", - X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF",X"FF"); -begin -process(clk) -begin - if rising_edge(clk) then - data <= rom_data(to_integer(unsigned(addr))); - end if; -end process; -end architecture; diff --git a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/sdram.sv b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/sdram.sv index 41f5b7a8..9f78c393 100644 --- a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/sdram.sv +++ b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/sdram.sv @@ -50,6 +50,8 @@ module sdram ( output reg [15:0] cpu1_q, input [16:1] cpu2_addr, output reg [15:0] cpu2_q, + input [16:1] cpu3_addr, + output reg [15:0] cpu3_q, input port2_req, output reg port2_ack, @@ -150,9 +152,9 @@ assign SDRAM_nRAS = sd_cmd[2]; assign SDRAM_nCAS = sd_cmd[1]; assign SDRAM_nWE = sd_cmd[0]; -reg [24:1] addr_latch[2]; +reg [24:1] addr_latch[3]; reg [24:1] addr_latch_next[2]; -reg [16:1] addr_last[2]; +reg [16:1] addr_last[4]; reg [16:2] addr_last2[2]; reg [15:0] din_latch[2]; reg [1:0] oe_latch; @@ -162,14 +164,15 @@ reg [1:0] ds[2]; reg port1_state; reg port2_state; -localparam PORT_NONE = 2'd0; -localparam PORT_CPU1 = 2'd1; -localparam PORT_CPU2 = 2'd2; -localparam PORT_SP = 2'd1; -localparam PORT_REQ = 2'd3; +localparam PORT_NONE = 3'd0; +localparam PORT_CPU1 = 3'd1; +localparam PORT_CPU2 = 3'd2; +localparam PORT_CPU3 = 3'd3; +localparam PORT_SP = 3'd1; +localparam PORT_REQ = 3'd4; -reg [1:0] next_port[2]; -reg [1:0] port[2]; +reg [2:0] next_port[2]; +reg [2:0] port[2]; reg refresh; reg [10:0] refresh_cnt; @@ -189,6 +192,9 @@ always @(*) begin end else if (cpu2_addr != addr_last[PORT_CPU2]) begin next_port[0] = PORT_CPU2; addr_latch_next[0] = { 8'd0, cpu2_addr }; + end else if (cpu3_addr != addr_last[PORT_CPU3]) begin + next_port[0] = PORT_CPU3; + addr_latch_next[0] = { 8'd0, cpu3_addr }; end else begin next_port[0] = PORT_NONE; addr_latch_next[0] = addr_latch[0]; @@ -321,6 +327,7 @@ always @(posedge clk) begin PORT_REQ: begin port1_q <= sd_din; port1_ack <= port1_req; end PORT_CPU1: begin cpu1_q <= sd_din; end PORT_CPU2: begin cpu2_q <= sd_din; end + PORT_CPU3: begin cpu3_q <= sd_din; end default: ; endcase; end diff --git a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter.vhd b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter.vhd index 99bba730..1a4e834a 100644 --- a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter.vhd +++ b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter.vhd @@ -151,7 +151,8 @@ port( separate_audio : in std_logic; audio_out_l : out std_logic_vector(15 downto 0); audio_out_r : out std_logic_vector(15 downto 0); - + csd_audio_out : out std_logic_vector( 9 downto 0); + coin1 : in std_logic; coin2 : in std_logic; shift : in std_logic; @@ -176,6 +177,8 @@ port( cpu_rom_do : in std_logic_vector(7 downto 0); snd_rom_addr : out std_logic_vector(12 downto 0); snd_rom_do : in std_logic_vector(7 downto 0); + csd_rom_addr : out std_logic_vector(14 downto 1); + csd_rom_do : in std_logic_vector(15 downto 0); sp_addr : out std_logic_vector(14 downto 0); sp_graphx32_do : in std_logic_vector(31 downto 0); dbg_cpu_addr : out std_logic_vector(15 downto 0) @@ -1154,6 +1157,17 @@ port map( -- data => sp_graphx_do --); +-- background & sprite palette +palette : entity work.gen_ram +generic map( dWidth => 9, aWidth => 6) +port map( + clk => clock_vidn, + we => palette_we, + addr => palette_addr, + d => cpu_addr(0) & cpu_do, + q => palette_do +); + -- Spy hunter sound board sound_board : entity work.spy_hunter_sound_board port map( @@ -1177,19 +1191,22 @@ port map( separate_audio => separate_audio, audio_out_l => audio_out_l, audio_out_r => audio_out_r, - + + cpu_rom_addr => snd_rom_addr, + cpu_rom_do => snd_rom_do, + dbg_cpu_addr => open --dbg_cpu_addr ); - --- background & sprite palette -palette : entity work.gen_ram -generic map( dWidth => 9, aWidth => 6) -port map( - clk => clock_vidn, - we => palette_we, - addr => palette_addr, - d => cpu_addr(0) & cpu_do, - q => palette_do + +-- Cheap Squeak Deluxe +csd: entity work.cheap_squeak_deluxe +port map ( + clock_40 => clock_40, + reset => reset, + input => output_4, + rom_addr => csd_rom_addr, + rom_do => csd_rom_do, + audio_out => csd_audio_out ); end struct; \ No newline at end of file diff --git a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter_sound_board.vhd b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter_sound_board.vhd index 1a6c1d15..ccc88bd5 100644 --- a/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter_sound_board.vhd +++ b/Arcade_MiST/Midway MCR Scroll/SpyHunter_MiST/rtl/spy_hunter_sound_board.vhd @@ -74,7 +74,10 @@ port( audio_out_l : out std_logic_vector(15 downto 0); audio_out_r : out std_logic_vector(15 downto 0); - + + cpu_rom_addr : out std_logic_vector(12 downto 0); + cpu_rom_do : in std_logic_vector(7 downto 0); + dbg_cpu_addr : out std_logic_vector(15 downto 0) ); end spy_hunter_sound_board; @@ -101,7 +104,7 @@ architecture struct of spy_hunter_sound_board is signal cpu_irq_n : std_logic; signal cpu_m1_n : std_logic; - signal cpu_rom_do : std_logic_vector( 7 downto 0); +-- signal cpu_rom_do : std_logic_vector( 7 downto 0); signal wram_we : std_logic; signal wram_do : std_logic_vector( 7 downto 0); @@ -436,12 +439,14 @@ port map( ); -- cpu program ROM 0x0000-0x3FFF -rom_cpu : entity work.spy_hunter_sound_cpu -port map( - clk => clock_sndn, - addr => cpu_addr(12 downto 0), - data => cpu_rom_do -); +--rom_cpu : entity work.spy_hunter_sound_cpu +--port map( +-- clk => clock_sndn, +-- addr => cpu_addr(12 downto 0), +-- data => cpu_rom_do +--); + +cpu_rom_addr <= cpu_addr(12 downto 0); -- working RAM 0x8000-0x83FF wram : entity work.gen_ram diff --git a/common/CPU/68000/FX68k/LICENSE b/common/CPU/68000/FX68k/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/common/CPU/68000/FX68k/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/common/CPU/68000/FX68k/README.md b/common/CPU/68000/FX68k/README.md new file mode 100644 index 00000000..b1c80178 --- /dev/null +++ b/common/CPU/68000/FX68k/README.md @@ -0,0 +1,17 @@ +# fx68k +FX68K 68000 cycle accurate SystemVerilog core + +Copyright (c) 2018 by Jorge Cwik +fx68k@fxatari.com + +FX68K is a 68000 cycle exact compatible core. At least in theory, it should be impossible to distinguish functionally from a real 68K processor. + +On Cyclone families it uses just over 5,100 LEs and about 5KB internal ram, reaching a max effective clock frequency close to 40MHz. Some optimizations are still possible to implement and increase the performance. + +The core is fully synchronous. Considerable effort was made to avoid any asynchronous logic. + +Written in SystemVerilog. + +The timing of the external bus signals is exactly as the original processor. The only feature that is not implemented yet is bus retry using the external HALT input signal. + +It was designed to replace an actual chip on a real board. This wasn't yet tested however and not all necessary output enable control signals are fully implemented. diff --git a/common/CPU/68000/FX68k/Rom.sv b/common/CPU/68000/FX68k/Rom.sv deleted file mode 100644 index 1b35c374..00000000 --- a/common/CPU/68000/FX68k/Rom.sv +++ /dev/null @@ -1,28 +0,0 @@ -// -// microrom and nanorom instantiation -// -// There is bit of wasting of resources here. An extra registering pipeline happens that is not needed. -// This is just for the purpose of helping inferring block RAM using pure generic code. Inferring RAM is important for performance. -// Might be more efficient to use vendor specific features such as clock enable. -// - -module uRom( input clk, input [UADDR_WIDTH-1:0] microAddr, output logic [UROM_WIDTH-1:0] microOutput); - reg [UROM_WIDTH-1:0] uRam[ UROM_DEPTH]; - initial begin - $readmemb("microrom.mem", uRam); - end - - always_ff @( posedge clk) - microOutput <= uRam[ microAddr]; -endmodule - - -module nanoRom( input clk, input [NADDR_WIDTH-1:0] nanoAddr, output logic [NANO_WIDTH-1:0] nanoOutput); - reg [NANO_WIDTH-1:0] nRam[ NANO_DEPTH]; - initial begin - $readmemb("nanorom.mem", nRam); - end - - always_ff @( posedge clk) - nanoOutput <= nRam[ nanoAddr]; -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/aluCorf.sv b/common/CPU/68000/FX68k/aluCorf.sv deleted file mode 100644 index d73bd08e..00000000 --- a/common/CPU/68000/FX68k/aluCorf.sv +++ /dev/null @@ -1,35 +0,0 @@ -// add bcd correction factor -// It would be more efficient to merge add/sub with main ALU !!! -module aluCorf( input [7:0] binResult, input bAdd, input cin, input hCarry, - output [7:0] bcdResult, output dC, output logic ov); - - reg [8:0] htemp; - reg [4:0] hNib; - - wire lowC = hCarry | (bAdd ? gt9( binResult[ 3:0]) : 1'b0); - wire highC = cin | (bAdd ? (gt9( htemp[7:4]) | htemp[8]) : 1'b0); - - always_comb begin - if( bAdd) begin - htemp = { 1'b0, binResult} + (lowC ? 4'h6 : 4'h0); - hNib = htemp[8:4] + (highC ? 4'h6 : 4'h0); - ov = hNib[3] & ~binResult[7]; - end - else begin - htemp = { 1'b0, binResult} - (lowC ? 4'h6 : 4'h0); - hNib = htemp[8:4] - (highC ? 4'h6 : 4'h0); - ov = ~hNib[3] & binResult[7]; - end - end - - assign bcdResult = { hNib[ 3:0], htemp[3:0]}; - assign dC = hNib[4] | cin; - - // Nibble > 9 - function gt9 (input [3:0] nib); - begin - gt9 = nib[3] & (nib[2] | nib[1]); - end - endfunction - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/aluGetOp.sv b/common/CPU/68000/FX68k/aluGetOp.sv deleted file mode 100644 index 8c779973..00000000 --- a/common/CPU/68000/FX68k/aluGetOp.sv +++ /dev/null @@ -1,90 +0,0 @@ -// Get current OP from row & col -module aluGetOp( input [15:0] row, input [2:0] col, input isCorf, - output logic [4:0] aluOp); - - always_comb begin - aluOp = 'X; - unique case( col) - 1: aluOp = OP_AND; - 5: aluOp = OP_EXT; - - default: - unique case( 1'b1) - row[1]: - unique case( col) - 2: aluOp = OP_SUB; - 3: aluOp = OP_SUBC; - 4,6: aluOp = OP_SLAA; - endcase - - row[2]: - unique case( col) - 2: aluOp = OP_ADD; - 3: aluOp = OP_ADDC; - 4: aluOp = OP_ASR; - endcase - - row[3]: - unique case( col) - 2: aluOp = OP_ADDX; - 3: aluOp = isCorf ? OP_ABCD : OP_ADD; - 4: aluOp = OP_ASL; - endcase - - row[4]: - aluOp = ( col == 4) ? OP_LSL : OP_AND; - - row[5], - row[6]: - unique case( col) - 2: aluOp = OP_SUB; - 3: aluOp = OP_SUBC; - 4: aluOp = OP_LSR; - endcase - - row[7]: // MUL - unique case( col) - 2: aluOp = OP_SUB; - 3: aluOp = OP_ADD; - 4: aluOp = OP_ROXR; - endcase - - row[8]: - // OP_AND For EXT.L - // But would be more efficient to change ucode and use column 1 instead of col3 at ublock extr1! - unique case( col) - 2: aluOp = OP_EXT; - 3: aluOp = OP_AND; - 4: aluOp = OP_ROXR; - endcase - - row[9]: - unique case( col) - 2: aluOp = OP_SUBX; - 3: aluOp = OP_SBCD; - 4: aluOp = OP_ROL; - endcase - - row[10]: - unique case( col) - 2: aluOp = OP_SUBX; - 3: aluOp = OP_SUBC; - 4: aluOp = OP_ROR; - endcase - - row[11]: - unique case( col) - 2: aluOp = OP_SUB0; - 3: aluOp = OP_SUB0; - 4: aluOp = OP_ROXL; - endcase - - row[12]: aluOp = OP_ADDX; - row[13]: aluOp = OP_EOR; - row[14]: aluOp = (col == 4) ? OP_EOR : OP_OR; - row[15]: aluOp = (col == 3) ? OP_ADD : OP_OR; // OP_ADD used by DBcc - - endcase - endcase - end -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/aluShifter.sv b/common/CPU/68000/FX68k/aluShifter.sv deleted file mode 100644 index c36d26eb..00000000 --- a/common/CPU/68000/FX68k/aluShifter.sv +++ /dev/null @@ -1,32 +0,0 @@ -module aluShifter( input [31:0] data, - input isByte, input isLong, swapWords, - input dir, input cin, - output logic [31:0] result); - // output reg cout - - logic [31:0] tdata; - - // size mux, put cin in position if dir == right - always_comb begin - tdata = data; - if( isByte & dir) - tdata[8] = cin; - else if( !isLong & dir) - tdata[16] = cin; - end - - always_comb begin - // Reverse alu/alue position for MUL & DIV - // Result reversed again - if( swapWords & dir) - result = { tdata[0], tdata[31:17], cin, tdata[15:1]}; - else if( swapWords) - result = { tdata[30:16], cin, tdata[14:0], tdata[31]}; - - else if( dir) - result = { cin, tdata[31:1]}; - else - result = { tdata[30:0], cin}; - end - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/busArbiter.sv b/common/CPU/68000/FX68k/busArbiter.sv deleted file mode 100644 index 89bd2fb3..00000000 --- a/common/CPU/68000/FX68k/busArbiter.sv +++ /dev/null @@ -1,87 +0,0 @@ -// -// DMA/BUS Arbitration -// - -module busArbiter( input s_clks Clks, - input BRi, BgackI, Halti, bgBlock, - output busAvail, - output logic BGn); - - enum int unsigned { DRESET = 0, DIDLE, D1, D_BR, D_BA, D_BRA, D3, D2} dmaPhase, next; - - always_comb begin - case(dmaPhase) - DRESET: next = DIDLE; - DIDLE: begin - if( bgBlock) - next = DIDLE; - else if( ~BgackI) - next = D_BA; - else if( ~BRi) - next = D1; - else - next = DIDLE; - end - - D_BA: begin // Loop while only BGACK asserted, BG negated here - if( ~BRi & !bgBlock) - next = D3; - else if( ~BgackI & !bgBlock) - next = D_BA; - else - next = DIDLE; - end - - D1: next = D_BR; // Loop while only BR asserted - D_BR: next = ~BRi & BgackI ? D_BR : D_BA; // No direct path to IDLE ! - - D3: next = D_BRA; - D_BRA: begin // Loop while both BR and BGACK asserted - case( {BgackI, BRi} ) - 2'b11: next = DIDLE; // Both deasserted - 2'b10: next = D_BR; // BR asserted only - 2'b01: next = D2; // BGACK asserted only - 2'b00: next = D_BRA; // Stay here while both asserted - endcase - end - - // Might loop here if both deasserted, should normally don't arrive here anyway? - // D2: next = (BgackI & BRi) | bgBlock ? D2: D_BA; - - D2: next = D_BA; - - default: next = DIDLE; // Should not reach here normally - endcase - end - - logic granting; - always_comb begin - unique case( next) - D1, D3, D_BR, D_BRA: granting = 1'b1; - default: granting = 1'b0; - endcase - end - - reg rGranted; - assign busAvail = Halti & BRi & BgackI & ~rGranted; - - always_ff @( posedge Clks.clk) begin - if( Clks.extReset) begin - dmaPhase <= DRESET; - rGranted <= 1'b0; - end - else if( Clks.enPhi2) begin - dmaPhase <= next; - // Internal signal changed on PHI2 - rGranted <= granting; - end - - // External Output changed on PHI1 - if( Clks.extReset) - BGn <= 1'b1; - else if( Clks.enPhi1) - BGn <= ~rGranted; - - end - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/busControl.sv b/common/CPU/68000/FX68k/busControl.sv deleted file mode 100644 index 8236fbd7..00000000 --- a/common/CPU/68000/FX68k/busControl.sv +++ /dev/null @@ -1,197 +0,0 @@ -module busControl( input s_clks Clks, input enT1, input enT4, - input permStart, permStop, iStop, - input aob0, - input isWrite, isByte, isRmc, - input busAvail, - output bgBlock, - output busAddrErr, - output waitBusCycle, - output busStarting, // Asserted during S0 - output logic addrOe, // Asserted from S1 to the end, whole bus cycle except S0 - output bciWrite, // Used for SSW on bus/addr error - - input rDtack, BeDebounced, Vpai, - output ASn, output LDSn, output UDSn, eRWn); - - reg rAS, rLDS, rUDS, rRWn; - assign ASn = rAS; - assign LDSn = rLDS; - assign UDSn = rUDS; - assign eRWn = rRWn; - - reg dataOe; - - reg bcPend; - reg isWriteReg, bciByte, isRmcReg, wendReg; - assign bciWrite = isWriteReg; - reg addrOeDelay; - reg isByteT4; - - wire canStart, busEnd; - wire bcComplete, bcReset; - - wire isRcmReset = bcComplete & bcReset & isRmcReg; - - assign busAddrErr = aob0 & ~bciByte; - - // Bus retry not really supported. - // It's BERR and HALT and not address error, and not read-modify cycle. - wire busRetry = ~busAddrErr & 1'b0; - - enum int unsigned { SRESET = 0, SIDLE, S0, S2, S4, S6, SRMC_RES} busPhase, next; - - always_ff @( posedge Clks.clk) begin - if( Clks.extReset) - busPhase <= SRESET; - else if( Clks.enPhi1) - busPhase <= next; - end - - always_comb begin - case( busPhase) - SRESET: next = SIDLE; - SRMC_RES: next = SIDLE; // Single cycle special state when read phase of RMC reset - S0: next = S2; - S2: next = S4; - S4: next = busEnd ? S6 : S4; - S6: next = isRcmReset ? SRMC_RES : (canStart ? S0 : SIDLE); - SIDLE: next = canStart ? S0 : SIDLE; - default: next = SIDLE; - endcase - end - - // Idle phase of RMC bus cycle. Might be better to just add a new state - wire rmcIdle = (busPhase == SIDLE) & ~ASn & isRmcReg; - - assign canStart = (busAvail | rmcIdle) & (bcPend | permStart) & !busRetry & !bcReset; - - wire busEnding = (next == SIDLE) | (next == S0); - - assign busStarting = (busPhase == S0); - - // term signal (DTACK, BERR, VPA, adress error) - assign busEnd = ~rDtack | iStop; - - // bcComplete asserted on raising edge of S6 (together with SNC). - assign bcComplete = (busPhase == S6); - - // Clear bus info latch on completion (regular or aborted) and no bus retry (and not PHI1). - // bciClear asserted half clock later on PHI2, and bci latches cleared async concurrently - wire bciClear = bcComplete & ~busRetry; - - // Reset on reset or (berr & berrDelay & (not halt or rmc) & not 6800 & in bus cycle) (and not PHI1) - assign bcReset = Clks.extReset | (addrOeDelay & BeDebounced & Vpai); - - // Enable uclock only on S6 (S8 on Bus Error) or not bciPermStop - assign waitBusCycle = wendReg & !bcComplete; - - // Block Bus Grant when starting new bus cycle. But No need if AS already asserted (read phase of RMC) - // Except that when that RMC phase aborted on bus error, it's asserted one cycle later! - assign bgBlock = ((busPhase == S0) & ASn) | (busPhase == SRMC_RES); - - always_ff @( posedge Clks.clk) begin - if( Clks.extReset) begin - addrOe <= 1'b0; - end - else if( Clks.enPhi2 & ( busPhase == S0)) // From S1, whole bus cycle except S0 - addrOe <= 1'b1; - else if( Clks.enPhi1 & (busPhase == SRMC_RES)) - addrOe <= 1'b0; - else if( Clks.enPhi1 & ~isRmcReg & busEnding) - addrOe <= 1'b0; - - if( Clks.enPhi1) - addrOeDelay <= addrOe; - - if( Clks.extReset) begin - rAS <= 1'b1; - rUDS <= 1'b1; - rLDS <= 1'b1; - rRWn <= 1'b1; - dataOe <= '0; - end - else begin - - if( Clks.enPhi2 & isWriteReg & (busPhase == S2)) - dataOe <= 1'b1; - else if( Clks.enPhi1 & (busEnding | (busPhase == SIDLE)) ) - dataOe <= 1'b0; - - if( Clks.enPhi1 & busEnding) - rRWn <= 1'b1; - else if( Clks.enPhi1 & isWriteReg) begin - // Unlike LDS/UDS Asserted even in address error - if( (busPhase == S0) & isWriteReg) - rRWn <= 1'b0; - end - - // AS. Actually follows addrOe half cycle later! - if( Clks.enPhi1 & (busPhase == S0)) - rAS <= 1'b0; - else if( Clks.enPhi2 & (busPhase == SRMC_RES)) // Bus error on read phase of RMC. Deasserted one cycle later - rAS <= 1'b1; - else if( Clks.enPhi2 & bcComplete & ~SRMC_RES) - if( ~isRmcReg) // Keep AS asserted on the IDLE phase of RMC - rAS <= 1'b1; - - if( Clks.enPhi1 & (busPhase == S0)) begin - if( ~isWriteReg & !busAddrErr) begin - rUDS <= ~(~bciByte | ~aob0); - rLDS <= ~(~bciByte | aob0); - end - end - else if( Clks.enPhi1 & isWriteReg & (busPhase == S2) & !busAddrErr) begin - rUDS <= ~(~bciByte | ~aob0); - rLDS <= ~(~bciByte | aob0); - end - else if( Clks.enPhi2 & bcComplete) begin - rUDS <= 1'b1; - rLDS <= 1'b1; - end - - end - - end - - // Bus cycle info latch. Needed because uinstr might change if the bus is busy and we must wait. - // Note that urom advances even on wait states. It waits *after* updating urom and nanorom latches. - // Even without wait states, ublocks of type ir (init reading) will not wait for bus completion. - // Originally latched on (permStart AND T1). - - // Bus cycle info latch: isRead, isByte, read-modify-cycle, and permStart (bus cycle pending). Some previously latched on T4? - // permStop also latched, but unconditionally on T1 - - // Might make more sense to register this outside this module - always_ff @( posedge Clks.clk) begin - if( enT4) begin - isByteT4 <= isByte; - end - end - - // Bus Cycle Info Latch - always_ff @( posedge Clks.clk) begin - if( Clks.pwrUp) begin - bcPend <= 1'b0; - wendReg <= 1'b0; - isWriteReg <= 1'b0; - bciByte <= 1'b0; - isRmcReg <= 1'b0; - end - - else if( Clks.enPhi2 & (bciClear | bcReset)) begin - bcPend <= 1'b0; - wendReg <= 1'b0; - end - else begin - if( enT1 & permStart) begin - isWriteReg <= isWrite; - bciByte <= isByteT4; - isRmcReg <= isRmc & ~isWrite; // We need special case the end of the read phase only. - bcPend <= 1'b1; - end - if( enT1) - wendReg <= permStop; - end - end - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/ccrTable.sv b/common/CPU/68000/FX68k/ccrTable.sv deleted file mode 100644 index b50f822f..00000000 --- a/common/CPU/68000/FX68k/ccrTable.sv +++ /dev/null @@ -1,76 +0,0 @@ -// Row/col CCR update table -module ccrTable( - input [2:0] col, input [15:0] row, input finish, - output logic [MASK_NBITS-1:0] ccrMask); - - localparam - KNZ00 = 5'b01111, // ok coz operators clear them - KKZKK = 5'b00100, - KNZKK = 5'b01100, - KNZ10 = 5'b01111, // Used by OP_EXT on divison overflow - KNZ0C = 5'b01111, // Used by DIV. V should be 0, but it is ok: - // DIVU: ends with quotient - 0, so V & C always clear. - // DIVS: ends with 1i (AND), again, V & C always clear. - - KNZVC = 5'b01111, - CUPDALL = 5'b11111, - CUNUSED = 5'bxxxxx; - - - logic [MASK_NBITS-1:0] ccrMask1; - - always_comb begin - unique case( col) - 1: ccrMask = ccrMask1; - - 2,3: - unique case( 1'b1) - row[1]: ccrMask = KNZ0C; // DIV, used as 3n in col3 - row[2], - row[3], // ABCD - row[5], - row[9], // SBCD/NBCD - row[10], // SUBX/NEGX - row[12]: ccrMask = CUPDALL; // ADDX - row[6], // CMP - row[7], // MUL - row[11]: ccrMask = KNZVC; // NOT - row[4], - row[8], // Not used in col 3 - row[13], - row[14]: ccrMask = KNZ00; - row[15]: ccrMask = 5'b0; // TAS/Scc, not used in col 3 - // default: ccrMask = CUNUSED; - endcase - - 4: - unique case( row) - // 1: DIV, only n (4n & 6n) - // 14: BCLR 4n - // 6,12,13,15 // not used - `ALU_ROW_02, - `ALU_ROW_03, // ASL (originally ANZVA) - `ALU_ROW_04, - `ALU_ROW_05: ccrMask = CUPDALL; // Shifts (originally ANZ0A) - - `ALU_ROW_07: ccrMask = KNZ00; // MUL (originally KNZ0A) - `ALU_ROW_09, - `ALU_ROW_10: ccrMask = KNZ00; // RO[lr] (originally KNZ0A) - `ALU_ROW_11: ccrMask = CUPDALL; // ROXL (originally ANZ0A) - default: ccrMask = CUNUSED; - endcase - - 5: ccrMask = row[1] ? KNZ10 : 5'b0; - default: ccrMask = CUNUSED; - endcase - end - - // Column 1 (AND) - always_comb begin - if( finish) - ccrMask1 = row[7] ? KNZ00 : KNZKK; - else - ccrMask1 = row[13] | row[14] ? KKZKK : KNZ00; - end - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/dataIo.sv b/common/CPU/68000/FX68k/dataIo.sv deleted file mode 100644 index c20f36d3..00000000 --- a/common/CPU/68000/FX68k/dataIo.sv +++ /dev/null @@ -1,97 +0,0 @@ -// -// Data bus I/O -// At a separate module because it is a bit complicated and the timing is special. -// Here we do the low/high byte mux and the special case of MOVEP. -// -// Original implementation is rather complex because both the internal and external buses are bidirectional. -// Input is latched async at the EDB register. -// We capture directly from the external data bus to the internal registers (IRC & DBIN) on PHI2, starting the external S7 phase, at a T4 internal period. - -module dataIo( input s_clks Clks, - input enT1, enT2, enT3, enT4, - input s_nanod Nanod, input s_irdecod Irdecod, - input [15:0] iEdb, - input aob0, - - input dobIdle, - input [15:0] dobInput, - - output logic [15:0] Irc, - output logic [15:0] dbin, - output logic [15:0] oEdb - ); - - reg [15:0] dob; - - // DBIN/IRC - - // Timing is different than any other register. We can latch only on the next T4 (bus phase S7). - // We need to register all control signals correctly because the next ublock will already be started. - // Can't latch control on T4 because if there are wait states there might be multiple T4 before we latch. - - reg xToDbin, xToIrc; - reg dbinNoLow, dbinNoHigh; - reg byteMux, isByte_T4; - - always_ff @( posedge Clks.clk) begin - - // Byte mux control. Can't latch at T1. AOB might be not ready yet. - // Must latch IRD decode at T1 (or T4). Then combine and latch only at T3. - - // Can't latch at T3, a new IRD might be loaded already at T1. - // Ok to latch at T4 if combination latched then at T3 - if( enT4) - isByte_T4 <= Irdecod.isByte; // Includes MOVEP from mem, we could OR it here - - if( enT3) begin - dbinNoHigh <= Nanod.noHighByte; - dbinNoLow <= Nanod.noLowByte; - byteMux <= Nanod.busByte & isByte_T4 & ~aob0; - end - - if( enT1) begin - // If on wait states, we continue latching until next T1 - xToDbin <= 1'b0; - xToIrc <= 1'b0; - end - else if( enT3) begin - xToDbin <= Nanod.todbin; - xToIrc <= Nanod.toIrc; - end - - // Capture on T4 of the next ucycle - // If there are wait states, we keep capturing every PHI2 until the next T1 - - if( xToIrc & Clks.enPhi2) - Irc <= iEdb; - if( xToDbin & Clks.enPhi2) begin - // Original connects both halves of EDB. - if( ~dbinNoLow) - dbin[ 7:0] <= byteMux ? iEdb[ 15:8] : iEdb[7:0]; - if( ~dbinNoHigh) - dbin[ 15:8] <= ~byteMux & dbinNoLow ? iEdb[ 7:0] : iEdb[ 15:8]; - end - end - - // DOB - logic byteCycle; - - always_ff @( posedge Clks.clk) begin - // Originaly on T1. Transfer to internal EDB also on T1 (stays enabled upto the next T1). But only on T4 (S3) output enables. - // It is safe to do on T3, then, but control signals if derived from IRD must be registered. - // Originally control signals are not registered. - - // Wait states don't affect DOB operation that is done at the start of the bus cycle. - - if( enT4) - byteCycle <= Nanod.busByte & Irdecod.isByte; // busIsByte but not MOVEP - - // Originally byte low/high interconnect is done at EDB, not at DOB. - if( enT3 & ~dobIdle) begin - dob[7:0] <= Nanod.noLowByte ? dobInput[15:8] : dobInput[ 7:0]; - dob[15:8] <= (byteCycle | Nanod.noHighByte) ? dobInput[ 7:0] : dobInput[15:8]; - end - end - assign oEdb = dob; - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/excUnit.sv b/common/CPU/68000/FX68k/excUnit.sv deleted file mode 100644 index b42b4616..00000000 --- a/common/CPU/68000/FX68k/excUnit.sv +++ /dev/null @@ -1,553 +0,0 @@ -/* - Execution unit - - Executes register transfers set by the microcode. Originally through a set of bidirectional buses. - Most sources are available at T3, but DBIN only at T4! CCR also might be updated at T4, but it is not connected to these buses. - We mux at T1 and T2, then transfer to the destination at T3. The exception is AOB that need to be updated earlier. - -*/ - -module excUnit( input s_clks Clks, - input enT1, enT2, enT3, enT4, - input s_nanod Nanod, input s_irdecod Irdecod, - input [15:0] Ird, // ALU row (and others) decoder needs it - input pswS, - input [15:0] ftu, - input [15:0] iEdb, - - output logic [7:0] ccr, - output [15:0] alue, - - output prenEmpty, au05z, - output logic dcr4, ze, - output logic aob0, - output [15:0] AblOut, - output logic [15:0] Irc, - output logic [15:0] oEdb, - output logic [23:1] eab); - -localparam REG_USP = 15; -localparam REG_SSP = 16; -localparam REG_DT = 17; - - // Register file - reg [15:0] regs68L[ 18]; - reg [15:0] regs68H[ 18]; - -// synthesis translate off - /* - It is bad practice to initialize simulation registers that the hardware doesn't. - There is risk that simulation would be different than the real hardware. But in this case is the other way around. - Some ROM uses something like sub.l An,An at powerup which clears the register - Simulator power ups the registers with 'X, as they are really undetermined at the real hardware. - But the simulator doesn't realize (it can't) that the same value is substracting from itself, - and that the result should be zero even when it's 'X - 'X. - */ - - initial begin - for( int i = 0; i < 18; i++) begin - regs68L[i] <= '0; - regs68H[i] <= '0; - end - end - - // For simulation display only - wire [31:0] SSP = { regs68H[REG_SSP], regs68L[REG_SSP]}; - -// synthesis translate on - - - wire [15:0] aluOut; - wire [15:0] dbin; - logic [15:0] dcrOutput; - - reg [15:0] PcL, PcH; - - reg [31:0] auReg, aob; - - reg [15:0] Ath, Atl; - - // Bus execution - reg [15:0] Dbl, Dbh; - reg [15:0] Abh, Abl; - reg [15:0] Abd, Dbd; - - assign AblOut = Abl; - assign au05z = (~| auReg[5:0]); - - logic [15:0] dblMux, dbhMux; - logic [15:0] abhMux, ablMux; - logic [15:0] abdMux, dbdMux; - - logic abdIsByte; - - logic Pcl2Dbl, Pch2Dbh; - logic Pcl2Abl, Pch2Abh; - - - // RX RY muxes - // RX and RY actual registers - logic [4:0] actualRx, actualRy; - logic [3:0] movemRx; - logic byteNotSpAlign; // Byte instruction and no sp word align - - // IRD decoded signals must be latched. See comments on decoder - // But nanostore decoding can't be latched before T4. - // - // If we need this earlier we can register IRD decode on T3 and use nano async - - logic [4:0] rxMux, ryMux; - logic [3:0] rxReg, ryReg; - logic rxIsSp, ryIsSp; - logic rxIsAreg, ryIsAreg; - - always_comb begin - - // Unique IF !! - if( Nanod.ssp) begin - rxMux = REG_SSP; - rxIsSp = 1'b1; - rxReg = 1'bX; - end - else if( Irdecod.rxIsUsp) begin - rxMux = REG_USP; - rxIsSp = 1'b1; - rxReg = 1'bX; - end - else if( Irdecod.rxIsDt & !Irdecod.implicitSp) begin - rxMux = REG_DT; - rxIsSp = 1'b0; - rxReg = 1'bX; - end - else begin - if( Irdecod.implicitSp) - rxReg = 15; - else if( Irdecod.rxIsMovem) - rxReg = movemRx; - else - rxReg = { Irdecod.rxIsAreg, Irdecod.rx}; - - if( (& rxReg)) begin - rxMux = pswS ? REG_SSP : 15; - rxIsSp = 1'b1; - end - else begin - rxMux = { 1'b0, rxReg}; - rxIsSp = 1'b0; - end - end - - // RZ has higher priority! - if( Irdecod.ryIsDt & !Nanod.rz) begin - ryMux = REG_DT; - ryIsSp = 1'b0; - ryReg = 'X; - end - else begin - ryReg = Nanod.rz ? Irc[15:12] : {Irdecod.ryIsAreg, Irdecod.ry}; - ryIsSp = (& ryReg); - if( ryIsSp & pswS) // No implicit SP on RY - ryMux = REG_SSP; - else - ryMux = { 1'b0, ryReg}; - end - - end - - always_ff @( posedge Clks.clk) begin - if( enT4) begin - byteNotSpAlign <= Irdecod.isByte & ~(Nanod.rxlDbl ? rxIsSp : ryIsSp); - - actualRx <= rxMux; - actualRy <= ryMux; - - rxIsAreg <= rxIsSp | rxMux[3]; - ryIsAreg <= ryIsSp | ryMux[3]; - end - - if( enT4) - abdIsByte <= Nanod.abdIsByte & Irdecod.isByte; - end - - // Set RX/RY low word to which bus segment is connected. - - wire ryl2Abl = Nanod.ryl2ab & (ryIsAreg | Nanod.ablAbd); - wire ryl2Abd = Nanod.ryl2ab & (~ryIsAreg | Nanod.ablAbd); - wire ryl2Dbl = Nanod.ryl2db & (ryIsAreg | Nanod.dblDbd); - wire ryl2Dbd = Nanod.ryl2db & (~ryIsAreg | Nanod.dblDbd); - - wire rxl2Abl = Nanod.rxl2ab & (rxIsAreg | Nanod.ablAbd); - wire rxl2Abd = Nanod.rxl2ab & (~rxIsAreg | Nanod.ablAbd); - wire rxl2Dbl = Nanod.rxl2db & (rxIsAreg | Nanod.dblDbd); - wire rxl2Dbd = Nanod.rxl2db & (~rxIsAreg | Nanod.dblDbd); - - // Buses. Main mux - - logic abhIdle, ablIdle, abdIdle; - logic dbhIdle, dblIdle, dbdIdle; - - always_comb begin - {abhIdle, ablIdle, abdIdle} = '0; - {dbhIdle, dblIdle, dbdIdle} = '0; - - unique case( 1'b1) - ryl2Dbd: dbdMux = regs68L[ actualRy]; - rxl2Dbd: dbdMux = regs68L[ actualRx]; - Nanod.alue2Dbd: dbdMux = alue; - Nanod.dbin2Dbd: dbdMux = dbin; - Nanod.alu2Dbd: dbdMux = aluOut; - Nanod.dcr2Dbd: dbdMux = dcrOutput; - default: begin dbdMux = 'X; dbdIdle = 1'b1; end - endcase - - unique case( 1'b1) - rxl2Dbl: dblMux = regs68L[ actualRx]; - ryl2Dbl: dblMux = regs68L[ actualRy]; - Nanod.ftu2Dbl: dblMux = ftu; - Nanod.au2Db: dblMux = auReg[15:0]; - Nanod.atl2Dbl: dblMux = Atl; - Pcl2Dbl: dblMux = PcL; - default: begin dblMux = 'X; dblIdle = 1'b1; end - endcase - - unique case( 1'b1) - Nanod.rxh2dbh: dbhMux = regs68H[ actualRx]; - Nanod.ryh2dbh: dbhMux = regs68H[ actualRy]; - Nanod.au2Db: dbhMux = auReg[31:16]; - Nanod.ath2Dbh: dbhMux = Ath; - Pch2Dbh: dbhMux = PcH; - default: begin dbhMux = 'X; dbhIdle = 1'b1; end - endcase - - unique case( 1'b1) - ryl2Abd: abdMux = regs68L[ actualRy]; - rxl2Abd: abdMux = regs68L[ actualRx]; - Nanod.dbin2Abd: abdMux = dbin; - Nanod.alu2Abd: abdMux = aluOut; - default: begin abdMux = 'X; abdIdle = 1'b1; end - endcase - - unique case( 1'b1) - Pcl2Abl: ablMux = PcL; - rxl2Abl: ablMux = regs68L[ actualRx]; - ryl2Abl: ablMux = regs68L[ actualRy]; - Nanod.ftu2Abl: ablMux = ftu; - Nanod.au2Ab: ablMux = auReg[15:0]; - Nanod.aob2Ab: ablMux = aob[15:0]; - Nanod.atl2Abl: ablMux = Atl; - default: begin ablMux = 'X; ablIdle = 1'b1; end - endcase - - unique case( 1'b1) - Pch2Abh: abhMux = PcH; - Nanod.rxh2abh: abhMux = regs68H[ actualRx]; - Nanod.ryh2abh: abhMux = regs68H[ actualRy]; - Nanod.au2Ab: abhMux = auReg[31:16]; - Nanod.aob2Ab: abhMux = aob[31:16]; - Nanod.ath2Abh: abhMux = Ath; - default: begin abhMux = 'X; abhIdle = 1'b1; end - endcase - - end - - // Source starts driving the bus on T1. Bus holds data until end of T3. Destination latches at T3. - - // These registers store the first level mux, without bus interconnections. - // Even when this uses almost to 100 registers, it saves a lot of comb muxing and it is much faster. - reg [15:0] preAbh, preAbl, preAbd; - reg [15:0] preDbh, preDbl, preDbd; - - always_ff @( posedge Clks.clk) begin - - // Register first level mux at T1 - if( enT1) begin - {preAbh, preAbl, preAbd} <= { abhMux, ablMux, abdMux}; - {preDbh, preDbl, preDbd} <= { dbhMux, dblMux, dbdMux}; - end - - // Process bus interconnection at T2. Many combinations only used on DIV - // We use a simple method. If a specific bus segment is not driven we know that it should get data from a neighbour segment. - // In some cases this is not true and the segment is really idle without any destination. But then it doesn't matter. - - if( enT2) begin - if( Nanod.extAbh) - Abh <= { 16{ ablIdle ? preAbd[ 15] : preAbl[ 15] }}; - else if( abhIdle) - Abh <= ablIdle ? preAbd : preAbl; - else - Abh <= preAbh; - - if( ~ablIdle) - Abl <= preAbl; - else - Abl <= Nanod.ablAbh ? preAbh : preAbd; - - Abd <= ~abdIdle ? preAbd : ablIdle ? preAbh : preAbl; - - if( Nanod.extDbh) - Dbh <= { 16{ dblIdle ? preDbd[ 15] : preDbl[ 15] }}; - else if( dbhIdle) - Dbh <= dblIdle ? preDbd : preDbl; - else - Dbh <= preDbh; - - if( ~dblIdle) - Dbl <= preDbl; - else - Dbl <= Nanod.dblDbh ? preDbh : preDbd; - - Dbd <= ~dbdIdle ? preDbd: dblIdle ? preDbh : preDbl; - - /* - Dbl <= dblMux; Dbh <= dbhMux; - Abd <= abdMux; Dbd <= dbdMux; - Abh <= abhMux; Abl <= ablMux; */ - end - end - - // AOB - // - // Originally change on T1. We do on T2, only then the output is enabled anyway. - // - // AOB[0] is used for address error. But even when raises on T1, seems not actually used until T2 or possibly T3. - // It is used on T1 when deasserted at the BSER exception ucode. Probably deassertion timing is not critical. - // But in that case (at BSER), AOB is loaded from AU, so we can safely transfer on T1. - - // We need to take directly from first level muxes that are updated and T1 - - wire au2Aob = Nanod.au2Aob | (Nanod.au2Db & Nanod.db2Aob); - - always_ff @( posedge Clks.clk) begin - // UNIQUE IF ! - - if( enT1 & au2Aob) // From AU we do can on T1 - aob <= auReg; - else if( enT2) begin - if( Nanod.db2Aob) - aob <= { preDbh, ~dblIdle ? preDbl : preDbd}; - else if( Nanod.ab2Aob) - aob <= { preAbh, ~ablIdle ? preAbl : preAbd}; - end - end - - assign eab = aob[23:1]; - assign aob0 = aob[0]; - - // AU - logic [31:0] auInpMux; - - // `ifdef ALW_COMB_BUG - // Old Modelsim bug. Doesn't update ouput always. Need excplicit sensitivity list !? - // always @( Nanod.auCntrl) begin - - always_comb begin - unique case( Nanod.auCntrl) - 3'b000: auInpMux = 0; - 3'b001: auInpMux = byteNotSpAlign | Nanod.noSpAlign ? 1 : 2; // +1/+2 - 3'b010: auInpMux = -4; - 3'b011: auInpMux = { Abh, Abl}; - 3'b100: auInpMux = 2; - 3'b101: auInpMux = 4; - 3'b110: auInpMux = -2; - 3'b111: auInpMux = byteNotSpAlign | Nanod.noSpAlign ? -1 : -2; // -1/-2 - default: auInpMux = 'X; - endcase - end - - // Simulation problem - // Sometimes (like in MULM1) DBH is not set. AU is used in these cases just as a 6 bits counter testing if bits 5-0 are zero. - // But when adding something like 32'hXXXX0000, the simulator (incorrectly) will set *all the 32 bits* of the result as X. - -// synthesis translate_off - `define SIMULBUGX32 1 - wire [16:0] aulow = Dbl + auInpMux[15:0]; - wire [31:0] auResult = {Dbh + auInpMux[31:16] + aulow[16], aulow[15:0]}; -// synthesis translate_on - - always_ff @( posedge Clks.clk) begin - if( Clks.pwrUp) - auReg <= '0; - else if( enT3 & Nanod.auClkEn) - `ifdef SIMULBUGX32 - auReg <= auResult; - `else - auReg <= { Dbh, Dbl } + auInpMux; - `endif - end - - - // Main A/D registers - - always_ff @( posedge Clks.clk) begin - if( enT3) begin - if( Nanod.dbl2rxl | Nanod.abl2rxl) begin - if( ~rxIsAreg) begin - if( Nanod.dbl2rxl) regs68L[ actualRx] <= Dbd; - else if( abdIsByte) regs68L[ actualRx][7:0] <= Abd[7:0]; - else regs68L[ actualRx] <= Abd; - end - else - regs68L[ actualRx] <= Nanod.dbl2rxl ? Dbl : Abl; - end - - if( Nanod.dbl2ryl | Nanod.abl2ryl) begin - if( ~ryIsAreg) begin - if( Nanod.dbl2ryl) regs68L[ actualRy] <= Dbd; - else if( abdIsByte) regs68L[ actualRy][7:0] <= Abd[7:0]; - else regs68L[ actualRy] <= Abd; - end - else - regs68L[ actualRy] <= Nanod.dbl2ryl ? Dbl : Abl; - end - - // High registers are easier. Both A & D on the same buses, and not byte ops. - if( Nanod.dbh2rxh | Nanod.abh2rxh) - regs68H[ actualRx] <= Nanod.dbh2rxh ? Dbh : Abh; - if( Nanod.dbh2ryh | Nanod.abh2ryh) - regs68H[ actualRy] <= Nanod.dbh2ryh ? Dbh : Abh; - - end - end - - // PC & AT - reg dbl2Pcl, dbh2Pch, abh2Pch, abl2Pcl; - - always_ff @( posedge Clks.clk) begin - if( Clks.extReset) begin - { dbl2Pcl, dbh2Pch, abh2Pch, abl2Pcl } <= '0; - - Pcl2Dbl <= 1'b0; - Pch2Dbh <= 1'b0; - Pcl2Abl <= 1'b0; - Pch2Abh <= 1'b0; - end - else if( enT4) begin // Must latch on T4 ! - dbl2Pcl <= Nanod.dbl2reg & Nanod.pcldbl; - dbh2Pch <= Nanod.dbh2reg & Nanod.pchdbh; - abh2Pch <= Nanod.abh2reg & Nanod.pchabh; - abl2Pcl <= Nanod.abl2reg & Nanod.pclabl; - - Pcl2Dbl <= Nanod.reg2dbl & Nanod.pcldbl; - Pch2Dbh <= Nanod.reg2dbh & Nanod.pchdbh; - Pcl2Abl <= Nanod.reg2abl & Nanod.pclabl; - Pch2Abh <= Nanod.reg2abh & Nanod.pchabh; - end - - // Unique IF !!! - if( enT1 & Nanod.au2Pc) - PcL <= auReg[15:0]; - else if( enT3) begin - if( dbl2Pcl) - PcL <= Dbl; - else if( abl2Pcl) - PcL <= Abl; - end - - // Unique IF !!! - if( enT1 & Nanod.au2Pc) - PcH <= auReg[31:16]; - else if( enT3) begin - if( dbh2Pch) - PcH <= Dbh; - else if( abh2Pch) - PcH <= Abh; - end - - // Unique IF !!! - if( enT3) begin - if( Nanod.dbl2Atl) - Atl <= Dbl; - else if( Nanod.abl2Atl) - Atl <= Abl; - end - - // Unique IF !!! - if( enT3) begin - if( Nanod.abh2Ath) - Ath <= Abh; - else if( Nanod.dbh2Ath) - Ath <= Dbh; - end - - end - - // Movem reg mask priority encoder - - wire rmIdle; - logic [3:0] prHbit; - logic [15:0] prenLatch; - - // Invert reg order for predecrement mode - assign prenEmpty = (~| prenLatch); - pren rmPren( .mask( prenLatch), .hbit (prHbit)); - - always_ff @( posedge Clks.clk) begin - // Cheating: PREN always loaded from DBIN - // Must be on T1 to branch earlier if reg mask is empty! - if( enT1 & Nanod.abl2Pren) - prenLatch <= dbin; - else if( enT3 & Nanod.updPren) begin - prenLatch [prHbit] <= 1'b0; - movemRx <= Irdecod.movemPreDecr ? ~prHbit : prHbit; - end - end - - // DCR - wire [15:0] dcrCode; - - wire [3:0] dcrInput = abdIsByte ? { 1'b0, Abd[ 2:0]} : Abd[ 3:0]; - onehotEncoder4 dcrDecoder( .bin( dcrInput), .bitMap( dcrCode)); - - always_ff @( posedge Clks.clk) begin - if( Clks.pwrUp) - dcr4 <= '0; - else if( enT3 & Nanod.abd2Dcr) begin - dcrOutput <= dcrCode; - dcr4 <= Abd[4]; - end - end - - // ALUB - reg [15:0] alub; - - always_ff @( posedge Clks.clk) begin - if( enT3) begin - // UNIQUE IF !! - if( Nanod.dbd2Alub) - alub <= Dbd; - else if( Nanod.abd2Alub) - alub <= Abd; // abdIsByte affects this !!?? - end - end - - wire alueClkEn = enT3 & Nanod.dbd2Alue; - - // DOB/DBIN/IRC - - logic [15:0] dobInput; - wire dobIdle = (~| Nanod.dobCtrl); - - always_comb begin - unique case (Nanod.dobCtrl) - NANO_DOB_ADB: dobInput = Abd; - NANO_DOB_DBD: dobInput = Dbd; - NANO_DOB_ALU: dobInput = aluOut; - default: dobInput = 'X; - endcase - end - - dataIo dataIo( .Clks, .enT1, .enT2, .enT3, .enT4, .Nanod, .Irdecod, - .iEdb, .dobIdle, .dobInput, .aob0, - .Irc, .dbin, .oEdb); - - fx68kAlu alu( - .clk( Clks.clk), .pwrUp( Clks.pwrUp), .enT1, .enT3, .enT4, - .ird( Ird), - .aluColumn( Nanod.aluColumn), .aluAddrCtrl( Nanod.aluActrl), - .init( Nanod.aluInit), .finish( Nanod.aluFinish), .aluIsByte( Irdecod.isByte), - .ftu2Ccr( Nanod.ftu2Ccr), - .alub, .ftu, .alueClkEn, .alue, - .aluDataCtrl( Nanod.aluDctrl), .iDataBus( Dbd), .iAddrBus(Abd), - .ze, .aluOut, .ccr); - -endmodule diff --git a/common/CPU/68000/FX68k/fx68k.sv b/common/CPU/68000/FX68k/fx68k.sv index 996d9ac3..d7717454 100644 --- a/common/CPU/68000/FX68k/fx68k.sv +++ b/common/CPU/68000/FX68k/fx68k.sv @@ -231,23 +231,12 @@ module fx68k( wire rstUrom; // For the time being, address translation is done for nanorom only. - microToNanoAddr microToNanoAddr( - .uAddr ( nma), - .orgAddr ( orgAddr) - ); + microToNanoAddr microToNanoAddr( .uAddr( nma), .orgAddr); // Output of these modules will be updated at T2 at the latest (depending on clock division) - nanoRom nanoRom( - .clk ( Clks.clk), - .nanoAddr (nanoAddr), - .nanoOutput (nanoOutput) - ); - - uRom uRom( - .clk ( Clks.clk), - .microAddr ( microAddr), - .microOutput( microOutput)); + nanoRom nanoRom( .clk( Clks.clk), .nanoAddr, .nanoOutput); + uRom uRom( .clk( Clks.clk), .microAddr, .microOutput); always_ff @( posedge Clks.clk) begin // uaddr originally latched on T1, except bits 6 & 7, the conditional bits, on T2 @@ -394,10 +383,10 @@ module fx68k( rFC <= '0; else if( enT1 & Nanod.permStart) begin // S0 phase of bus cycle rFC[2] <= pswS; - // PC relativ access is marked as FC type 'n' (0) at ucode. + // If FC is type 'n' (0) at ucode, access type depends on PC relative mode // We don't care about RZ in this case. Those uinstructions with RZ don't start a bus cycle. - rFC[1] <= microLatch[ 16] | ( ~microLatch[ 15] & ~Irdecod.isPcRel); - rFC[0] <= microLatch[ 15] | ( ~microLatch[ 16] & Irdecod.isPcRel); + rFC[1] <= microLatch[ 16] | ( ~microLatch[ 15] & Irdecod.isPcRel); + rFC[0] <= microLatch[ 15] | ( ~microLatch[ 16] & ~Irdecod.isPcRel); end end @@ -639,4 +628,2054 @@ module fx68k( tvnMux = { 8'h0, Irdecod.macroTvn, 2'b00}; end -endmodule \ No newline at end of file +endmodule + +// Nanorom (plus) decoder for die nanocode +module nDecoder3( input s_clks Clks, input s_irdecod Irdecod, output s_nanod Nanod, + input enT2, enT4, + input [UROM_WIDTH-1:0] microLatch, + input [NANO_WIDTH-1:0] nanoLatch); + +localparam NANO_IR2IRD = 67; +localparam NANO_TOIRC = 66; +localparam NANO_ALU_COL = 63; // ALU operator column order is 63-64-65 ! +localparam NANO_ALU_FI = 61; // ALU finish-init 62-61 +localparam NANO_TODBIN = 60; +localparam NANO_ALUE = 57; // 57-59 shared with DCR control +localparam NANO_DCR = 57; // 57-59 shared with ALUE control +localparam NANO_DOBCTRL_1 = 56; // Input to control and permwrite +localparam NANO_LOWBYTE = 55; // Used by MOVEP +localparam NANO_HIGHBYTE = 54; +localparam NANO_DOBCTRL_0 = 53; // Input to control and permwrite +localparam NANO_ALU_DCTRL = 51; // 52-51 databus input mux control +localparam NANO_ALU_ACTRL = 50; // addrbus input mux control +localparam NANO_DBD2ALUB = 49; +localparam NANO_ABD2ALUB = 48; +localparam NANO_DBIN2DBD = 47; +localparam NANO_DBIN2ABD = 46; +localparam NANO_ALU2ABD = 45; +localparam NANO_ALU2DBD = 44; +localparam NANO_RZ = 43; +localparam NANO_BUSBYTE = 42; // If *both* this set and instruction is byte sized, then bus cycle is byte sized. +localparam NANO_PCLABL = 41; +localparam NANO_RXL_DBL = 40; // Switches RXL/RYL on DBL/ABL buses +localparam NANO_PCLDBL = 39; +localparam NANO_ABDHRECHARGE = 38; +localparam NANO_REG2ABL = 37; // register to ABL +localparam NANO_ABL2REG = 36; // ABL to register +localparam NANO_ABLABD = 35; +localparam NANO_DBLDBD = 34; +localparam NANO_DBL2REG = 33; // DBL to register +localparam NANO_REG2DBL = 32; // register to DBL +localparam NANO_ATLCTRL = 29; // 31-29 +localparam NANO_FTUCONTROL = 25; +localparam NANO_SSP = 24; +localparam NANO_RXH_DBH = 22; // Switches RXH/RYH on DBH/ABH buses +localparam NANO_AUOUT = 20; // 21-20 +localparam NANO_AUCLKEN = 19; +localparam NANO_AUCTRL = 16; // 18-16 +localparam NANO_DBLDBH = 15; +localparam NANO_ABLABH = 14; +localparam NANO_EXT_ABH = 13; +localparam NANO_EXT_DBH = 12; +localparam NANO_ATHCTRL = 9; // 11-9 +localparam NANO_REG2ABH = 8; // register to ABH +localparam NANO_ABH2REG = 7; // ABH to register +localparam NANO_REG2DBH = 6; // register to DBH +localparam NANO_DBH2REG = 5; // DBH to register +localparam NANO_AOBCTRL = 3; // 4-3 +localparam NANO_PCH = 0; // 1-0 PchDbh PchAbh +localparam NANO_NO_SP_ALGN = 0; // Same bits as above when both set + +localparam NANO_FTU_UPDTPEND = 1; // Also loads FTU constant according to IRD ! +localparam NANO_FTU_INIT_ST = 15; // Set S, clear T (but not TPEND) +localparam NANO_FTU_CLRTPEND = 14; +localparam NANO_FTU_TVN = 13; +localparam NANO_FTU_ABL2PREN = 12; // ABL => FTU & ABL => PREN. Both transfers enabled, but only one will be used depending on uroutine. +localparam NANO_FTU_SSW = 11; +localparam NANO_FTU_RSTPREN = 10; +localparam NANO_FTU_IRD = 9; +localparam NANO_FTU_2ABL = 8; +localparam NANO_FTU_RDSR = 7; +localparam NANO_FTU_INL = 6; +localparam NANO_FTU_PSWI = 5; // Read Int Mask into FTU +localparam NANO_FTU_DBL = 4; +localparam NANO_FTU_2SR = 2; +localparam NANO_FTU_CONST = 1; + + reg [3:0] ftuCtrl; + + logic [2:0] athCtrl, atlCtrl; + assign athCtrl = nanoLatch[ NANO_ATHCTRL+2: NANO_ATHCTRL]; + assign atlCtrl = nanoLatch[ NANO_ATLCTRL+2: NANO_ATLCTRL]; + wire [1:0] aobCtrl = nanoLatch[ NANO_AOBCTRL+1:NANO_AOBCTRL]; + wire [1:0] dobCtrl = {nanoLatch[ NANO_DOBCTRL_1], nanoLatch[NANO_DOBCTRL_0]}; + + always_ff @( posedge Clks.clk) begin + if( enT4) begin + // Reverse order! + ftuCtrl <= { nanoLatch[ NANO_FTUCONTROL+0], nanoLatch[ NANO_FTUCONTROL+1], nanoLatch[ NANO_FTUCONTROL+2], nanoLatch[ NANO_FTUCONTROL+3]} ; + + Nanod.auClkEn <= !nanoLatch[ NANO_AUCLKEN]; + Nanod.auCntrl <= nanoLatch[ NANO_AUCTRL+2 : NANO_AUCTRL+0]; + Nanod.noSpAlign <= (nanoLatch[ NANO_NO_SP_ALGN + 1:NANO_NO_SP_ALGN] == 2'b11); + Nanod.extDbh <= nanoLatch[ NANO_EXT_DBH]; + Nanod.extAbh <= nanoLatch[ NANO_EXT_ABH]; + Nanod.todbin <= nanoLatch[ NANO_TODBIN]; + Nanod.toIrc <= nanoLatch[ NANO_TOIRC]; + + // ablAbd is disabled on byte transfers (adbhCharge plus irdIsByte). Not sure the combination makes much sense. + // It happens in a few cases but I don't see anything enabled on abL (or abH) section anyway. + + Nanod.ablAbd <= nanoLatch[ NANO_ABLABD]; + Nanod.ablAbh <= nanoLatch[ NANO_ABLABH]; + Nanod.dblDbd <= nanoLatch[ NANO_DBLDBD]; + Nanod.dblDbh <= nanoLatch[ NANO_DBLDBH]; + + Nanod.dbl2Atl <= (atlCtrl == 3'b010); + Nanod.atl2Dbl <= (atlCtrl == 3'b011); + Nanod.abl2Atl <= (atlCtrl == 3'b100); + Nanod.atl2Abl <= (atlCtrl == 3'b101); + + Nanod.aob2Ab <= (athCtrl == 3'b101); // Used on BSER1 only + + Nanod.abh2Ath <= (athCtrl == 3'b001) | (athCtrl == 3'b101); + Nanod.dbh2Ath <= (athCtrl == 3'b100); + Nanod.ath2Dbh <= (athCtrl == 3'b110); + Nanod.ath2Abh <= (athCtrl == 3'b011); + + Nanod.alu2Dbd <= nanoLatch[ NANO_ALU2DBD]; + Nanod.alu2Abd <= nanoLatch[ NANO_ALU2ABD]; + + Nanod.abd2Dcr <= (nanoLatch[ NANO_DCR+1:NANO_DCR] == 2'b11); + Nanod.dcr2Dbd <= (nanoLatch[ NANO_DCR+2:NANO_DCR+1] == 2'b11); + Nanod.dbd2Alue <= (nanoLatch[ NANO_ALUE+2:NANO_ALUE+1] == 2'b10); + Nanod.alue2Dbd <= (nanoLatch[ NANO_ALUE+1:NANO_ALUE] == 2'b01); + + Nanod.dbd2Alub <= nanoLatch[ NANO_DBD2ALUB]; + Nanod.abd2Alub <= nanoLatch[ NANO_ABD2ALUB]; + + // Originally not latched. We better should because we transfer one cycle later, T3 instead of T1. + Nanod.dobCtrl <= dobCtrl; + // Nanod.adb2Dob <= (dobCtrl == 2'b10); Nanod.dbd2Dob <= (dobCtrl == 2'b01); Nanod.alu2Dob <= (dobCtrl == 2'b11); + + end + end + + // Update SSW at the start of Bus/Addr error ucode + assign Nanod.updSsw = Nanod.aob2Ab; + + assign Nanod.updTpend = (ftuCtrl == NANO_FTU_UPDTPEND); + assign Nanod.clrTpend = (ftuCtrl == NANO_FTU_CLRTPEND); + assign Nanod.tvn2Ftu = (ftuCtrl == NANO_FTU_TVN); + assign Nanod.const2Ftu = (ftuCtrl == NANO_FTU_CONST); + assign Nanod.ftu2Dbl = (ftuCtrl == NANO_FTU_DBL) | ( ftuCtrl == NANO_FTU_INL); + assign Nanod.ftu2Abl = (ftuCtrl == NANO_FTU_2ABL); + assign Nanod.inl2psw = (ftuCtrl == NANO_FTU_INL); + assign Nanod.pswIToFtu = (ftuCtrl == NANO_FTU_PSWI); + assign Nanod.ftu2Sr = (ftuCtrl == NANO_FTU_2SR); + assign Nanod.sr2Ftu = (ftuCtrl == NANO_FTU_RDSR); + assign Nanod.ird2Ftu = (ftuCtrl == NANO_FTU_IRD); // Used on bus/addr error + assign Nanod.ssw2Ftu = (ftuCtrl == NANO_FTU_SSW); + assign Nanod.initST = (ftuCtrl == NANO_FTU_INL) | (ftuCtrl == NANO_FTU_CLRTPEND) | (ftuCtrl == NANO_FTU_INIT_ST); + assign Nanod.abl2Pren = (ftuCtrl == NANO_FTU_ABL2PREN); + assign Nanod.updPren = (ftuCtrl == NANO_FTU_RSTPREN); + + assign Nanod.Ir2Ird = nanoLatch[ NANO_IR2IRD]; + + // ALU control better latched later after combining with IRD decoding + + assign Nanod.aluDctrl = nanoLatch[ NANO_ALU_DCTRL+1 : NANO_ALU_DCTRL]; + assign Nanod.aluActrl = nanoLatch[ NANO_ALU_ACTRL]; + assign Nanod.aluColumn = { nanoLatch[ NANO_ALU_COL], nanoLatch[ NANO_ALU_COL+1], nanoLatch[ NANO_ALU_COL+2]}; + wire [1:0] aluFinInit = nanoLatch[ NANO_ALU_FI+1:NANO_ALU_FI]; + assign Nanod.aluFinish = (aluFinInit == 2'b10); + assign Nanod.aluInit = (aluFinInit == 2'b01); + + // FTU 2 CCR encoded as both ALU Init and ALU Finish set. + // In theory this encoding allows writes to CCR without writing to SR + // But FTU 2 CCR and to SR are both set together at nanorom. + assign Nanod.ftu2Ccr = ( aluFinInit == 2'b11); + + assign Nanod.abdIsByte = nanoLatch[ NANO_ABDHRECHARGE]; + + // Not being latched on T4 creates non unique case warning! + assign Nanod.au2Db = (nanoLatch[ NANO_AUOUT + 1: NANO_AUOUT] == 2'b01); + assign Nanod.au2Ab = (nanoLatch[ NANO_AUOUT + 1: NANO_AUOUT] == 2'b10); + assign Nanod.au2Pc = (nanoLatch[ NANO_AUOUT + 1: NANO_AUOUT] == 2'b11); + + assign Nanod.db2Aob = (aobCtrl == 2'b10); + assign Nanod.ab2Aob = (aobCtrl == 2'b01); + assign Nanod.au2Aob = (aobCtrl == 2'b11); + + assign Nanod.dbin2Abd = nanoLatch[ NANO_DBIN2ABD]; + assign Nanod.dbin2Dbd = nanoLatch[ NANO_DBIN2DBD]; + + assign Nanod.permStart = (| aobCtrl); + assign Nanod.isWrite = ( | dobCtrl); + assign Nanod.waitBusFinish = nanoLatch[ NANO_TOIRC] | nanoLatch[ NANO_TODBIN] | Nanod.isWrite; + assign Nanod.busByte = nanoLatch[ NANO_BUSBYTE]; + + assign Nanod.noLowByte = nanoLatch[ NANO_LOWBYTE]; + assign Nanod.noHighByte = nanoLatch[ NANO_HIGHBYTE]; + + // Not registered. Register at T4 after combining + // Might be better to remove all those and combine here instead of at execution unit !! + assign Nanod.abl2reg = nanoLatch[ NANO_ABL2REG]; + assign Nanod.abh2reg = nanoLatch[ NANO_ABH2REG]; + assign Nanod.dbl2reg = nanoLatch[ NANO_DBL2REG]; + assign Nanod.dbh2reg = nanoLatch[ NANO_DBH2REG]; + assign Nanod.reg2dbl = nanoLatch[ NANO_REG2DBL]; + assign Nanod.reg2dbh = nanoLatch[ NANO_REG2DBH]; + assign Nanod.reg2abl = nanoLatch[ NANO_REG2ABL]; + assign Nanod.reg2abh = nanoLatch[ NANO_REG2ABH]; + + assign Nanod.ssp = nanoLatch[ NANO_SSP]; + + assign Nanod.rz = nanoLatch[ NANO_RZ]; + + // Actually DTL can't happen on PC relative mode. See IR decoder. + + wire dtldbd = 1'b0; + wire dthdbh = 1'b0; + wire dtlabd = 1'b0; + wire dthabh = 1'b0; + + wire dblSpecial = Nanod.pcldbl | dtldbd; + wire dbhSpecial = Nanod.pchdbh | dthdbh; + wire ablSpecial = Nanod.pclabl | dtlabd; + wire abhSpecial = Nanod.pchabh | dthabh; + + // + // Combine with IRD decoding + // Careful that IRD is updated only on T1! All output depending on IRD must be latched on T4! + // + + // PC used instead of RY on PC relative instuctions + + assign Nanod.rxlDbl = nanoLatch[ NANO_RXL_DBL]; + wire isPcRel = Irdecod.isPcRel & !Nanod.rz; + wire pcRelDbl = isPcRel & !nanoLatch[ NANO_RXL_DBL]; + wire pcRelDbh = isPcRel & !nanoLatch[ NANO_RXH_DBH]; + wire pcRelAbl = isPcRel & nanoLatch[ NANO_RXL_DBL]; + wire pcRelAbh = isPcRel & nanoLatch[ NANO_RXH_DBH]; + + assign Nanod.pcldbl = nanoLatch[ NANO_PCLDBL] | pcRelDbl; + assign Nanod.pchdbh = (nanoLatch[ NANO_PCH+1:NANO_PCH] == 2'b01) | pcRelDbh; + + assign Nanod.pclabl = nanoLatch[ NANO_PCLABL] | pcRelAbl; + assign Nanod.pchabh = (nanoLatch[ NANO_PCH+1:NANO_PCH] == 2'b10) | pcRelAbh; + + // Might be better not to register these signals to allow latching RX/RY mux earlier! + // But then must latch Irdecod.isPcRel on T3! + + always_ff @( posedge Clks.clk) begin + if( enT4) begin + Nanod.rxl2db <= Nanod.reg2dbl & !dblSpecial & nanoLatch[ NANO_RXL_DBL]; + Nanod.rxl2ab <= Nanod.reg2abl & !ablSpecial & !nanoLatch[ NANO_RXL_DBL]; + + Nanod.dbl2rxl <= Nanod.dbl2reg & !dblSpecial & nanoLatch[ NANO_RXL_DBL]; + Nanod.abl2rxl <= Nanod.abl2reg & !ablSpecial & !nanoLatch[ NANO_RXL_DBL]; + + Nanod.rxh2dbh <= Nanod.reg2dbh & !dbhSpecial & nanoLatch[ NANO_RXH_DBH]; + Nanod.rxh2abh <= Nanod.reg2abh & !abhSpecial & !nanoLatch[ NANO_RXH_DBH]; + + Nanod.dbh2rxh <= Nanod.dbh2reg & !dbhSpecial & nanoLatch[ NANO_RXH_DBH]; + Nanod.abh2rxh <= Nanod.abh2reg & !abhSpecial & !nanoLatch[ NANO_RXH_DBH]; + + Nanod.dbh2ryh <= Nanod.dbh2reg & !dbhSpecial & !nanoLatch[ NANO_RXH_DBH]; + Nanod.abh2ryh <= Nanod.abh2reg & !abhSpecial & nanoLatch[ NANO_RXH_DBH]; + + Nanod.dbl2ryl <= Nanod.dbl2reg & !dblSpecial & !nanoLatch[ NANO_RXL_DBL]; + Nanod.abl2ryl <= Nanod.abl2reg & !ablSpecial & nanoLatch[ NANO_RXL_DBL]; + + Nanod.ryl2db <= Nanod.reg2dbl & !dblSpecial & !nanoLatch[ NANO_RXL_DBL]; + Nanod.ryl2ab <= Nanod.reg2abl & !ablSpecial & nanoLatch[ NANO_RXL_DBL]; + + Nanod.ryh2dbh <= Nanod.reg2dbh & !dbhSpecial & !nanoLatch[ NANO_RXH_DBH]; + Nanod.ryh2abh <= Nanod.reg2abh & !abhSpecial & nanoLatch[ NANO_RXH_DBH]; + end + + // Originally isTas only delayed on T2 (and seems only a late mask rev fix) + // Better latch the combination on T4 + if( enT4) + Nanod.isRmc <= Irdecod.isTas & nanoLatch[ NANO_BUSBYTE]; + end + + +endmodule + +// +// IRD execution decoder. Complements nano code decoder +// +// IRD updated on T1, while ncode still executing. To avoid using the next IRD, +// decoded signals must be registered on T3, or T4 before using them. +// +module irdDecode( input [15:0] ird, + output s_irdecod Irdecod); + + wire [3:0] line = ird[15:12]; + logic [15:0] lineOnehot; + + // This can be registered and pipelined from the IR decoder ! + onehotEncoder4 irdLines( line, lineOnehot); + + wire isRegShift = (lineOnehot['he]) & (ird[7:6] != 2'b11); + wire isDynShift = isRegShift & ird[5]; + + assign Irdecod.isPcRel = (& ird[ 5:3]) & ~isDynShift & !ird[2] & ird[1]; + assign Irdecod.isTas = lineOnehot[4] & (ird[11:6] == 6'b101011); + + assign Irdecod.rx = ird[11:9]; + assign Irdecod.ry = ird[ 2:0]; + + wire isPreDecr = (ird[ 5:3] == 3'b100); + wire eaAreg = (ird[5:3] == 3'b001); + + // rx is A or D + // movem + always_comb begin + unique case( 1'b1) + lineOnehot[1], + lineOnehot[2], + lineOnehot[3]: + // MOVE: RX always Areg except if dest mode is Dn 000 + Irdecod.rxIsAreg = (| ird[8:6]); + + lineOnehot[4]: Irdecod.rxIsAreg = (& ird[8:6]); // not CHK (LEA) + + lineOnehot['h8]: Irdecod.rxIsAreg = eaAreg & ird[8] & ~ird[7]; // SBCD + lineOnehot['hc]: Irdecod.rxIsAreg = eaAreg & ird[8] & ~ird[7]; // ABCD/EXG An,An + + lineOnehot['h9], + lineOnehot['hb], + lineOnehot['hd]: Irdecod.rxIsAreg = + (ird[7] & ird[6]) | // SUBA/CMPA/ADDA + (eaAreg & ird[8] & (ird[7:6] != 2'b11)); // SUBX/CMPM/ADDX + default: + Irdecod.rxIsAreg = Irdecod.implicitSp; + endcase + end + + // RX is movem + always_comb begin + Irdecod.rxIsMovem = lineOnehot[4] & ~ird[8] & ~Irdecod.implicitSp; + end + assign Irdecod.movemPreDecr = Irdecod.rxIsMovem & isPreDecr; + + // RX is DT. + // but SSP explicit or pc explicit has higher priority! + // addq/subq (scc & dbcc also, but don't use rx) + // Immediate including static bit + assign Irdecod.rxIsDt = lineOnehot[5] | (lineOnehot[0] & ~ird[8]); + + // RX is USP + assign Irdecod.rxIsUsp = lineOnehot[4] & (ird[ 11:4] == 8'he6); + + // RY is DT + // rz or PC explicit has higher priority + + wire eaImmOrAbs = (ird[5:3] == 3'b111) & ~ird[1]; + assign Irdecod.ryIsDt = eaImmOrAbs & ~isRegShift; + + // RY is Address register + always_comb begin + logic eaIsAreg; + + // On most cases RY is Areg expect if mode is 000 (DATA REG) or 111 (IMM, ABS,PC REL) + eaIsAreg = (ird[5:3] != 3'b000) & (ird[5:3] != 3'b111); + + unique case( 1'b1) + // MOVE: RY always Areg expect if mode is 000 (DATA REG) or 111 (IMM, ABS,PC REL) + // Most lines, including misc line 4, also. + default: Irdecod.ryIsAreg = eaIsAreg; + + lineOnehot[5]: // DBcc is an exception + Irdecod.ryIsAreg = eaIsAreg & (ird[7:3] != 5'b11001); + + lineOnehot[6], + lineOnehot[7]: Irdecod.ryIsAreg = 1'b0; + + lineOnehot['he]: + Irdecod.ryIsAreg = ~isRegShift; + endcase + end + + // Byte sized instruction + + // Original implementation sets this for some instructions that aren't really byte size + // but doesn't matter because they don't have a byte transfer enabled at nanocode, such as MOVEQ + + wire xIsScc = (ird[7:6] == 2'b11) & (ird[5:3] != 3'b001); + wire xStaticMem = (ird[11:8] == 4'b1000) & (ird[5:4] == 2'b00); // Static bit to mem + always_comb begin + unique case( 1'b1) + lineOnehot[0]: + Irdecod.isByte = + ( ird[8] & (ird[5:4] != 2'b00) ) | // Dynamic bit to mem + ( (ird[11:8] == 4'b1000) & (ird[5:4] != 2'b00) ) | // Static bit to mem + ( (ird[8:7] == 2'b10) & (ird[5:3] == 3'b001) ) | // Movep from mem only! For byte mux + ( (ird[8:6] == 3'b000) & !xStaticMem ); // Immediate byte + + lineOnehot[1]: Irdecod.isByte = 1'b1; // MOVE.B + + + lineOnehot[4]: Irdecod.isByte = (ird[7:6] == 2'b00) | Irdecod.isTas; + lineOnehot[5]: Irdecod.isByte = (ird[7:6] == 2'b00) | xIsScc; + + lineOnehot[8], + lineOnehot[9], + lineOnehot['hb], + lineOnehot['hc], + lineOnehot['hd], + lineOnehot['he]: Irdecod.isByte = (ird[7:6] == 2'b00); + + default: Irdecod.isByte = 1'b0; + endcase + end + + // Need it for special byte size. Bus is byte, but whole register word is modified. + assign Irdecod.isMovep = lineOnehot[0] & ird[8] & eaAreg; + + + // rxIsSP implicit use of RX for actual SP transfer + // + // This logic is simple and will include some instructions that don't actually reference SP. + // But doesn't matter as long as they don't perform any RX transfer. + + always_comb begin + unique case( 1'b1) + lineOnehot[6]: Irdecod.implicitSp = (ird[11:8] == 4'b0001); // BSR + lineOnehot[4]: + // Misc like RTS, JSR, etc + Irdecod.implicitSp = (ird[11:8] == 4'b1110) | (ird[11:6] == 6'b1000_01); + default: Irdecod.implicitSp = 1'b0; + endcase + end + + // Modify CCR (and not SR) + // Probably overkill !! Only needs to distinguish SR vs CCR + // RTR, MOVE to CCR, xxxI to CCR + assign Irdecod.toCcr = ( lineOnehot[4] & ((ird[11:0] == 12'he77) | (ird[11:6] == 6'b010011)) ) | + ( lineOnehot[0] & (ird[8:6] == 3'b000)); + + // FTU constants + // This should not be latched on T3/T4. Latch on T2 or not at all. FTU needs it on next T3. + // Note: Reset instruction gets constant from ALU not from FTU! + logic [15:0] ftuConst; + wire [3:0] zero28 = (ird[11:9] == 0) ? 4'h8 : { 1'b0, ird[11:9]}; // xltate 0,1-7 into 8,1-7 + + always_comb begin + unique case( 1'b1) + lineOnehot[6], // Bcc short + lineOnehot[7]: ftuConst = { { 8{ ird[ 7]}}, ird[ 7:0] }; // MOVEQ + + lineOnehot['h5], // addq/subq/static shift double check this + lineOnehot['he]: ftuConst = { 12'b0, zero28}; + + // MULU/MULS DIVU/DIVS + lineOnehot['h8], + lineOnehot['hc]: ftuConst = 16'h0f; + + lineOnehot[4]: ftuConst = 16'h80; // TAS + + default: ftuConst = '0; + endcase + end + assign Irdecod.ftuConst = ftuConst; + + // + // TRAP Vector # for group 2 exceptions + // + + always_comb begin + if( lineOnehot[4]) begin + case ( ird[6:5]) + 2'b00,2'b01: Irdecod.macroTvn = 6; // CHK + 2'b11: Irdecod.macroTvn = 7; // TRAPV + 2'b10: Irdecod.macroTvn = {2'b10, ird[3:0]}; // TRAP + endcase + end + else + Irdecod.macroTvn = 5; // Division by zero + end + + + wire eaAdir = (ird[ 5:3] == 3'b001); + wire size11 = ird[7] & ird[6]; + + // Opcodes variants that don't affect flags + // ADDA/SUBA ADDQ/SUBQ MOVEA + + assign Irdecod.inhibitCcr = + ( (lineOnehot[9] | lineOnehot['hd]) & size11) | // ADDA/SUBA + ( lineOnehot[5] & eaAdir) | // ADDQ/SUBQ to An (originally checks for line[4] as well !?) + ( (lineOnehot[2] | lineOnehot[3]) & ird[8:6] == 3'b001); // MOVEA + +endmodule + +/* + Execution unit + + Executes register transfers set by the microcode. Originally through a set of bidirectional buses. + Most sources are available at T3, but DBIN only at T4! CCR also might be updated at T4, but it is not connected to these buses. + We mux at T1 and T2, then transfer to the destination at T3. The exception is AOB that need to be updated earlier. + +*/ + +module excUnit( input s_clks Clks, + input enT1, enT2, enT3, enT4, + input s_nanod Nanod, input s_irdecod Irdecod, + input [15:0] Ird, // ALU row (and others) decoder needs it + input pswS, + input [15:0] ftu, + input [15:0] iEdb, + + output logic [7:0] ccr, + output [15:0] alue, + + output prenEmpty, au05z, + output logic dcr4, ze, + output logic aob0, + output [15:0] AblOut, + output logic [15:0] Irc, + output logic [15:0] oEdb, + output logic [23:1] eab); + +localparam REG_USP = 15; +localparam REG_SSP = 16; +localparam REG_DT = 17; + + // Register file + reg [15:0] regs68L[ 18]; + reg [15:0] regs68H[ 18]; + +// synthesis translate off + /* + It is bad practice to initialize simulation registers that the hardware doesn't. + There is risk that simulation would be different than the real hardware. But in this case is the other way around. + Some ROM uses something like sub.l An,An at powerup which clears the register + Simulator power ups the registers with 'X, as they are really undetermined at the real hardware. + But the simulator doesn't realize (it can't) that the same value is substracting from itself, + and that the result should be zero even when it's 'X - 'X. + */ + + initial begin + for( int i = 0; i < 18; i++) begin + regs68L[i] <= '0; + regs68H[i] <= '0; + end + end + + // For simulation display only + wire [31:0] SSP = { regs68H[REG_SSP], regs68L[REG_SSP]}; + +// synthesis translate on + + + wire [15:0] aluOut; + wire [15:0] dbin; + logic [15:0] dcrOutput; + + reg [15:0] PcL, PcH; + + reg [31:0] auReg, aob; + + reg [15:0] Ath, Atl; + + // Bus execution + reg [15:0] Dbl, Dbh; + reg [15:0] Abh, Abl; + reg [15:0] Abd, Dbd; + + assign AblOut = Abl; + assign au05z = (~| auReg[5:0]); + + logic [15:0] dblMux, dbhMux; + logic [15:0] abhMux, ablMux; + logic [15:0] abdMux, dbdMux; + + logic abdIsByte; + + logic Pcl2Dbl, Pch2Dbh; + logic Pcl2Abl, Pch2Abh; + + + // RX RY muxes + // RX and RY actual registers + logic [4:0] actualRx, actualRy; + logic [3:0] movemRx; + logic byteNotSpAlign; // Byte instruction and no sp word align + + // IRD decoded signals must be latched. See comments on decoder + // But nanostore decoding can't be latched before T4. + // + // If we need this earlier we can register IRD decode on T3 and use nano async + + logic [4:0] rxMux, ryMux; + logic [3:0] rxReg, ryReg; + logic rxIsSp, ryIsSp; + logic rxIsAreg, ryIsAreg; + + always_comb begin + + // Unique IF !! + if( Nanod.ssp) begin + rxMux = REG_SSP; + rxIsSp = 1'b1; + rxReg = 1'bX; + end + else if( Irdecod.rxIsUsp) begin + rxMux = REG_USP; + rxIsSp = 1'b1; + rxReg = 1'bX; + end + else if( Irdecod.rxIsDt & !Irdecod.implicitSp) begin + rxMux = REG_DT; + rxIsSp = 1'b0; + rxReg = 1'bX; + end + else begin + if( Irdecod.implicitSp) + rxReg = 15; + else if( Irdecod.rxIsMovem) + rxReg = movemRx; + else + rxReg = { Irdecod.rxIsAreg, Irdecod.rx}; + + if( (& rxReg)) begin + rxMux = pswS ? REG_SSP : 15; + rxIsSp = 1'b1; + end + else begin + rxMux = { 1'b0, rxReg}; + rxIsSp = 1'b0; + end + end + + // RZ has higher priority! + if( Irdecod.ryIsDt & !Nanod.rz) begin + ryMux = REG_DT; + ryIsSp = 1'b0; + ryReg = 'X; + end + else begin + ryReg = Nanod.rz ? Irc[15:12] : {Irdecod.ryIsAreg, Irdecod.ry}; + ryIsSp = (& ryReg); + if( ryIsSp & pswS) // No implicit SP on RY + ryMux = REG_SSP; + else + ryMux = { 1'b0, ryReg}; + end + + end + + always_ff @( posedge Clks.clk) begin + if( enT4) begin + byteNotSpAlign <= Irdecod.isByte & ~(Nanod.rxlDbl ? rxIsSp : ryIsSp); + + actualRx <= rxMux; + actualRy <= ryMux; + + rxIsAreg <= rxIsSp | rxMux[3]; + ryIsAreg <= ryIsSp | ryMux[3]; + end + + if( enT4) + abdIsByte <= Nanod.abdIsByte & Irdecod.isByte; + end + + // Set RX/RY low word to which bus segment is connected. + + wire ryl2Abl = Nanod.ryl2ab & (ryIsAreg | Nanod.ablAbd); + wire ryl2Abd = Nanod.ryl2ab & (~ryIsAreg | Nanod.ablAbd); + wire ryl2Dbl = Nanod.ryl2db & (ryIsAreg | Nanod.dblDbd); + wire ryl2Dbd = Nanod.ryl2db & (~ryIsAreg | Nanod.dblDbd); + + wire rxl2Abl = Nanod.rxl2ab & (rxIsAreg | Nanod.ablAbd); + wire rxl2Abd = Nanod.rxl2ab & (~rxIsAreg | Nanod.ablAbd); + wire rxl2Dbl = Nanod.rxl2db & (rxIsAreg | Nanod.dblDbd); + wire rxl2Dbd = Nanod.rxl2db & (~rxIsAreg | Nanod.dblDbd); + + // Buses. Main mux + + logic abhIdle, ablIdle, abdIdle; + logic dbhIdle, dblIdle, dbdIdle; + + always_comb begin + {abhIdle, ablIdle, abdIdle} = '0; + {dbhIdle, dblIdle, dbdIdle} = '0; + + unique case( 1'b1) + ryl2Dbd: dbdMux = regs68L[ actualRy]; + rxl2Dbd: dbdMux = regs68L[ actualRx]; + Nanod.alue2Dbd: dbdMux = alue; + Nanod.dbin2Dbd: dbdMux = dbin; + Nanod.alu2Dbd: dbdMux = aluOut; + Nanod.dcr2Dbd: dbdMux = dcrOutput; + default: begin dbdMux = 'X; dbdIdle = 1'b1; end + endcase + + unique case( 1'b1) + rxl2Dbl: dblMux = regs68L[ actualRx]; + ryl2Dbl: dblMux = regs68L[ actualRy]; + Nanod.ftu2Dbl: dblMux = ftu; + Nanod.au2Db: dblMux = auReg[15:0]; + Nanod.atl2Dbl: dblMux = Atl; + Pcl2Dbl: dblMux = PcL; + default: begin dblMux = 'X; dblIdle = 1'b1; end + endcase + + unique case( 1'b1) + Nanod.rxh2dbh: dbhMux = regs68H[ actualRx]; + Nanod.ryh2dbh: dbhMux = regs68H[ actualRy]; + Nanod.au2Db: dbhMux = auReg[31:16]; + Nanod.ath2Dbh: dbhMux = Ath; + Pch2Dbh: dbhMux = PcH; + default: begin dbhMux = 'X; dbhIdle = 1'b1; end + endcase + + unique case( 1'b1) + ryl2Abd: abdMux = regs68L[ actualRy]; + rxl2Abd: abdMux = regs68L[ actualRx]; + Nanod.dbin2Abd: abdMux = dbin; + Nanod.alu2Abd: abdMux = aluOut; + default: begin abdMux = 'X; abdIdle = 1'b1; end + endcase + + unique case( 1'b1) + Pcl2Abl: ablMux = PcL; + rxl2Abl: ablMux = regs68L[ actualRx]; + ryl2Abl: ablMux = regs68L[ actualRy]; + Nanod.ftu2Abl: ablMux = ftu; + Nanod.au2Ab: ablMux = auReg[15:0]; + Nanod.aob2Ab: ablMux = aob[15:0]; + Nanod.atl2Abl: ablMux = Atl; + default: begin ablMux = 'X; ablIdle = 1'b1; end + endcase + + unique case( 1'b1) + Pch2Abh: abhMux = PcH; + Nanod.rxh2abh: abhMux = regs68H[ actualRx]; + Nanod.ryh2abh: abhMux = regs68H[ actualRy]; + Nanod.au2Ab: abhMux = auReg[31:16]; + Nanod.aob2Ab: abhMux = aob[31:16]; + Nanod.ath2Abh: abhMux = Ath; + default: begin abhMux = 'X; abhIdle = 1'b1; end + endcase + + end + + // Source starts driving the bus on T1. Bus holds data until end of T3. Destination latches at T3. + + // These registers store the first level mux, without bus interconnections. + // Even when this uses almost to 100 registers, it saves a lot of comb muxing and it is much faster. + reg [15:0] preAbh, preAbl, preAbd; + reg [15:0] preDbh, preDbl, preDbd; + + always_ff @( posedge Clks.clk) begin + + // Register first level mux at T1 + if( enT1) begin + {preAbh, preAbl, preAbd} <= { abhMux, ablMux, abdMux}; + {preDbh, preDbl, preDbd} <= { dbhMux, dblMux, dbdMux}; + end + + // Process bus interconnection at T2. Many combinations only used on DIV + // We use a simple method. If a specific bus segment is not driven we know that it should get data from a neighbour segment. + // In some cases this is not true and the segment is really idle without any destination. But then it doesn't matter. + + if( enT2) begin + if( Nanod.extAbh) + Abh <= { 16{ ablIdle ? preAbd[ 15] : preAbl[ 15] }}; + else if( abhIdle) + Abh <= ablIdle ? preAbd : preAbl; + else + Abh <= preAbh; + + if( ~ablIdle) + Abl <= preAbl; + else + Abl <= Nanod.ablAbh ? preAbh : preAbd; + + Abd <= ~abdIdle ? preAbd : ablIdle ? preAbh : preAbl; + + if( Nanod.extDbh) + Dbh <= { 16{ dblIdle ? preDbd[ 15] : preDbl[ 15] }}; + else if( dbhIdle) + Dbh <= dblIdle ? preDbd : preDbl; + else + Dbh <= preDbh; + + if( ~dblIdle) + Dbl <= preDbl; + else + Dbl <= Nanod.dblDbh ? preDbh : preDbd; + + Dbd <= ~dbdIdle ? preDbd: dblIdle ? preDbh : preDbl; + + /* + Dbl <= dblMux; Dbh <= dbhMux; + Abd <= abdMux; Dbd <= dbdMux; + Abh <= abhMux; Abl <= ablMux; */ + end + end + + // AOB + // + // Originally change on T1. We do on T2, only then the output is enabled anyway. + // + // AOB[0] is used for address error. But even when raises on T1, seems not actually used until T2 or possibly T3. + // It is used on T1 when deasserted at the BSER exception ucode. Probably deassertion timing is not critical. + // But in that case (at BSER), AOB is loaded from AU, so we can safely transfer on T1. + + // We need to take directly from first level muxes that are updated and T1 + + wire au2Aob = Nanod.au2Aob | (Nanod.au2Db & Nanod.db2Aob); + + always_ff @( posedge Clks.clk) begin + // UNIQUE IF ! + + if( enT1 & au2Aob) // From AU we do can on T1 + aob <= auReg; + else if( enT2) begin + if( Nanod.db2Aob) + aob <= { preDbh, ~dblIdle ? preDbl : preDbd}; + else if( Nanod.ab2Aob) + aob <= { preAbh, ~ablIdle ? preAbl : preAbd}; + end + end + + assign eab = aob[23:1]; + assign aob0 = aob[0]; + + // AU + logic [31:0] auInpMux; + + // `ifdef ALW_COMB_BUG + // Old Modelsim bug. Doesn't update ouput always. Need excplicit sensitivity list !? + // always @( Nanod.auCntrl) begin + + always_comb begin + unique case( Nanod.auCntrl) + 3'b000: auInpMux = 0; + 3'b001: auInpMux = byteNotSpAlign | Nanod.noSpAlign ? 1 : 2; // +1/+2 + 3'b010: auInpMux = -4; + 3'b011: auInpMux = { Abh, Abl}; + 3'b100: auInpMux = 2; + 3'b101: auInpMux = 4; + 3'b110: auInpMux = -2; + 3'b111: auInpMux = byteNotSpAlign | Nanod.noSpAlign ? -1 : -2; // -1/-2 + default: auInpMux = 'X; + endcase + end + + // Simulation problem + // Sometimes (like in MULM1) DBH is not set. AU is used in these cases just as a 6 bits counter testing if bits 5-0 are zero. + // But when adding something like 32'hXXXX0000, the simulator (incorrectly) will set *all the 32 bits* of the result as X. + +// synthesis translate_off + `define SIMULBUGX32 1 + wire [16:0] aulow = Dbl + auInpMux[15:0]; + wire [31:0] auResult = {Dbh + auInpMux[31:16] + aulow[16], aulow[15:0]}; +// synthesis translate_on + + always_ff @( posedge Clks.clk) begin + if( Clks.pwrUp) + auReg <= '0; + else if( enT3 & Nanod.auClkEn) + `ifdef SIMULBUGX32 + auReg <= auResult; + `else + auReg <= { Dbh, Dbl } + auInpMux; + `endif + end + + + // Main A/D registers + + always_ff @( posedge Clks.clk) begin + if( enT3) begin + if( Nanod.dbl2rxl | Nanod.abl2rxl) begin + if( ~rxIsAreg) begin + if( Nanod.dbl2rxl) regs68L[ actualRx] <= Dbd; + else if( abdIsByte) regs68L[ actualRx][7:0] <= Abd[7:0]; + else regs68L[ actualRx] <= Abd; + end + else + regs68L[ actualRx] <= Nanod.dbl2rxl ? Dbl : Abl; + end + + if( Nanod.dbl2ryl | Nanod.abl2ryl) begin + if( ~ryIsAreg) begin + if( Nanod.dbl2ryl) regs68L[ actualRy] <= Dbd; + else if( abdIsByte) regs68L[ actualRy][7:0] <= Abd[7:0]; + else regs68L[ actualRy] <= Abd; + end + else + regs68L[ actualRy] <= Nanod.dbl2ryl ? Dbl : Abl; + end + + // High registers are easier. Both A & D on the same buses, and not byte ops. + if( Nanod.dbh2rxh | Nanod.abh2rxh) + regs68H[ actualRx] <= Nanod.dbh2rxh ? Dbh : Abh; + if( Nanod.dbh2ryh | Nanod.abh2ryh) + regs68H[ actualRy] <= Nanod.dbh2ryh ? Dbh : Abh; + + end + end + + // PC & AT + reg dbl2Pcl, dbh2Pch, abh2Pch, abl2Pcl; + + always_ff @( posedge Clks.clk) begin + if( Clks.extReset) begin + { dbl2Pcl, dbh2Pch, abh2Pch, abl2Pcl } <= '0; + + Pcl2Dbl <= 1'b0; + Pch2Dbh <= 1'b0; + Pcl2Abl <= 1'b0; + Pch2Abh <= 1'b0; + end + else if( enT4) begin // Must latch on T4 ! + dbl2Pcl <= Nanod.dbl2reg & Nanod.pcldbl; + dbh2Pch <= Nanod.dbh2reg & Nanod.pchdbh; + abh2Pch <= Nanod.abh2reg & Nanod.pchabh; + abl2Pcl <= Nanod.abl2reg & Nanod.pclabl; + + Pcl2Dbl <= Nanod.reg2dbl & Nanod.pcldbl; + Pch2Dbh <= Nanod.reg2dbh & Nanod.pchdbh; + Pcl2Abl <= Nanod.reg2abl & Nanod.pclabl; + Pch2Abh <= Nanod.reg2abh & Nanod.pchabh; + end + + // Unique IF !!! + if( enT1 & Nanod.au2Pc) + PcL <= auReg[15:0]; + else if( enT3) begin + if( dbl2Pcl) + PcL <= Dbl; + else if( abl2Pcl) + PcL <= Abl; + end + + // Unique IF !!! + if( enT1 & Nanod.au2Pc) + PcH <= auReg[31:16]; + else if( enT3) begin + if( dbh2Pch) + PcH <= Dbh; + else if( abh2Pch) + PcH <= Abh; + end + + // Unique IF !!! + if( enT3) begin + if( Nanod.dbl2Atl) + Atl <= Dbl; + else if( Nanod.abl2Atl) + Atl <= Abl; + end + + // Unique IF !!! + if( enT3) begin + if( Nanod.abh2Ath) + Ath <= Abh; + else if( Nanod.dbh2Ath) + Ath <= Dbh; + end + + end + + // Movem reg mask priority encoder + + wire rmIdle; + logic [3:0] prHbit; + logic [15:0] prenLatch; + + // Invert reg order for predecrement mode + assign prenEmpty = (~| prenLatch); + pren rmPren( .mask( prenLatch), .hbit (prHbit)); + + always_ff @( posedge Clks.clk) begin + // Cheating: PREN always loaded from DBIN + // Must be on T1 to branch earlier if reg mask is empty! + if( enT1 & Nanod.abl2Pren) + prenLatch <= dbin; + else if( enT3 & Nanod.updPren) begin + prenLatch [prHbit] <= 1'b0; + movemRx <= Irdecod.movemPreDecr ? ~prHbit : prHbit; + end + end + + // DCR + wire [15:0] dcrCode; + + wire [3:0] dcrInput = abdIsByte ? { 1'b0, Abd[ 2:0]} : Abd[ 3:0]; + onehotEncoder4 dcrDecoder( .bin( dcrInput), .bitMap( dcrCode)); + + always_ff @( posedge Clks.clk) begin + if( Clks.pwrUp) + dcr4 <= '0; + else if( enT3 & Nanod.abd2Dcr) begin + dcrOutput <= dcrCode; + dcr4 <= Abd[4]; + end + end + + // ALUB + reg [15:0] alub; + + always_ff @( posedge Clks.clk) begin + if( enT3) begin + // UNIQUE IF !! + if( Nanod.dbd2Alub) + alub <= Dbd; + else if( Nanod.abd2Alub) + alub <= Abd; // abdIsByte affects this !!?? + end + end + + wire alueClkEn = enT3 & Nanod.dbd2Alue; + + // DOB/DBIN/IRC + + logic [15:0] dobInput; + wire dobIdle = (~| Nanod.dobCtrl); + + always_comb begin + unique case (Nanod.dobCtrl) + NANO_DOB_ADB: dobInput = Abd; + NANO_DOB_DBD: dobInput = Dbd; + NANO_DOB_ALU: dobInput = aluOut; + default: dobInput = 'X; + endcase + end + + dataIo dataIo( .Clks, .enT1, .enT2, .enT3, .enT4, .Nanod, .Irdecod, + .iEdb, .dobIdle, .dobInput, .aob0, + .Irc, .dbin, .oEdb); + + fx68kAlu alu( + .clk( Clks.clk), .pwrUp( Clks.pwrUp), .enT1, .enT3, .enT4, + .ird( Ird), + .aluColumn( Nanod.aluColumn), .aluAddrCtrl( Nanod.aluActrl), + .init( Nanod.aluInit), .finish( Nanod.aluFinish), .aluIsByte( Irdecod.isByte), + .ftu2Ccr( Nanod.ftu2Ccr), + .alub, .ftu, .alueClkEn, .alue, + .aluDataCtrl( Nanod.aluDctrl), .iDataBus( Dbd), .iAddrBus(Abd), + .ze, .aluOut, .ccr); + +endmodule + +// +// Data bus I/O +// At a separate module because it is a bit complicated and the timing is special. +// Here we do the low/high byte mux and the special case of MOVEP. +// +// Original implementation is rather complex because both the internal and external buses are bidirectional. +// Input is latched async at the EDB register. +// We capture directly from the external data bus to the internal registers (IRC & DBIN) on PHI2, starting the external S7 phase, at a T4 internal period. + +module dataIo( input s_clks Clks, + input enT1, enT2, enT3, enT4, + input s_nanod Nanod, input s_irdecod Irdecod, + input [15:0] iEdb, + input aob0, + + input dobIdle, + input [15:0] dobInput, + + output logic [15:0] Irc, + output logic [15:0] dbin, + output logic [15:0] oEdb + ); + + reg [15:0] dob; + + // DBIN/IRC + + // Timing is different than any other register. We can latch only on the next T4 (bus phase S7). + // We need to register all control signals correctly because the next ublock will already be started. + // Can't latch control on T4 because if there are wait states there might be multiple T4 before we latch. + + reg xToDbin, xToIrc; + reg dbinNoLow, dbinNoHigh; + reg byteMux, isByte_T4; + + always_ff @( posedge Clks.clk) begin + + // Byte mux control. Can't latch at T1. AOB might be not ready yet. + // Must latch IRD decode at T1 (or T4). Then combine and latch only at T3. + + // Can't latch at T3, a new IRD might be loaded already at T1. + // Ok to latch at T4 if combination latched then at T3 + if( enT4) + isByte_T4 <= Irdecod.isByte; // Includes MOVEP from mem, we could OR it here + + if( enT3) begin + dbinNoHigh <= Nanod.noHighByte; + dbinNoLow <= Nanod.noLowByte; + byteMux <= Nanod.busByte & isByte_T4 & ~aob0; + end + + if( enT1) begin + // If on wait states, we continue latching until next T1 + xToDbin <= 1'b0; + xToIrc <= 1'b0; + end + else if( enT3) begin + xToDbin <= Nanod.todbin; + xToIrc <= Nanod.toIrc; + end + + // Capture on T4 of the next ucycle + // If there are wait states, we keep capturing every PHI2 until the next T1 + + if( xToIrc & Clks.enPhi2) + Irc <= iEdb; + if( xToDbin & Clks.enPhi2) begin + // Original connects both halves of EDB. + if( ~dbinNoLow) + dbin[ 7:0] <= byteMux ? iEdb[ 15:8] : iEdb[7:0]; + if( ~dbinNoHigh) + dbin[ 15:8] <= ~byteMux & dbinNoLow ? iEdb[ 7:0] : iEdb[ 15:8]; + end + end + + // DOB + logic byteCycle; + + always_ff @( posedge Clks.clk) begin + // Originaly on T1. Transfer to internal EDB also on T1 (stays enabled upto the next T1). But only on T4 (S3) output enables. + // It is safe to do on T3, then, but control signals if derived from IRD must be registered. + // Originally control signals are not registered. + + // Wait states don't affect DOB operation that is done at the start of the bus cycle. + + if( enT4) + byteCycle <= Nanod.busByte & Irdecod.isByte; // busIsByte but not MOVEP + + // Originally byte low/high interconnect is done at EDB, not at DOB. + if( enT3 & ~dobIdle) begin + dob[7:0] <= Nanod.noLowByte ? dobInput[15:8] : dobInput[ 7:0]; + dob[15:8] <= (byteCycle | Nanod.noHighByte) ? dobInput[ 7:0] : dobInput[15:8]; + end + end + assign oEdb = dob; + +endmodule + + +// Provides ucode routine entries (A1/A3) for each opcode +// Also checks for illegal opcode and priv violation + +// This is one of the slowest part of the processor. +// But no need to optimize or pipeline because the result is not needed until at least 4 cycles. +// IR updated at the least one microinstruction earlier. +// Just need to configure the timing analizer correctly. + +module uaddrDecode( + input [15:0] opcode, + output [UADDR_WIDTH-1:0] a1, a2, a3, + output logic isPriv, isIllegal, isLineA, isLineF, + output [15:0] lineBmap); + + wire [3:0] line = opcode[15:12]; + logic [3:0] eaCol, movEa; + + onehotEncoder4 irLineDecod( line, lineBmap); + + assign isLineA = lineBmap[ 'hA]; + assign isLineF = lineBmap[ 'hF]; + + pla_lined pla_lined( .movEa( movEa), .col( eaCol), + .opcode( opcode), .lineBmap( lineBmap), + .palIll( isIllegal), .plaA1( a1), .plaA2( a2), .plaA3( a3) ); + + // ea decoding + assign eaCol = eaDecode( opcode[ 5:0]); + assign movEa = eaDecode( {opcode[ 8:6], opcode[ 11:9]} ); + + // EA decode + function [3:0] eaDecode; + input [5:0] eaBits; + begin + unique case( eaBits[ 5:3]) + 3'b111: + case( eaBits[ 2:0]) + 3'b000: eaDecode = 7; // Absolute short + 3'b001: eaDecode = 8; // Absolute long + 3'b010: eaDecode = 9; // PC displacement + 3'b011: eaDecode = 10; // PC offset + 3'b100: eaDecode = 11; // Immediate + default: eaDecode = 12; // Invalid + endcase + + default: eaDecode = eaBits[5:3]; // Register based EAs + endcase + end + endfunction + + + /* + Privileged instructions: + + ANDI/EORI/ORI SR + MOVE to SR + MOVE to/from USP + RESET + RTE + STOP + */ + + always_comb begin + unique case( lineBmap) + + // ori/andi/eori SR + 'h01: isPriv = ((opcode & 16'hf5ff) == 16'h007c); + + 'h10: + begin + // No priority !!! + if( (opcode & 16'hffc0) == 16'h46c0) // move to sr + isPriv = 1'b1; + + else if( (opcode & 16'hfff0) == 16'h4e60) // move usp + isPriv = 1'b1; + + else if( opcode == 16'h4e70 || // reset + opcode == 16'h4e73 || // rte + opcode == 16'h4e72) // stop + isPriv = 1'b1; + else + isPriv = 1'b0; + end + + default: isPriv = 1'b0; + endcase + end + + +endmodule + +// bin to one-hot, 4 bits to 16-bit bitmap +module onehotEncoder4( input [3:0] bin, output reg [15:0] bitMap); + always_comb begin + case( bin) + 'b0000: bitMap = 16'h0001; + 'b0001: bitMap = 16'h0002; + 'b0010: bitMap = 16'h0004; + 'b0011: bitMap = 16'h0008; + 'b0100: bitMap = 16'h0010; + 'b0101: bitMap = 16'h0020; + 'b0110: bitMap = 16'h0040; + 'b0111: bitMap = 16'h0080; + 'b1000: bitMap = 16'h0100; + 'b1001: bitMap = 16'h0200; + 'b1010: bitMap = 16'h0400; + 'b1011: bitMap = 16'h0800; + 'b1100: bitMap = 16'h1000; + 'b1101: bitMap = 16'h2000; + 'b1110: bitMap = 16'h4000; + 'b1111: bitMap = 16'h8000; + endcase + end +endmodule + +// priority encoder +// used by MOVEM regmask +// this might benefit from device specific features +// MOVEM doesn't need speed, will read the result 2 CPU cycles after each update. +module pren( mask, hbit); + parameter size = 16; + parameter outbits = 4; + + input [size-1:0] mask; + output reg [outbits-1:0] hbit; + // output reg idle; + + always @( mask) begin + integer i; + hbit = 0; + // idle = 1; + for( i = size-1; i >= 0; i = i - 1) begin + if( mask[ i]) begin + hbit = i; + // idle = 0; + end + end + end + +endmodule + +// Microcode sequencer + +module sequencer( input s_clks Clks, input enT3, + input [UROM_WIDTH-1:0] microLatch, + input A0Err, BerrA, busAddrErr, Spuria, Avia, + input Tpend, intPend, isIllegal, isPriv, excRst, isLineA, isLineF, + input [15:0] psw, + input prenEmpty, au05z, dcr4, ze, i11, + input [1:0] alue01, + input [15:0] Ird, + input [UADDR_WIDTH-1:0] a1, a2, a3, + output logic [3:0] tvn, + output logic [UADDR_WIDTH-1:0] nma); + + logic [UADDR_WIDTH-1:0] uNma; + logic [UADDR_WIDTH-1:0] grp1Nma; + logic [1:0] c0c1; + reg a0Rst; + wire A0Sel; + wire inGrp0Exc; + + // assign nma = Clks.extReset ? RSTP0_NMA : (A0Err ? BSER1_NMA : uNma); + // assign nma = A0Err ? (a0Rst ? RSTP0_NMA : BSER1_NMA) : uNma; + + // word type I: 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 + // NMA : .. .. 09 08 01 00 05 04 03 02 07 06 .. .. .. .. .. + + wire [UADDR_WIDTH-1:0] dbNma = { microLatch[ 14:13], microLatch[ 6:5], microLatch[ 10:7], microLatch[ 12:11]}; + + // Group 0 exception. + // Separated block from regular NMA. Otherwise simulation might depend on order of assigments. + always_comb begin + if( A0Err) begin + if( a0Rst) // Reset + nma = RSTP0_NMA; + else if( inGrp0Exc) // Double fault + nma = HALT1_NMA; + else // Bus or address error + nma = BSER1_NMA; + end + else + nma = uNma; + end + + always_comb begin + // Format II (conditional) or I (direct branch) + if( microLatch[1]) + uNma = { microLatch[ 14:13], c0c1, microLatch[ 10:7], microLatch[ 12:11]}; + else + case( microLatch[ 3:2]) + 0: uNma = dbNma; // DB + 1: uNma = A0Sel ? grp1Nma : a1; + 2: uNma = a2; + 3: uNma = a3; + endcase + end + + // Format II, conditional, NMA decoding + wire [1:0] enl = { Ird[6], prenEmpty}; // Updated on T3 + + wire [1:0] ms0 = { Ird[8], alue01[0]}; + wire [3:0] m01 = { au05z, Ird[8], alue01}; + wire [1:0] nz1 = { psw[ NF], psw[ ZF]}; + wire [1:0] nv = { psw[ NF], psw[ VF]}; + + logic ccTest; + wire [4:0] cbc = microLatch[ 6:2]; // CBC bits + + always_comb begin + unique case( cbc) + 'h0: c0c1 = {i11, i11}; // W/L offset EA, from IRC + + 'h1: c0c1 = (au05z) ? 2'b01 : 2'b11; // Updated on T3 + 'h11: c0c1 = (au05z) ? 2'b00 : 2'b11; + + 'h02: c0c1 = { 1'b0, ~psw[ CF]}; // C used in DIV + 'h12: c0c1 = { 1'b1, ~psw[ CF]}; + + 'h03: c0c1 = {psw[ ZF], psw[ ZF]}; // Z used in DIVU + + 'h04: // nz1, used in DIVS + case( nz1) + 'b00: c0c1 = 2'b10; + 'b10: c0c1 = 2'b01; + 'b01,'b11: c0c1 = 2'b11; + endcase + + 'h05: c0c1 = {psw[ NF], 1'b1}; // N used in CHK and DIV + 'h15: c0c1 = {1'b1, psw[ NF]}; + + // nz2, used in DIVS (same combination as nz1) + 'h06: c0c1 = { ~nz1[1] & ~nz1[0], 1'b1}; + + 'h07: // ms0 used in MUL + case( ms0) + 'b10, 'b00: c0c1 = 2'b11; + 'b01: c0c1 = 2'b01; + 'b11: c0c1 = 2'b10; + endcase + + 'h08: // m01 used in MUL + case( m01) + 'b0000,'b0001,'b0100,'b0111: c0c1 = 2'b11; + 'b0010,'b0011,'b0101: c0c1 = 2'b01; + 'b0110: c0c1 = 2'b10; + default: c0c1 = 2'b00; + endcase + + // Conditional + 'h09: c0c1 = (ccTest) ? 2'b11 : 2'b01; + 'h19: c0c1 = (ccTest) ? 2'b11 : 2'b10; + + // DCR bit 4 (high or low word) + 'h0c: c0c1 = dcr4 ? 2'b01: 2'b11; + 'h1c: c0c1 = dcr4 ? 2'b10: 2'b11; + + // DBcc done + 'h0a: c0c1 = ze ? 2'b11 : 2'b00; + + // nv, used in CHK + 'h0b: c0c1 = (nv == 2'b00) ? 2'b00 : 2'b11; + + // V, used in trapv + 'h0d: c0c1 = { ~psw[ VF], ~psw[VF]}; + + // enl, combination of pren idle and word/long on IRD + 'h0e,'h1e: + case( enl) + 2'b00: c0c1 = 'b10; + 2'b10: c0c1 = 'b11; + // 'hx1 result 00/01 depending on condition 0e/1e + 2'b01,2'b11: + c0c1 = { 1'b0, microLatch[ 6]}; + endcase + + default: c0c1 = 'X; + endcase + end + + // CCR conditional + always_comb begin + unique case( Ird[ 11:8]) + 'h0: ccTest = 1'b1; // T + 'h1: ccTest = 1'b0; // F + 'h2: ccTest = ~psw[ CF] & ~psw[ ZF]; // HI + 'h3: ccTest = psw[ CF] | psw[ZF]; // LS + 'h4: ccTest = ~psw[ CF]; // CC (HS) + 'h5: ccTest = psw[ CF]; // CS (LO) + 'h6: ccTest = ~psw[ ZF]; // NE + 'h7: ccTest = psw[ ZF]; // EQ + 'h8: ccTest = ~psw[ VF]; // VC + 'h9: ccTest = psw[ VF]; // VS + 'ha: ccTest = ~psw[ NF]; // PL + 'hb: ccTest = psw[ NF]; // MI + 'hc: ccTest = (psw[ NF] & psw[ VF]) | (~psw[ NF] & ~psw[ VF]); // GE + 'hd: ccTest = (psw[ NF] & ~psw[ VF]) | (~psw[ NF] & psw[ VF]); // LT + 'he: ccTest = (psw[ NF] & psw[ VF] & ~psw[ ZF]) | + (~psw[ NF] & ~psw[ VF] & ~psw[ ZF]); // GT + 'hf: ccTest = psw[ ZF] | (psw[ NF] & ~psw[VF]) | (~psw[ NF] & psw[VF]); // LE + endcase + end + + // Exception logic + logic rTrace, rInterrupt; + logic rIllegal, rPriv, rLineA, rLineF; + logic rExcRst, rExcAdrErr, rExcBusErr; + logic rSpurious, rAutovec; + wire grp1LatchEn, grp0LatchEn; + + // Originally control signals latched on T4. Then exception latches updated on T3 + assign grp1LatchEn = microLatch[0] & (microLatch[1] | !microLatch[4]); + assign grp0LatchEn = microLatch[4] & !microLatch[1]; + + assign inGrp0Exc = rExcRst | rExcBusErr | rExcAdrErr; + + always_ff @( posedge Clks.clk) begin + if( grp0LatchEn & enT3) begin + rExcRst <= excRst; + rExcBusErr <= BerrA; + rExcAdrErr <= busAddrErr; + rSpurious <= Spuria; + rAutovec <= Avia; + end + + // Update group 1 exception latches + // Inputs from IR decoder updated on T1 as soon as IR loaded + // Trace pending updated on T3 at the start of the instruction + // Interrupt pending on T2 + if( grp1LatchEn & enT3) begin + rTrace <= Tpend; + rInterrupt <= intPend; + rIllegal <= isIllegal & ~isLineA & ~isLineF; + rLineA <= isLineA; + rLineF <= isLineF; + rPriv <= isPriv & !psw[ SF]; + end + end + + // exception priority + always_comb begin + grp1Nma = TRAC1_NMA; + if( rExcRst) + tvn = '0; // Might need to change that to signal in exception + else if( rExcBusErr | rExcAdrErr) + tvn = { 1'b1, rExcAdrErr}; + + // Seudo group 0 exceptions. Just for updating TVN + else if( rSpurious | rAutovec) + tvn = rSpurious ? TVN_SPURIOUS : TVN_AUTOVEC; + + else if( rTrace) + tvn = 9; + else if( rInterrupt) begin + tvn = TVN_INTERRUPT; + grp1Nma = ITLX1_NMA; + end + else begin + unique case( 1'b1) // Can't happen more than one of these + rIllegal: tvn = 4; + rPriv: tvn = 8; + rLineA: tvn = 10; + rLineF: tvn = 11; + default: tvn = 1; // Signal no group 0/1 exception + endcase + end + end + + assign A0Sel = rIllegal | rLineF | rLineA | rPriv | rTrace | rInterrupt; + + always_ff @( posedge Clks.clk) begin + if( Clks.extReset) + a0Rst <= 1'b1; + else if( enT3) + a0Rst <= 1'b0; + end + +endmodule + + +// +// DMA/BUS Arbitration +// + +module busArbiter( input s_clks Clks, + input BRi, BgackI, Halti, bgBlock, + output busAvail, + output logic BGn); + + enum int unsigned { DRESET = 0, DIDLE, D1, D_BR, D_BA, D_BRA, D3, D2} dmaPhase, next; + + always_comb begin + case(dmaPhase) + DRESET: next = DIDLE; + DIDLE: begin + if( bgBlock) + next = DIDLE; + else if( ~BgackI) + next = D_BA; + else if( ~BRi) + next = D1; + else + next = DIDLE; + end + + D_BA: begin // Loop while only BGACK asserted, BG negated here + if( ~BRi & !bgBlock) + next = D3; + else if( ~BgackI & !bgBlock) + next = D_BA; + else + next = DIDLE; + end + + D1: next = D_BR; // Loop while only BR asserted + D_BR: next = ~BRi & BgackI ? D_BR : D_BA; // No direct path to IDLE ! + + D3: next = D_BRA; + D_BRA: begin // Loop while both BR and BGACK asserted + case( {BgackI, BRi} ) + 2'b11: next = DIDLE; // Both deasserted + 2'b10: next = D_BR; // BR asserted only + 2'b01: next = D2; // BGACK asserted only + 2'b00: next = D_BRA; // Stay here while both asserted + endcase + end + + // Might loop here if both deasserted, should normally don't arrive here anyway? + // D2: next = (BgackI & BRi) | bgBlock ? D2: D_BA; + + D2: next = D_BA; + + default: next = DIDLE; // Should not reach here normally + endcase + end + + logic granting; + always_comb begin + unique case( next) + D1, D3, D_BR, D_BRA: granting = 1'b1; + default: granting = 1'b0; + endcase + end + + reg rGranted; + assign busAvail = Halti & BRi & BgackI & ~rGranted; + + always_ff @( posedge Clks.clk) begin + if( Clks.extReset) begin + dmaPhase <= DRESET; + rGranted <= 1'b0; + end + else if( Clks.enPhi2) begin + dmaPhase <= next; + // Internal signal changed on PHI2 + rGranted <= granting; + end + + // External Output changed on PHI1 + if( Clks.extReset) + BGn <= 1'b1; + else if( Clks.enPhi1) + BGn <= ~rGranted; + + end + +endmodule + +module busControl( input s_clks Clks, input enT1, input enT4, + input permStart, permStop, iStop, + input aob0, + input isWrite, isByte, isRmc, + input busAvail, + output bgBlock, + output busAddrErr, + output waitBusCycle, + output busStarting, // Asserted during S0 + output logic addrOe, // Asserted from S1 to the end, whole bus cycle except S0 + output bciWrite, // Used for SSW on bus/addr error + + input rDtack, BeDebounced, Vpai, + output ASn, output LDSn, output UDSn, eRWn); + + reg rAS, rLDS, rUDS, rRWn; + assign ASn = rAS; + assign LDSn = rLDS; + assign UDSn = rUDS; + assign eRWn = rRWn; + + reg dataOe; + + reg bcPend; + reg isWriteReg, bciByte, isRmcReg, wendReg; + assign bciWrite = isWriteReg; + reg addrOeDelay; + reg isByteT4; + + wire canStart, busEnd; + wire bcComplete, bcReset; + + wire isRcmReset = bcComplete & bcReset & isRmcReg; + + assign busAddrErr = aob0 & ~bciByte; + + // Bus retry not really supported. + // It's BERR and HALT and not address error, and not read-modify cycle. + wire busRetry = ~busAddrErr & 1'b0; + + enum int unsigned { SRESET = 0, SIDLE, S0, S2, S4, S6, SRMC_RES} busPhase, next; + + always_ff @( posedge Clks.clk) begin + if( Clks.extReset) + busPhase <= SRESET; + else if( Clks.enPhi1) + busPhase <= next; + end + + always_comb begin + case( busPhase) + SRESET: next = SIDLE; + SRMC_RES: next = SIDLE; // Single cycle special state when read phase of RMC reset + S0: next = S2; + S2: next = S4; + S4: next = busEnd ? S6 : S4; + S6: next = isRcmReset ? SRMC_RES : (canStart ? S0 : SIDLE); + SIDLE: next = canStart ? S0 : SIDLE; + default: next = SIDLE; + endcase + end + + // Idle phase of RMC bus cycle. Might be better to just add a new state + wire rmcIdle = (busPhase == SIDLE) & ~ASn & isRmcReg; + + assign canStart = (busAvail | rmcIdle) & (bcPend | permStart) & !busRetry & !bcReset; + + wire busEnding = (next == SIDLE) | (next == S0); + + assign busStarting = (busPhase == S0); + + // term signal (DTACK, BERR, VPA, adress error) + assign busEnd = ~rDtack | iStop; + + // bcComplete asserted on raising edge of S6 (together with SNC). + assign bcComplete = (busPhase == S6); + + // Clear bus info latch on completion (regular or aborted) and no bus retry (and not PHI1). + // bciClear asserted half clock later on PHI2, and bci latches cleared async concurrently + wire bciClear = bcComplete & ~busRetry; + + // Reset on reset or (berr & berrDelay & (not halt or rmc) & not 6800 & in bus cycle) (and not PHI1) + assign bcReset = Clks.extReset | (addrOeDelay & BeDebounced & Vpai); + + // Enable uclock only on S6 (S8 on Bus Error) or not bciPermStop + assign waitBusCycle = wendReg & !bcComplete; + + // Block Bus Grant when starting new bus cycle. But No need if AS already asserted (read phase of RMC) + // Except that when that RMC phase aborted on bus error, it's asserted one cycle later! + assign bgBlock = ((busPhase == S0) & ASn) | (busPhase == SRMC_RES); + + always_ff @( posedge Clks.clk) begin + if( Clks.extReset) begin + addrOe <= 1'b0; + end + else if( Clks.enPhi2 & ( busPhase == S0)) // From S1, whole bus cycle except S0 + addrOe <= 1'b1; + else if( Clks.enPhi1 & (busPhase == SRMC_RES)) + addrOe <= 1'b0; + else if( Clks.enPhi1 & ~isRmcReg & busEnding) + addrOe <= 1'b0; + + if( Clks.enPhi1) + addrOeDelay <= addrOe; + + if( Clks.extReset) begin + rAS <= 1'b1; + rUDS <= 1'b1; + rLDS <= 1'b1; + rRWn <= 1'b1; + dataOe <= '0; + end + else begin + + if( Clks.enPhi2 & isWriteReg & (busPhase == S2)) + dataOe <= 1'b1; + else if( Clks.enPhi1 & (busEnding | (busPhase == SIDLE)) ) + dataOe <= 1'b0; + + if( Clks.enPhi1 & busEnding) + rRWn <= 1'b1; + else if( Clks.enPhi1 & isWriteReg) begin + // Unlike LDS/UDS Asserted even in address error + if( (busPhase == S0) & isWriteReg) + rRWn <= 1'b0; + end + + // AS. Actually follows addrOe half cycle later! + if( Clks.enPhi1 & (busPhase == S0)) + rAS <= 1'b0; + else if( Clks.enPhi2 & (busPhase == SRMC_RES)) // Bus error on read phase of RMC. Deasserted one cycle later + rAS <= 1'b1; + else if( Clks.enPhi2 & bcComplete & ~SRMC_RES) + if( ~isRmcReg) // Keep AS asserted on the IDLE phase of RMC + rAS <= 1'b1; + + if( Clks.enPhi1 & (busPhase == S0)) begin + if( ~isWriteReg & !busAddrErr) begin + rUDS <= ~(~bciByte | ~aob0); + rLDS <= ~(~bciByte | aob0); + end + end + else if( Clks.enPhi1 & isWriteReg & (busPhase == S2) & !busAddrErr) begin + rUDS <= ~(~bciByte | ~aob0); + rLDS <= ~(~bciByte | aob0); + end + else if( Clks.enPhi2 & bcComplete) begin + rUDS <= 1'b1; + rLDS <= 1'b1; + end + + end + + end + + // Bus cycle info latch. Needed because uinstr might change if the bus is busy and we must wait. + // Note that urom advances even on wait states. It waits *after* updating urom and nanorom latches. + // Even without wait states, ublocks of type ir (init reading) will not wait for bus completion. + // Originally latched on (permStart AND T1). + + // Bus cycle info latch: isRead, isByte, read-modify-cycle, and permStart (bus cycle pending). Some previously latched on T4? + // permStop also latched, but unconditionally on T1 + + // Might make more sense to register this outside this module + always_ff @( posedge Clks.clk) begin + if( enT4) begin + isByteT4 <= isByte; + end + end + + // Bus Cycle Info Latch + always_ff @( posedge Clks.clk) begin + if( Clks.pwrUp) begin + bcPend <= 1'b0; + wendReg <= 1'b0; + isWriteReg <= 1'b0; + bciByte <= 1'b0; + isRmcReg <= 1'b0; + end + + else if( Clks.enPhi2 & (bciClear | bcReset)) begin + bcPend <= 1'b0; + wendReg <= 1'b0; + end + else begin + if( enT1 & permStart) begin + isWriteReg <= isWrite; + bciByte <= isByteT4; + isRmcReg <= isRmc & ~isWrite; // We need special case the end of the read phase only. + bcPend <= 1'b1; + end + if( enT1) + wendReg <= permStop; + end + end + +endmodule + +// +// microrom and nanorom instantiation +// +// There is bit of wasting of resources here. An extra registering pipeline happens that is not needed. +// This is just for the purpose of helping inferring block RAM using pure generic code. Inferring RAM is important for performance. +// Might be more efficient to use vendor specific features such as clock enable. +// + +module uRom( input clk, input [UADDR_WIDTH-1:0] microAddr, output logic [UROM_WIDTH-1:0] microOutput); + reg [UROM_WIDTH-1:0] uRam[ UROM_DEPTH]; + initial begin + $readmemb("microrom.mem", uRam); + end + + always_ff @( posedge clk) + microOutput <= uRam[ microAddr]; +endmodule + + +module nanoRom( input clk, input [NADDR_WIDTH-1:0] nanoAddr, output logic [NANO_WIDTH-1:0] nanoOutput); + reg [NANO_WIDTH-1:0] nRam[ NANO_DEPTH]; + initial begin + $readmemb("nanorom.mem", nRam); + end + + always_ff @( posedge clk) + nanoOutput <= nRam[ nanoAddr]; +endmodule + +// Translate uaddr to nanoaddr +module microToNanoAddr( + input [UADDR_WIDTH-1:0] uAddr, + output [NADDR_WIDTH-1:0] orgAddr); + + wire [UADDR_WIDTH-1:2] baseAddr = uAddr[UADDR_WIDTH-1:2]; + logic [NADDR_WIDTH-1:2] orgBase; + assign orgAddr = { orgBase, uAddr[1:0]}; + + always @( baseAddr) + begin + // nano ROM (136 addresses) + case( baseAddr) + +'h00: orgBase = 7'h0 ; +'h01: orgBase = 7'h1 ; +'h02: orgBase = 7'h2 ; +'h03: orgBase = 7'h2 ; +'h08: orgBase = 7'h3 ; +'h09: orgBase = 7'h4 ; +'h0A: orgBase = 7'h5 ; +'h0B: orgBase = 7'h5 ; +'h10: orgBase = 7'h6 ; +'h11: orgBase = 7'h7 ; +'h12: orgBase = 7'h8 ; +'h13: orgBase = 7'h8 ; +'h18: orgBase = 7'h9 ; +'h19: orgBase = 7'hA ; +'h1A: orgBase = 7'hB ; +'h1B: orgBase = 7'hB ; +'h20: orgBase = 7'hC ; +'h21: orgBase = 7'hD ; +'h22: orgBase = 7'hE ; +'h23: orgBase = 7'hD ; +'h28: orgBase = 7'hF ; +'h29: orgBase = 7'h10 ; +'h2A: orgBase = 7'h11 ; +'h2B: orgBase = 7'h10 ; +'h30: orgBase = 7'h12 ; +'h31: orgBase = 7'h13 ; +'h32: orgBase = 7'h14 ; +'h33: orgBase = 7'h14 ; +'h38: orgBase = 7'h15 ; +'h39: orgBase = 7'h16 ; +'h3A: orgBase = 7'h17 ; +'h3B: orgBase = 7'h17 ; +'h40: orgBase = 7'h18 ; +'h41: orgBase = 7'h18 ; +'h42: orgBase = 7'h18 ; +'h43: orgBase = 7'h18 ; +'h44: orgBase = 7'h19 ; +'h45: orgBase = 7'h19 ; +'h46: orgBase = 7'h19 ; +'h47: orgBase = 7'h19 ; +'h48: orgBase = 7'h1A ; +'h49: orgBase = 7'h1A ; +'h4A: orgBase = 7'h1A ; +'h4B: orgBase = 7'h1A ; +'h4C: orgBase = 7'h1B ; +'h4D: orgBase = 7'h1B ; +'h4E: orgBase = 7'h1B ; +'h4F: orgBase = 7'h1B ; +'h54: orgBase = 7'h1C ; +'h55: orgBase = 7'h1D ; +'h56: orgBase = 7'h1E ; +'h57: orgBase = 7'h1F ; +'h5C: orgBase = 7'h20 ; +'h5D: orgBase = 7'h21 ; +'h5E: orgBase = 7'h22 ; +'h5F: orgBase = 7'h23 ; +'h70: orgBase = 7'h24 ; +'h71: orgBase = 7'h24 ; +'h72: orgBase = 7'h24 ; +'h73: orgBase = 7'h24 ; +'h74: orgBase = 7'h24 ; +'h75: orgBase = 7'h24 ; +'h76: orgBase = 7'h24 ; +'h77: orgBase = 7'h24 ; +'h78: orgBase = 7'h25 ; +'h79: orgBase = 7'h25 ; +'h7A: orgBase = 7'h25 ; +'h7B: orgBase = 7'h25 ; +'h7C: orgBase = 7'h25 ; +'h7D: orgBase = 7'h25 ; +'h7E: orgBase = 7'h25 ; +'h7F: orgBase = 7'h25 ; +'h84: orgBase = 7'h26 ; +'h85: orgBase = 7'h27 ; +'h86: orgBase = 7'h28 ; +'h87: orgBase = 7'h29 ; +'h8C: orgBase = 7'h2A ; +'h8D: orgBase = 7'h2B ; +'h8E: orgBase = 7'h2C ; +'h8F: orgBase = 7'h2D ; +'h94: orgBase = 7'h2E ; +'h95: orgBase = 7'h2F ; +'h96: orgBase = 7'h30 ; +'h97: orgBase = 7'h31 ; +'h9C: orgBase = 7'h32 ; +'h9D: orgBase = 7'h33 ; +'h9E: orgBase = 7'h34 ; +'h9F: orgBase = 7'h35 ; +'hA4: orgBase = 7'h36 ; +'hA5: orgBase = 7'h36 ; +'hA6: orgBase = 7'h37 ; +'hA7: orgBase = 7'h37 ; +'hAC: orgBase = 7'h38 ; +'hAD: orgBase = 7'h38 ; +'hAE: orgBase = 7'h39 ; +'hAF: orgBase = 7'h39 ; +'hB4: orgBase = 7'h3A ; +'hB5: orgBase = 7'h3A ; +'hB6: orgBase = 7'h3B ; +'hB7: orgBase = 7'h3B ; +'hBC: orgBase = 7'h3C ; +'hBD: orgBase = 7'h3C ; +'hBE: orgBase = 7'h3D ; +'hBF: orgBase = 7'h3D ; +'hC0: orgBase = 7'h3E ; +'hC1: orgBase = 7'h3F ; +'hC2: orgBase = 7'h40 ; +'hC3: orgBase = 7'h41 ; +'hC8: orgBase = 7'h42 ; +'hC9: orgBase = 7'h43 ; +'hCA: orgBase = 7'h44 ; +'hCB: orgBase = 7'h45 ; +'hD0: orgBase = 7'h46 ; +'hD1: orgBase = 7'h47 ; +'hD2: orgBase = 7'h48 ; +'hD3: orgBase = 7'h49 ; +'hD8: orgBase = 7'h4A ; +'hD9: orgBase = 7'h4B ; +'hDA: orgBase = 7'h4C ; +'hDB: orgBase = 7'h4D ; +'hE0: orgBase = 7'h4E ; +'hE1: orgBase = 7'h4E ; +'hE2: orgBase = 7'h4F ; +'hE3: orgBase = 7'h4F ; +'hE8: orgBase = 7'h50 ; +'hE9: orgBase = 7'h50 ; +'hEA: orgBase = 7'h51 ; +'hEB: orgBase = 7'h51 ; +'hF0: orgBase = 7'h52 ; +'hF1: orgBase = 7'h52 ; +'hF2: orgBase = 7'h52 ; +'hF3: orgBase = 7'h52 ; +'hF8: orgBase = 7'h53 ; +'hF9: orgBase = 7'h53 ; +'hFA: orgBase = 7'h53 ; +'hFB: orgBase = 7'h53 ; + + default: + orgBase = 'X; + endcase + end + +endmodule + +// +// For compilation test only +// + +`ifdef FX68K_TEST +module fx68kTop( input clk32, + input extReset, + // input pwrUp, + + input DTACKn, input VPAn, + input BERRn, + input BRn, BGACKn, + input IPL0n, input IPL1n, input IPL2n, + input [15:0] iEdb, + + output [15:0] oEdb, + output eRWn, output ASn, output LDSn, output UDSn, + output logic E, output VMAn, + output FC0, output FC1, output FC2, + output BGn, + output oRESETn, output oHALTEDn, + output [23:1] eab + ); + + // Clock must be at least twice the desired frequency. A 32 MHz clock means a maximum 16 MHz effective frequency. + // In this example we divide the clock by 4. Resulting on an effective processor running at 8 MHz. + + reg [1:0] clkDivisor = '0; + always @( posedge clk32) begin + clkDivisor <= clkDivisor + 1'b1; + end + + /* + These two signals must be a single cycle pulse. They don't need to be registered. + Same signal can't be asserted twice in a row. Other than that there are no restrictions. + There can be any number of cycles, or none, even variable non constant cycles, between each pulse. + */ + + wire enPhi1 = (clkDivisor == 2'b11); + wire enPhi2 = (clkDivisor == 2'b01); + + + fx68k fx68k( .clk( clk32), + .extReset, .pwrUp( extReset), .enPhi1, .enPhi2, + + .DTACKn, .VPAn, .BERRn, .BRn, .BGACKn, + .IPL0n, .IPL1n, .IPL2n, + .iEdb, + + .oEdb, + .eRWn, .ASn, .LDSn, .UDSn, + .E, .VMAn, + .FC0, .FC1, .FC2, + .BGn, + .oRESETn, .oHALTEDn, .eab); + +endmodule +`endif diff --git a/common/CPU/68000/FX68k/fx68k.txt b/common/CPU/68000/FX68k/fx68k.txt index 7ad0b47f..3397c02f 100644 --- a/common/CPU/68000/FX68k/fx68k.txt +++ b/common/CPU/68000/FX68k/fx68k.txt @@ -72,3 +72,16 @@ set_multicycle_path -setup -from [get_pins fx68k/Ir*/C] -to [get_pins fx68k/micr set_multicycle_path -hold -from [get_pins fx68k/Ir*/C] -to [get_pins fx68k/nanoAddr_reg*/D] 1 set_multicycle_path -hold -from [get_pins fx68k/Ir*/C] -to [get_pins fx68k/microAddr_reg*/D] 1 + +The update of the CCR flags is also time critical. Some compilers might benefit with the following constraints, but this wasn't fully verified yet: + + +# Altera/Intel +# set_multicycle_path -start -setup -from [fx68k:fx68k|nanoLatch[*]] +# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 2 +# set_multicycle_path -start -setup -from [fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|oper[*]] +# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 2 +# set_multicycle_path -start -hold -from [fx68k:fx68k|nanoLatch[*]] +# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 1 +# set_multicycle_path -start -hold -from [fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|oper[*]] +# -to [get_keepers fx68k:fx68k|excUnit:excUnit|fx68kAlu:alu|pswCcr[*]] 1 diff --git a/common/CPU/68000/FX68k/fx68k.vhd b/common/CPU/68000/FX68k/fx68k.vhd new file mode 100644 index 00000000..1f169a8b --- /dev/null +++ b/common/CPU/68000/FX68k/fx68k.vhd @@ -0,0 +1,39 @@ +library IEEE; +use IEEE.std_logic_1164.all; + +package fx68k is +COMPONENT fx68k +PORT +( + clk : in std_logic; + extReset : in std_logic; -- External sync reset on emulated system + pwrUp : in std_logic; -- Asserted together with reset on emulated system coldstart + enPhi1 : in std_logic; + enPhi2 : in std_logic; -- Clock enables. Next cycle is PHI1 or PHI2 + + eRWn : out std_logic; + ASn : out std_logic; + LDSn : out std_logic; + UDSn : out std_logic; + E : out std_logic; + VMAn : out std_logic; + FC0 : out std_logic; + FC1 : out std_logic; + FC2 : out std_logic; + BGn : out std_logic; + oRESETn : out std_logic; + oHALTEDn : out std_logic; + DTACKn : in std_logic; + VPAn : in std_logic; + BERRn : in std_logic; + BRn : in std_logic; + BGACKn : in std_logic; + IPL0n : in std_logic; + IPL1n : in std_logic; + IPL2n : in std_logic; + iEdb : in std_logic_vector(15 downto 0); + oEdb : out std_logic_vector(15 downto 0); + eab : out std_logic_vector(23 downto 1) +); +END COMPONENT; +end package; \ No newline at end of file diff --git a/common/CPU/68000/FX68k/fx68kAlu.sv b/common/CPU/68000/FX68k/fx68kAlu.sv index 347b033d..95059c43 100644 --- a/common/CPU/68000/FX68k/fx68kAlu.sv +++ b/common/CPU/68000/FX68k/fx68kAlu.sv @@ -96,31 +96,15 @@ module fx68kAlu ( input clk, pwrUp, enT1, enT3, enT4, wire [15:0] cRow; wire cIsArX; wire cNoCcrEn; - rowDecoder rowDecoder( - .ird ( ird), - .row ( cRow), - .noCcrEn ( cNoCcrEn), - .isArX ( cIsArX) - ); + rowDecoder rowDecoder( .ird( ird), .row( cRow), .noCcrEn( cNoCcrEn), .isArX( cIsArX)); // Get Operation & CCR Mask from row/col // Registering them on T4 increase performance. But slowest part seems to be corf ! wire [4:0] cMask; wire [4:0] aluOp; - aluGetOp aluGetOp( - .row ( row), - .col ( aluColumn), - .isCorf ( isCorf), - .aluOp ( aluOp) - ); - - ccrTable ccrTable( - .col ( aluColumn), - .row ( row), - .finish ( finish), - .ccrMask ( cMask) - ); + aluGetOp aluGetOp( .row, .col( aluColumn), .isCorf, .aluOp); + ccrTable ccrTable( .col( aluColumn), .row( row), .finish, .ccrMask( cMask)); // Inefficient, uCode could help ! wire shftIsMul = row[7]; @@ -177,26 +161,16 @@ module fx68kAlu ( input clk, pwrUp, enT1, enT3, enT4, // Can't be registered because uses bus operands that aren't available early ! wire shftMsb = isLong ? alue[15] : (isByte ? aOperand[7] : aOperand[15]); - aluShifter shifter( - .data ( { alue, aOperand}), - .swapWords ( shftIsMul | shftIsDiv), - .cin ( shftCin), - .dir ( shftRight), - .isByte ( isByte), - .isLong ( isLong), - .result ( shftResult) - ); + aluShifter shifter( .data( { alue, aOperand}), + .swapWords( shftIsMul | shftIsDiv), + .cin( shftCin), .dir( shftRight), .isByte( isByte), .isLong( isLong), + .result( shftResult)); wire [7:0] bcdResult; wire bcdC, bcdV; - aluCorf aluCorf( - .binResult ( aluLatch[7:0]), - .hCarry ( coreH), - .bAdd ( (oper != OP_SBCD) ), - .cin ( pswCcr[ XF]), - .bcdResult ( bcdResult), - .dC ( bcdC), - .ov ( bcdV)); + aluCorf aluCorf( .binResult( aluLatch[7:0]), .hCarry( coreH), + .bAdd( (oper != OP_SBCD) ), .cin( pswCcr[ XF]), + .bcdResult( bcdResult), .dC( bcdC), .ov( bcdV)); // BCD adjust is among the slowest processing on ALU ! // Precompute and register BCD result on T1 @@ -332,7 +306,7 @@ module fx68kAlu ( input clk, pwrUp, enT1, enT3, enT4, ccrTemp[XF] = pswCcr[XF]; ccrTemp[CF] = 0; ccrTemp[VF] = 0; - // Not on all operators !!! + // Not on all operators ccrTemp[ ZF] = isByte ? ~(| result[7:0]) : ~(| result); ccrTemp[ NF] = isByte ? result[7] : result[15]; @@ -341,7 +315,8 @@ module fx68kAlu ( input clk, pwrUp, enT1, enT3, enT4, OP_EXT: // Division overflow. if( aluColumn == 5) begin - ccrTemp[VF] = 1'b1; ccrTemp[NF] = 1'b1; + ccrTemp[VF] = 1'b1; + ccrTemp[NF] = 1'b1; ccrTemp[ ZF] = 1'b0; end OP_SUB0, // used by NOT @@ -438,7 +413,8 @@ module fx68kAlu ( input clk, pwrUp, enT1, enT3, enT4, logic [4:0] ccrMasked; always_comb begin ccrMasked = (ccrTemp & ccrMask) | (pswCcr & ~ccrMask); - if( finish | isCorf | isArX) + // if( finish | isCorf | isArX) // No need to check specicially for isCorf as they always have the "finish" flag anyway + if( finish | isArX) ccrMasked[ ZF] = ccrTemp[ ZF] & pswCcr[ ZF]; end @@ -476,4 +452,388 @@ module fx68kAlu ( input clk, pwrUp, enT1, enT3, enT4, endmodule +// add bcd correction factor +// It would be more efficient to merge add/sub with main ALU !!! +module aluCorf( input [7:0] binResult, input bAdd, input cin, input hCarry, + output [7:0] bcdResult, output dC, output logic ov); + reg [8:0] htemp; + reg [4:0] hNib; + + wire lowC = hCarry | (bAdd ? gt9( binResult[ 3:0]) : 1'b0); + wire highC = cin | (bAdd ? (gt9( htemp[7:4]) | htemp[8]) : 1'b0); + + always_comb begin + if( bAdd) begin + htemp = { 1'b0, binResult} + (lowC ? 4'h6 : 4'h0); + hNib = htemp[8:4] + (highC ? 4'h6 : 4'h0); + ov = hNib[3] & ~binResult[7]; + end + else begin + htemp = { 1'b0, binResult} - (lowC ? 4'h6 : 4'h0); + hNib = htemp[8:4] - (highC ? 4'h6 : 4'h0); + ov = ~hNib[3] & binResult[7]; + end + end + + assign bcdResult = { hNib[ 3:0], htemp[3:0]}; + assign dC = hNib[4] | cin; + + // Nibble > 9 + function gt9 (input [3:0] nib); + begin + gt9 = nib[3] & (nib[2] | nib[1]); + end + endfunction + +endmodule + + +module aluShifter( input [31:0] data, + input isByte, input isLong, swapWords, + input dir, input cin, + output logic [31:0] result); + // output reg cout + + logic [31:0] tdata; + + // size mux, put cin in position if dir == right + always_comb begin + tdata = data; + if( isByte & dir) + tdata[8] = cin; + else if( !isLong & dir) + tdata[16] = cin; + end + + always_comb begin + // Reverse alu/alue position for MUL & DIV + // Result reversed again + if( swapWords & dir) + result = { tdata[0], tdata[31:17], cin, tdata[15:1]}; + else if( swapWords) + result = { tdata[30:16], cin, tdata[14:0], tdata[31]}; + + else if( dir) + result = { cin, tdata[31:1]}; + else + result = { tdata[30:0], cin}; + end + +endmodule + + +// Get current OP from row & col +module aluGetOp( input [15:0] row, input [2:0] col, input isCorf, + output logic [4:0] aluOp); + + always_comb begin + aluOp = 'X; + unique case( col) + 1: aluOp = OP_AND; + 5: aluOp = OP_EXT; + + default: + unique case( 1'b1) + row[1]: + unique case( col) + 2: aluOp = OP_SUB; + 3: aluOp = OP_SUBC; + 4,6: aluOp = OP_SLAA; + endcase + + row[2]: + unique case( col) + 2: aluOp = OP_ADD; + 3: aluOp = OP_ADDC; + 4: aluOp = OP_ASR; + endcase + + row[3]: + unique case( col) + 2: aluOp = OP_ADDX; + 3: aluOp = isCorf ? OP_ABCD : OP_ADD; + 4: aluOp = OP_ASL; + endcase + + row[4]: + aluOp = ( col == 4) ? OP_LSL : OP_AND; + + row[5], + row[6]: + unique case( col) + 2: aluOp = OP_SUB; + 3: aluOp = OP_SUBC; + 4: aluOp = OP_LSR; + endcase + + row[7]: // MUL + unique case( col) + 2: aluOp = OP_SUB; + 3: aluOp = OP_ADD; + 4: aluOp = OP_ROXR; + endcase + + row[8]: + // OP_AND For EXT.L + // But would be more efficient to change ucode and use column 1 instead of col3 at ublock extr1! + unique case( col) + 2: aluOp = OP_EXT; + 3: aluOp = OP_AND; + 4: aluOp = OP_ROXR; + endcase + + row[9]: + unique case( col) + 2: aluOp = OP_SUBX; + 3: aluOp = OP_SBCD; + 4: aluOp = OP_ROL; + endcase + + row[10]: + unique case( col) + 2: aluOp = OP_SUBX; + 3: aluOp = OP_SUBC; + 4: aluOp = OP_ROR; + endcase + + row[11]: + unique case( col) + 2: aluOp = OP_SUB0; + 3: aluOp = OP_SUB0; + 4: aluOp = OP_ROXL; + endcase + + row[12]: aluOp = OP_ADDX; + row[13]: aluOp = OP_EOR; + row[14]: aluOp = (col == 4) ? OP_EOR : OP_OR; + row[15]: aluOp = (col == 3) ? OP_ADD : OP_OR; // OP_ADD used by DBcc + + endcase + endcase + end +endmodule + +// Decodes IRD into ALU row (1-15) +// Slow, but no need to optimize for speed since IRD is latched at least two CPU cycles before it is used +// We also register the result after combining with column from nanocode +// +// Many opcodes are not decoded because they either don't do any ALU op, +// or use only columns 1 and 5 that are the same for all rows. + +module rowDecoder( input [15:0] ird, + output logic [15:0] row, output noCcrEn, output logic isArX); + + + // Addr or data register direct + wire eaRdir = (ird[ 5:4] == 2'b00); + // Addr register direct + wire eaAdir = (ird[ 5:3] == 3'b001); + wire size11 = ird[7] & ird[6]; + + always_comb begin + case( ird[15:12]) + 'h4, + 'h9, + 'hd: + isArX = row[10] | row[12]; + default: + isArX = 1'b0; + endcase + end + + always_comb begin + unique case( ird[15:12]) + + 'h4: begin + if( ird[8]) + row = `ALU_ROW_06; // chk (or lea) + else case( ird[11:9]) + 'b000: row = `ALU_ROW_10; // negx + 'b001: row = `ALU_ROW_04; // clr + 'b010: row = `ALU_ROW_05; // neg + 'b011: row = `ALU_ROW_11; // not + 'b100: row = (ird[7]) ? `ALU_ROW_08 : `ALU_ROW_09; // nbcd/swap/ext(or pea) + 'b101: row = `ALU_ROW_15; // tst & tas + default: row = 0; + endcase + end + + 'h0: begin + if( ird[8]) // dynamic bit + row = ird[7] ? `ALU_ROW_14 : `ALU_ROW_13; + else case( ird[ 11:9]) + 'b000: row = `ALU_ROW_14; // ori + 'b001: row = `ALU_ROW_04; // andi + 'b010: row = `ALU_ROW_05; // subi + 'b011: row = `ALU_ROW_02; // addi + 'b100: row = ird[7] ? `ALU_ROW_14 : `ALU_ROW_13; // static bit + 'b101: row = `ALU_ROW_13; // eori + 'b110: row = `ALU_ROW_06; // cmpi + default: row = 0; + endcase + end + + // MOVE + // move.b originally also rows 5 & 15. Only because IRD bit 14 is not decoded. + // It's the same for move the operations performed by MOVE.B + + 'h1,'h2,'h3: row = `ALU_ROW_02; + + 'h5: + if( size11) + row = `ALU_ROW_15; // As originally and easier to decode + else + row = ird[8] ? `ALU_ROW_05 : `ALU_ROW_02; // addq/subq + 'h6: row = 0; //bcc/bra/bsr + 'h7: row = `ALU_ROW_02; // moveq + 'h8: + if( size11) // div + row = `ALU_ROW_01; + else if( ird[8] & eaRdir) // sbcd + row = `ALU_ROW_09; + else + row = `ALU_ROW_14; // or + 'h9: + if( ird[8] & ~size11 & eaRdir) + row = `ALU_ROW_10; // subx + else + row = `ALU_ROW_05; // sub/suba + 'hb: + if( ird[8] & ~size11 & ~eaAdir) + row = `ALU_ROW_13; // eor + else + row = `ALU_ROW_06; // cmp/cmpa/cmpm + 'hc: + if( size11) + row = `ALU_ROW_07; // mul + else if( ird[8] & eaRdir) // abcd + row = `ALU_ROW_03; + else + row = `ALU_ROW_04; // and + 'hd: + if( ird[8] & ~size11 & eaRdir) + row = `ALU_ROW_12; // addx + else + row = `ALU_ROW_02; // add/adda + 'he: + begin + reg [1:0] stype; + + if( size11) // memory shift/rotate + stype = ird[ 10:9]; + else // register shift/rotate + stype = ird[ 4:3]; + + case( {stype, ird[8]}) + 0: row = `ALU_ROW_02; // ASR + 1: row = `ALU_ROW_03; // ASL + 2: row = `ALU_ROW_05; // LSR + 3: row = `ALU_ROW_04; // LSL + 4: row = `ALU_ROW_08; // ROXR + 5: row = `ALU_ROW_11; // ROXL + 6: row = `ALU_ROW_10; // ROR + 7: row = `ALU_ROW_09; // ROL + endcase + end + + default: row = 0; + endcase + end + + // Decode opcodes that don't affect flags + // ADDA/SUBA ADDQ/SUBQ MOVEA + + assign noCcrEn = + // ADDA/SUBA + ( ird[15] & ~ird[13] & ird[12] & size11) | + // ADDQ/SUBQ to An + ( (ird[15:12] == 4'h5) & eaAdir) | + // MOVEA + ( (~ird[15] & ~ird[14] & ird[13]) & ird[8:6] == 3'b001); + +endmodule + +// Row/col CCR update table +module ccrTable( + input [2:0] col, input [15:0] row, input finish, + output logic [MASK_NBITS-1:0] ccrMask); + + localparam + KNZ00 = 5'b01111, // ok coz operators clear them + KKZKK = 5'b00100, + KNZKK = 5'b01100, + KNZ10 = 5'b01111, // Used by OP_EXT on divison overflow + KNZ0C = 5'b01111, // Used by DIV. V should be 0, but it is ok: + // DIVU: ends with quotient - 0, so V & C always clear. + // DIVS: ends with 1i (AND), again, V & C always clear. + + KNZVC = 5'b01111, + XNKVC = 5'b11011, // Used by BCD instructions. Don't modify Z at all at the binary operation. Only at the BCD correction cycle + + CUPDALL = 5'b11111, + CUNUSED = 5'bxxxxx; + + + logic [MASK_NBITS-1:0] ccrMask1; + + always_comb begin + unique case( col) + 1: ccrMask = ccrMask1; + + 2,3: + unique case( 1'b1) + row[1]: ccrMask = KNZ0C; // DIV, used as 3n in col3 + + row[3], // ABCD + row[9]: // SBCD/NBCD + ccrMask = (col == 2) ? XNKVC : CUPDALL; + + row[2], + row[5], + row[10], // SUBX/NEGX + row[12]: ccrMask = CUPDALL; // ADDX + + row[6], // CMP + row[7], // MUL + row[11]: ccrMask = KNZVC; // NOT + row[4], + row[8], // Not used in col 3 + row[13], + row[14]: ccrMask = KNZ00; + row[15]: ccrMask = 5'b0; // TAS/Scc, not used in col 3 + // default: ccrMask = CUNUSED; + endcase + + 4: + unique case( row) + // 1: DIV, only n (4n & 6n) + // 14: BCLR 4n + // 6,12,13,15 // not used + `ALU_ROW_02, + `ALU_ROW_03, // ASL (originally ANZVA) + `ALU_ROW_04, + `ALU_ROW_05: ccrMask = CUPDALL; // Shifts (originally ANZ0A) + + `ALU_ROW_07: ccrMask = KNZ00; // MUL (originally KNZ0A) + `ALU_ROW_09, + `ALU_ROW_10: ccrMask = KNZ00; // RO[lr] (originally KNZ0A) + `ALU_ROW_08, // ROXR (originally ANZ0A) + `ALU_ROW_11: ccrMask = CUPDALL; // ROXL (originally ANZ0A) + default: ccrMask = CUNUSED; + endcase + + 5: ccrMask = row[1] ? KNZ10 : 5'b0; + default: ccrMask = CUNUSED; + endcase + end + + // Column 1 (AND) + always_comb begin + if( finish) + ccrMask1 = row[7] ? KNZ00 : KNZKK; + else + ccrMask1 = row[13] | row[14] ? KKZKK : KNZ00; + end + +endmodule diff --git a/common/CPU/68000/FX68k/fx68k_tb.sv b/common/CPU/68000/FX68k/fx68k_tb.sv deleted file mode 100644 index de558a77..00000000 --- a/common/CPU/68000/FX68k/fx68k_tb.sv +++ /dev/null @@ -1,57 +0,0 @@ - -// -// For compilation test only -// - -module fx68k_tb( input clk32, - input extReset, - // input pwrUp, - - input DTACKn, input VPAn, - input BERRn, - input BRn, BGACKn, - input IPL0n, input IPL1n, input IPL2n, - input [15:0] iEdb, - - output [15:0] oEdb, - output eRWn, output ASn, output LDSn, output UDSn, - output logic E, output VMAn, - output FC0, output FC1, output FC2, - output BGn, - output oRESETn, output oHALTEDn, - output [23:1] eab - ); - - // Clock must be at least twice the desired frequency. A 32 MHz clock means a maximum 16 MHz effective frequency. - // In this example we divide the clock by 4. Resulting on an effective processor running at 8 MHz. - - reg [1:0] clkDivisor = '0; - always @( posedge clk32) begin - clkDivisor <= clkDivisor + 1'b1; - end - - /* - These two signals must be a single cycle pulse. They don't need to be registered. - Same signal can't be asserted twice in a row. Other than that there are no restrictions. - There can be any number of cycles, or none, even variable non constant cycles, between each pulse. - */ - - wire enPhi1 = (clkDivisor == 2'b11); - wire enPhi2 = (clkDivisor == 2'b01); - - - fx68k fx68k( .clk( clk32), - .extReset, .pwrUp( extReset), .enPhi1, .enPhi2, - - .DTACKn, .VPAn, .BERRn, .BRn, .BGACKn, - .IPL0n, .IPL1n, .IPL2n, - .iEdb, - - .oEdb, - .eRWn, .ASn, .LDSn, .UDSn, - .E, .VMAn, - .FC0, .FC1, .FC2, - .BGn, - .oRESETn, .oHALTEDn, .eab); - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/irdDecode.sv b/common/CPU/68000/FX68k/irdDecode.sv deleted file mode 100644 index 0a3d193a..00000000 --- a/common/CPU/68000/FX68k/irdDecode.sv +++ /dev/null @@ -1,208 +0,0 @@ -// -// IRD execution decoder. Complements nano code decoder -// -// IRD updated on T1, while ncode still executing. To avoid using the next IRD, -// decoded signals must be registered on T3, or T4 before using them. -// -module irdDecode( input [15:0] ird, - output s_irdecod Irdecod); - - wire [3:0] line = ird[15:12]; - logic [15:0] lineOnehot; - - // This can be registered and pipelined from the IR decoder ! - onehotEncoder4 irdLines( line, lineOnehot); - - wire isRegShift = (lineOnehot['he]) & (ird[7:6] != 2'b11); - wire isDynShift = isRegShift & ird[5]; - - assign Irdecod.isPcRel = (& ird[ 5:3]) & ~isDynShift & !ird[2] & ird[1]; - assign Irdecod.isTas = lineOnehot[4] & (ird[11:6] == 6'b101011); - - assign Irdecod.rx = ird[11:9]; - assign Irdecod.ry = ird[ 2:0]; - - wire isPreDecr = (ird[ 5:3] == 3'b100); - wire eaAreg = (ird[5:3] == 3'b001); - - // rx is A or D - // movem - always_comb begin - unique case( 1'b1) - lineOnehot[1], - lineOnehot[2], - lineOnehot[3]: - // MOVE: RX always Areg except if dest mode is Dn 000 - Irdecod.rxIsAreg = (| ird[8:6]); - - lineOnehot[4]: Irdecod.rxIsAreg = (& ird[8:6]); // not CHK (LEA) - - lineOnehot['h8]: Irdecod.rxIsAreg = eaAreg & ird[8] & ~ird[7]; // SBCD - lineOnehot['hc]: Irdecod.rxIsAreg = eaAreg & ird[8] & ~ird[7]; // ABCD/EXG An,An - - lineOnehot['h9], - lineOnehot['hb], - lineOnehot['hd]: Irdecod.rxIsAreg = - (ird[7] & ird[6]) | // SUBA/CMPA/ADDA - (eaAreg & ird[8] & (ird[7:6] != 2'b11)); // SUBX/CMPM/ADDX - default: - Irdecod.rxIsAreg = Irdecod.implicitSp; - endcase - end - - // RX is movem - always_comb begin - Irdecod.rxIsMovem = lineOnehot[4] & ~ird[8] & ~Irdecod.implicitSp; - end - assign Irdecod.movemPreDecr = Irdecod.rxIsMovem & isPreDecr; - - // RX is DT. - // but SSP explicit or pc explicit has higher priority! - // addq/subq (scc & dbcc also, but don't use rx) - // Immediate including static bit - assign Irdecod.rxIsDt = lineOnehot[5] | (lineOnehot[0] & ~ird[8]); - - // RX is USP - assign Irdecod.rxIsUsp = lineOnehot[4] & (ird[ 11:4] == 8'he6); - - // RY is DT - // rz or PC explicit has higher priority - - wire eaImmOrAbs = (ird[5:3] == 3'b111) & ~ird[1]; - assign Irdecod.ryIsDt = eaImmOrAbs & ~isRegShift; - - // RY is Address register - always_comb begin - logic eaIsAreg; - - // On most cases RY is Areg expect if mode is 000 (DATA REG) or 111 (IMM, ABS,PC REL) - eaIsAreg = (ird[5:3] != 3'b000) & (ird[5:3] != 3'b111); - - unique case( 1'b1) - // MOVE: RY always Areg expect if mode is 000 (DATA REG) or 111 (IMM, ABS,PC REL) - // Most lines, including misc line 4, also. - default: Irdecod.ryIsAreg = eaIsAreg; - - lineOnehot[5]: // DBcc is an exception - Irdecod.ryIsAreg = eaIsAreg & (ird[7:3] != 5'b11001); - - lineOnehot[6], - lineOnehot[7]: Irdecod.ryIsAreg = 1'b0; - - lineOnehot['he]: - Irdecod.ryIsAreg = ~isRegShift; - endcase - end - - // Byte sized instruction - - // Original implementation sets this for some instructions that aren't really byte size - // but doesn't matter because they don't have a byte transfer enabled at nanocode, such as MOVEQ - - wire xIsScc = (ird[7:6] == 2'b11) & (ird[5:3] != 3'b001); - wire xStaticMem = (ird[11:8] == 4'b1000) & (ird[5:4] == 2'b00); // Static bit to mem - always_comb begin - unique case( 1'b1) - lineOnehot[0]: - Irdecod.isByte = - ( ird[8] & (ird[5:4] != 2'b00) ) | // Dynamic bit to mem - ( (ird[11:8] == 4'b1000) & (ird[5:4] != 2'b00) ) | // Static bit to mem - ( (ird[8:7] == 2'b10) & (ird[5:3] == 3'b001) ) | // Movep from mem only! For byte mux - ( (ird[8:6] == 3'b000) & !xStaticMem ); // Immediate byte - - lineOnehot[1]: Irdecod.isByte = 1'b1; // MOVE.B - - - lineOnehot[4]: Irdecod.isByte = (ird[7:6] == 2'b00) | Irdecod.isTas; - lineOnehot[5]: Irdecod.isByte = (ird[7:6] == 2'b00) | xIsScc; - - lineOnehot[8], - lineOnehot[9], - lineOnehot['hb], - lineOnehot['hc], - lineOnehot['hd], - lineOnehot['he]: Irdecod.isByte = (ird[7:6] == 2'b00); - - default: Irdecod.isByte = 1'b0; - endcase - end - - // Need it for special byte size. Bus is byte, but whole register word is modified. - assign Irdecod.isMovep = lineOnehot[0] & ird[8] & eaAreg; - - - // rxIsSP implicit use of RX for actual SP transfer - // - // This logic is simple and will include some instructions that don't actually reference SP. - // But doesn't matter as long as they don't perform any RX transfer. - - always_comb begin - unique case( 1'b1) - lineOnehot[6]: Irdecod.implicitSp = (ird[11:8] == 4'b0001); // BSR - lineOnehot[4]: - // Misc like RTS, JSR, etc - Irdecod.implicitSp = (ird[11:8] == 4'b1110) | (ird[11:6] == 6'b1000_01); - default: Irdecod.implicitSp = 1'b0; - endcase - end - - // Modify CCR (and not SR) - // Probably overkill !! Only needs to distinguish SR vs CCR - // RTR, MOVE to CCR, xxxI to CCR - assign Irdecod.toCcr = ( lineOnehot[4] & ((ird[11:0] == 12'he77) | (ird[11:6] == 6'b010011)) ) | - ( lineOnehot[0] & (ird[8:6] == 3'b000)); - - // FTU constants - // This should not be latched on T3/T4. Latch on T2 or not at all. FTU needs it on next T3. - // Note: Reset instruction gets constant from ALU not from FTU! - logic [15:0] ftuConst; - wire [3:0] zero28 = (ird[11:9] == 0) ? 4'h8 : { 1'b0, ird[11:9]}; // xltate 0,1-7 into 8,1-7 - - always_comb begin - unique case( 1'b1) - lineOnehot[6], // Bcc short - lineOnehot[7]: ftuConst = { { 8{ ird[ 7]}}, ird[ 7:0] }; // MOVEQ - - lineOnehot['h5], // addq/subq/static shift double check this - lineOnehot['he]: ftuConst = { 12'b0, zero28}; - - // MULU/MULS DIVU/DIVS - lineOnehot['h8], - lineOnehot['hc]: ftuConst = 16'h0f; - - lineOnehot[4]: ftuConst = 16'h80; // TAS - - default: ftuConst = '0; - endcase - end - assign Irdecod.ftuConst = ftuConst; - - // - // TRAP Vector # for group 2 exceptions - // - - always_comb begin - if( lineOnehot[4]) begin - case ( ird[6:5]) - 2'b00,2'b01: Irdecod.macroTvn = 6; // CHK - 2'b11: Irdecod.macroTvn = 7; // TRAPV - 2'b10: Irdecod.macroTvn = {2'b10, ird[3:0]}; // TRAP - endcase - end - else - Irdecod.macroTvn = 5; // Division by zero - end - - - wire eaAdir = (ird[ 5:3] == 3'b001); - wire size11 = ird[7] & ird[6]; - - // Opcodes variants that don't affect flags - // ADDA/SUBA ADDQ/SUBQ MOVEA - - assign Irdecod.inhibitCcr = - ( (lineOnehot[9] | lineOnehot['hd]) & size11) | // ADDA/SUBA - ( lineOnehot[5] & eaAdir) | // ADDQ/SUBQ to An (originally checks for line[4] as well !?) - ( (lineOnehot[2] | lineOnehot[3]) & ird[8:6] == 3'b001); // MOVEA - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/microToNanoAddr.sv b/common/CPU/68000/FX68k/microToNanoAddr.sv deleted file mode 100644 index 0113eb96..00000000 --- a/common/CPU/68000/FX68k/microToNanoAddr.sv +++ /dev/null @@ -1,157 +0,0 @@ -// Translate uaddr to nanoaddr -module microToNanoAddr( - input [UADDR_WIDTH-1:0] uAddr, - output [NADDR_WIDTH-1:0] orgAddr); - - wire [UADDR_WIDTH-1:2] baseAddr = uAddr[UADDR_WIDTH-1:2]; - logic [NADDR_WIDTH-1:2] orgBase; - assign orgAddr = { orgBase, uAddr[1:0]}; - - always @( baseAddr) - begin - // nano ROM (136 addresses) - case( baseAddr) - -'h00: orgBase = 7'h0 ; -'h01: orgBase = 7'h1 ; -'h02: orgBase = 7'h2 ; -'h03: orgBase = 7'h2 ; -'h08: orgBase = 7'h3 ; -'h09: orgBase = 7'h4 ; -'h0A: orgBase = 7'h5 ; -'h0B: orgBase = 7'h5 ; -'h10: orgBase = 7'h6 ; -'h11: orgBase = 7'h7 ; -'h12: orgBase = 7'h8 ; -'h13: orgBase = 7'h8 ; -'h18: orgBase = 7'h9 ; -'h19: orgBase = 7'hA ; -'h1A: orgBase = 7'hB ; -'h1B: orgBase = 7'hB ; -'h20: orgBase = 7'hC ; -'h21: orgBase = 7'hD ; -'h22: orgBase = 7'hE ; -'h23: orgBase = 7'hD ; -'h28: orgBase = 7'hF ; -'h29: orgBase = 7'h10 ; -'h2A: orgBase = 7'h11 ; -'h2B: orgBase = 7'h10 ; -'h30: orgBase = 7'h12 ; -'h31: orgBase = 7'h13 ; -'h32: orgBase = 7'h14 ; -'h33: orgBase = 7'h14 ; -'h38: orgBase = 7'h15 ; -'h39: orgBase = 7'h16 ; -'h3A: orgBase = 7'h17 ; -'h3B: orgBase = 7'h17 ; -'h40: orgBase = 7'h18 ; -'h41: orgBase = 7'h18 ; -'h42: orgBase = 7'h18 ; -'h43: orgBase = 7'h18 ; -'h44: orgBase = 7'h19 ; -'h45: orgBase = 7'h19 ; -'h46: orgBase = 7'h19 ; -'h47: orgBase = 7'h19 ; -'h48: orgBase = 7'h1A ; -'h49: orgBase = 7'h1A ; -'h4A: orgBase = 7'h1A ; -'h4B: orgBase = 7'h1A ; -'h4C: orgBase = 7'h1B ; -'h4D: orgBase = 7'h1B ; -'h4E: orgBase = 7'h1B ; -'h4F: orgBase = 7'h1B ; -'h54: orgBase = 7'h1C ; -'h55: orgBase = 7'h1D ; -'h56: orgBase = 7'h1E ; -'h57: orgBase = 7'h1F ; -'h5C: orgBase = 7'h20 ; -'h5D: orgBase = 7'h21 ; -'h5E: orgBase = 7'h22 ; -'h5F: orgBase = 7'h23 ; -'h70: orgBase = 7'h24 ; -'h71: orgBase = 7'h24 ; -'h72: orgBase = 7'h24 ; -'h73: orgBase = 7'h24 ; -'h74: orgBase = 7'h24 ; -'h75: orgBase = 7'h24 ; -'h76: orgBase = 7'h24 ; -'h77: orgBase = 7'h24 ; -'h78: orgBase = 7'h25 ; -'h79: orgBase = 7'h25 ; -'h7A: orgBase = 7'h25 ; -'h7B: orgBase = 7'h25 ; -'h7C: orgBase = 7'h25 ; -'h7D: orgBase = 7'h25 ; -'h7E: orgBase = 7'h25 ; -'h7F: orgBase = 7'h25 ; -'h84: orgBase = 7'h26 ; -'h85: orgBase = 7'h27 ; -'h86: orgBase = 7'h28 ; -'h87: orgBase = 7'h29 ; -'h8C: orgBase = 7'h2A ; -'h8D: orgBase = 7'h2B ; -'h8E: orgBase = 7'h2C ; -'h8F: orgBase = 7'h2D ; -'h94: orgBase = 7'h2E ; -'h95: orgBase = 7'h2F ; -'h96: orgBase = 7'h30 ; -'h97: orgBase = 7'h31 ; -'h9C: orgBase = 7'h32 ; -'h9D: orgBase = 7'h33 ; -'h9E: orgBase = 7'h34 ; -'h9F: orgBase = 7'h35 ; -'hA4: orgBase = 7'h36 ; -'hA5: orgBase = 7'h36 ; -'hA6: orgBase = 7'h37 ; -'hA7: orgBase = 7'h37 ; -'hAC: orgBase = 7'h38 ; -'hAD: orgBase = 7'h38 ; -'hAE: orgBase = 7'h39 ; -'hAF: orgBase = 7'h39 ; -'hB4: orgBase = 7'h3A ; -'hB5: orgBase = 7'h3A ; -'hB6: orgBase = 7'h3B ; -'hB7: orgBase = 7'h3B ; -'hBC: orgBase = 7'h3C ; -'hBD: orgBase = 7'h3C ; -'hBE: orgBase = 7'h3D ; -'hBF: orgBase = 7'h3D ; -'hC0: orgBase = 7'h3E ; -'hC1: orgBase = 7'h3F ; -'hC2: orgBase = 7'h40 ; -'hC3: orgBase = 7'h41 ; -'hC8: orgBase = 7'h42 ; -'hC9: orgBase = 7'h43 ; -'hCA: orgBase = 7'h44 ; -'hCB: orgBase = 7'h45 ; -'hD0: orgBase = 7'h46 ; -'hD1: orgBase = 7'h47 ; -'hD2: orgBase = 7'h48 ; -'hD3: orgBase = 7'h49 ; -'hD8: orgBase = 7'h4A ; -'hD9: orgBase = 7'h4B ; -'hDA: orgBase = 7'h4C ; -'hDB: orgBase = 7'h4D ; -'hE0: orgBase = 7'h4E ; -'hE1: orgBase = 7'h4E ; -'hE2: orgBase = 7'h4F ; -'hE3: orgBase = 7'h4F ; -'hE8: orgBase = 7'h50 ; -'hE9: orgBase = 7'h50 ; -'hEA: orgBase = 7'h51 ; -'hEB: orgBase = 7'h51 ; -'hF0: orgBase = 7'h52 ; -'hF1: orgBase = 7'h52 ; -'hF2: orgBase = 7'h52 ; -'hF3: orgBase = 7'h52 ; -'hF8: orgBase = 7'h53 ; -'hF9: orgBase = 7'h53 ; -'hFA: orgBase = 7'h53 ; -'hFB: orgBase = 7'h53 ; - - default: - orgBase = 'X; - endcase - end - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/nDecoder3.sv b/common/CPU/68000/FX68k/nDecoder3.sv deleted file mode 100644 index 8b6f9759..00000000 --- a/common/CPU/68000/FX68k/nDecoder3.sv +++ /dev/null @@ -1,274 +0,0 @@ -// Nanorom (plus) decoder for die nanocode -module nDecoder3( input s_clks Clks, input s_irdecod Irdecod, output s_nanod Nanod, - input enT2, enT4, - input [UROM_WIDTH-1:0] microLatch, - input [NANO_WIDTH-1:0] nanoLatch); - -localparam NANO_IR2IRD = 67; -localparam NANO_TOIRC = 66; -localparam NANO_ALU_COL = 63; // ALU operator column order is 63-64-65 ! -localparam NANO_ALU_FI = 61; // ALU finish-init 62-61 -localparam NANO_TODBIN = 60; -localparam NANO_ALUE = 57; // 57-59 shared with DCR control -localparam NANO_DCR = 57; // 57-59 shared with ALUE control -localparam NANO_DOBCTRL_1 = 56; // Input to control and permwrite -localparam NANO_LOWBYTE = 55; // Used by MOVEP -localparam NANO_HIGHBYTE = 54; -localparam NANO_DOBCTRL_0 = 53; // Input to control and permwrite -localparam NANO_ALU_DCTRL = 51; // 52-51 databus input mux control -localparam NANO_ALU_ACTRL = 50; // addrbus input mux control -localparam NANO_DBD2ALUB = 49; -localparam NANO_ABD2ALUB = 48; -localparam NANO_DBIN2DBD = 47; -localparam NANO_DBIN2ABD = 46; -localparam NANO_ALU2ABD = 45; -localparam NANO_ALU2DBD = 44; -localparam NANO_RZ = 43; -localparam NANO_BUSBYTE = 42; // If *both* this set and instruction is byte sized, then bus cycle is byte sized. -localparam NANO_PCLABL = 41; -localparam NANO_RXL_DBL = 40; // Switches RXL/RYL on DBL/ABL buses -localparam NANO_PCLDBL = 39; -localparam NANO_ABDHRECHARGE = 38; -localparam NANO_REG2ABL = 37; // register to ABL -localparam NANO_ABL2REG = 36; // ABL to register -localparam NANO_ABLABD = 35; -localparam NANO_DBLDBD = 34; -localparam NANO_DBL2REG = 33; // DBL to register -localparam NANO_REG2DBL = 32; // register to DBL -localparam NANO_ATLCTRL = 29; // 31-29 -localparam NANO_FTUCONTROL = 25; -localparam NANO_SSP = 24; -localparam NANO_RXH_DBH = 22; // Switches RXH/RYH on DBH/ABH buses -localparam NANO_AUOUT = 20; // 21-20 -localparam NANO_AUCLKEN = 19; -localparam NANO_AUCTRL = 16; // 18-16 -localparam NANO_DBLDBH = 15; -localparam NANO_ABLABH = 14; -localparam NANO_EXT_ABH = 13; -localparam NANO_EXT_DBH = 12; -localparam NANO_ATHCTRL = 9; // 11-9 -localparam NANO_REG2ABH = 8; // register to ABH -localparam NANO_ABH2REG = 7; // ABH to register -localparam NANO_REG2DBH = 6; // register to DBH -localparam NANO_DBH2REG = 5; // DBH to register -localparam NANO_AOBCTRL = 3; // 4-3 -localparam NANO_PCH = 0; // 1-0 PchDbh PchAbh -localparam NANO_NO_SP_ALGN = 0; // Same bits as above when both set - -localparam NANO_FTU_UPDTPEND = 1; // Also loads FTU constant according to IRD ! -localparam NANO_FTU_INIT_ST = 15; // Set S, clear T (but not TPEND) -localparam NANO_FTU_CLRTPEND = 14; -localparam NANO_FTU_TVN = 13; -localparam NANO_FTU_ABL2PREN = 12; // ABL => FTU & ABL => PREN. Both transfers enabled, but only one will be used depending on uroutine. -localparam NANO_FTU_SSW = 11; -localparam NANO_FTU_RSTPREN = 10; -localparam NANO_FTU_IRD = 9; -localparam NANO_FTU_2ABL = 8; -localparam NANO_FTU_RDSR = 7; -localparam NANO_FTU_INL = 6; -localparam NANO_FTU_PSWI = 5; // Read Int Mask into FTU -localparam NANO_FTU_DBL = 4; -localparam NANO_FTU_2SR = 2; -localparam NANO_FTU_CONST = 1; - - reg [3:0] ftuCtrl; - - logic [2:0] athCtrl, atlCtrl; - assign athCtrl = nanoLatch[ NANO_ATHCTRL+2: NANO_ATHCTRL]; - assign atlCtrl = nanoLatch[ NANO_ATLCTRL+2: NANO_ATLCTRL]; - wire [1:0] aobCtrl = nanoLatch[ NANO_AOBCTRL+1:NANO_AOBCTRL]; - wire [1:0] dobCtrl = {nanoLatch[ NANO_DOBCTRL_1], nanoLatch[NANO_DOBCTRL_0]}; - - always_ff @( posedge Clks.clk) begin - if( enT4) begin - // Reverse order! - ftuCtrl <= { nanoLatch[ NANO_FTUCONTROL+0], nanoLatch[ NANO_FTUCONTROL+1], nanoLatch[ NANO_FTUCONTROL+2], nanoLatch[ NANO_FTUCONTROL+3]} ; - - Nanod.auClkEn <= !nanoLatch[ NANO_AUCLKEN]; - Nanod.auCntrl <= nanoLatch[ NANO_AUCTRL+2 : NANO_AUCTRL+0]; - Nanod.noSpAlign <= (nanoLatch[ NANO_NO_SP_ALGN + 1:NANO_NO_SP_ALGN] == 2'b11); - Nanod.extDbh <= nanoLatch[ NANO_EXT_DBH]; - Nanod.extAbh <= nanoLatch[ NANO_EXT_ABH]; - Nanod.todbin <= nanoLatch[ NANO_TODBIN]; - Nanod.toIrc <= nanoLatch[ NANO_TOIRC]; - - // ablAbd is disabled on byte transfers (adbhCharge plus irdIsByte). Not sure the combination makes much sense. - // It happens in a few cases but I don't see anything enabled on abL (or abH) section anyway. - - Nanod.ablAbd <= nanoLatch[ NANO_ABLABD]; - Nanod.ablAbh <= nanoLatch[ NANO_ABLABH]; - Nanod.dblDbd <= nanoLatch[ NANO_DBLDBD]; - Nanod.dblDbh <= nanoLatch[ NANO_DBLDBH]; - - Nanod.dbl2Atl <= (atlCtrl == 3'b010); - Nanod.atl2Dbl <= (atlCtrl == 3'b011); - Nanod.abl2Atl <= (atlCtrl == 3'b100); - Nanod.atl2Abl <= (atlCtrl == 3'b101); - - Nanod.aob2Ab <= (athCtrl == 3'b101); // Used on BSER1 only - - Nanod.abh2Ath <= (athCtrl == 3'b001) | (athCtrl == 3'b101); - Nanod.dbh2Ath <= (athCtrl == 3'b100); - Nanod.ath2Dbh <= (athCtrl == 3'b110); - Nanod.ath2Abh <= (athCtrl == 3'b011); - - Nanod.alu2Dbd <= nanoLatch[ NANO_ALU2DBD]; - Nanod.alu2Abd <= nanoLatch[ NANO_ALU2ABD]; - - Nanod.abd2Dcr <= (nanoLatch[ NANO_DCR+1:NANO_DCR] == 2'b11); - Nanod.dcr2Dbd <= (nanoLatch[ NANO_DCR+2:NANO_DCR+1] == 2'b11); - Nanod.dbd2Alue <= (nanoLatch[ NANO_ALUE+2:NANO_ALUE+1] == 2'b10); - Nanod.alue2Dbd <= (nanoLatch[ NANO_ALUE+1:NANO_ALUE] == 2'b01); - - Nanod.dbd2Alub <= nanoLatch[ NANO_DBD2ALUB]; - Nanod.abd2Alub <= nanoLatch[ NANO_ABD2ALUB]; - - // Originally not latched. We better should because we transfer one cycle later, T3 instead of T1. - Nanod.dobCtrl <= dobCtrl; - // Nanod.adb2Dob <= (dobCtrl == 2'b10); Nanod.dbd2Dob <= (dobCtrl == 2'b01); Nanod.alu2Dob <= (dobCtrl == 2'b11); - - end - end - - // Update SSW at the start of Bus/Addr error ucode - assign Nanod.updSsw = Nanod.aob2Ab; - - assign Nanod.updTpend = (ftuCtrl == NANO_FTU_UPDTPEND); - assign Nanod.clrTpend = (ftuCtrl == NANO_FTU_CLRTPEND); - assign Nanod.tvn2Ftu = (ftuCtrl == NANO_FTU_TVN); - assign Nanod.const2Ftu = (ftuCtrl == NANO_FTU_CONST); - assign Nanod.ftu2Dbl = (ftuCtrl == NANO_FTU_DBL) | ( ftuCtrl == NANO_FTU_INL); - assign Nanod.ftu2Abl = (ftuCtrl == NANO_FTU_2ABL); - assign Nanod.inl2psw = (ftuCtrl == NANO_FTU_INL); - assign Nanod.pswIToFtu = (ftuCtrl == NANO_FTU_PSWI); - assign Nanod.ftu2Sr = (ftuCtrl == NANO_FTU_2SR); - assign Nanod.sr2Ftu = (ftuCtrl == NANO_FTU_RDSR); - assign Nanod.ird2Ftu = (ftuCtrl == NANO_FTU_IRD); // Used on bus/addr error - assign Nanod.ssw2Ftu = (ftuCtrl == NANO_FTU_SSW); - assign Nanod.initST = (ftuCtrl == NANO_FTU_INL) | (ftuCtrl == NANO_FTU_CLRTPEND) | (ftuCtrl == NANO_FTU_INIT_ST); - assign Nanod.abl2Pren = (ftuCtrl == NANO_FTU_ABL2PREN); - assign Nanod.updPren = (ftuCtrl == NANO_FTU_RSTPREN); - - assign Nanod.Ir2Ird = nanoLatch[ NANO_IR2IRD]; - - // ALU control better latched later after combining with IRD decoding - - assign Nanod.aluDctrl = nanoLatch[ NANO_ALU_DCTRL+1 : NANO_ALU_DCTRL]; - assign Nanod.aluActrl = nanoLatch[ NANO_ALU_ACTRL]; - assign Nanod.aluColumn = { nanoLatch[ NANO_ALU_COL], nanoLatch[ NANO_ALU_COL+1], nanoLatch[ NANO_ALU_COL+2]}; - wire [1:0] aluFinInit = nanoLatch[ NANO_ALU_FI+1:NANO_ALU_FI]; - assign Nanod.aluFinish = (aluFinInit == 2'b10); - assign Nanod.aluInit = (aluFinInit == 2'b01); - - // FTU 2 CCR encoded as both ALU Init and ALU Finish set. - // In theory this encoding allows writes to CCR without writing to SR - // But FTU 2 CCR and to SR are both set together at nanorom. - assign Nanod.ftu2Ccr = ( aluFinInit == 2'b11); - - assign Nanod.abdIsByte = nanoLatch[ NANO_ABDHRECHARGE]; - - // Not being latched on T4 creates non unique case warning! - assign Nanod.au2Db = (nanoLatch[ NANO_AUOUT + 1: NANO_AUOUT] == 2'b01); - assign Nanod.au2Ab = (nanoLatch[ NANO_AUOUT + 1: NANO_AUOUT] == 2'b10); - assign Nanod.au2Pc = (nanoLatch[ NANO_AUOUT + 1: NANO_AUOUT] == 2'b11); - - assign Nanod.db2Aob = (aobCtrl == 2'b10); - assign Nanod.ab2Aob = (aobCtrl == 2'b01); - assign Nanod.au2Aob = (aobCtrl == 2'b11); - - assign Nanod.dbin2Abd = nanoLatch[ NANO_DBIN2ABD]; - assign Nanod.dbin2Dbd = nanoLatch[ NANO_DBIN2DBD]; - - assign Nanod.permStart = (| aobCtrl); - assign Nanod.isWrite = ( | dobCtrl); - assign Nanod.waitBusFinish = nanoLatch[ NANO_TOIRC] | nanoLatch[ NANO_TODBIN] | Nanod.isWrite; - assign Nanod.busByte = nanoLatch[ NANO_BUSBYTE]; - - assign Nanod.noLowByte = nanoLatch[ NANO_LOWBYTE]; - assign Nanod.noHighByte = nanoLatch[ NANO_HIGHBYTE]; - - // Not registered. Register at T4 after combining - // Might be better to remove all those and combine here instead of at execution unit !! - assign Nanod.abl2reg = nanoLatch[ NANO_ABL2REG]; - assign Nanod.abh2reg = nanoLatch[ NANO_ABH2REG]; - assign Nanod.dbl2reg = nanoLatch[ NANO_DBL2REG]; - assign Nanod.dbh2reg = nanoLatch[ NANO_DBH2REG]; - assign Nanod.reg2dbl = nanoLatch[ NANO_REG2DBL]; - assign Nanod.reg2dbh = nanoLatch[ NANO_REG2DBH]; - assign Nanod.reg2abl = nanoLatch[ NANO_REG2ABL]; - assign Nanod.reg2abh = nanoLatch[ NANO_REG2ABH]; - - assign Nanod.ssp = nanoLatch[ NANO_SSP]; - - assign Nanod.rz = nanoLatch[ NANO_RZ]; - - // Actually DTL can't happen on PC relative mode. See IR decoder. - - wire dtldbd = 1'b0; - wire dthdbh = 1'b0; - wire dtlabd = 1'b0; - wire dthabh = 1'b0; - - wire dblSpecial = Nanod.pcldbl | dtldbd; - wire dbhSpecial = Nanod.pchdbh | dthdbh; - wire ablSpecial = Nanod.pclabl | dtlabd; - wire abhSpecial = Nanod.pchabh | dthabh; - - // - // Combine with IRD decoding - // Careful that IRD is updated only on T1! All output depending on IRD must be latched on T4! - // - - // PC used instead of RY on PC relative instuctions - - assign Nanod.rxlDbl = nanoLatch[ NANO_RXL_DBL]; - wire isPcRel = Irdecod.isPcRel & !Nanod.rz; - wire pcRelDbl = isPcRel & !nanoLatch[ NANO_RXL_DBL]; - wire pcRelDbh = isPcRel & !nanoLatch[ NANO_RXH_DBH]; - wire pcRelAbl = isPcRel & nanoLatch[ NANO_RXL_DBL]; - wire pcRelAbh = isPcRel & nanoLatch[ NANO_RXH_DBH]; - - assign Nanod.pcldbl = nanoLatch[ NANO_PCLDBL] | pcRelDbl; - assign Nanod.pchdbh = (nanoLatch[ NANO_PCH+1:NANO_PCH] == 2'b01) | pcRelDbh; - - assign Nanod.pclabl = nanoLatch[ NANO_PCLABL] | pcRelAbl; - assign Nanod.pchabh = (nanoLatch[ NANO_PCH+1:NANO_PCH] == 2'b10) | pcRelAbh; - - // Might be better not to register these signals to allow latching RX/RY mux earlier! - // But then must latch Irdecod.isPcRel on T3! - - always_ff @( posedge Clks.clk) begin - if( enT4) begin - Nanod.rxl2db <= Nanod.reg2dbl & !dblSpecial & nanoLatch[ NANO_RXL_DBL]; - Nanod.rxl2ab <= Nanod.reg2abl & !ablSpecial & !nanoLatch[ NANO_RXL_DBL]; - - Nanod.dbl2rxl <= Nanod.dbl2reg & !dblSpecial & nanoLatch[ NANO_RXL_DBL]; - Nanod.abl2rxl <= Nanod.abl2reg & !ablSpecial & !nanoLatch[ NANO_RXL_DBL]; - - Nanod.rxh2dbh <= Nanod.reg2dbh & !dbhSpecial & nanoLatch[ NANO_RXH_DBH]; - Nanod.rxh2abh <= Nanod.reg2abh & !abhSpecial & !nanoLatch[ NANO_RXH_DBH]; - - Nanod.dbh2rxh <= Nanod.dbh2reg & !dbhSpecial & nanoLatch[ NANO_RXH_DBH]; - Nanod.abh2rxh <= Nanod.abh2reg & !abhSpecial & !nanoLatch[ NANO_RXH_DBH]; - - Nanod.dbh2ryh <= Nanod.dbh2reg & !dbhSpecial & !nanoLatch[ NANO_RXH_DBH]; - Nanod.abh2ryh <= Nanod.abh2reg & !abhSpecial & nanoLatch[ NANO_RXH_DBH]; - - Nanod.dbl2ryl <= Nanod.dbl2reg & !dblSpecial & !nanoLatch[ NANO_RXL_DBL]; - Nanod.abl2ryl <= Nanod.abl2reg & !ablSpecial & nanoLatch[ NANO_RXL_DBL]; - - Nanod.ryl2db <= Nanod.reg2dbl & !dblSpecial & !nanoLatch[ NANO_RXL_DBL]; - Nanod.ryl2ab <= Nanod.reg2abl & !ablSpecial & nanoLatch[ NANO_RXL_DBL]; - - Nanod.ryh2dbh <= Nanod.reg2dbh & !dbhSpecial & !nanoLatch[ NANO_RXH_DBH]; - Nanod.ryh2abh <= Nanod.reg2abh & !abhSpecial & nanoLatch[ NANO_RXH_DBH]; - end - - // Originally isTas only delayed on T2 (and seems only a late mask rev fix) - // Better latch the combination on T4 - if( enT4) - Nanod.isRmc <= Irdecod.isTas & nanoLatch[ NANO_BUSBYTE]; - end - - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/onehotEncoder4.sv b/common/CPU/68000/FX68k/onehotEncoder4.sv deleted file mode 100644 index c7771b41..00000000 --- a/common/CPU/68000/FX68k/onehotEncoder4.sv +++ /dev/null @@ -1,23 +0,0 @@ -// bin to one-hot, 4 bits to 16-bit bitmap -module onehotEncoder4( input [3:0] bin, output reg [15:0] bitMap); - always_comb begin - case( bin) - 'b0000: bitMap = 16'h0001; - 'b0001: bitMap = 16'h0002; - 'b0010: bitMap = 16'h0004; - 'b0011: bitMap = 16'h0008; - 'b0100: bitMap = 16'h0010; - 'b0101: bitMap = 16'h0020; - 'b0110: bitMap = 16'h0040; - 'b0111: bitMap = 16'h0080; - 'b1000: bitMap = 16'h0100; - 'b1001: bitMap = 16'h0200; - 'b1010: bitMap = 16'h0400; - 'b1011: bitMap = 16'h0800; - 'b1100: bitMap = 16'h1000; - 'b1101: bitMap = 16'h2000; - 'b1110: bitMap = 16'h4000; - 'b1111: bitMap = 16'h8000; - endcase - end -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/pren.sv b/common/CPU/68000/FX68k/pren.sv deleted file mode 100644 index ff46c068..00000000 --- a/common/CPU/68000/FX68k/pren.sv +++ /dev/null @@ -1,25 +0,0 @@ -// priority encoder -// used by MOVEM regmask -// this might benefit from device specific features -// MOVEM doesn't need speed, will read the result 2 CPU cycles after each update. -module pren( mask, hbit); - parameter size = 16; - parameter outbits = 4; - - input [size-1:0] mask; - output reg [outbits-1:0] hbit; - // output reg idle; - - always @( mask) begin - integer i; - hbit = 0; - // idle = 1; - for( i = size-1; i >= 0; i = i - 1) begin - if( mask[ i]) begin - hbit = i; - // idle = 0; - end - end - end - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/rowDecoder.sv b/common/CPU/68000/FX68k/rowDecoder.sv deleted file mode 100644 index 8fa9c038..00000000 --- a/common/CPU/68000/FX68k/rowDecoder.sv +++ /dev/null @@ -1,139 +0,0 @@ -// Decodes IRD into ALU row (1-15) -// Slow, but no need to optimize for speed since IRD is latched at least two CPU cycles before it is used -// We also register the result after combining with column from nanocode -// -// Many opcodes are not decoded because they either don't do any ALU op, -// or use only columns 1 and 5 that are the same for all rows. - -module rowDecoder( input [15:0] ird, - output logic [15:0] row, output noCcrEn, output logic isArX); - - - // Addr or data register direct - wire eaRdir = (ird[ 5:4] == 2'b00); - // Addr register direct - wire eaAdir = (ird[ 5:3] == 3'b001); - wire size11 = ird[7] & ird[6]; - - always_comb begin - case( ird[15:12]) - 'h4, - 'h9, - 'hd: - isArX = row[10] | row[12]; - default: - isArX = 1'b0; - endcase - end - - always_comb begin - unique case( ird[15:12]) - - 'h4: begin - if( ird[8]) - row = `ALU_ROW_06; // chk (or lea) - else case( ird[11:9]) - 'b000: row = `ALU_ROW_10; // negx - 'b001: row = `ALU_ROW_04; // clr - 'b010: row = `ALU_ROW_05; // neg - 'b011: row = `ALU_ROW_11; // not - 'b100: row = (ird[7]) ? `ALU_ROW_08 : `ALU_ROW_09; // nbcd/swap/ext(or pea) - 'b101: row = `ALU_ROW_15; // tst & tas - default: row = 0; - endcase - end - - 'h0: begin - if( ird[8]) // dynamic bit - row = ird[7] ? `ALU_ROW_14 : `ALU_ROW_13; - else case( ird[ 11:9]) - 'b000: row = `ALU_ROW_14; // ori - 'b001: row = `ALU_ROW_04; // andi - 'b010: row = `ALU_ROW_05; // subi - 'b011: row = `ALU_ROW_02; // addi - 'b100: row = ird[7] ? `ALU_ROW_14 : `ALU_ROW_13; // static bit - 'b101: row = `ALU_ROW_13; // eori - 'b110: row = `ALU_ROW_06; // cmpi - default: row = 0; - endcase - end - - // MOVE - // move.b originally also rows 5 & 15. Only because IRD bit 14 is not decoded. - // It's the same for move the operations performed by MOVE.B - - 'h1,'h2,'h3: row = `ALU_ROW_02; - - 'h5: - if( size11) - row = `ALU_ROW_15; // As originally and easier to decode - else - row = ird[8] ? `ALU_ROW_05 : `ALU_ROW_02; // addq/subq - 'h6: row = 0; //bcc/bra/bsr - 'h7: row = `ALU_ROW_02; // moveq - 'h8: - if( size11) // div - row = `ALU_ROW_01; - else if( ird[8] & eaRdir) // sbcd - row = `ALU_ROW_09; - else - row = `ALU_ROW_14; // or - 'h9: - if( ird[8] & ~size11 & eaRdir) - row = `ALU_ROW_10; // subx - else - row = `ALU_ROW_05; // sub/suba - 'hb: - if( ird[8] & ~size11 & ~eaAdir) - row = `ALU_ROW_13; // eor - else - row = `ALU_ROW_06; // cmp/cmpa/cmpm - 'hc: - if( size11) - row = `ALU_ROW_07; // mul - else if( ird[8] & eaRdir) // abcd - row = `ALU_ROW_03; - else - row = `ALU_ROW_04; // and - 'hd: - if( ird[8] & ~size11 & eaRdir) - row = `ALU_ROW_12; // addx - else - row = `ALU_ROW_02; // add/adda - 'he: - begin - reg [1:0] stype; - - if( size11) // memory shift/rotate - stype = ird[ 10:9]; - else // register shift/rotate - stype = ird[ 4:3]; - - case( {stype, ird[8]}) - 0: row = `ALU_ROW_02; // ASR - 1: row = `ALU_ROW_03; // ASL - 2: row = `ALU_ROW_05; // LSR - 3: row = `ALU_ROW_04; // LSL - 4: row = `ALU_ROW_08; // ROXR - 5: row = `ALU_ROW_11; // ROXL - 6: row = `ALU_ROW_10; // ROR - 7: row = `ALU_ROW_09; // ROL - endcase - end - - default: row = 0; - endcase - end - - // Decode opcodes that don't affect flags - // ADDA/SUBA ADDQ/SUBQ MOVEA - - assign noCcrEn = - // ADDA/SUBA - ( ird[15] & ~ird[13] & ird[12] & size11) | - // ADDQ/SUBQ to An - ( (ird[15:12] == 4'h5) & eaAdir) | - // MOVEA - ( (~ird[15] & ~ird[14] & ird[13]) & ird[8:6] == 3'b001); - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/sequencer.sv b/common/CPU/68000/FX68k/sequencer.sv deleted file mode 100644 index dade6edc..00000000 --- a/common/CPU/68000/FX68k/sequencer.sv +++ /dev/null @@ -1,237 +0,0 @@ -// Microcode sequencer - -module sequencer( input s_clks Clks, input enT3, - input [UROM_WIDTH-1:0] microLatch, - input A0Err, BerrA, busAddrErr, Spuria, Avia, - input Tpend, intPend, isIllegal, isPriv, excRst, isLineA, isLineF, - input [15:0] psw, - input prenEmpty, au05z, dcr4, ze, i11, - input [1:0] alue01, - input [15:0] Ird, - input [UADDR_WIDTH-1:0] a1, a2, a3, - output logic [3:0] tvn, - output logic [UADDR_WIDTH-1:0] nma); - - logic [UADDR_WIDTH-1:0] uNma; - logic [UADDR_WIDTH-1:0] grp1Nma; - logic [1:0] c0c1; - reg a0Rst; - wire A0Sel; - wire inGrp0Exc; - - // assign nma = Clks.extReset ? RSTP0_NMA : (A0Err ? BSER1_NMA : uNma); - // assign nma = A0Err ? (a0Rst ? RSTP0_NMA : BSER1_NMA) : uNma; - - // word type I: 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 - // NMA : .. .. 09 08 01 00 05 04 03 02 07 06 .. .. .. .. .. - - wire [UADDR_WIDTH-1:0] dbNma = { microLatch[ 14:13], microLatch[ 6:5], microLatch[ 10:7], microLatch[ 12:11]}; - - // Group 0 exception. - // Separated block from regular NMA. Otherwise simulation might depend on order of assigments. - always_comb begin - if( A0Err) begin - if( a0Rst) // Reset - nma = RSTP0_NMA; - else if( inGrp0Exc) // Double fault - nma = HALT1_NMA; - else // Bus or address error - nma = BSER1_NMA; - end - else - nma = uNma; - end - - always_comb begin - // Format II (conditional) or I (direct branch) - if( microLatch[1]) - uNma = { microLatch[ 14:13], c0c1, microLatch[ 10:7], microLatch[ 12:11]}; - else - case( microLatch[ 3:2]) - 0: uNma = dbNma; // DB - 1: uNma = A0Sel ? grp1Nma : a1; - 2: uNma = a2; - 3: uNma = a3; - endcase - end - - // Format II, conditional, NMA decoding - wire [1:0] enl = { Ird[6], prenEmpty}; // Updated on T3 - - wire [1:0] ms0 = { Ird[8], alue01[0]}; - wire [3:0] m01 = { au05z, Ird[8], alue01}; - wire [1:0] nz1 = { psw[ NF], psw[ ZF]}; - wire [1:0] nv = { psw[ NF], psw[ VF]}; - - logic ccTest; - wire [4:0] cbc = microLatch[ 6:2]; // CBC bits - - always_comb begin - unique case( cbc) - 'h0: c0c1 = {i11, i11}; // W/L offset EA, from IRC - - 'h1: c0c1 = (au05z) ? 2'b01 : 2'b11; // Updated on T3 - 'h11: c0c1 = (au05z) ? 2'b00 : 2'b11; - - 'h02: c0c1 = { 1'b0, ~psw[ CF]}; // C used in DIV - 'h12: c0c1 = { 1'b1, ~psw[ CF]}; - - 'h03: c0c1 = {psw[ ZF], psw[ ZF]}; // Z used in DIVU - - 'h04: // nz1, used in DIVS - case( nz1) - 'b00: c0c1 = 2'b10; - 'b10: c0c1 = 2'b01; - 'b01,'b11: c0c1 = 2'b11; - endcase - - 'h05: c0c1 = {psw[ NF], 1'b1}; // N used in CHK and DIV - 'h15: c0c1 = {1'b1, psw[ NF]}; - - // nz2, used in DIVS (same combination as nz1) - 'h06: c0c1 = { ~nz1[1] & ~nz1[0], 1'b1}; - - 'h07: // ms0 used in MUL - case( ms0) - 'b10, 'b00: c0c1 = 2'b11; - 'b01: c0c1 = 2'b01; - 'b11: c0c1 = 2'b10; - endcase - - 'h08: // m01 used in MUL - case( m01) - 'b0000,'b0001,'b0100,'b0111: c0c1 = 2'b11; - 'b0010,'b0011,'b0101: c0c1 = 2'b01; - 'b0110: c0c1 = 2'b10; - default: c0c1 = 2'b00; - endcase - - // Conditional - 'h09: c0c1 = (ccTest) ? 2'b11 : 2'b01; - 'h19: c0c1 = (ccTest) ? 2'b11 : 2'b10; - - // DCR bit 4 (high or low word) - 'h0c: c0c1 = dcr4 ? 2'b01: 2'b11; - 'h1c: c0c1 = dcr4 ? 2'b10: 2'b11; - - // DBcc done - 'h0a: c0c1 = ze ? 2'b11 : 2'b00; - - // nv, used in CHK - 'h0b: c0c1 = (nv == 2'b00) ? 2'b00 : 2'b11; - - // V, used in trapv - 'h0d: c0c1 = { ~psw[ VF], ~psw[VF]}; - - // enl, combination of pren idle and word/long on IRD - 'h0e,'h1e: - case( enl) - 2'b00: c0c1 = 'b10; - 2'b10: c0c1 = 'b11; - // 'hx1 result 00/01 depending on condition 0e/1e - 2'b01,2'b11: - c0c1 = { 1'b0, microLatch[ 6]}; - endcase - - default: c0c1 = 'X; - endcase - end - - // CCR conditional - always_comb begin - unique case( Ird[ 11:8]) - 'h0: ccTest = 1'b1; // T - 'h1: ccTest = 1'b0; // F - 'h2: ccTest = ~psw[ CF] & ~psw[ ZF]; // HI - 'h3: ccTest = psw[ CF] | psw[ZF]; // LS - 'h4: ccTest = ~psw[ CF]; // CC (HS) - 'h5: ccTest = psw[ CF]; // CS (LO) - 'h6: ccTest = ~psw[ ZF]; // NE - 'h7: ccTest = psw[ ZF]; // EQ - 'h8: ccTest = ~psw[ VF]; // VC - 'h9: ccTest = psw[ VF]; // VS - 'ha: ccTest = ~psw[ NF]; // PL - 'hb: ccTest = psw[ NF]; // MI - 'hc: ccTest = (psw[ NF] & psw[ VF]) | (~psw[ NF] & ~psw[ VF]); // GE - 'hd: ccTest = (psw[ NF] & ~psw[ VF]) | (~psw[ NF] & psw[ VF]); // LT - 'he: ccTest = (psw[ NF] & psw[ VF] & ~psw[ ZF]) | - (~psw[ NF] & ~psw[ VF] & ~psw[ ZF]); // GT - 'hf: ccTest = psw[ ZF] | (psw[ NF] & ~psw[VF]) | (~psw[ NF] & psw[VF]); // LE - endcase - end - - // Exception logic - logic rTrace, rInterrupt; - logic rIllegal, rPriv, rLineA, rLineF; - logic rExcRst, rExcAdrErr, rExcBusErr; - logic rSpurious, rAutovec; - wire grp1LatchEn, grp0LatchEn; - - // Originally control signals latched on T4. Then exception latches updated on T3 - assign grp1LatchEn = microLatch[0] & (microLatch[1] | !microLatch[4]); - assign grp0LatchEn = microLatch[4] & !microLatch[1]; - - assign inGrp0Exc = rExcRst | rExcBusErr | rExcAdrErr; - - always_ff @( posedge Clks.clk) begin - if( grp0LatchEn & enT3) begin - rExcRst <= excRst; - rExcBusErr <= BerrA; - rExcAdrErr <= busAddrErr; - rSpurious <= Spuria; - rAutovec <= Avia; - end - - // Update group 1 exception latches - // Inputs from IR decoder updated on T1 as soon as IR loaded - // Trace pending updated on T3 at the start of the instruction - // Interrupt pending on T2 - if( grp1LatchEn & enT3) begin - rTrace <= Tpend; - rInterrupt <= intPend; - rIllegal <= isIllegal & ~isLineA & ~isLineF; - rLineA <= isLineA; - rLineF <= isLineF; - rPriv <= isPriv & !psw[ SF]; - end - end - - // exception priority - always_comb begin - grp1Nma = TRAC1_NMA; - if( rExcRst) - tvn = '0; // Might need to change that to signal in exception - else if( rExcBusErr | rExcAdrErr) - tvn = { 1'b1, rExcAdrErr}; - - // Seudo group 0 exceptions. Just for updating TVN - else if( rSpurious | rAutovec) - tvn = rSpurious ? TVN_SPURIOUS : TVN_AUTOVEC; - - else if( rTrace) - tvn = 9; - else if( rInterrupt) begin - tvn = TVN_INTERRUPT; - grp1Nma = ITLX1_NMA; - end - else begin - unique case( 1'b1) // Can't happen more than one of these - rIllegal: tvn = 4; - rPriv: tvn = 8; - rLineA: tvn = 10; - rLineF: tvn = 11; - default: tvn = 1; // Signal no group 0/1 exception - endcase - end - end - - assign A0Sel = rIllegal | rLineF | rLineA | rPriv | rTrace | rInterrupt; - - always_ff @( posedge Clks.clk) begin - if( Clks.extReset) - a0Rst <= 1'b1; - else if( enT3) - a0Rst <= 1'b0; - end - -endmodule \ No newline at end of file diff --git a/common/CPU/68000/FX68k/uaddrDecode.sv b/common/CPU/68000/FX68k/uaddrDecode.sv deleted file mode 100644 index 3efdc011..00000000 --- a/common/CPU/68000/FX68k/uaddrDecode.sv +++ /dev/null @@ -1,91 +0,0 @@ -// Provides ucode routine entries (A1/A3) for each opcode -// Also checks for illegal opcode and priv violation - -// This is one of the slowest part of the processor. -// But no need to optimize or pipeline because the result is not needed until at least 4 cycles. -// IR updated at the least one microinstruction earlier. -// Just need to configure the timing analizer correctly. - -module uaddrDecode( - input [15:0] opcode, - output [UADDR_WIDTH-1:0] a1, a2, a3, - output logic isPriv, isIllegal, isLineA, isLineF, - output [15:0] lineBmap); - - wire [3:0] line = opcode[15:12]; - logic [3:0] eaCol, movEa; - - onehotEncoder4 irLineDecod( line, lineBmap); - - assign isLineA = lineBmap[ 'hA]; - assign isLineF = lineBmap[ 'hF]; - - pla_lined pla_lined( .movEa( movEa), .col( eaCol), - .opcode( opcode), .lineBmap( lineBmap), - .palIll( isIllegal), .plaA1( a1), .plaA2( a2), .plaA3( a3) ); - - // ea decoding - assign eaCol = eaDecode( opcode[ 5:0]); - assign movEa = eaDecode( {opcode[ 8:6], opcode[ 11:9]} ); - - // EA decode - function [3:0] eaDecode; - input [5:0] eaBits; - begin - unique case( eaBits[ 5:3]) - 3'b111: - case( eaBits[ 2:0]) - 3'b000: eaDecode = 7; // Absolute short - 3'b001: eaDecode = 8; // Absolute long - 3'b010: eaDecode = 9; // PC displacement - 3'b011: eaDecode = 10; // PC offset - 3'b100: eaDecode = 11; // Immediate - default: eaDecode = 12; // Invalid - endcase - - default: eaDecode = eaBits[5:3]; // Register based EAs - endcase - end - endfunction - - - /* - Privileged instructions: - - ANDI/EORI/ORI SR - MOVE to SR - MOVE to/from USP - RESET - RTE - STOP - */ - - always_comb begin - unique case( lineBmap) - - // ori/andi/eori SR - 'h01: isPriv = ((opcode & 16'hf5ff) == 16'h007c); - - 'h10: - begin - // No priority !!! - if( (opcode & 16'hffc0) == 16'h46c0) // move to sr - isPriv = 1'b1; - - else if( (opcode & 16'hfff0) == 16'h4e60) // move usp - isPriv = 1'b1; - - else if( opcode == 16'h4e70 || // reset - opcode == 16'h4e73 || // rte - opcode == 16'h4e72) // stop - isPriv = 1'b1; - else - isPriv = 1'b0; - end - - default: isPriv = 1'b0; - endcase - end - - -endmodule \ No newline at end of file