diff --git a/cores/plus_too/PlusToo.qpf b/cores/plus_too/PlusToo.qpf new file mode 100644 index 0000000..b5c18d4 --- /dev/null +++ b/cores/plus_too/PlusToo.qpf @@ -0,0 +1,30 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2011 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. +# +# -------------------------------------------------------------------------- # +# +# Quartus II +# Version 11.0 Build 157 04/27/2011 SJ Web Edition +# Date created = 10:34:40 September 15, 2011 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "11.0" +DATE = "10:34:40 September 15, 2011" + +# Revisions + +PROJECT_REVISION = "plusToo_top" diff --git a/cores/plus_too/TG68.vhd b/cores/plus_too/TG68.vhd new file mode 100644 index 0000000..1d25a53 --- /dev/null +++ b/cores/plus_too/TG68.vhd @@ -0,0 +1,225 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- -- +-- This is the TOP-Level for TG68_fast to generate 68K Bus signals -- +-- -- +-- Copyright (c) 2007-2008 Tobias Gubener -- +-- -- +-- This source file is free software: you can redistribute it and/or modify -- +-- it under the terms of the GNU Lesser General Public License as published -- +-- by the Free Software Foundation, either version 3 of the License, or -- +-- (at your option) any later version. -- +-- -- +-- This source file is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of -- +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- +-- GNU General Public License for more details. -- +-- -- +-- You should have received a copy of the GNU General Public License -- +-- along with this program. If not, see . -- +-- -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- +-- Revision 1.02 2008/01/23 +-- bugfix Timing +-- +-- Revision 1.01 2007/11/28 +-- add MOVEP +-- Bugfix Interrupt in MOVEQ +-- +-- Revision 1.0 2007/11/05 +-- Clean up code and first release +-- +-- known bugs/todo: +-- Add CHK INSTRUCTION +-- full decode ILLEGAL INSTRUCTIONS +-- Add FDC Output +-- add odd Address test +-- add TRACE +-- Movem with regmask==x0000 + + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity TG68 is + port( + clk : in std_logic; + reset : in std_logic; + clkena_in : in std_logic:='1'; + data_in : in std_logic_vector(15 downto 0); + IPL : in std_logic_vector(2 downto 0):="111"; + dtack : in std_logic; + addr : out std_logic_vector(31 downto 0); + data_out : out std_logic_vector(15 downto 0); + as : out std_logic; + uds : out std_logic; + lds : out std_logic; + rw : out std_logic; + drive_data : out std_logic --enable for data_out driver + ); +end TG68; + +ARCHITECTURE logic OF TG68 IS + + COMPONENT TG68_fast + PORT ( + clk : in std_logic; + reset : in std_logic; + clkena_in : in std_logic; + data_in : in std_logic_vector(15 downto 0); + IPL : in std_logic_vector(2 downto 0); + test_IPL : in std_logic; + address : out std_logic_vector(31 downto 0); + data_write : out std_logic_vector(15 downto 0); + state_out : out std_logic_vector(1 downto 0); + decodeOPC : buffer std_logic; + wr : out std_logic; + UDS, LDS : out std_logic + ); + END COMPONENT; + + + SIGNAL as_s : std_logic; + SIGNAL as_e : std_logic; + SIGNAL uds_s : std_logic; + SIGNAL uds_e : std_logic; + SIGNAL lds_s : std_logic; + SIGNAL lds_e : std_logic; + SIGNAL rw_s : std_logic; + SIGNAL rw_e : std_logic; + SIGNAL waitm : std_logic; + SIGNAL clkena_e : std_logic; + SIGNAL S_state : std_logic_vector(1 downto 0); + SIGNAL decode : std_logic; + SIGNAL wr : std_logic; + SIGNAL uds_in : std_logic; + SIGNAL lds_in : std_logic; + SIGNAL state : std_logic_vector(1 downto 0); + SIGNAL clkena : std_logic; + SIGNAL n_clk : std_logic; + SIGNAL cpuIPL : std_logic_vector(2 downto 0); + + +BEGIN + + n_clk <= NOT clk; + +TG68_fast_inst: TG68_fast + PORT MAP ( + clk => n_clk, -- : in std_logic; + reset => reset, -- : in std_logic; + clkena_in => clkena, -- : in std_logic; + data_in => data_in, -- : in std_logic_vector(15 downto 0); + IPL => cpuIPL, -- : in std_logic_vector(2 downto 0); + test_IPL => '0', -- : in std_logic; + address => addr, -- : out std_logic_vector(31 downto 0); + data_write => data_out, -- : out std_logic_vector(15 downto 0); + state_out => state, -- : out std_logic_vector(1 downto 0); + decodeOPC => decode, -- : buffer std_logic; + wr => wr, -- : out std_logic; + UDS => uds_in, -- : out std_logic; + LDS => lds_in -- : out std_logic; + ); + + --PROCESS (clk) + PROCESS (clk, clkena_in, clkena_e, state) + BEGIN + IF clkena_in='1' AND (clkena_e='1' OR state="01") THEN + clkena <= '1'; + ELSE + clkena <= '0'; + END IF; + END PROCESS; + +PROCESS (clk, reset, state, as_s, as_e, rw_s, rw_e, uds_s, uds_e, lds_s, lds_e) + BEGIN + IF state="01" THEN + as <= '1'; + rw <= '1'; + uds <= '1'; + lds <= '1'; + ELSE + as <= as_s AND as_e; + rw <= rw_s AND rw_e; + uds <= uds_s AND uds_e; + lds <= lds_s AND lds_e; + END IF; + IF reset='0' THEN + S_state <= "11"; + as_s <= '1'; + rw_s <= '1'; + uds_s <= '1'; + lds_s <= '1'; + ELSIF rising_edge(clk) THEN + IF clkena_in='1' THEN + as_s <= '1'; + rw_s <= '1'; + uds_s <= '1'; + lds_s <= '1'; + IF state/="01" OR decode='1' THEN + CASE S_state IS + WHEN "00" => as_s <= '0'; + rw_s <= wr; + IF wr='1' THEN + uds_s <= uds_in; + lds_s <= lds_in; + END IF; + S_state <= "01"; + WHEN "01" => as_s <= '0'; + rw_s <= wr; + uds_s <= uds_in; + lds_s <= lds_in; + S_state <= "10"; + WHEN "10" => + rw_s <= wr; + IF waitm='0' THEN + S_state <= "11"; + END IF; + WHEN "11" => + S_state <= "00"; + WHEN OTHERS => null; + END CASE; + END IF; + END IF; + END IF; + IF reset='0' THEN + as_e <= '1'; + rw_e <= '1'; + uds_e <= '1'; + lds_e <= '1'; + clkena_e <= '0'; + cpuIPL <= "111"; + drive_data <= '0'; + ELSIF falling_edge(clk) THEN + IF clkena_in='1' THEN + as_e <= '1'; + rw_e <= '1'; + uds_e <= '1'; + lds_e <= '1'; + clkena_e <= '0'; + drive_data <= '0'; + CASE S_state IS + WHEN "00" => null; + WHEN "01" => drive_data <= NOT wr; + WHEN "10" => as_e <= '0'; + uds_e <= uds_in; + lds_e <= lds_in; + cpuIPL <= IPL; + drive_data <= NOT wr; + IF state="01" THEN + clkena_e <= '1'; + waitm <= '0'; + ELSE + clkena_e <= NOT dtack; + waitm <= dtack; + END IF; + WHEN OTHERS => null; + END CASE; + END IF; + END IF; + END PROCESS; +END; \ No newline at end of file diff --git a/cores/plus_too/TG68_fast.vhd b/cores/plus_too/TG68_fast.vhd new file mode 100644 index 0000000..60cb486 --- /dev/null +++ b/cores/plus_too/TG68_fast.vhd @@ -0,0 +1,3257 @@ +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- -- +-- This is the 68000 software compatible Kernal of TG68 -- +-- -- +-- Copyright (c) 2007-2010 Tobias Gubener -- +-- -- +-- This source file is free software: you can redistribute it and/or modify -- +-- it under the terms of the GNU Lesser General Public License as published -- +-- by the Free Software Foundation, either version 3 of the License, or -- +-- (at your option) any later version. -- +-- -- +-- This source file is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of -- +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- +-- GNU General Public License for more details. -- +-- -- +-- You should have received a copy of the GNU General Public License -- +-- along with this program. If not, see . -- +-- -- +------------------------------------------------------------------------------ +------------------------------------------------------------------------------ +-- +-- Revision 1.08 2010/06/14 +-- Bugfix Movem with regmask==xFFFF +-- Add missing Illegal $4AFC +-- +-- Revision 1.07 2009/10/02 +-- Bugfix Movem with regmask==x0000 +-- +-- Revision 1.06 2009/02/10 +-- Bugfix shift and rotations opcodes when the bitcount and the data are in the same register: +-- Example lsr.l D2,D2 +-- Thanks to Peter Graf for report +-- +-- Revision 1.05 2009/01/26 +-- Implement missing RTR +-- Thanks to Peter Graf for report +-- +-- Revision 1.04 2007/12/29 +-- size improvement +-- change signal "microaddr" to one hot state machine +-- +-- Revision 1.03 2007/12/21 +-- Thanks to Andreas Ehliar +-- Split regfile to use blockram for registers +-- insert "WHEN OTHERS => null;" on END CASE; +-- +-- Revision 1.02 2007/12/17 +-- Bugfix jsr nn.w +-- +-- Revision 1.01 2007/11/28 +-- add MOVEP +-- Bugfix Interrupt in MOVEQ +-- +-- Revision 1.0 2007/11/05 +-- Clean up code and first release +-- +-- known bugs/todo: +-- Add CHK INSTRUCTION +-- full decode ILLEGAL INSTRUCTIONS +-- Add FC Output +-- add odd Address test +-- add TRACE + + +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.all; + +entity TG68_fast is + port(clk : in std_logic; + reset : in std_logic; --low active + clkena_in : in std_logic:='1'; + data_in : in std_logic_vector(15 downto 0); + IPL : in std_logic_vector(2 downto 0):="111"; + test_IPL : in std_logic:='0'; --only for debugging + address : out std_logic_vector(31 downto 0); + data_write : out std_logic_vector(15 downto 0); + state_out : out std_logic_vector(1 downto 0); + LDS, UDS : out std_logic; + decodeOPC : buffer std_logic; + wr : out std_logic + ); +end TG68_fast; + +architecture logic of TG68_fast is + + signal state : std_logic_vector(1 downto 0); + signal clkena : std_logic; + signal TG68_PC : std_logic_vector(31 downto 0); + signal TG68_PC_add : std_logic_vector(31 downto 0); + signal memaddr : std_logic_vector(31 downto 0); + signal memaddr_in : std_logic_vector(31 downto 0); + signal ea_data : std_logic_vector(31 downto 0); + signal ea_data_OP1 : std_logic; + signal setaddrlong : std_logic; + signal OP1out, OP2out : std_logic_vector(31 downto 0); + signal OP1outbrief : std_logic_vector(15 downto 0); + signal OP1in : std_logic_vector(31 downto 0); + signal data_write_tmp : std_logic_vector(31 downto 0); + signal Xtmp : std_logic_vector(31 downto 0); + signal PC_dataa, PC_datab, PC_result : std_logic_vector(31 downto 0); + signal setregstore : std_logic; + signal datatype : std_logic_vector(1 downto 0); + signal longread : std_logic; + signal longreaddirect : std_logic; + signal long_done : std_logic; + signal nextpass : std_logic; + signal setnextpass : std_logic; + signal setdispbyte : std_logic; + signal setdisp : std_logic; + signal setdispbrief : std_logic; + signal regdirectsource : std_logic; + signal endOPC : std_logic; + signal postadd : std_logic; + signal presub : std_logic; + signal addsub_a : std_logic_vector(31 downto 0); + signal addsub_b : std_logic_vector(31 downto 0); + signal addsub_q : std_logic_vector(31 downto 0); + signal briefext : std_logic_vector(31 downto 0); + signal setbriefext : std_logic; + signal addsub : std_logic; + signal c_in : std_logic_vector(3 downto 0); + signal c_out : std_logic_vector(2 downto 0); + signal add_result : std_logic_vector(33 downto 0); + signal addsub_ofl : std_logic_vector(2 downto 0); + signal flag_z : std_logic_vector(2 downto 0); + + signal last_data_read : std_logic_vector(15 downto 0); + signal data_read : std_logic_vector(31 downto 0); + + signal registerin : std_logic_vector(31 downto 0); + signal reg_QA : std_logic_vector(31 downto 0); + signal reg_QB : std_logic_vector(31 downto 0); + signal Hwrena,Lwrena : std_logic; + signal Regwrena : std_logic; + signal rf_dest_addr : std_logic_vector(6 downto 0); + signal rf_source_addr : std_logic_vector(6 downto 0); + signal rf_dest_addr_tmp : std_logic_vector(6 downto 0); + signal rf_source_addr_tmp : std_logic_vector(6 downto 0); + signal opcode : std_logic_vector(15 downto 0); + signal laststate : std_logic_vector(1 downto 0); + signal setstate : std_logic_vector(1 downto 0); + + signal mem_address : std_logic_vector(31 downto 0); + signal memaddr_a : std_logic_vector(31 downto 0); + signal mem_data_read : std_logic_vector(31 downto 0); + signal mem_data_write : std_logic_vector(31 downto 0); + signal set_mem_rega : std_logic; + signal data_read_ram : std_logic_vector(31 downto 0); + signal data_read_uart : std_logic_vector(7 downto 0); + + signal counter_reg : std_logic_vector(31 downto 0); + + signal TG68_PC_br8 : std_logic; + signal TG68_PC_brw : std_logic; + signal TG68_PC_nop : std_logic; + signal setgetbrief : std_logic; + signal getbrief : std_logic; + signal brief : std_logic_vector(15 downto 0); + signal dest_areg : std_logic; + signal source_areg : std_logic; + signal data_is_source : std_logic; + signal set_store_in_tmp : std_logic; + signal store_in_tmp : std_logic; + signal write_back : std_logic; + signal setaddsub : std_logic; + signal setstackaddr : std_logic; + signal writePC : std_logic; + signal writePC_add : std_logic; + signal set_TG68_PC_dec: std_logic; + signal TG68_PC_dec : std_logic_vector(1 downto 0); + signal directPC : std_logic; + signal set_directPC : std_logic; + signal execOPC : std_logic; + signal fetchOPC : std_logic; + signal Flags : std_logic_vector(15 downto 0); --T.S..III ...XNZVC + signal set_Flags : std_logic_vector(3 downto 0); --NZVC + signal exec_ADD : std_logic; + signal exec_OR : std_logic; + signal exec_AND : std_logic; + signal exec_EOR : std_logic; + signal exec_MOVE : std_logic; + signal exec_MOVEQ : std_logic; + signal exec_MOVESR : std_logic; + signal exec_DIRECT : std_logic; + signal exec_ADDQ : std_logic; + signal exec_CMP : std_logic; + signal exec_ROT : std_logic; + signal exec_exg : std_logic; + signal exec_swap : std_logic; + signal exec_write_back: std_logic; + signal exec_tas : std_logic; + signal exec_EXT : std_logic; + signal exec_ABCD : std_logic; + signal exec_SBCD : std_logic; + signal exec_MULU : std_logic; + signal exec_DIVU : std_logic; + signal exec_Scc : std_logic; + signal exec_CPMAW : std_logic; + signal set_exec_ADD : std_logic; + signal set_exec_OR : std_logic; + signal set_exec_AND : std_logic; + signal set_exec_EOR : std_logic; + signal set_exec_MOVE : std_logic; + signal set_exec_MOVEQ : std_logic; + signal set_exec_MOVESR: std_logic; + signal set_exec_ADDQ : std_logic; + signal set_exec_CMP : std_logic; + signal set_exec_ROT : std_logic; + signal set_exec_tas : std_logic; + signal set_exec_EXT : std_logic; + signal set_exec_ABCD : std_logic; + signal set_exec_SBCD : std_logic; + signal set_exec_MULU : std_logic; + signal set_exec_DIVU : std_logic; + signal set_exec_Scc : std_logic; + signal set_exec_CPMAW : std_logic; + + signal condition : std_logic; + signal OP2out_one : std_logic; + signal OP1out_zero : std_logic; + signal ea_to_pc : std_logic; + signal ea_build : std_logic; + signal ea_only : std_logic; + signal get_ea_now : std_logic; + signal source_lowbits : std_logic; + signal dest_hbits : std_logic; + signal rot_rot : std_logic; + signal rot_lsb : std_logic; + signal rot_msb : std_logic; + signal rot_XC : std_logic; + signal set_rot_nop : std_logic; + signal rot_nop : std_logic; + signal rot_out : std_logic_vector(31 downto 0); + signal rot_bits : std_logic_vector(1 downto 0); + signal rot_cnt : std_logic_vector(5 downto 0); + signal set_rot_cnt : std_logic_vector(5 downto 0); + signal movem_busy : std_logic; + signal set_movem_busy : std_logic; + signal movem_addr : std_logic; + signal movem_regaddr : std_logic_vector(3 downto 0); + signal movem_mask : std_logic_vector(15 downto 0); + signal set_get_movem_mask : std_logic; + signal get_movem_mask : std_logic; + signal maskzero : std_logic; + signal test_maskzero : std_logic; + signal movem_muxa : std_logic_vector(7 downto 0); + signal movem_muxb : std_logic_vector(3 downto 0); + signal movem_muxc : std_logic_vector(1 downto 0); + signal movem_presub : std_logic; + signal save_memaddr : std_logic; + signal movem_bits : std_logic_vector(4 downto 0); + signal ea_calc_b : std_logic_vector(31 downto 0); + signal set_mem_addsub : std_logic; + signal bit_bits : std_logic_vector(1 downto 0); + signal bit_number_reg : std_logic_vector(4 downto 0); + signal bit_number : std_logic_vector(4 downto 0); + signal exec_Bits : std_logic; + signal bits_out : std_logic_vector(31 downto 0); + signal one_bit_in : std_logic; + signal one_bit_out : std_logic; + signal set_get_bitnumber : std_logic; + signal get_bitnumber : std_logic; + signal mem_byte : std_logic; + signal wait_mem_byte : std_logic; + signal movepl : std_logic; + signal movepw : std_logic; + signal set_movepl : std_logic; + signal set_movepw : std_logic; + signal set_direct_data: std_logic; + signal use_direct_data: std_logic; + signal direct_data : std_logic; + signal set_get_extendedOPC : std_logic; + signal get_extendedOPC: std_logic; + signal setstate_delay : std_logic_vector(1 downto 0); + signal setstate_mux : std_logic_vector(1 downto 0); + signal use_XZFlag : std_logic; + signal use_XFlag : std_logic; + + signal dummy_a : std_logic_vector(8 downto 0); + signal niba_l : std_logic_vector(5 downto 0); + signal niba_h : std_logic_vector(5 downto 0); + signal niba_lc : std_logic; + signal niba_hc : std_logic; + signal bcda_lc : std_logic; + signal bcda_hc : std_logic; + signal dummy_s : std_logic_vector(8 downto 0); + signal nibs_l : std_logic_vector(5 downto 0); + signal nibs_h : std_logic_vector(5 downto 0); + signal nibs_lc : std_logic; + signal nibs_hc : std_logic; + signal dummy_mulu : std_logic_vector(31 downto 0); + signal dummy_div : std_logic_vector(31 downto 0); + signal dummy_div_sub : std_logic_vector(16 downto 0); + signal dummy_div_over : std_logic_vector(16 downto 0); + signal set_V_Flag : std_logic; + signal OP1sign : std_logic; + signal set_sign : std_logic; + signal sign : std_logic; + signal sign2 : std_logic; + signal muls_msb : std_logic; + signal mulu_reg : std_logic_vector(31 downto 0); + signal div_reg : std_logic_vector(31 downto 0); + signal div_sign : std_logic; + signal div_quot : std_logic_vector(31 downto 0); + signal div_ovl : std_logic; + signal pre_V_Flag : std_logic; + signal set_vectoraddr : std_logic; + signal writeSR : std_logic; + signal trap_illegal : std_logic; + signal trap_priv : std_logic; + signal trap_1010 : std_logic; + signal trap_1111 : std_logic; + signal trap_trap : std_logic; + signal trap_trapv : std_logic; + signal trap_interrupt : std_logic; + signal trapmake : std_logic; + signal trapd : std_logic; +-- signal trap_PC : std_logic_vector(31 downto 0); + signal trap_SR : std_logic_vector(15 downto 0); + + signal set_directSR : std_logic; + signal directSR : std_logic; + signal set_directCCR : std_logic; + signal directCCR : std_logic; + signal set_stop : std_logic; + signal stop : std_logic; + signal trap_vector : std_logic_vector(31 downto 0); + signal to_USP : std_logic; + signal from_USP : std_logic; + signal to_SR : std_logic; + signal from_SR : std_logic; + signal illegal_write_mode : std_logic; + signal illegal_read_mode : std_logic; + signal illegal_byteaddr : std_logic; + signal use_SP : std_logic; + + signal no_Flags : std_logic; + signal IPL_nr : std_logic_vector(2 downto 0); + signal rIPL_nr : std_logic_vector(2 downto 0); + signal interrupt : std_logic; + signal SVmode : std_logic; + signal trap_chk : std_logic; + signal test_delay : std_logic_vector(2 downto 0); + signal set_PCmarker : std_logic; + signal PCmarker : std_logic; + signal set_Z_error : std_logic; + signal Z_error : std_logic; + + type micro_states is (idle, nop, ld_nn, st_nn, ld_dAn1, ld_dAn2, ld_AnXn1, ld_AnXn2, ld_AnXn3, st_dAn1, st_dAn2, + st_AnXn1, st_AnXn2, st_AnXn3, bra1, bra2, bsr1, bsr2, dbcc1, dbcc2, + movem, andi, op_AxAy, cmpm, link, int1, int2, int3, int4, rte, trap1, trap2, trap3, + movep1, movep2, movep3, movep4, movep5, init1, init2, + mul1, mul2, mul3, mul4, mul5, mul6, mul7, mul8, mul9, mul10, mul11, mul12, mul13, mul14, mul15, + div1, div2, div3, div4, div5, div6, div7, div8, div9, div10, div11, div12, div13, div14, div15 ); + signal micro_state : micro_states; + signal next_micro_state : micro_states; + + type regfile_t is array(0 to 16) of std_logic_vector(15 downto 0); + signal regfile_low : regfile_t; + signal regfile_high : regfile_t; + signal RWindex_A : integer range 0 to 16; + signal RWindex_B : integer range 0 to 16; + + +BEGIN + +----------------------------------------------------------------------------- +-- Registerfile +----------------------------------------------------------------------------- + + RWindex_A <= conv_integer(rf_dest_addr(4)&(rf_dest_addr(3 downto 0) XOR "1111")); + RWindex_B <= conv_integer(rf_source_addr(4)&(rf_source_addr(3 downto 0) XOR "1111")); + + PROCESS (clk) + BEGIN + IF falling_edge(clk) THEN + IF clkena='1' THEN + reg_QA <= regfile_high(RWindex_A) & regfile_low(RWindex_A); + reg_QB <= regfile_high(RWindex_B) & regfile_low(RWindex_B); + END IF; + END IF; + IF rising_edge(clk) THEN + IF clkena='1' THEN + IF Lwrena='1' THEN + regfile_low(RWindex_A) <= registerin(15 downto 0); + END IF; + IF Hwrena='1' THEN + regfile_high(RWindex_A) <= registerin(31 downto 16); + END IF; + END IF; + END IF; + END PROCESS; + + + + address <= TG68_PC when state="00" else X"ffffffff" when state="01" else memaddr; + LDS <= '0' WHEN (datatype/="00" OR state="00" OR memaddr(0)='1') AND state/="01" ELSE '1'; + UDS <= '0' WHEN (datatype/="00" OR state="00" OR memaddr(0)='0') AND state/="01" ELSE '1'; + state_out <= state; + wr <= '0' WHEN state="11" ELSE '1'; + IPL_nr <= NOT IPL; + + +----------------------------------------------------------------------------- +-- "ALU" +----------------------------------------------------------------------------- +PROCESS (addsub_a, addsub_b, addsub, add_result, c_in) + BEGIN + IF addsub='1' THEN --ADD + add_result <= (('0'&addsub_a&c_in(0))+('0'&addsub_b&c_in(0))); + ELSE --SUB + add_result <= (('0'&addsub_a&'0')-('0'&addsub_b&c_in(0))); + END IF; + addsub_q <= add_result(32 downto 1); + c_in(1) <= add_result(9) XOR addsub_a(8) XOR addsub_b(8); + c_in(2) <= add_result(17) XOR addsub_a(16) XOR addsub_b(16); + c_in(3) <= add_result(33); + addsub_ofl(0) <= (c_in(1) XOR add_result(8) XOR addsub_a(7) XOR addsub_b(7)); --V Byte + addsub_ofl(1) <= (c_in(2) XOR add_result(16) XOR addsub_a(15) XOR addsub_b(15)); --V Word + addsub_ofl(2) <= (c_in(3) XOR add_result(32) XOR addsub_a(31) XOR addsub_b(31)); --V Long + c_out <= c_in(3 downto 1); +END PROCESS; + +----------------------------------------------------------------------------- +-- MEM_IO +----------------------------------------------------------------------------- +PROCESS (clk, reset, clkena_in, opcode, rIPL_nr, longread, get_extendedOPC, memaddr, memaddr_a, set_mem_addsub, movem_presub, + movem_busy, state, PCmarker, execOPC, datatype, setdisp, setdispbrief, briefext, setdispbyte, brief, + set_mem_rega, reg_QA, setaddrlong, data_read, decodeOPC, TG68_PC, data_in, long_done, last_data_read, mem_byte, + data_write_tmp, addsub_q, set_vectoraddr, trap_vector, interrupt) + BEGIN + clkena <= clkena_in AND NOT longread AND NOT get_extendedOPC; + + IF rising_edge(clk) THEN + IF clkena='1' THEN + trap_vector(31 downto 8) <= (others => '0'); + -- IF trap_addr_fault='1' THEN + -- trap_vector(7 downto 0) <= X"08"; + -- END IF; + -- IF trap_addr_error='1' THEN + -- trap_vector(7 downto 0) <= X"0C"; + -- END IF; + IF trap_illegal='1' THEN + trap_vector(7 downto 0) <= X"10"; + END IF; + IF z_error='1' THEN + trap_vector(7 downto 0) <= X"14"; + END IF; +-- IF trap_chk='1' THEN +-- trap_vector(7 downto 0) <= X"18"; +-- END IF; + IF trap_trapv='1' THEN + trap_vector(7 downto 0) <= X"1C"; + END IF; + IF trap_priv='1' THEN + trap_vector(7 downto 0) <= X"20"; + END IF; + -- IF trap_trace='1' THEN + -- trap_vector(7 downto 0) <= X"24"; + -- END IF; + IF trap_1010='1' THEN + trap_vector(7 downto 0) <= X"28"; + END IF; + IF trap_1111='1' THEN + trap_vector(7 downto 0) <= X"2C"; + END IF; + IF trap_trap='1' THEN + trap_vector(7 downto 2) <= "10"&opcode(3 downto 0); + END IF; + IF interrupt='1' THEN + trap_vector(7 downto 2) <= "011"&rIPL_nr; + END IF; + END IF; + END IF; + + memaddr_a(3 downto 0) <= "0000"; + memaddr_a(7 downto 4) <= (OTHERS=>memaddr_a(3)); + memaddr_a(15 downto 8) <= (OTHERS=>memaddr_a(7)); + memaddr_a(31 downto 16) <= (OTHERS=>memaddr_a(15)); + IF movem_presub='1' THEN + IF movem_busy='1' OR longread='1' THEN + memaddr_a(3 downto 0) <= "1110"; + END IF; + ELSIF state(1)='1' OR (get_extendedOPC='1' AND PCmarker='1') THEN + memaddr_a(1) <= '1'; + ELSIF execOPC='1' THEN + IF datatype="10" THEN + memaddr_a(3 downto 0) <= "1100"; + ELSE + memaddr_a(3 downto 0) <= "1110"; + END IF; + ELSIF setdisp='1' THEN + IF setdispbrief='1' THEN + memaddr_a <= briefext; + ELSIF setdispbyte='1' THEN + memaddr_a(7 downto 0) <= brief(7 downto 0); + ELSE + memaddr_a(15 downto 0) <= brief; + END IF; + END IF; + + memaddr_in <= memaddr+memaddr_a; + IF longread='0' THEN + IF set_mem_addsub='1' THEN + memaddr_in <= addsub_q; + ELSIF set_vectoraddr='1' THEN + memaddr_in <= trap_vector; + ELSIF interrupt='1' THEN + memaddr_in <= "1111111111111111111111111111"&rIPL_nr&'0'; + ELSIF set_mem_rega='1' THEN + memaddr_in <= reg_QA; + ELSIF setaddrlong='1' AND longread='0' THEN + memaddr_in <= data_read; + ELSIF decodeOPC='1' THEN + memaddr_in <= TG68_PC; + END IF; + END IF; + + data_read(15 downto 0) <= data_in; + data_read(31 downto 16) <= (OTHERS=>data_in(15)); + IF long_done='1' THEN + data_read(31 downto 16) <= last_data_read; + END IF; + IF mem_byte='1' AND memaddr(0)='0' THEN + data_read(7 downto 0) <= data_in(15 downto 8); + END IF; + + IF longread='1' THEN + data_write <= data_write_tmp(31 downto 16); + ELSE + data_write(7 downto 0) <= data_write_tmp(7 downto 0); + IF mem_byte='1' THEN + data_write(15 downto 8) <= data_write_tmp(7 downto 0); + ELSE + data_write(15 downto 8) <= data_write_tmp(15 downto 8); + IF datatype="00" THEN + data_write(7 downto 0) <= data_write_tmp(15 downto 8); + END IF; + END IF; + END IF; + + IF reset='0' THEN + longread <= '0'; + long_done <= '0'; + ELSIF rising_edge(clk) THEN + IF clkena_in='1' THEN + last_data_read <= data_in; + long_done <= longread; + IF get_extendedOPC='0' OR (get_extendedOPC='1' AND PCmarker='1') THEN + memaddr <= memaddr_in; + END IF; + IF get_extendedOPC='0' THEN + + IF ((setstate_mux(1)='1' AND datatype="10") OR longreaddirect='1') AND longread='0' AND interrupt='0' THEN + longread <= '1'; + ELSE + longread <= '0'; + END IF; + END IF; + + END IF; + END IF; + END PROCESS; +----------------------------------------------------------------------------- +-- brief +----------------------------------------------------------------------------- +process (clk, brief, OP1out) + begin + IF brief(11)='1' THEN + OP1outbrief <= OP1out(31 downto 16); + ELSE + OP1outbrief <= (OTHERS=>OP1out(15)); + END IF; + IF rising_edge(clk) THEN + IF clkena='1' THEN + briefext <= OP1outbrief&OP1out(15 downto 0); +-- CASE brief(10 downto 9) IS +-- WHEN "00" => briefext <= OP1outbrief&OP1out(15 downto 0); +-- WHEN "01" => briefext <= OP1outbrief(14 downto 0)&OP1out(15 downto 0)&'0'; +-- WHEN "10" => briefext <= OP1outbrief(13 downto 0)&OP1out(15 downto 0)&"00"; +-- WHEN "11" => briefext <= OP1outbrief(12 downto 0)&OP1out(15 downto 0)&"000"; +-- END CASE; + end if; + end if; + end process; + +----------------------------------------------------------------------------- +-- PC Calc + fetch opcode +----------------------------------------------------------------------------- +process (clk, reset, opcode, TG68_PC, TG68_PC_dec, TG68_PC_br8, TG68_PC_brw, PC_dataa, PC_datab, execOPC, last_data_read, get_extendedOPC, + setstate_delay, setstate) + begin + PC_dataa <= TG68_PC; + PC_datab(2 downto 0) <= "010"; + PC_datab(7 downto 3) <= (others => PC_datab(2)); + PC_datab(15 downto 8) <= (others => PC_datab(7)); + PC_datab(31 downto 16) <= (others => PC_datab(15)); + IF execOPC='0' THEN + IF TG68_PC_br8='1' THEN + PC_datab(7 downto 0) <= opcode(7 downto 0); + END IF; + IF TG68_PC_dec(1)='1' THEN + PC_datab(2) <= '1'; + END IF; + IF TG68_PC_brw = '1' THEN + PC_datab(15 downto 0) <= last_data_read(15 downto 0); + END IF; + END IF; + TG68_PC_add <= PC_dataa+PC_datab; + + IF get_extendedOPC='1' THEN + setstate_mux <= setstate_delay; + ELSE + setstate_mux <= setstate; + END IF; + + + IF reset = '0' THEN + opcode(15 downto 12) <= X"7"; --moveq + opcode(8 downto 6) <= "010"; --long + TG68_PC <= (others =>'0'); + state <= "01"; + decodeOPC <= '0'; + fetchOPC <= '0'; + endOPC <= '0'; + interrupt <= '0'; + trap_interrupt <= '1'; + execOPC <= '0'; + getbrief <= '0'; + TG68_PC_dec <= "00"; + directPC <= '0'; + directSR <= '0'; + directCCR <= '0'; + stop <= '0'; + exec_ADD <= '0'; + exec_OR <= '0'; + exec_AND <= '0'; + exec_EOR <= '0'; + exec_MOVE <= '0'; + exec_MOVEQ <= '0'; + exec_MOVESR <= '0'; + exec_ADDQ <= '0'; + exec_CMP <= '0'; + exec_ROT <= '0'; + exec_EXT <= '0'; + exec_ABCD <= '0'; + exec_SBCD <= '0'; + exec_MULU <= '0'; + exec_DIVU <= '0'; + exec_Scc <= '0'; + exec_CPMAW <= '0'; + mem_byte <= '0'; + rot_cnt <="000001"; + rot_nop <= '0'; + get_extendedOPC <= '0'; + get_bitnumber <= '0'; + get_movem_mask <= '0'; + test_maskzero <= '0'; + movepl <= '0'; + movepw <= '0'; + test_delay <= "000"; + PCmarker <= '0'; + ELSIF rising_edge(clk) THEN + IF clkena_in='1' THEN + get_extendedOPC <= set_get_extendedOPC; + get_bitnumber <= set_get_bitnumber; + get_movem_mask <= set_get_movem_mask; + test_maskzero <= get_movem_mask; + setstate_delay <= setstate; + + TG68_PC_dec <= TG68_PC_dec(0)&set_TG68_PC_dec; + IF directPC='1' AND clkena='1' THEN + TG68_PC <= data_read; + ELSIF ea_to_pc='1' AND longread='0' THEN + TG68_PC <= memaddr_in; + ELSIF (state ="00" AND TG68_PC_nop='0') OR TG68_PC_br8='1' OR TG68_PC_brw='1' OR TG68_PC_dec(1)='1' THEN + TG68_PC <= TG68_PC_add; + END IF; + + IF get_bitnumber='1' THEN + bit_number_reg <= data_read(4 downto 0); + END IF; + + IF clkena='1' OR get_extendedOPC='1' THEN + IF set_get_extendedOPC='1' THEN + state <= "00"; + ELSIF get_extendedOPC='1' THEN + state <= setstate_mux; + ELSIF fetchOPC='1' OR (state="10" AND write_back='1' AND setstate/="10") OR set_rot_cnt/="000001" OR stop='1' THEN + state <= "01"; --decode cycle, execute cycle + ELSE + state <= setstate_mux; + END IF; + IF setstate_mux(1)='1' AND datatype="00" AND set_get_extendedOPC='0' AND wait_mem_byte='0' THEN + mem_byte <= '1'; + ELSE + mem_byte <= '0'; + END IF; + + END IF; + END IF; + + IF clkena='1' THEN + exec_ADD <= '0'; + exec_OR <= '0'; + exec_AND <= '0'; + exec_EOR <= '0'; + exec_MOVE <= '0'; + exec_MOVEQ <= '0'; + exec_MOVESR <= '0'; + exec_ADDQ <= '0'; + exec_CMP <= '0'; + exec_ROT <= '0'; + exec_ABCD <= '0'; + exec_SBCD <= '0'; + fetchOPC <= '0'; + exec_CPMAW <= '0'; + endOPC <= '0'; + interrupt <= '0'; + execOPC <= '0'; + exec_EXT <= '0'; + exec_Scc <= '0'; + rot_nop <= '0'; + decodeOPC <= fetchOPC; + directPC <= set_directPC; + directSR <= set_directSR; + directCCR <= set_directCCR; + exec_MULU <= set_exec_MULU; + exec_DIVU <= set_exec_DIVU; + movepl <= '0'; + movepw <= '0'; + + stop <= set_stop OR (stop AND NOT interrupt); + IF set_PCmarker='1' THEN + PCmarker <= '1'; + ELSIF (state="10" AND longread='0') OR (ea_only='1' AND get_ea_now='1') THEN + PCmarker <= '0'; + END IF; + IF (decodeOPC OR execOPC)='1' THEN + rot_cnt <= set_rot_cnt; + END IF; + IF next_micro_state=idle AND setstate_mux="00" AND (setnextpass='0' OR ea_only='1') AND endOPC='0' AND movem_busy='0' AND set_movem_busy='0' AND set_get_bitnumber='0' THEN + nextpass <= '0'; + IF (exec_write_back='0' OR state="11") AND set_rot_cnt="000001" THEN + endOPC <= '1'; + IF Flags(10 downto 8) '0'); + ELSIF from_SR='1' THEN + OP1out(15 downto 0) <= Flags; + ELSIF ea_data_OP1='1' AND set_store_in_tmp='1' THEN + OP1out <= ea_data; + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- set source regaddr +----------------------------------------------------------------------------- +PROCESS (opcode, Flags, movem_addr, movem_presub, movem_regaddr, source_lowbits, source_areg, from_USP, rf_source_addr_tmp) + BEGIN + rf_source_addr <= rf_source_addr_tmp; + IF rf_source_addr_tmp(3 downto 0)="1111" AND from_USP='0' THEN + rf_source_addr(4) <= Flags(13); + END IF; + IF movem_addr='1' THEN + IF movem_presub='1' THEN + rf_source_addr_tmp <= "000"&(movem_regaddr XOR "1111"); + ELSE + rf_source_addr_tmp <= "000"&movem_regaddr; + END IF; + ELSIF from_USP='1' THEN + rf_source_addr_tmp <= "0001111"; + ELSIF source_lowbits='1' THEN + rf_source_addr_tmp <= "000"&source_areg&opcode(2 downto 0); + ELSE + rf_source_addr_tmp <= "000"&source_areg&opcode(11 downto 9); + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- set OP2 +----------------------------------------------------------------------------- +PROCESS (OP2out, reg_QB, opcode, datatype, OP2out_one, exec_EXT, exec_MOVEQ, EXEC_ADDQ, use_direct_data, data_write_tmp, + ea_data_OP1, set_store_in_tmp, ea_data, movepl) + BEGIN + OP2out(15 downto 0) <= reg_QB(15 downto 0); + OP2out(31 downto 16) <= (OTHERS => OP2out(15)); + IF OP2out_one='1' THEN + OP2out(15 downto 0) <= "1111111111111111"; + ELSIF exec_EXT='1' THEN + IF opcode(6)='0' THEN --ext.w + OP2out(15 downto 8) <= (OTHERS => OP2out(7)); + END IF; + ELSIF use_direct_data='1' THEN + OP2out <= data_write_tmp; + ELSIF ea_data_OP1='0' AND set_store_in_tmp='1' THEN + OP2out <= ea_data; + ELSIF exec_MOVEQ='1' THEN + OP2out(7 downto 0) <= opcode(7 downto 0); + OP2out(15 downto 8) <= (OTHERS => opcode(7)); + ELSIF exec_ADDQ='1' THEN + OP2out(2 downto 0) <= opcode(11 downto 9); + IF opcode(11 downto 9)="000" THEN + OP2out(3) <='1'; + ELSE + OP2out(3) <='0'; + END IF; + OP2out(15 downto 4) <= (OTHERS => '0'); + ELSIF datatype="10" OR movepl='1' THEN + OP2out(31 downto 16) <= reg_QB(31 downto 16); + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- addsub +----------------------------------------------------------------------------- +PROCESS (OP1out, OP2out, presub, postadd, execOPC, OP2out_one, datatype, use_SP, use_XZFlag, use_XFlag, Flags, setaddsub) + BEGIN + addsub_a <= OP1out; + addsub_b <= OP2out; + addsub <= NOT presub; + c_in(0) <='0'; + IF execOPC='0' AND OP2out_one='0' THEN + IF datatype="00" AND use_SP='0' THEN + addsub_b <= "00000000000000000000000000000001"; + ELSIF datatype="10" AND (presub OR postadd)='1' THEN + addsub_b <= "00000000000000000000000000000100"; + ELSE + addsub_b <= "00000000000000000000000000000010"; + END IF; + ELSE + IF (use_XZFlag='1' OR use_XFlag='1') AND Flags(4)='1' THEN + c_in(0) <= '1'; + END IF; + addsub <= setaddsub; + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- Write Reg +----------------------------------------------------------------------------- +PROCESS (clkena, OP1in, datatype, presub, postadd, endOPC, regwrena, state, execOPC, last_data_read, movem_addr, rf_dest_addr, reg_QA, maskzero) + BEGIN + Lwrena <= '0'; + Hwrena <= '0'; + registerin <= OP1in; + + IF (presub='1' OR postadd='1') AND endOPC='0' THEN -- -(An)+ + Hwrena <= '1'; + Lwrena <= '1'; + ELSIF Regwrena='1' AND maskzero='0' THEN --read (mem) + Lwrena <= '1'; + CASE datatype IS + WHEN "00" => --BYTE + registerin(15 downto 8) <= reg_QA(15 downto 8); + WHEN "01" => --WORD + IF rf_dest_addr(3)='1' OR movem_addr='1' THEN + Hwrena <='1'; + END IF; + WHEN OTHERS => --LONG + Hwrena <= '1'; + END CASE; + END IF; + END PROCESS; + +------------------------------------------------------------------------------ +--ALU +------------------------------------------------------------------------------ +PROCESS (opcode, OP1in, OP1out, OP2out, datatype, c_out, exec_ABCD, exec_SBCD, exec_CPMAW, exec_MOVESR, bits_out, Flags, flag_z, use_XZFlag, addsub_ofl, + dummy_s, dummy_a, niba_hc, niba_h, niba_l, niba_lc, nibs_hc, nibs_h, nibs_l, nibs_lc, addsub_q, movem_addr, data_read, exec_MULU, exec_DIVU, exec_OR, + exec_AND, exec_Scc, exec_EOR, exec_MOVE, exec_exg, exec_ROT, execOPC, exec_swap, exec_Bits, rot_out, dummy_mulu, dummy_div, save_memaddr, memaddr, + memaddr_in, ea_only, get_ea_now) + BEGIN + +--BCD_ARITH------------------------------------------------------------------- + --ADC + dummy_a <= niba_hc&(niba_h(4 downto 1)+('0',niba_hc,niba_hc,'0'))&(niba_l(4 downto 1)+('0',niba_lc,niba_lc,'0')); + niba_l <= ('0'&OP1out(3 downto 0)&'1') + ('0'&OP2out(3 downto 0)&Flags(4)); + niba_lc <= niba_l(5) OR (niba_l(4) AND niba_l(3)) OR (niba_l(4) AND niba_l(2)); + + niba_h <= ('0'&OP1out(7 downto 4)&'1') + ('0'&OP2out(7 downto 4)&niba_lc); + niba_hc <= niba_h(5) OR (niba_h(4) AND niba_h(3)) OR (niba_h(4) AND niba_h(2)); + --SBC + dummy_s <= nibs_hc&(nibs_h(4 downto 1)-('0',nibs_hc,nibs_hc,'0'))&(nibs_l(4 downto 1)-('0',nibs_lc,nibs_lc,'0')); + nibs_l <= ('0'&OP1out(3 downto 0)&'0') - ('0'&OP2out(3 downto 0)&Flags(4)); + nibs_lc <= nibs_l(5); + + nibs_h <= ('0'&OP1out(7 downto 4)&'0') - ('0'&OP2out(7 downto 4)&nibs_lc); + nibs_hc <= nibs_h(5); +------------------------------------------------------------------------------ + + flag_z <= "000"; + + OP1in <= addsub_q; + IF movem_addr='1' THEN + OP1in <= data_read; + ELSIF exec_ABCD='1' THEN + OP1in(7 downto 0) <= dummy_a(7 downto 0); + ELSIF exec_SBCD='1' THEN + OP1in(7 downto 0) <= dummy_s(7 downto 0); + ELSIF exec_MULU='1' THEN + OP1in <= dummy_mulu; + ELSIF exec_DIVU='1' AND execOPC='1' THEN + OP1in <= dummy_div; + ELSIF exec_OR='1' THEN + OP1in <= OP2out OR OP1out; + ELSIF exec_AND='1' OR exec_Scc='1' THEN + OP1in <= OP2out AND OP1out; + ELSIF exec_EOR='1' THEN + OP1in <= OP2out XOR OP1out; + ELSIF exec_MOVE='1' OR exec_exg='1' THEN + OP1in <= OP2out; + ELSIF exec_ROT='1' THEN + OP1in <= rot_out; + ELSIF save_memaddr='1' THEN + OP1in <= memaddr; + ELSIF get_ea_now='1' AND ea_only='1' THEN + OP1in <= memaddr_in; + ELSIF exec_swap='1' THEN + OP1in <= OP1out(15 downto 0)& OP1out(31 downto 16); + ELSIF exec_bits='1' THEN + OP1in <= bits_out; + ELSIF exec_MOVESR='1' THEN + OP1in(15 downto 0) <= Flags; + END IF; + + IF use_XZFlag='1' AND flags(2)='0' THEN + flag_z <= "000"; + ELSIF OP1in(7 downto 0)="00000000" THEN + flag_z(0) <= '1'; + IF OP1in(15 downto 8)="00000000" THEN + flag_z(1) <= '1'; + IF OP1in(31 downto 16)="0000000000000000" THEN + flag_z(2) <= '1'; + END IF; + END IF; + END IF; + +-- --Flags NZVC + IF datatype="00" THEN --Byte + set_flags <= OP1IN(7)&flag_z(0)&addsub_ofl(0)&c_out(0); + IF exec_ABCD='1' THEN + set_flags(0) <= dummy_a(8); + ELSIF exec_SBCD='1' THEN + set_flags(0) <= dummy_s(8); + END IF; + ELSIF datatype="10" OR exec_CPMAW='1' THEN --Long + set_flags <= OP1IN(31)&flag_z(2)&addsub_ofl(2)&c_out(2); + ELSE --Word + set_flags <= OP1IN(15)&flag_z(1)&addsub_ofl(1)&c_out(1); + END IF; + END PROCESS; + +------------------------------------------------------------------------------ +--Flags +------------------------------------------------------------------------------ +PROCESS (clk, reset, opcode) + BEGIN + IF reset='0' THEN + Flags(13) <= '1'; + SVmode <= '1'; + Flags(10 downto 8) <= "111"; + ELSIF rising_edge(clk) THEN + + IF clkena = '1' THEN + IF directSR='1' THEN + Flags <= data_read(15 downto 0); + END IF; + IF directCCR='1' THEN + Flags(7 downto 0) <= data_read(7 downto 0); + END IF; + IF interrupt='1' THEN + Flags(10 downto 8) <=rIPL_nr; + SVmode <= '1'; + END IF; + IF writeSR='1' OR interrupt='1' THEN + Flags(13) <='1'; + END IF; + IF endOPC='1' AND to_SR='0' THEN + SVmode <= Flags(13); + END IF; + IF execOPC='1' AND to_SR='1' THEN + Flags(7 downto 0) <= OP1in(7 downto 0); --CCR + IF datatype="01" AND (opcode(14)='0' OR opcode(9)='1') THEN --move to CCR wird als word gespeichert + Flags(15 downto 8) <= OP1in(15 downto 8); --SR + SVmode <= OP1in(13); + END IF; + ELSIF Z_error='1' THEN + IF opcode(8)='0' THEN + Flags(3 downto 0) <= "1000"; + ELSE + Flags(3 downto 0) <= "0100"; + END IF; + ELSIF no_Flags='0' AND trapmake='0' THEN + IF exec_ADD='1' THEN + Flags(4) <= set_flags(0); + ELSIF exec_ROT='1' AND rot_bits/="11" AND rot_nop='0' THEN + Flags(4) <= rot_XC; + END IF; + + IF (exec_ADD OR exec_CMP)='1' THEN + Flags(3 downto 0) <= set_flags; + ELSIF decodeOPC='1' and set_exec_ROT='1' THEN + Flags(1) <= '0'; + ELSIF exec_DIVU='1' THEN + IF set_V_Flag='1' THEN + Flags(3 downto 0) <= "1010"; + ELSE + Flags(3 downto 0) <= OP1IN(15)&flag_z(1)&"00"; + END IF; + ELSIF exec_OR='1' OR exec_AND='1' OR exec_EOR='1' OR exec_MOVE='1' OR exec_swap='1' OR exec_MULU='1' THEN + Flags(3 downto 0) <= set_flags(3 downto 2)&"00"; + ELSIF exec_ROT='1' THEN + Flags(3 downto 2) <= set_flags(3 downto 2); + Flags(0) <= rot_XC; + IF rot_bits="00" THEN --ASL/ASR + Flags(1) <= ((set_flags(3) XOR rot_rot) OR Flags(1)); + END IF; + ELSIF exec_bits='1' THEN + Flags(2) <= NOT one_bit_in; + END IF; + END IF; + END IF; + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- execute opcode +----------------------------------------------------------------------------- +PROCESS (clk, reset, OP2out, opcode, fetchOPC, decodeOPC, execOPC, endOPC, nextpass, condition, set_V_flag, trapmake, trapd, interrupt, trap_interrupt, rot_nop, + Z_error, c_in, rot_cnt, one_bit_in, bit_number_reg, bit_number, ea_only, get_ea_now, ea_build, datatype, exec_write_back, get_extendedOPC, + Flags, SVmode, movem_addr, movem_busy, getbrief, set_exec_AND, set_exec_OR, set_exec_EOR, TG68_PC_dec, c_out, OP1out, micro_state) + BEGIN + TG68_PC_br8 <= '0'; + TG68_PC_brw <= '0'; + TG68_PC_nop <= '0'; + setstate <= "00"; + Regwrena <= '0'; + postadd <= '0'; + presub <= '0'; + movem_presub <= '0'; + setaddsub <= '1'; + setaddrlong <= '0'; + setnextpass <= '0'; + regdirectsource <= '0'; + setdisp <= '0'; + setdispbyte <= '0'; + setdispbrief <= '0'; + setbriefext <= '0'; + setgetbrief <= '0'; + longreaddirect <= '0'; + dest_areg <= '0'; + source_areg <= '0'; + data_is_source <= '0'; + write_back <= '0'; + setstackaddr <= '0'; + writePC <= '0'; + writePC_add <= '0'; + set_TG68_PC_dec <= '0'; + set_directPC <= '0'; + set_exec_ADD <= '0'; + set_exec_OR <= '0'; + set_exec_AND <= '0'; + set_exec_EOR <= '0'; + set_exec_MOVE <= '0'; + set_exec_MOVEQ <= '0'; + set_exec_MOVESR <= '0'; + set_exec_ADDQ <= '0'; + set_exec_CMP <= '0'; + set_exec_ROT <= '0'; + set_exec_EXT <= '0'; + set_exec_CPMAW <= '0'; + OP2out_one <= '0'; + ea_to_pc <= '0'; + ea_build <= '0'; + get_ea_now <= '0'; + rot_bits <= "XX"; + set_rot_nop <= '0'; + set_rot_cnt <= "000001"; + set_movem_busy <= '0'; + set_get_movem_mask <= '0'; + save_memaddr <= '0'; + set_mem_addsub <= '0'; + exec_exg <= '0'; + exec_swap <= '0'; + exec_Bits <= '0'; + set_get_bitnumber <= '0'; + dest_hbits <= '0'; + source_lowbits <= '0'; + set_mem_rega <= '0'; + ea_data_OP1 <= '0'; + ea_only <= '0'; + set_direct_data <= '0'; + set_get_extendedOPC <= '0'; + set_exec_tas <= '0'; + OP1out_zero <= '0'; + use_XZFlag <= '0'; + use_XFlag <= '0'; + set_exec_ABCD <= '0'; + set_exec_SBCD <= '0'; + set_exec_MULU <= '0'; + set_exec_DIVU <= '0'; + set_exec_Scc <= '0'; + trap_illegal <='0'; + trap_priv <='0'; + trap_1010 <='0'; + trap_1111 <='0'; + trap_trap <='0'; + trap_trapv <= '0'; + trapmake <='0'; + set_vectoraddr <='0'; + writeSR <= '0'; + set_directSR <= '0'; + set_directCCR <= '0'; + set_stop <= '0'; + from_SR <= '0'; + to_SR <= '0'; + from_USP <= '0'; + to_USP <= '0'; + illegal_write_mode <= '0'; + illegal_read_mode <= '0'; + illegal_byteaddr <= '0'; + no_Flags <= '0'; + set_PCmarker <= '0'; + use_SP <= '0'; + set_Z_error <= '0'; + wait_mem_byte <= '0'; + set_movepl <= '0'; + set_movepw <= '0'; + + trap_chk <= '0'; + next_micro_state <= idle; + +------------------------------------------------------------------------------ +--Sourcepass +------------------------------------------------------------------------------ + IF ea_only='0' AND get_ea_now='1' THEN + setstate <= "10"; + END IF; + + IF ea_build='1' THEN + CASE opcode(5 downto 3) IS --source + WHEN "010"|"011"|"100" => -- -(An)+ + get_ea_now <='1'; + setnextpass <= '1'; + IF opcode(4)='1' THEN + set_mem_rega <= '1'; + ELSE + set_mem_addsub <= '1'; + END IF; + IF opcode(3)='1' THEN --(An)+ + postadd <= '1'; + IF opcode(2 downto 0)="111" THEN + use_SP <= '1'; + END IF; + END IF; + IF opcode(5)='1' THEN -- -(An) + presub <= '1'; + IF opcode(2 downto 0)="111" THEN + use_SP <= '1'; + END IF; + END IF; + IF opcode(4 downto 3)/="10" THEN + regwrena <= '1'; + END IF; + WHEN "101" => --(d16,An) + next_micro_state <= ld_dAn1; + setgetbrief <='1'; + set_mem_regA <= '1'; + WHEN "110" => --(d8,An,Xn) + next_micro_state <= ld_AnXn1; + setgetbrief <='1'; + set_mem_regA <= '1'; + WHEN "111" => + CASE opcode(2 downto 0) IS + WHEN "000" => --(xxxx).w + next_micro_state <= ld_nn; + WHEN "001" => --(xxxx).l + longreaddirect <= '1'; + next_micro_state <= ld_nn; + WHEN "010" => --(d16,PC) + next_micro_state <= ld_dAn1; + setgetbrief <= '1'; + set_PCmarker <= '1'; + WHEN "011" => --(d8,PC,Xn) + next_micro_state <= ld_AnXn1; + setgetbrief <= '1'; + set_PCmarker <= '1'; + WHEN "100" => --#data + setnextpass <= '1'; + set_direct_data <= '1'; + IF datatype="10" THEN + longreaddirect <= '1'; + END IF; + WHEN OTHERS => + END CASE; + WHEN OTHERS => + END CASE; + END IF; +------------------------------------------------------------------------------ +--prepere opcode +------------------------------------------------------------------------------ + CASE opcode(7 downto 6) IS + WHEN "00" => datatype <= "00"; --Byte + WHEN "01" => datatype <= "01"; --Word + WHEN OTHERS => datatype <= "10"; --Long + END CASE; + + IF execOPC='1' AND endOPC='0' AND exec_write_back='1' THEN + setstate <="11"; + END IF; + +------------------------------------------------------------------------------ +--test illegal mode +------------------------------------------------------------------------------ + IF (opcode(5 downto 3)="111" AND opcode(2 downto 1)/="00") OR (opcode(5 downto 3)="001" AND datatype="00") THEN + illegal_write_mode <= '1'; + END IF; + IF (opcode(5 downto 2)="1111" AND opcode(1 downto 0)/="00") OR (opcode(5 downto 3)="001" AND datatype="00") THEN + illegal_read_mode <= '1'; + END IF; + IF opcode(5 downto 3)="001" AND datatype="00" THEN + illegal_byteaddr <= '1'; + END IF; + + + CASE opcode(15 downto 12) IS +-- 0000 ---------------------------------------------------------------------------- + WHEN "0000" => + IF opcode(8)='1' AND opcode(5 downto 3)="001" THEN --movep + datatype <= "00"; --Byte + use_SP <= '1'; + no_Flags <='1'; + IF opcode(7)='0' THEN + set_exec_move <= '1'; + set_movepl <= '1'; + END IF; + IF decodeOPC='1' THEN + IF opcode(7)='0' THEN + set_direct_data <= '1'; + END IF; + next_micro_state <= movep1; + setgetbrief <='1'; + set_mem_regA <= '1'; + END IF; + IF opcode(7)='0' AND endOPC='1' THEN + IF opcode(6)='1' THEN + datatype <= "10"; --Long + ELSE + datatype <= "01"; --Word + END IF; + dest_hbits <='1'; + regwrena <= '1'; + END IF; + ELSE + IF opcode(8)='1' OR opcode(11 downto 8)="1000" THEN --Bits + IF execOPC='1' AND get_extendedOPC='0' THEN + IF opcode(7 downto 6)/="00" AND endOPC='1' THEN + regwrena <= '1'; + END IF; + exec_Bits <= '1'; + ea_data_OP1 <= '1'; + END IF; +-- IF get_extendedOPC='1' THEN +-- datatype <= "01"; --Word +-- ELS + IF opcode(5 downto 4)="00" THEN + datatype <= "10"; --Long + ELSE + datatype <= "00"; --Byte + IF opcode(7 downto 6)/="00" THEN + write_back <= '1'; + END IF; + END IF; + IF decodeOPC='1' THEN + ea_build <= '1'; + IF opcode(8)='0' THEN + IF opcode(5 downto 4)/="00" THEN --Dn, An + set_get_extendedOPC <= '1'; + END IF; + set_get_bitnumber <= '1'; + END IF; + END IF; + ELSE --andi, ...xxxi + IF opcode(11 downto 8)="0000" THEN --ORI + set_exec_OR <= '1'; + END IF; + IF opcode(11 downto 8)="0010" THEN --ANDI + set_exec_AND <= '1'; + END IF; + IF opcode(11 downto 8)="0100" OR opcode(11 downto 8)="0110" THEN --SUBI, ADDI + set_exec_ADD <= '1'; + END IF; + IF opcode(11 downto 8)="1010" THEN --EORI + set_exec_EOR <= '1'; + END IF; + IF opcode(11 downto 8)="1100" THEN --CMPI + set_exec_CMP <= '1'; + ELSIF trapmake='0' THEN + write_back <= '1'; + END IF; + IF opcode(7)='0' AND opcode(5 downto 0)="111100" AND (set_exec_AND OR set_exec_OR OR set_exec_EOR)='1' THEN --SR +-- IF opcode(7)='0' AND opcode(5 downto 0)="111100" AND (opcode(11 downto 8)="0010" OR opcode(11 downto 8)="0000" OR opcode(11 downto 8)="1010") THEN --SR + IF SVmode='0' AND opcode(6)='1' THEN --SR + trap_priv <= '1'; + trapmake <= '1'; + ELSE + from_SR <= '1'; + to_SR <= '1'; + IF decodeOPC='1' THEN + setnextpass <= '1'; + set_direct_data <= '1'; + END IF; + END IF; + ELSE + IF decodeOPC='1' THEN + IF opcode(11 downto 8)="0010" OR opcode(11 downto 8)="0000" OR opcode(11 downto 8)="0100" --ANDI, ORI, SUBI + OR opcode(11 downto 8)="0110" OR opcode(11 downto 8)="1010" OR opcode(11 downto 8)="1100" THEN --ADDI, EORI, CMPI + -- IF (set_exec_AND OR set_exec_OR OR set_exec_ADD --ANDI, ORI, SUBI + -- OR set_exec_EOR OR set_exec_CMP)='1' THEN --ADDI, EORI, CMPI + + next_micro_state <= andi; + set_direct_data <= '1'; + IF datatype="10" THEN + longreaddirect <= '1'; + END IF; + END IF; + END IF; + + IF execOPC='1' THEN + ea_data_OP1 <= '1'; + IF opcode(11 downto 8)/="1100" THEN --CMPI + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + IF opcode(11 downto 8)="1100" OR opcode(11 downto 8)="0100" THEN --CMPI, SUBI + setaddsub <= '0'; + END IF; + END IF; + END IF; + END IF; + END IF; + +-- 0001, 0010, 0011 ----------------------------------------------------------------- + WHEN "0001"|"0010"|"0011" => --move.b, move.l, move.w + set_exec_MOVE <= '1'; + IF opcode(8 downto 6)="001" THEN + no_Flags <= '1'; + END IF; + IF opcode(5 downto 4)="00" THEN --Dn, An + regdirectsource <= '1'; + END IF; + CASE opcode(13 downto 12) IS + WHEN "01" => datatype <= "00"; --Byte + WHEN "10" => datatype <= "10"; --Long + WHEN OTHERS => datatype <= "01"; --Word + END CASE; + source_lowbits <= '1'; -- Dn=> An=> + IF opcode(3)='1' THEN + source_areg <= '1'; + END IF; + IF getbrief='1' AND nextpass='1' THEN -- =>(d16,An) =>(d8,An,Xn) + set_mem_rega <= '1'; + END IF; + + IF execOPC='1' AND opcode(8 downto 7)="00" THEN + Regwrena <= '1'; + END IF; + + IF nextpass='1' OR execOPC='1' OR opcode(5 downto 4)="00" THEN + dest_hbits <= '1'; + IF opcode(8 downto 6)/="000" THEN + dest_areg <= '1'; + END IF; + END IF; + + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + + IF micro_state=idle AND (nextpass='1' OR (opcode(5 downto 4)="00" AND decodeOPC='1')) THEN + CASE opcode(8 downto 6) IS --destination +-- WHEN "000" => --Dn +-- WHEN "001" => --An + WHEN "010"|"011"|"100" => --destination -(an)+ + IF opcode(7)='1' THEN + set_mem_rega <= '1'; + ELSE + set_mem_addsub <= '1'; + END IF; + IF opcode(6)='1' THEN --(An)+ + postadd <= '1'; + IF opcode(11 downto 9)="111" THEN + use_SP <= '1'; + END IF; + END IF; + IF opcode(8)='1' THEN -- -(An) + presub <= '1'; + IF opcode(11 downto 9)="111" THEN + use_SP <= '1'; + END IF; + END IF; + IF opcode(7 downto 6)/="10" THEN + regwrena <= '1'; + END IF; + setstate <= "11"; + next_micro_state <= nop; + WHEN "101" => --(d16,An) + next_micro_state <= st_dAn1; + set_mem_regA <= '1'; + setgetbrief <= '1'; + WHEN "110" => --(d8,An,Xn) + next_micro_state <= st_AnXn1; + set_mem_regA <= '1'; + setgetbrief <= '1'; + WHEN "111" => + CASE opcode(11 downto 9) IS + WHEN "000" => --(xxxx).w + next_micro_state <= st_nn; + WHEN "001" => --(xxxx).l + longreaddirect <= '1'; + next_micro_state <= st_nn; + WHEN OTHERS => + END CASE; + WHEN OTHERS => + END CASE; + END IF; +-- 0100 ---------------------------------------------------------------------------- + WHEN "0100" => --rts_group + IF opcode(8)='1' THEN --lea + IF opcode(6)='1' THEN --lea + IF opcode(7)='1' THEN + ea_only <= '1'; + IF opcode(5 downto 3)="010" THEN --lea (Am),An + set_exec_move <='1'; + no_Flags <='1'; + dest_areg <= '1'; + dest_hbits <= '1'; + source_lowbits <= '1'; + source_areg <= '1'; + IF execOPC='1' THEN + Regwrena <= '1'; + END IF; + ELSE + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + END IF; + IF get_ea_now='1' THEN + dest_areg <= '1'; + dest_hbits <= '1'; + regwrena <= '1'; + END IF; + ELSE + trap_illegal <= '1'; + trapmake <= '1'; + END IF; + ELSE --chk + IF opcode(7)='1' THEN + set_exec_ADD <= '1'; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + datatype <= "01"; --Word + IF execOPC='1' THEN + setaddsub <= '0'; +--first alternative + ea_data_OP1 <= '1'; + IF c_out(1)='1' OR OP1out(15)='1' OR OP2out(15)='1' THEN + -- trap_chk <= '1'; --first I must change the Trap System + -- trapmake <= '1'; + END IF; +--second alternative +-- IF (c_out(1)='0' AND flag_z(1)='0') OR OP1out(15)='1' OR OP2out(15)='1' THEN +-- -- trap_chk <= '1'; --first I must change the Trap System +-- -- trapmake <= '1'; +-- END IF; +-- dest_hbits <= '1'; +-- source_lowbits <='1'; + END IF; + ELSE + trap_illegal <= '1'; -- chk long for 68020 + trapmake <= '1'; + END IF; + END IF; + ELSE + CASE opcode(11 downto 9) IS + WHEN "000"=> + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF opcode(7 downto 6)="11" THEN --move from SR + set_exec_MOVESR <= '1'; + datatype <= "01"; + write_back <='1'; -- im 68000 wird auch erst gelesen + IF execOPC='1' THEN + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + ELSE --negx + use_XFlag <= '1'; + write_back <='1'; + set_exec_ADD <= '1'; + setaddsub <='0'; + IF execOPC='1' THEN + source_lowbits <= '1'; + OP1out_zero <= '1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + END IF; + WHEN "001"=> + IF opcode(7 downto 6)="11" THEN --move from CCR 68010 + trap_illegal <= '1'; + trapmake <= '1'; + ELSE --clr + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + write_back <='1'; + set_exec_AND <= '1'; + IF execOPC='1' THEN + OP1out_zero <= '1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + END IF; + WHEN "010"=> + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF opcode(7 downto 6)="11" THEN --move to CCR + set_exec_MOVE <= '1'; + datatype <= "01"; + IF execOPC='1' THEN + source_lowbits <= '1'; + to_SR <= '1'; + END IF; + ELSE --neg + write_back <='1'; + set_exec_ADD <= '1'; + setaddsub <='0'; + IF execOPC='1' THEN + source_lowbits <= '1'; + OP1out_zero <= '1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + END IF; + WHEN "011"=> --not, move toSR + IF opcode(7 downto 6)="11" THEN --move to SR + IF SVmode='1' THEN + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + set_exec_MOVE <= '1'; + datatype <= "01"; + IF execOPC='1' THEN + source_lowbits <= '1'; + to_SR <= '1'; + END IF; + ELSE + trap_priv <= '1'; + trapmake <= '1'; + END IF; + ELSE --not + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + write_back <='1'; + set_exec_EOR <= '1'; + IF execOPC='1' THEN + OP2out_one <= '1'; + ea_data_OP1 <= '1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + END IF; + WHEN "100"|"110"=> + IF opcode(7)='1' THEN --movem, ext + IF opcode(5 downto 3)="000" AND opcode(10)='0' THEN --ext + source_lowbits <= '1'; + IF decodeOPC='1' THEN + set_exec_EXT <= '1'; + set_exec_move <= '1'; + END IF; + IF opcode(6)='0' THEN + datatype <= "01"; --WORD + END IF; + IF execOPC='1' THEN + regwrena <= '1'; + END IF; + ELSE --movem +-- IF opcode(11 downto 7)="10001" OR opcode(11 downto 7)="11001" THEN --MOVEM + ea_only <= '1'; + IF decodeOPC='1' THEN + datatype <= "01"; --Word + set_get_movem_mask <='1'; + set_get_extendedOPC <='1'; + + IF opcode(5 downto 3)="010" OR opcode(5 downto 3)="011" OR opcode(5 downto 3)="100" THEN + set_mem_rega <= '1'; + setstate <= "01"; + IF opcode(10)='0' THEN + set_movem_busy <='1'; + ELSE + next_micro_state <= movem; + END IF; + ELSE + ea_build <= '1'; + END IF; + + ELSE + IF opcode(6)='0' THEN + datatype <= "01"; --Word + END IF; + END IF; + IF execOPC='1' THEN + IF opcode(5 downto 3)="100" OR opcode(5 downto 3)="011" THEN + regwrena <= '1'; + save_memaddr <= '1'; + END IF; + END IF; + IF get_ea_now='1' THEN + set_movem_busy <= '1'; + IF opcode(10)='0' THEN + setstate <="01"; + ELSE + setstate <="10"; + END IF; + END IF; + IF opcode(5 downto 3)="100" THEN + movem_presub <= '1'; + END IF; + IF movem_addr='1' THEN + IF opcode(10)='1' THEN + regwrena <= '1'; + END IF; + END IF; + IF movem_busy='1' THEN + IF opcode(10)='0' THEN + setstate <="11"; + ELSE + setstate <="10"; + END IF; + END IF; + END IF; + ELSE + IF opcode(10)='1' THEN --MUL, DIV 68020 + trap_illegal <= '1'; + trapmake <= '1'; + ELSE --pea, swap + IF opcode(6)='1' THEN + datatype <= "10"; + IF opcode(5 downto 3)="000" THEN --swap + IF execOPC='1' THEN + exec_swap <= '1'; + regwrena <= '1'; + END IF; + ELSIF opcode(5 downto 3)="001" THEN --bkpt + + ELSE --pea + ea_only <= '1'; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF nextpass='1' AND micro_state=idle THEN + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + setstate <="11"; + next_micro_state <= nop; + END IF; + IF get_ea_now='1' THEN + setstate <="01"; + END IF; + END IF; + ELSE --nbcd + IF decodeOPC='1' THEN --nbcd + ea_build <= '1'; + END IF; + use_XFlag <= '1'; + write_back <='1'; + set_exec_ADD <= '1'; + set_exec_SBCD <= '1'; + IF execOPC='1' THEN + source_lowbits <= '1'; + OP1out_zero <= '1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + END IF; + END IF; + END IF; + + WHEN "101"=> --tst, tas + IF opcode(7 downto 2)="111111" THEN --4AFC illegal + trap_illegal <= '1'; + trapmake <= '1'; + ELSE + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF execOPC='1' THEN + dest_hbits <= '1'; --for Flags + source_lowbits <= '1'; + -- IF opcode(3)='1' THEN --MC68020... + -- source_areg <= '1'; + -- END IF; + END IF; + set_exec_MOVE <= '1'; + IF opcode(7 downto 6)="11" THEN --tas + set_exec_tas <= '1'; + write_back <= '1'; + datatype <= "00"; --Byte + IF execOPC='1' AND endOPC='1' THEN + regwrena <= '1'; + END IF; + END IF; + END IF; +-- WHEN "110"=> + WHEN "111"=> --4EXX + IF opcode(7)='1' THEN --jsr, jmp + datatype <= "10"; + ea_only <= '1'; + IF nextpass='1' AND micro_state=idle THEN + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + setstate <="11"; + next_micro_state <= nop; + END IF; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF get_ea_now='1' THEN --jsr + IF opcode(6)='0' THEN + setstate <="01"; + END IF; + ea_to_pc <= '1'; + IF opcode(5 downto 1)="11100" THEN + writePC_add <= '1'; + ELSE + writePC <= '1'; + END IF; + END IF; + ELSE -- + CASE opcode(6 downto 0) IS + WHEN "1000000"|"1000001"|"1000010"|"1000011"|"1000100"|"1000101"|"1000110"|"1000111"| --trap + "1001000"|"1001001"|"1001010"|"1001011"|"1001100"|"1001101"|"1001110"|"1001111" => --trap + trap_trap <='1'; + trapmake <= '1'; + WHEN "1010000"|"1010001"|"1010010"|"1010011"|"1010100"|"1010101"|"1010110"|"1010111" => --link + datatype <= "10"; + IF decodeOPC='1' THEN + next_micro_state <= link; + set_exec_MOVE <= '1'; --f?r displacement + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + source_lowbits <= '1'; + source_areg <= '1'; + END IF; + IF execOPC='1' THEN + setstackaddr <='1'; + regwrena <= '1'; + END IF; + + WHEN "1011000"|"1011001"|"1011010"|"1011011"|"1011100"|"1011101"|"1011110"|"1011111" => --unlink + datatype <= "10"; + IF decodeOPC='1' THEN + setstate <= "10"; + set_mem_rega <= '1'; + ELSIF execOPC='1' THEN + regwrena <= '1'; + exec_exg <= '1'; + ELSE + setstackaddr <='1'; + regwrena <= '1'; + get_ea_now <= '1'; + ea_only <= '1'; + END IF; + + WHEN "1100000"|"1100001"|"1100010"|"1100011"|"1100100"|"1100101"|"1100110"|"1100111" => --move An,USP + IF SVmode='1' THEN + no_Flags <= '1'; + to_USP <= '1'; + setstackaddr <= '1'; + source_lowbits <= '1'; + source_areg <= '1'; + set_exec_MOVE <= '1'; + datatype <= "10"; + IF execOPC='1' THEN + regwrena <= '1'; + END IF; + ELSE + trap_priv <= '1'; + trapmake <= '1'; + END IF; + WHEN "1101000"|"1101001"|"1101010"|"1101011"|"1101100"|"1101101"|"1101110"|"1101111" => --move USP,An + IF SVmode='1' THEN + no_Flags <= '1'; + from_USP <= '1'; + set_exec_MOVE <= '1'; + datatype <= "10"; + IF execOPC='1' THEN + regwrena <= '1'; + END IF; + ELSE + trap_priv <= '1'; + trapmake <= '1'; + END IF; + + WHEN "1110000" => --reset + IF SVmode='0' THEN + trap_priv <= '1'; + trapmake <= '1'; + END IF; + + WHEN "1110001" => --nop + + WHEN "1110010" => --stop + IF SVmode='0' THEN + trap_priv <= '1'; + trapmake <= '1'; + ELSE + IF decodeOPC='1' THEN + setnextpass <= '1'; + set_directSR <= '1'; + set_stop <= '1'; + END IF; + END IF; + + WHEN "1110011" => --rte + IF SVmode='1' THEN + IF decodeOPC='1' THEN + datatype <= "01"; + setstate <= "10"; + postadd <= '1'; + setstackaddr <= '1'; + set_mem_rega <= '1'; + set_directSR <= '1'; + next_micro_state <= rte; + END IF; + ELSE + trap_priv <= '1'; + trapmake <= '1'; + END IF; + + WHEN "1110101" => --rts + IF decodeOPC='1' THEN + datatype <= "10"; + setstate <= "10"; + postadd <= '1'; + setstackaddr <= '1'; + set_mem_rega <= '1'; + set_directPC <= '1'; + next_micro_state <= nop; + END IF; + + WHEN "1110110" => --trapv + IF Flags(1)='1' THEN + trap_trapv <= '1'; + trapmake <= '1'; + END IF; + + WHEN "1110111" => --rtr + IF decodeOPC='1' THEN + datatype <= "01"; + setstate <= "10"; + postadd <= '1'; + setstackaddr <= '1'; + set_mem_rega <= '1'; + set_directCCR <= '1'; + next_micro_state <= rte; + END IF; + + + WHEN OTHERS => + trap_illegal <= '1'; + trapmake <= '1'; + END CASE; + END IF; + WHEN OTHERS => null; + END CASE; + END IF; + +-- 0101 ---------------------------------------------------------------------------- + WHEN "0101" => --subq, addq + + IF opcode(7 downto 6)="11" THEN --dbcc + IF opcode(5 downto 3)="001" THEN --dbcc + datatype <= "01"; --Word + IF decodeOPC='1' THEN + next_micro_state <= nop; + OP2out_one <= '1'; + IF condition='0' THEN + Regwrena <= '1'; + IF c_in(2)='1' THEN + next_micro_state <= dbcc1; + END IF; + END IF; + data_is_source <= '1'; + END IF; + ELSE --Scc + datatype <= "00"; --Byte + write_back <= '1'; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF condition='0' THEN + set_exec_Scc <= '1'; + END IF; + IF execOPC='1' THEN + IF condition='1' THEN + OP2out_one <= '1'; + exec_EXG <= '1'; + ELSE + OP1out_zero <= '1'; + END IF; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + END IF; + ELSE --addq, subq + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF opcode(5 downto 3)="001" THEN + no_Flags <= '1'; + END IF; + write_back <= '1'; + set_exec_ADDQ <= '1'; + set_exec_ADD <= '1'; + IF execOPC='1' THEN + ea_data_OP1 <= '1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + IF opcode(8)='1' THEN + setaddsub <= '0'; + END IF; + END IF; + END IF; + +-- 0110 ---------------------------------------------------------------------------- + WHEN "0110" => --bra,bsr,bcc + datatype <= "10"; + + IF micro_state=idle THEN + IF opcode(11 downto 8)="0001" THEN --bsr + IF opcode(7 downto 0)="00000000" THEN + next_micro_state <= bsr1; + ELSE + next_micro_state <= bsr2; + setstate <= "01"; + END IF; + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + ELSE --bra + IF opcode(7 downto 0)="00000000" THEN + next_micro_state <= bra1; + END IF; + IF condition='1' THEN + TG68_PC_br8 <= '1'; + END IF; + END IF; + END IF; + +-- 0111 ---------------------------------------------------------------------------- + WHEN "0111" => --moveq + IF opcode(8)='0' THEN + IF trap_interrupt='0' THEN + datatype <= "10"; --Long + Regwrena <= '1'; + set_exec_MOVEQ <= '1'; + set_exec_MOVE <= '1'; + dest_hbits <= '1'; + END IF; + ELSE + trap_illegal <= '1'; + trapmake <= '1'; + END IF; + +-- 1000 ---------------------------------------------------------------------------- + WHEN "1000" => --or + IF opcode(7 downto 6)="11" THEN --divu, divs + IF opcode(5 downto 4)="00" THEN --Dn, An + regdirectsource <= '1'; + END IF; + IF (micro_state=idle AND nextpass='1') OR (opcode(5 downto 4)="00" AND decodeOPC='1') THEN + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div1; + END IF; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF execOPC='1' AND z_error='0' AND set_V_Flag='0' THEN + regwrena <= '1'; + END IF; + IF (micro_state/=idle AND nextpass='1') OR execOPC='1' THEN + dest_hbits <= '1'; + source_lowbits <='1'; + ELSE + datatype <= "01"; + END IF; + + + ELSIF opcode(8)='1' AND opcode(5 downto 4)="00" THEN --sbcd, pack , unpack + IF opcode(7 downto 6)="00" THEN --sbcd + use_XZFlag <= '1'; + set_exec_ADD <= '1'; + set_exec_SBCD <= '1'; + IF opcode(3)='1' THEN + write_back <= '1'; + IF decodeOPC='1' THEN + set_direct_data <= '1'; + setstate <= "10"; + set_mem_addsub <= '1'; + presub <= '1'; + next_micro_state <= op_AxAy; + END IF; + END IF; + IF execOPC='1' THEN + ea_data_OP1 <= '1'; + dest_hbits <= '1'; + source_lowbits <='1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + ELSE --pack, unpack + trap_illegal <= '1'; + trapmake <= '1'; + END IF; + ELSE --or + set_exec_OR <= '1'; + IF opcode(8)='1' THEN + write_back <= '1'; + END IF; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF execOPC='1' THEN + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + IF opcode(8)='1' THEN + ea_data_OP1 <= '1'; + ELSE + dest_hbits <= '1'; + source_lowbits <='1'; + IF opcode(3)='1' THEN + source_areg <= '1'; + END IF; + END IF; + END IF; + END IF; + +-- 1001, 1101 ----------------------------------------------------------------------- + WHEN "1001"|"1101" => --sub, add + set_exec_ADD <= '1'; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF opcode(8 downto 6)="011" THEN --adda.w, suba.w + datatype <= "01"; --Word + END IF; + IF execOPC='1' THEN + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + IF opcode(14)='0' THEN + setaddsub <= '0'; + END IF; + END IF; + IF opcode(8)='1' AND opcode(5 downto 4)="00" AND opcode(7 downto 6)/="11" THEN --addx, subx + use_XZFlag <= '1'; + IF opcode(3)='1' THEN + write_back <= '1'; + IF decodeOPC='1' THEN + set_direct_data <= '1'; + setstate <= "10"; + set_mem_addsub <= '1'; + presub <= '1'; + next_micro_state <= op_AxAy; + END IF; + END IF; + IF execOPC='1' THEN + ea_data_OP1 <= '1'; + dest_hbits <= '1'; + source_lowbits <='1'; + END IF; + ELSE --sub, add + IF opcode(8)='1' AND opcode(7 downto 6)/="11" THEN + write_back <= '1'; + END IF; + IF execOPC='1' THEN + IF opcode(7 downto 6)="11" THEN --adda, suba + no_Flags <= '1'; + dest_areg <='1'; + dest_hbits <= '1'; + source_lowbits <='1'; + IF opcode(3)='1' THEN + source_areg <= '1'; + END IF; + ELSE + IF opcode(8)='1' THEN + ea_data_OP1 <= '1'; + ELSE + dest_hbits <= '1'; + source_lowbits <='1'; + IF opcode(3)='1' THEN + source_areg <= '1'; + END IF; + END IF; + END IF; + END IF; + END IF; + +-- 1010 ---------------------------------------------------------------------------- + WHEN "1010" => --Trap 1010 + trap_1010 <= '1'; + trapmake <= '1'; +-- 1011 ---------------------------------------------------------------------------- + WHEN "1011" => --eor, cmp + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF opcode(8 downto 6)="011" THEN --cmpa.w + datatype <= "01"; --Word + set_exec_CPMAW <= '1'; + END IF; + IF opcode(8)='1' AND opcode(5 downto 3)="001" AND opcode(7 downto 6)/="11" THEN --cmpm + set_exec_CMP <= '1'; + IF decodeOPC='1' THEN + set_direct_data <= '1'; + setstate <= "10"; + set_mem_rega <= '1'; + postadd <= '1'; + next_micro_state <= cmpm; + END IF; + IF execOPC='1' THEN + ea_data_OP1 <= '1'; + setaddsub <= '0'; + END IF; + ELSE --sub, add + IF opcode(8)='1' AND opcode(7 downto 6)/="11" THEN --eor + set_exec_EOR <= '1'; + write_back <= '1'; + ELSE --cmp + set_exec_CMP <= '1'; + END IF; + + IF execOPC='1' THEN + IF opcode(8)='1' AND opcode(7 downto 6)/="11" THEN --eor + ea_data_OP1 <= '1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + ELSE --cmp + source_lowbits <='1'; + IF opcode(3)='1' THEN + source_areg <= '1'; + END IF; + IF opcode(7 downto 6)="11" THEN --cmpa + dest_areg <='1'; + END IF; + dest_hbits <= '1'; + setaddsub <= '0'; + END IF; + END IF; + END IF; + +-- 1100 ---------------------------------------------------------------------------- + WHEN "1100" => --and, exg + IF opcode(7 downto 6)="11" THEN --mulu, muls + IF opcode(5 downto 4)="00" THEN --Dn, An + regdirectsource <= '1'; + END IF; + IF (micro_state=idle AND nextpass='1') OR (opcode(5 downto 4)="00" AND decodeOPC='1') THEN + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul1; + END IF; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + IF execOPC='1' THEN + regwrena <= '1'; + END IF; + IF (micro_state/=idle AND nextpass='1') OR execOPC='1' THEN + dest_hbits <= '1'; + source_lowbits <='1'; + ELSE + datatype <= "01"; + END IF; + + ELSIF opcode(8)='1' AND opcode(5 downto 4)="00" THEN --exg, abcd + IF opcode(7 downto 6)="00" THEN --abcd + use_XZFlag <= '1'; +-- datatype <= "00"; --ist schon default + set_exec_ADD <= '1'; + set_exec_ABCD <= '1'; + IF opcode(3)='1' THEN + write_back <= '1'; + IF decodeOPC='1' THEN + set_direct_data <= '1'; + setstate <= "10"; + set_mem_addsub <= '1'; + presub <= '1'; + next_micro_state <= op_AxAy; + END IF; + END IF; + IF execOPC='1' THEN + ea_data_OP1 <= '1'; + dest_hbits <= '1'; + source_lowbits <='1'; + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + END IF; + ELSE --exg + datatype <= "10"; + regwrena <= '1'; + IF opcode(6)='1' AND opcode(3)='1' THEN + dest_areg <= '1'; + source_areg <= '1'; + END IF; + IF decodeOPC='1' THEN + set_mem_rega <= '1'; + exec_exg <= '1'; + ELSE + save_memaddr <= '1'; + dest_hbits <= '1'; + END IF; + END IF; + ELSE --and + set_exec_AND <= '1'; + IF opcode(8)='1' THEN + write_back <= '1'; + END IF; + IF decodeOPC='1' THEN + ea_build <= '1'; + END IF; + + IF execOPC='1' THEN + IF endOPC='1' THEN + Regwrena <= '1'; + END IF; + IF opcode(8)='1' THEN + ea_data_OP1 <= '1'; + ELSE + dest_hbits <= '1'; + source_lowbits <='1'; + IF opcode(3)='1' THEN + source_areg <= '1'; + END IF; + END IF; + END IF; + END IF; + +-- 1110 ---------------------------------------------------------------------------- + WHEN "1110" => --rotation + set_exec_ROT <= '1'; + IF opcode(7 downto 6)="11" THEN + datatype <= "01"; + rot_bits <= opcode(10 downto 9); + ea_data_OP1 <= '1'; + write_back <= '1'; + ELSE + rot_bits <= opcode(4 downto 3); + data_is_source <= '1'; + END IF; + + IF decodeOPC='1' THEN + IF opcode(7 downto 6)="11" THEN + ea_build <= '1'; + ELSE + IF opcode(5)='1' THEN + IF OP2out(5 downto 0)/="000000" THEN + set_rot_cnt <= OP2out(5 downto 0); + ELSE + set_rot_nop <= '1'; + END IF; + ELSE + set_rot_cnt(2 downto 0) <= opcode(11 downto 9); + IF opcode(11 downto 9)="000" THEN + set_rot_cnt(3) <='1'; + ELSE + set_rot_cnt(3) <='0'; + END IF; + END IF; + END IF; + END IF; + IF opcode(7 downto 6)/="11" THEN + IF execOPC='1' AND rot_nop='0' THEN + Regwrena <= '1'; + set_rot_cnt <= rot_cnt-1; + END IF; + END IF; + +-- ---------------------------------------------------------------------------- + WHEN OTHERS => + trap_1111 <= '1'; + trapmake <= '1'; + + END CASE; + +-- END PROCESS; + +----------------------------------------------------------------------------- +-- execute microcode +----------------------------------------------------------------------------- +--PROCESS (micro_state) +-- BEGIN + IF Z_error='1' THEN -- divu by zero + trapmake <= '1'; --wichtig f?r USP + IF trapd='0' THEN + writePC <= '1'; + END IF; + END IF; + + IF trapmake='1' AND trapd='0' THEN + next_micro_state <= trap1; + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + setstate <= "11"; + datatype <= "10"; + END IF; + + IF interrupt='1' THEN + next_micro_state <= int1; + setstate <= "10"; +-- datatype <= "01"; --wirkt sich auf Flags aus + END IF; + + IF reset='0' THEN + micro_state <= init1; + ELSIF rising_edge(clk) THEN + IF clkena='1' THEN + trapd <= trapmake; + IF fetchOPC='1' THEN + micro_state <= idle; + ELSE + micro_state <= next_micro_state; + END IF; + END IF; + END IF; + CASE micro_state IS + WHEN ld_nn => -- (nnnn).w/l=> + get_ea_now <='1'; + setnextpass <= '1'; + setaddrlong <= '1'; + + WHEN st_nn => -- =>(nnnn).w/l + setstate <= "11"; + setaddrlong <= '1'; + next_micro_state <= nop; + + WHEN ld_dAn1 => -- d(An)=>, --d(PC)=> + setstate <= "01"; + next_micro_state <= ld_dAn2; + WHEN ld_dAn2 => -- d(An)=>, --d(PC)=> + get_ea_now <='1'; + setdisp <= '1'; --word + setnextpass <= '1'; + + WHEN ld_AnXn1 => -- d(An,Xn)=>, --d(PC,Xn)=> + setstate <= "01"; + next_micro_state <= ld_AnXn2; + WHEN ld_AnXn2 => -- d(An,Xn)=>, --d(PC,Xn)=> + setdisp <= '1'; --byte + setdispbyte <= '1'; + setstate <= "01"; + setbriefext <= '1'; + next_micro_state <= ld_AnXn3; + WHEN ld_AnXn3 => + get_ea_now <='1'; + setdisp <= '1'; --brief + setdispbrief <= '1'; + setnextpass <= '1'; + + WHEN st_dAn1 => -- =>d(An) + setstate <= "01"; + next_micro_state <= st_dAn2; + WHEN st_dAn2 => -- =>d(An) + setstate <= "11"; + setdisp <= '1'; --word + next_micro_state <= nop; + + WHEN st_AnXn1 => -- =>d(An,Xn) + setstate <= "01"; + next_micro_state <= st_AnXn2; + WHEN st_AnXn2 => -- =>d(An,Xn) + setdisp <= '1'; --byte + setdispbyte <= '1'; + setstate <= "01"; + setbriefext <= '1'; + next_micro_state <= st_AnXn3; + WHEN st_AnXn3 => + setstate <= "11"; + setdisp <= '1'; --brief + setdispbrief <= '1'; + next_micro_state <= nop; + + WHEN bra1 => --bra + IF condition='1' THEN + TG68_PC_br8 <= '1'; --pc+0000 + setstate <= "01"; + next_micro_state <= bra2; + END IF; + WHEN bra2 => --bra + TG68_PC_brw <= '1'; + + WHEN bsr1 => --bsr + set_TG68_PC_dec <= '1'; --in 2 Takten -2 + setstate <= "01"; + next_micro_state <= bsr2; + WHEN bsr2 => --bsr + IF TG68_PC_dec(0)='1' THEN + TG68_PC_brw <= '1'; + ELSE + TG68_PC_br8 <= '1'; + END IF; + writePC <= '1'; + setstate <= "11"; + next_micro_state <= nop; + + WHEN dbcc1 => --dbcc + TG68_PC_nop <= '1'; + setstate <= "01"; + next_micro_state <= dbcc2; + WHEN dbcc2 => --dbcc + TG68_PC_brw <= '1'; + + WHEN movem => --movem + set_movem_busy <='1'; + setstate <= "10"; + + WHEN andi => --andi + IF opcode(5 downto 4)/="00" THEN + ea_build <= '1'; + setnextpass <= '1'; + END IF; + + WHEN op_AxAy => -- op -(Ax),-(Ay) + presub <= '1'; + dest_hbits <= '1'; + dest_areg <= '1'; + set_mem_addsub <= '1'; + setstate <= "10"; + + WHEN cmpm => -- cmpm (Ay)+,(Ax)+ + postadd <= '1'; + dest_hbits <= '1'; + dest_areg <= '1'; + set_mem_rega <= '1'; + setstate <= "10"; + + WHEN link => -- link + setstate <="11"; + save_memaddr <= '1'; + regwrena <= '1'; + + WHEN int1 => -- interrupt + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + setstate <= "11"; + datatype <= "10"; + next_micro_state <= int2; + WHEN int2 => -- interrupt + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + setstate <= "11"; + datatype <= "01"; + writeSR <= '1'; + next_micro_state <= int3; + WHEN int3 => -- interrupt + set_vectoraddr <= '1'; + datatype <= "10"; + set_directPC <= '1'; + setstate <= "10"; + next_micro_state <= int4; + WHEN int4 => -- interrupt + datatype <= "10"; + + WHEN rte => -- RTE + datatype <= "10"; + setstate <= "10"; + postadd <= '1'; + setstackaddr <= '1'; + set_mem_rega <= '1'; + set_directPC <= '1'; + next_micro_state <= nop; + + WHEN trap1 => -- TRAP + presub <= '1'; + setstackaddr <='1'; + set_mem_addsub <= '1'; + setstate <= "11"; + datatype <= "01"; + writeSR <= '1'; + next_micro_state <= trap2; + WHEN trap2 => -- TRAP + set_vectoraddr <= '1'; + datatype <= "10"; + set_directPC <= '1'; +-- longreaddirect <= '1'; + setstate <= "10"; + next_micro_state <= trap3; + WHEN trap3 => -- TRAP + datatype <= "10"; + + WHEN movep1 => -- MOVEP d(An) + setstate <= "01"; + IF opcode(6)='1' THEN + set_movepl <= '1'; + END IF; + next_micro_state <= movep2; + WHEN movep2 => + setdisp <= '1'; + IF opcode(7)='0' THEN + setstate <= "10"; + ELSE + setstate <= "11"; + wait_mem_byte <= '1'; + END IF; + next_micro_state <= movep3; + WHEN movep3 => + IF opcode(6)='1' THEN + set_movepw <= '1'; + next_micro_state <= movep4; + END IF; + IF opcode(7)='0' THEN + setstate <= "10"; + ELSE + setstate <= "11"; + END IF; + WHEN movep4 => + IF opcode(7)='0' THEN + setstate <= "10"; + ELSE + wait_mem_byte <= '1'; + setstate <= "11"; + END IF; + next_micro_state <= movep5; + WHEN movep5 => + IF opcode(7)='0' THEN + setstate <= "10"; + ELSE + setstate <= "11"; + END IF; + + WHEN init1 => -- init SP + longreaddirect <= '1'; + next_micro_state <= init2; + WHEN init2 => -- init PC + get_ea_now <='1'; --\ + ea_only <= '1'; --- OP1in <= memaddr_in + setaddrlong <= '1'; -- memaddr_in <= data_read + regwrena <= '1'; + setstackaddr <='1'; -- dest_addr <= SP + set_directPC <= '1'; + longreaddirect <= '1'; + next_micro_state <= nop; + + WHEN mul1 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul2; + WHEN mul2 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul3; + WHEN mul3 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul4; + WHEN mul4 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul5; + WHEN mul5 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul6; + WHEN mul6 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul7; + WHEN mul7 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul8; + WHEN mul8 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul9; + WHEN mul9 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul10; + WHEN mul10 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul11; + WHEN mul11 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul12; + WHEN mul12 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul13; + WHEN mul13 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul14; + WHEN mul14 => -- mulu + set_exec_MULU <= '1'; + setstate <="01"; + next_micro_state <= mul15; + WHEN mul15 => -- mulu + set_exec_MULU <= '1'; + + WHEN div1 => -- divu + IF OP2out(15 downto 0)=x"0000" THEN --div zero + set_Z_error <= '1'; + ELSE + set_exec_DIVU <= '1'; + next_micro_state <= div2; + END IF; + setstate <="01"; + WHEN div2 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div3; + WHEN div3 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div4; + WHEN div4 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div5; + WHEN div5 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div6; + WHEN div6 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div7; + WHEN div7 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div8; + WHEN div8 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div9; + WHEN div9 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div10; + WHEN div10 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div11; + WHEN div11 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div12; + WHEN div12 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div13; + WHEN div13 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div14; + WHEN div14 => -- divu + set_exec_DIVU <= '1'; + setstate <="01"; + next_micro_state <= div15; + WHEN div15 => -- divu + set_exec_DIVU <= '1'; + + WHEN OTHERS => null; + END CASE; + END PROCESS; + +----------------------------------------------------------------------------- +-- Conditions +----------------------------------------------------------------------------- +PROCESS (opcode, Flags) + BEGIN + CASE opcode(11 downto 8) IS + WHEN X"0" => condition <= '1'; + WHEN X"1" => condition <= '0'; + WHEN X"2" => condition <= NOT Flags(0) AND NOT Flags(2); + WHEN X"3" => condition <= Flags(0) OR Flags(2); + WHEN X"4" => condition <= NOT Flags(0); + WHEN X"5" => condition <= Flags(0); + WHEN X"6" => condition <= NOT Flags(2); + WHEN X"7" => condition <= Flags(2); + WHEN X"8" => condition <= NOT Flags(1); + WHEN X"9" => condition <= Flags(1); + WHEN X"a" => condition <= NOT Flags(3); + WHEN X"b" => condition <= Flags(3); + WHEN X"c" => condition <= (Flags(3) AND Flags(1)) OR (NOT Flags(3) AND NOT Flags(1)); + WHEN X"d" => condition <= (Flags(3) AND NOT Flags(1)) OR (NOT Flags(3) AND Flags(1)); + WHEN X"e" => condition <= (Flags(3) AND Flags(1) AND NOT Flags(2)) OR (NOT Flags(3) AND NOT Flags(1) AND NOT Flags(2)); + WHEN X"f" => condition <= (Flags(3) AND NOT Flags(1)) OR (NOT Flags(3) AND Flags(1)) OR Flags(2); + WHEN OTHERS => null; + END CASE; + END PROCESS; + +----------------------------------------------------------------------------- +-- Bits +----------------------------------------------------------------------------- +PROCESS (opcode, OP1out, OP2out, one_bit_in, one_bit_out, bit_Number, bit_number_reg) + BEGIN + CASE opcode(7 downto 6) IS + WHEN "00" => --btst + one_bit_out <= one_bit_in; + WHEN "01" => --bchg + one_bit_out <= NOT one_bit_in; + WHEN "10" => --bclr + one_bit_out <= '0'; + WHEN "11" => --bset + one_bit_out <= '1'; + WHEN OTHERS => null; + END CASE; + + IF opcode(8)='0' THEN + IF opcode(5 downto 4)="00" THEN + bit_number <= bit_number_reg(4 downto 0); + ELSE + bit_number <= "00"&bit_number_reg(2 downto 0); + END IF; + ELSE + IF opcode(5 downto 4)="00" THEN + bit_number <= OP2out(4 downto 0); + ELSE + bit_number <= "00"&OP2out(2 downto 0); + END IF; + END IF; + + bits_out <= OP1out; + CASE bit_Number IS + WHEN "00000" => one_bit_in <= OP1out(0); + bits_out(0) <= one_bit_out; + WHEN "00001" => one_bit_in <= OP1out(1); + bits_out(1) <= one_bit_out; + WHEN "00010" => one_bit_in <= OP1out(2); + bits_out(2) <= one_bit_out; + WHEN "00011" => one_bit_in <= OP1out(3); + bits_out(3) <= one_bit_out; + WHEN "00100" => one_bit_in <= OP1out(4); + bits_out(4) <= one_bit_out; + WHEN "00101" => one_bit_in <= OP1out(5); + bits_out(5) <= one_bit_out; + WHEN "00110" => one_bit_in <= OP1out(6); + bits_out(6) <= one_bit_out; + WHEN "00111" => one_bit_in <= OP1out(7); + bits_out(7) <= one_bit_out; + WHEN "01000" => one_bit_in <= OP1out(8); + bits_out(8) <= one_bit_out; + WHEN "01001" => one_bit_in <= OP1out(9); + bits_out(9) <= one_bit_out; + WHEN "01010" => one_bit_in <= OP1out(10); + bits_out(10) <= one_bit_out; + WHEN "01011" => one_bit_in <= OP1out(11); + bits_out(11) <= one_bit_out; + WHEN "01100" => one_bit_in <= OP1out(12); + bits_out(12) <= one_bit_out; + WHEN "01101" => one_bit_in <= OP1out(13); + bits_out(13) <= one_bit_out; + WHEN "01110" => one_bit_in <= OP1out(14); + bits_out(14) <= one_bit_out; + WHEN "01111" => one_bit_in <= OP1out(15); + bits_out(15) <= one_bit_out; + WHEN "10000" => one_bit_in <= OP1out(16); + bits_out(16) <= one_bit_out; + WHEN "10001" => one_bit_in <= OP1out(17); + bits_out(17) <= one_bit_out; + WHEN "10010" => one_bit_in <= OP1out(18); + bits_out(18) <= one_bit_out; + WHEN "10011" => one_bit_in <= OP1out(19); + bits_out(19) <= one_bit_out; + WHEN "10100" => one_bit_in <= OP1out(20); + bits_out(20) <= one_bit_out; + WHEN "10101" => one_bit_in <= OP1out(21); + bits_out(21) <= one_bit_out; + WHEN "10110" => one_bit_in <= OP1out(22); + bits_out(22) <= one_bit_out; + WHEN "10111" => one_bit_in <= OP1out(23); + bits_out(23) <= one_bit_out; + WHEN "11000" => one_bit_in <= OP1out(24); + bits_out(24) <= one_bit_out; + WHEN "11001" => one_bit_in <= OP1out(25); + bits_out(25) <= one_bit_out; + WHEN "11010" => one_bit_in <= OP1out(26); + bits_out(26) <= one_bit_out; + WHEN "11011" => one_bit_in <= OP1out(27); + bits_out(27) <= one_bit_out; + WHEN "11100" => one_bit_in <= OP1out(28); + bits_out(28) <= one_bit_out; + WHEN "11101" => one_bit_in <= OP1out(29); + bits_out(29) <= one_bit_out; + WHEN "11110" => one_bit_in <= OP1out(30); + bits_out(30) <= one_bit_out; + WHEN "11111" => one_bit_in <= OP1out(31); + bits_out(31) <= one_bit_out; + WHEN OTHERS => null; + END CASE; + END PROCESS; + +----------------------------------------------------------------------------- +-- Rotation +----------------------------------------------------------------------------- +PROCESS (opcode, OP1out, Flags, rot_bits, rot_msb, rot_lsb, rot_rot, rot_nop) + BEGIN + CASE opcode(7 downto 6) IS + WHEN "00" => --Byte + rot_rot <= OP1out(7); + WHEN "01"|"11" => --Word + rot_rot <= OP1out(15); + WHEN "10" => --Long + rot_rot <= OP1out(31); + WHEN OTHERS => null; + END CASE; + + CASE rot_bits IS + WHEN "00" => --ASL, ASR + rot_lsb <= '0'; + rot_msb <= rot_rot; + WHEN "01" => --LSL, LSR + rot_lsb <= '0'; + rot_msb <= '0'; + WHEN "10" => --ROXL, ROXR + rot_lsb <= Flags(4); + rot_msb <= Flags(4); + WHEN "11" => --ROL, ROR + rot_lsb <= rot_rot; + rot_msb <= OP1out(0); + WHEN OTHERS => null; + END CASE; + + IF rot_nop='1' THEN + rot_out <= OP1out; + rot_XC <= Flags(0); + ELSE + IF opcode(8)='1' THEN --left + rot_out <= OP1out(30 downto 0)&rot_lsb; + rot_XC <= rot_rot; + ELSE --right + rot_XC <= OP1out(0); + rot_out <= rot_msb&OP1out(31 downto 1); + CASE opcode(7 downto 6) IS + WHEN "00" => --Byte + rot_out(7) <= rot_msb; + WHEN "01"|"11" => --Word + rot_out(15) <= rot_msb; + WHEN OTHERS => + END CASE; + END IF; + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- MULU/MULS +----------------------------------------------------------------------------- +PROCESS (clk, opcode, OP2out, muls_msb, mulu_reg, OP1sign, sign2) + BEGIN + IF rising_edge(clk) THEN + IF clkena='1' THEN + IF decodeOPC='1' THEN + IF opcode(8)='1' AND reg_QB(15)='1' THEN --MULS Neg faktor + OP1sign <= '1'; + mulu_reg <= "0000000000000000"&(0-reg_QB(15 downto 0)); + ELSE + OP1sign <= '0'; + mulu_reg <= "0000000000000000"®_QB(15 downto 0); + END IF; + ELSIF exec_MULU='1' THEN + mulu_reg <= dummy_mulu; + END IF; + END IF; + END IF; + + IF (opcode(8)='1' AND OP2out(15)='1') OR OP1sign='1' THEN + muls_msb <= mulu_reg(31); + ELSE + muls_msb <= '0'; + END IF; + + IF opcode(8)='1' AND OP2out(15)='1' THEN + sign2 <= '1'; + ELSE + sign2 <= '0'; + END IF; + + IF mulu_reg(0)='1' THEN + IF OP1sign='1' THEN + dummy_mulu <= (muls_msb&mulu_reg(31 downto 16))-(sign2&OP2out(15 downto 0))& mulu_reg(15 downto 1); + ELSE + dummy_mulu <= (muls_msb&mulu_reg(31 downto 16))+(sign2&OP2out(15 downto 0))& mulu_reg(15 downto 1); + END IF; + ELSE + dummy_mulu <= muls_msb&mulu_reg(31 downto 1); + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- DIVU +----------------------------------------------------------------------------- +PROCESS (clk, execOPC, opcode, OP1out, OP2out, div_reg, dummy_div_sub, div_quot, div_sign, dummy_div_over, dummy_div) + BEGIN + set_V_Flag <= '0'; + + IF rising_edge(clk) THEN + IF clkena='1' THEN + IF decodeOPC='1' THEN + IF opcode(8)='1' AND reg_QB(31)='1' THEN -- Neg divisor + div_sign <= '1'; + div_reg <= 0-reg_QB; + ELSE + div_sign <= '0'; + div_reg <= reg_QB; + END IF; + ELSIF exec_DIVU='1' THEN + div_reg <= div_quot; + END IF; + END IF; + END IF; + + dummy_div_over <= ('0'&OP1out(31 downto 16))-('0'&OP2out(15 downto 0)); + + IF opcode(8)='1' AND OP2out(15) ='1' THEN + dummy_div_sub <= (div_reg(31 downto 15))+('1'&OP2out(15 downto 0)); + ELSE + dummy_div_sub <= (div_reg(31 downto 15))-('0'&OP2out(15 downto 0)); + END IF; + + IF (dummy_div_sub(16))='1' THEN + div_quot(31 downto 16) <= div_reg(30 downto 15); + ELSE + div_quot(31 downto 16) <= dummy_div_sub(15 downto 0); + END IF; + + div_quot(15 downto 0) <= div_reg(14 downto 0)&NOT dummy_div_sub(16); + + IF execOPC='1' AND opcode(8)='1' AND (OP2out(15) XOR div_sign)='1' THEN + dummy_div(15 downto 0) <= 0-div_quot(15 downto 0); + ELSE + dummy_div(15 downto 0) <= div_quot(15 downto 0); + END IF; + + IF div_sign='1' THEN + dummy_div(31 downto 16) <= 0-div_quot(31 downto 16); + ELSE + dummy_div(31 downto 16) <= div_quot(31 downto 16); + END IF; + + IF (opcode(8)='1' AND (OP2out(15) XOR div_sign XOR dummy_div(15))='1' AND dummy_div(15 downto 0)/=X"0000") --Overflow DIVS + OR (opcode(8)='0' AND dummy_div_over(16)='0') THEN --Overflow DIVU + set_V_Flag <= '1'; + END IF; + END PROCESS; + +----------------------------------------------------------------------------- +-- Movem +----------------------------------------------------------------------------- +PROCESS (reset, clk, movem_mask, movem_muxa ,movem_muxb, movem_muxc) + BEGIN + IF movem_mask(7 downto 0)="00000000" THEN + movem_muxa <= movem_mask(15 downto 8); + movem_regaddr(3) <= '1'; + ELSE + movem_muxa <= movem_mask(7 downto 0); + movem_regaddr(3) <= '0'; + END IF; + IF movem_muxa(3 downto 0)="0000" THEN + movem_muxb <= movem_muxa(7 downto 4); + movem_regaddr(2) <= '1'; + ELSE + movem_muxb <= movem_muxa(3 downto 0); + movem_regaddr(2) <= '0'; + END IF; + IF movem_muxb(1 downto 0)="00" THEN + movem_muxc <= movem_muxb(3 downto 2); + movem_regaddr(1) <= '1'; + ELSE + movem_muxc <= movem_muxb(1 downto 0); + movem_regaddr(1) <= '0'; + END IF; + IF movem_muxc(0)='0' THEN + movem_regaddr(0) <= '1'; + ELSE + movem_regaddr(0) <= '0'; + END IF; + + movem_bits <= ("0000"&movem_mask(0))+("0000"&movem_mask(1))+("0000"&movem_mask(2))+("0000"&movem_mask(3))+ + ("0000"&movem_mask(4))+("0000"&movem_mask(5))+("0000"&movem_mask(6))+("0000"&movem_mask(7))+ + ("0000"&movem_mask(8))+("0000"&movem_mask(9))+("0000"&movem_mask(10))+("0000"&movem_mask(11))+ + ("0000"&movem_mask(12))+("0000"&movem_mask(13))+("0000"&movem_mask(14))+("0000"&movem_mask(15)); + + IF reset = '0' THEN + movem_busy <= '0'; + movem_addr <= '0'; + maskzero <= '0'; + ELSIF rising_edge(clk) THEN + IF clkena_in='1' AND get_movem_mask='1' THEN + movem_mask <= data_read(15 downto 0); + END IF; + IF clkena_in='1' AND test_maskzero='1' THEN + IF movem_mask=X"0000" THEN + maskzero <= '1'; + END IF; + END IF; + IF clkena_in='1' AND endOPC='1' THEN + maskzero <= '0'; + END IF; + IF clkena='1' THEN + IF set_movem_busy='1' THEN + IF movem_bits(4 downto 1) /= "0000" OR opcode(10)='0' THEN + movem_busy <= '1'; + END IF; + movem_addr <= '1'; + END IF; + IF movem_addr='1' THEN + CASE movem_regaddr IS + WHEN "0000" => movem_mask(0) <= '0'; + WHEN "0001" => movem_mask(1) <= '0'; + WHEN "0010" => movem_mask(2) <= '0'; + WHEN "0011" => movem_mask(3) <= '0'; + WHEN "0100" => movem_mask(4) <= '0'; + WHEN "0101" => movem_mask(5) <= '0'; + WHEN "0110" => movem_mask(6) <= '0'; + WHEN "0111" => movem_mask(7) <= '0'; + WHEN "1000" => movem_mask(8) <= '0'; + WHEN "1001" => movem_mask(9) <= '0'; + WHEN "1010" => movem_mask(10) <= '0'; + WHEN "1011" => movem_mask(11) <= '0'; + WHEN "1100" => movem_mask(12) <= '0'; + WHEN "1101" => movem_mask(13) <= '0'; + WHEN "1110" => movem_mask(14) <= '0'; + WHEN "1111" => movem_mask(15) <= '0'; + WHEN OTHERS => null; + END CASE; + IF opcode(10)='1' THEN + IF movem_bits="00010" OR movem_bits="00001" OR movem_bits="00000" THEN + movem_busy <= '0'; + END IF; + END IF; + IF movem_bits="00001" OR movem_bits="00000" THEN + movem_busy <= '0'; + movem_addr <= '0'; + END IF; + END IF; + END IF; + END IF; + END PROCESS; +END; + \ No newline at end of file diff --git a/cores/plus_too/addrController_top.v b/cores/plus_too/addrController_top.v new file mode 100644 index 0000000..8df5529 --- /dev/null +++ b/cores/plus_too/addrController_top.v @@ -0,0 +1,161 @@ +module addrController_top( + // clocks: + input clk8, // 8.125 MHz CPU clock + + // system config: + input configROMSize, // 0 = 64K ROM, 1 = 128K ROM + input [1:0] configRAMSize, // 0 = 128K, 1 = 512K, 2 = 1MB, 3 = 4MB RAM + + // 68000 CPU memory interface: + input [23:0] cpuAddr, + input _cpuAS, + input _cpuUDS, + input _cpuLDS, + input _cpuRW, + output _cpuDTACK, + + // RAM/ROM: + output [21:0] memoryAddr, + output _memoryUDS, + output _memoryLDS, + output _romCS, + output _romOE, + output _romWE, + output _ramCS, + output _ramOE, + output _ramWE, + output videoBusControl, + + // peripherals: + output selectSCC, + output selectIWM, + output selectVIA, + output selectInterruptVectors, + + // video: + output hsync, + output vsync, + output _hblank, + output _vblank, + output loadNormalPixels, + output loadDebugPixels, + + // audio: + output loadSound, + + // misc + input memoryOverlayOn, + + // extra/debug ROM interface + input [21:0] extraRomReadAddr, + output extraRomReadAck +); + + // interleaved RAM access for CPU and video + reg [1:0] busCycle; + always @(posedge clk8) begin + busCycle <= busCycle + 1'b1; + end + // video controls memory bus during the first clock of the four-clock cycle + assign videoBusControl = busCycle == 2'b00; + + // DTACK generation + // TODO: delay DTACK for once full bus cycle when RAM is accessed, to match Mac Plus memory timing + // TODO: according to datasheet, /DTACK should continue to be asserted through the final bus cycle too + assign _cpuDTACK = ~(_cpuAS == 1'b0 && busCycle == 2'b10 && videoBusControl == 1'b0); + + // interconnects + wire selectRAM, selectROM; + wire [21:0] videoAddr; + + // RAM/ROM control signals + wire videoControlActive = _hblank == 1'b1 || loadSound; + assign _romCS = ~((videoBusControl == 1'b1 && videoControlActive == 1'b0) || (videoBusControl == 1'b0 && selectROM == 1'b1)); + assign _romOE = ~((videoBusControl == 1'b1 && videoControlActive == 1'b0) || (videoBusControl == 1'b0 && selectROM == 1'b1 && _cpuRW == 1'b1)); + assign _romWE = 1'b1; + assign _ramCS = ~((videoBusControl == 1'b1 && videoControlActive == 1'b1) || (videoBusControl == 1'b0 && selectRAM == 1'b1)); + assign _ramOE = ~((videoBusControl == 1'b1 && videoControlActive == 1'b1) || (videoBusControl == 1'b0 && selectRAM == 1'b1 && _cpuRW == 1'b1)); + assign _ramWE = ~(videoBusControl == 1'b0 && selectRAM && _cpuRW == 1'b0); + assign _memoryUDS = videoBusControl ? 1'b0 : _cpuUDS; + assign _memoryLDS = videoBusControl ? 1'b0 : _cpuLDS; + wire [21:0] addrMux = videoBusControl ? videoAddr : cpuAddr[21:0]; + wire [21:0] macAddr; + assign macAddr[15:0] = addrMux[15:0]; + + // simulate smaller RAM/ROM sizes + assign macAddr[16] = selectROM == 1'b1 && configROMSize == 1'b0 ? 1'b0 : // force A16 to 0 for 64K ROM access + addrMux[16]; + assign macAddr[17] = selectRAM == 1'b1 && configRAMSize == 2'b00 ? 1'b0 : // force A17 to 0 for 128K RAM access + selectROM == 1'b1 && configROMSize == 1'b1 ? 1'b0 : // force A17 to 0 for 128K ROM access + selectROM == 1'b1 && configROMSize == 1'b0 ? 1'b1 : // force A17 to 1 for 64K ROM access (64K ROM image is at $20000) + addrMux[17]; + assign macAddr[18] = selectRAM == 1'b1 && configRAMSize == 2'b00 ? 1'b0 : // force A18 to 0 for 128K RAM access + selectROM == 1'b1 ? 1'b0 : // force A18 to 0 for ROM access + addrMux[18]; + assign macAddr[19] = selectRAM == 1'b1 && configRAMSize[1] == 1'b0 ? 1'b0 : // force A19 to 0 for 128K or 512K RAM access + selectROM == 1'b1 ? 1'b0 : // force A19 to 0 for ROM access + addrMux[19]; + assign macAddr[20] = selectRAM == 1'b1 && configRAMSize != 2'b11 ? 1'b0 : // force A20 to 0 for all but 4MB RAM access + selectROM == 1'b1 ? 1'b0 : // force A20 to 0 for ROM access + addrMux[20]; + assign macAddr[21] = selectRAM == 1'b1 && configRAMSize != 2'b11 ? 1'b0 : // force A21 to 0 for all but 4MB RAM access + selectROM == 1'b1 ? 1'b0 : // force A21 to 0 for ROM access + addrMux[21]; + + assign extraRomReadAck = videoBusControl == 1'b1 && videoControlActive == 1'b0; + assign memoryAddr = videoBusControl == 1'b1 && videoControlActive == 1'b0 ? extraRomReadAddr : macAddr; + + // address decoding + wire selectSCCByAddress; + addrDecoder ad( + .address(cpuAddr), + .enable(!videoBusControl), + ._cpuAS(_cpuAS), + .memoryOverlayOn(memoryOverlayOn), + .selectRAM(selectRAM), + .selectROM(selectROM), + .selectSCC(selectSCCByAddress), + .selectIWM(selectIWM), + .selectVIA(selectVIA), + .selectInterruptVectors(selectInterruptVectors)); + + /* SCC register access is a mess. Reads and writes can have side-effects that alter the meaning of subsequent reads + and writes to the same address. It's not safe to do multiple reads of the same address, or multiple writes of the + same value to the same address. So we need to be sure we only perform one read or write per 4-clock CPU bus cycle. + + To complicate things, the CPU latches read data half-way through the last clock of the cycle, then deasserts the + address, address strobe, and data for the remainder of the cycle (although RW remains valid). This behavior may + be specified to TG68 and not shared by the real 68000. + + For writes to the SCC, we enable SCC only on clock 2, to guarantee one write per bus cycle. + + For reads, it's more difficult. If we enable SCC only on clock 2, then it won't be enabled during clock 3 when the + CPU latches the data, so the read will fail. If we enable it only on clock 3, then the AS won't be asserted all + the way to the end of the clock, so the read side-effect will fail. If we enable it on clock 2 and 3, then the + CPU will read the post-side-effect value instead of the pre-side-effect value. + + The solution used here is to enable reads on clock 2 (when the side-effect is performed), and for the first half + of clock 3, and to apply a one cycle delay to CPU data reads from the SCC. Reads only enable for the first half + of clock 3 in case a later 68000 variant continues to assert AS all the way to the end of the clock, to ensure + side-effects are not applied again. + + Another solution would be to create a custom clock for the SCC, whose positive edge is the negative edge of + clock 3 of the bus cycle. + */ + assign selectSCC = selectSCCByAddress && (busCycle == 2'b10 || // reads and writes enable on clock 2 + (_cpuRW == 1'b1 && busCycle == 2'b11 && clk8)); // reads enable on first half of clock 3 + + // video + videoTimer vt( + .clk8(clk8), + .busCycle(busCycle), + .videoAddr(videoAddr), + .hsync(hsync), + .vsync(vsync), + ._hblank(_hblank), + ._vblank(_vblank), + .loadNormalPixels(loadNormalPixels), + .loadDebugPixels(loadDebugPixels), + .loadSound(loadSound)); + +endmodule diff --git a/cores/plus_too/addrDecoder.v b/cores/plus_too/addrDecoder.v new file mode 100644 index 0000000..8b4da3d --- /dev/null +++ b/cores/plus_too/addrDecoder.v @@ -0,0 +1,134 @@ +/* + ($000000 - $03FFFF) RAM 4MB, or Overlay ROM 4MB + + ($400000 - $4FFFFF) ROM 1MB + 64K Mac 128K/512K ROM is $400000 - $40FFFF + 128K Mac 512Ke/Plus ROM is $400000 - $41FFFF + If ROM is mirrored when A17 is 1, then SCSI is assumed to be unavailable + + ($580000 - $580FFF) SCSI (Mac Plus only, not implemented here) + + ($600000 - $7FFFFF) Overlay RAM 2MB + + ($9FFFF8 - $BFFFFF) SCC + The SCC is on the upper byte of the data bus, so you must use only even-addressed byte reads. + When writing, you must use only odd-addressed byte writes (the MC68000 puts your data on both bytes of the bus, so it works correctly). + A byte read of an odd SCC read address tries to reset the entire SCC. + A word access to any SCC address will shift the phase of the computer's high-frequency timing by 128 ns. + + ($9FFFF8) SCC read channel B control + ($9FFFFA) SCC read channel A control + ($9FFFFC) SCC read channel B data in/out + ($9FFFFE) SCC read channel A data in/out + + ($BFFFF9) SCC write channel B control + ($BFFFFB) SCC write channel A control + ($BFFFFD) SCC write channel B data in/out + ($BFFFFF) SCC write channel A data in/out + + ($DFE1FF - $DFFFFF) IWM + The IWM is on the lower byte of the data bus, so use odd-addressed byte accesses only. + The 16 IWM registers are {8'hDF, 8'b111xxxx1, 8'hFF}: + 0 $0 ph0L CA0 off (0) + 1 $200 ph0H CA0 on (1) + 2 $400 ph1L CA1 off (0) + 3 $600 ph1H CA1 on (1) + 4 $800 h2L CA2 off (0) + 5 $A00 ph2H CA2 on (1) + 6 $C00 ph3L LSTRB off (low) + 7 $E00 ph3H LSTRB on (high) + 8 $1000 mtrOff disk enable off + 9 $1200 mtrOn disk enable on + 10 $1400 intDrive select internal drive + 11 $1600 extDrive select external drive + 12 $1800 q6L Q6 off + 13 $1A00 q6H Q6 on + 14 $1C00 q7L Q7 off, read register + 15 $1E00 q7H Q7 on, write register + + ($EFE1FE - $EFFFFE) VIA + The VIA is on the upper byte of the data bus, so use even-addressed byte accesses only. + The 16 VIA registers are {8'hEF, 8'b111xxxx1, 8'hFE}: + 0 $0 vBufB register B + 1 $200 ????? not used? + 2 $400 vDirB register B direction register + 3 $600 vDirA register A direction register + 4 $800 vT1C timer 1 counter (low-order byte) + 5 $A00 vT1CH timer 1 counter (high-order byte) + 6 $C00 vT1L timer 1 latch (low-order byte) + 7 $E00 vT1LH timer 1 latch (high-order byte) + 8 $1000 vT2C timer 2 counter (low-order byte) + 9 $1200 vT2CH timer 2 counter (high-order byte) + 10 $1400 vSR shift register (keyboard) + 11 $1600 vACR auxiliary control register + 12 $1800 vPCR peripheral control register + 13 $1A00 vIFR interrupt flag register + 14 $1C00 vIER interrupt enable register + 15 $1E00 vBufA register A + + ($F00000 - $F00005) memory phase read test + + ($F80000 - $FFFFEF) space for test software + + ($FFFFF0 - $FFFFFF) interrupt vectors + + Note: This can all be decoded using only the highest 4 address bits, if SCSI, phase read test, and test software are not used. + 7 other address bits are used by peripherals to determine which register to access: + A12-A9 - IWM and VIA + A2-A0 - SCC + +*/ + +module addrDecoder( + input [23:0] address, + input enable, + input _cpuAS, + input memoryOverlayOn, + output reg selectRAM, + output reg selectROM, + output reg selectSCC, + output reg selectIWM, + output reg selectVIA, + output reg selectInterruptVectors +); + + always @(*) begin + selectRAM = 0; + selectROM = 0; + selectSCC = 0; + selectIWM = 0; + selectVIA = 0; + selectInterruptVectors = 0; + + if (_cpuAS == 0 && enable == 1'b1) begin + casez (address[23:20]) + 4'b00??: begin + if (memoryOverlayOn == 0) + selectRAM = 1'b1; + else begin + if (address[23:20] == 0) begin + // Mac Plus: repeated images of overlay ROM only extend to $0F0000 + // Mac 512K: more repeated ROM images at $020000-$02FFFF + selectROM = 1'b1; + end + end + end + 4'b0100: + selectROM = 1'b1; + 4'b0110: + if (memoryOverlayOn) + selectRAM = 1'b1; + 4'b10?1: + selectSCC = 1'b1; + 4'b1101: + selectIWM = 1'b1; + 4'b1110: + selectVIA = 1'b1; + 4'b1111: + selectInterruptVectors = 1'b1; + default: + ; // select nothing + endcase + end + end +endmodule diff --git a/cores/plus_too/clock325MHz.qip b/cores/plus_too/clock325MHz.qip new file mode 100644 index 0000000..bf6a93b --- /dev/null +++ b/cores/plus_too/clock325MHz.qip @@ -0,0 +1,4 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "13.1" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "clock325MHz.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "clock325MHz.ppf"] diff --git a/cores/plus_too/clock325MHz.v b/cores/plus_too/clock325MHz.v new file mode 100644 index 0000000..dff1eae --- /dev/null +++ b/cores/plus_too/clock325MHz.v @@ -0,0 +1,365 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: clock325MHz.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.4 Build 182 03/12/2014 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2014 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module clock325MHz ( + inclk0, + c0, + c1, + c2, + locked); + + input inclk0; + output c0; + output c1; + output c2; + output locked; + + wire [4:0] sub_wire0; + wire sub_wire2; + wire [0:0] sub_wire7 = 1'h0; + wire [2:2] sub_wire4 = sub_wire0[2:2]; + wire [0:0] sub_wire3 = sub_wire0[0:0]; + wire [1:1] sub_wire1 = sub_wire0[1:1]; + wire c1 = sub_wire1; + wire locked = sub_wire2; + wire c0 = sub_wire3; + wire c2 = sub_wire4; + wire sub_wire5 = inclk0; + wire [1:0] sub_wire6 = {sub_wire7, sub_wire5}; + + altpll altpll_component ( + .inclk (sub_wire6), + .clk (sub_wire0), + .locked (sub_wire2), + .activeclock (), + .areset (1'b0), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.bandwidth_type = "AUTO", + altpll_component.clk0_divide_by = 54, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 65, + altpll_component.clk0_phase_shift = "0", + altpll_component.clk1_divide_by = 27, + altpll_component.clk1_duty_cycle = 50, + altpll_component.clk1_multiply_by = 130, + altpll_component.clk1_phase_shift = "0", + altpll_component.clk2_divide_by = 27, + altpll_component.clk2_duty_cycle = 50, + altpll_component.clk2_multiply_by = 130, + altpll_component.clk2_phase_shift = "-2500", + altpll_component.compensate_clock = "CLK0", + altpll_component.inclk0_input_frequency = 37037, + altpll_component.intended_device_family = "Cyclone III", + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=clock325MHz", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.pll_type = "AUTO", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_UNUSED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_USED", + altpll_component.port_clk2 = "PORT_USED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.self_reset_on_loss_lock = "OFF", + altpll_component.width_clock = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "1" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "54" +// Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "1" +// Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "1" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "32.500000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "130.000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "130.000000" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "27.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "ps" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "65" +// Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "1" +// Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "1" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "32.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "130.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "130.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "-2500.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "ps" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "clock325MHz.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.000" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK2 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLK1 STRING "1" +// Retrieval info: PRIVATE: USE_CLK2 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA2 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "54" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "65" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK1_DIVIDE_BY NUMERIC "27" +// Retrieval info: CONSTANT: CLK1_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK1_MULTIPLY_BY NUMERIC "130" +// Retrieval info: CONSTANT: CLK1_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: CLK2_DIVIDE_BY NUMERIC "27" +// Retrieval info: CONSTANT: CLK2_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK2_MULTIPLY_BY NUMERIC "130" +// Retrieval info: CONSTANT: CLK2_PHASE_SHIFT STRING "-2500" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PLL_TYPE STRING "AUTO" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: SELF_RESET_ON_LOSS_LOCK STRING "OFF" +// Retrieval info: CONSTANT: WIDTH_CLOCK NUMERIC "5" +// Retrieval info: USED_PORT: @clk 0 0 5 0 OUTPUT_CLK_EXT VCC "@clk[4..0]" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" +// Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 +// Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz_bb.v FALSE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/cores/plus_too/clock325MHz_bb.v b/cores/plus_too/clock325MHz_bb.v new file mode 100644 index 0000000..63303af --- /dev/null +++ b/cores/plus_too/clock325MHz_bb.v @@ -0,0 +1,194 @@ +// megafunction wizard: %ALTPLL%VBB% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: clock325MHz.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 11.0 Build 157 04/27/2011 SJ Web Edition +// ************************************************************ + +//Copyright (C) 1991-2011 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + +module clock325MHz ( + inclk0, + c0); + + input inclk0; + output c0; + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_CUSTOM STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "1" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "20" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "32.500000" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "50.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "0" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "13" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "100.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "0" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "clock325MHz.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "20" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "13" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: USED_PORT: @clk 0 0 6 0 OUTPUT_CLK_EXT VCC "@clk[5..0]" +// Retrieval info: USED_PORT: @extclk 0 0 4 0 OUTPUT_CLK_EXT VCC "@extclk[3..0]" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL clock325MHz_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/cores/plus_too/dataController_top.v b/cores/plus_too/dataController_top.v new file mode 100644 index 0000000..16788a9 --- /dev/null +++ b/cores/plus_too/dataController_top.v @@ -0,0 +1,205 @@ +module dataController_top( + // clocks: + input clk32, // 32.5 MHz pixel clock + input clk8, // 8.125 MHz CPU clock + output clk8out, // this module generates the 8.125MHz clock used for itself and other modules + + // system control: + input _systemReset, + + // 68000 CPU control: + output _cpuReset, + output [2:0] _cpuIPL, + + // 68000 CPU memory interface: + input [15:0] cpuDataIn, + input [3:0] cpuAddrRegHi, // A12-A9 + input [1:0] cpuAddrRegLo, // A2-A1 + input _cpuUDS, + input _cpuLDS, + input _cpuRW, + output [15:0] cpuDataOut, + output cpuDriveData, + + // peripherals: + input selectSCC, + input selectIWM, + input selectVIA, + input selectInterruptVectors, + + // RAM/ROM: + input videoBusControl, + input [15:0] memoryDataIn, + output [15:0] memoryDataOut, + output memoryDriveData, + + // keyboard: + input keyClk, // need pull-up + input keyData, // need pull-up + + // mouse: + inout mouseClk, // need pull-up + inout mouseData, // need pull-up + + // serial: + input serialIn, // need pull-up + output serialOut, + + // video: + output pixelOut, + input _hblank, + input _vblank, + input loadPixels, + + // audio: + input loadSound, + output sound, + + // debugging: + input interruptButton, + + // misc + output memoryOverlayOn, + input [1:0] insertDisk, + output [1:0] diskInDrive, + + output [21:0] extraRomReadAddr, + input extraRomReadAck +); + + // divide 32.5 MHz clock by four to get CPU clock + reg [1:0] clkPhase; + always @(posedge clk32) begin + clkPhase <= clkPhase + 1'b1; + end + assign clk8out = clkPhase[1]; + + // CPU reset generation + // For initial CPU reset, RESET and HALT must be asserted for at least 100ms = 800,000 clocks of clk8 + reg [19:0] resetDelay; // 20 bits = 1 million + wire isResetting = resetDelay != 0; + + initial begin + // force a reset when the FPGA configuration is completed + resetDelay <= 20'hFFFFF; + end + + always @(posedge clk8 or negedge _systemReset) begin + if (_systemReset == 1'b0) begin + resetDelay <= 20'hFFFFF; + end + else if (isResetting) begin + resetDelay <= resetDelay - 1'b1; + end + end + assign _cpuReset = isResetting ? 1'b0 : 1'b1; + + // interconnects + wire SEL; + wire _viaIrq, _sccIrq, sccWReq; + wire [15:0] viaDataOut; + wire [15:0] iwmDataOut; + wire [7:0] sccDataOut; + wire mouseX1, mouseX2, mouseY1, mouseY2, mouseButton; + + // interrupt control + assign _cpuIPL = { interruptButton, _sccIrq, ~(_sccIrq & ~_viaIrq) }; + + // Sound + assign sound = 0; + + // Serial port + assign serialOut = 0; + + // CPU-side data output mux + assign cpuDataOut = selectIWM ? iwmDataOut : + selectVIA ? viaDataOut : + selectSCC ? { sccDataOutDelayed, 8'hEF } : + selectInterruptVectors ? { 13'h3, cpuAddrRegLo } : // use A3-A1 to construct an interrupt vector number offset from $18 + memoryDataIn; + assign cpuDriveData = _cpuRW == 1'b1; + + // Memory-side + assign memoryDataOut = cpuDataIn; + assign memoryDriveData = _cpuRW == 1'b0 && videoBusControl == 1'b0; + + // VIA + via v( + .clk8(clk8), + ._reset(_cpuReset), + .selectVIA(selectVIA), + ._cpuRW(_cpuRW), + ._cpuUDS(_cpuUDS), + .dataIn(cpuDataIn), + .cpuAddrRegHi(cpuAddrRegHi), + ._hblank(_hblank), + ._vblank(_vblank), + .mouseY2(mouseY2), + .mouseX2(mouseX2), + .mouseButton(mouseButton), + .sccWReq(sccWReq), + ._irq(_viaIrq), + .dataOut(viaDataOut), + .memoryOverlayOn(memoryOverlayOn), + .SEL(SEL)); + + // IWM + iwm i( + .clk8(clk8), + ._reset(_cpuReset), + .selectIWM(selectIWM), + ._cpuRW(_cpuRW), + ._cpuLDS(_cpuLDS), + .dataIn(cpuDataIn), + .cpuAddrRegHi(cpuAddrRegHi), + .SEL(SEL), + .dataOut(iwmDataOut), + .insertDisk(insertDisk), + .diskInDrive(diskInDrive), + + .extraRomReadAddr(extraRomReadAddr), + .extraRomReadAck(extraRomReadAck), + .extraRomReadData(memoryDataIn[7:0])); + + // SCC + scc s( + .sysclk(clk8), + .reset_hw(~_cpuReset), + .cs(selectSCC && (_cpuLDS == 1'b0 || _cpuUDS == 1'b0)), + .we(~_cpuRW), + .rs(cpuAddrRegLo), + .wdata(cpuDataIn[15:8]), + .rdata(sccDataOut), + ._irq(_sccIrq), + .dcd_a(mouseX1), + .dcd_b(mouseY1), + .wreq(sccWReq)); + + // apply a one cycle delay to CPU data reads from the SCC: + // see comment about SCC register access in addrController_top.v + reg [7:0] sccDataOutDelayed; + always @(posedge clk8) begin + sccDataOutDelayed <= sccDataOut; + end + + // Video + videoShifter vs( + .clk32(clk32), + .clkPhase(clkPhase), + .dataIn(memoryDataIn), + .loadPixels(loadPixels), + .pixelOut(pixelOut)); + + // Mouse + ps2_mouse mouse( + .sysclk(clk8), + .reset(~_cpuReset), + .ps2dat(mouseData), + .ps2clk(mouseClk), + .x1(mouseX1), + .y1(mouseY1), + .x2(mouseX2), + .y2(mouseY2), + .button(mouseButton)); + +endmodule diff --git a/cores/plus_too/data_io.v b/cores/plus_too/data_io.v new file mode 100644 index 0000000..c1a3ffc --- /dev/null +++ b/cores/plus_too/data_io.v @@ -0,0 +1,118 @@ +// +// data_io.v +// +// io controller writable ram for the MiST board +// https://github.com/mist-devel +// +// Copyright (c) 2015 Till Harbaum +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +module data_io ( + // io controller spi interface + input sck, + input ss, + input sdi, + + output downloading, // signal indicating an active download + output reg [4:0] index, // menu index used to upload the file + + // external ram interface + input clk, + output reg wr, + output reg [23:0] addr, + output reg [15:0] data +); + +// ********************************************************************************* +// spi client +// ********************************************************************************* + +// this core supports only the display related OSD commands +// of the minimig +reg [14:0] sbuf; +reg [7:0] cmd; +reg [4:0] cnt; +reg rclk; + +reg [23:0] laddr; +reg [15:0] ldata; + +localparam UIO_FILE_TX = 8'h53; +localparam UIO_FILE_TX_DAT = 8'h54; +localparam UIO_FILE_INDEX = 8'h55; + +assign downloading = downloading_reg; +reg downloading_reg = 1'b0; + +// data_io has its own SPI interface to the io controller +always@(posedge sck, posedge ss) begin + if(ss == 1'b1) + cnt <= 5'd0; + else begin + rclk <= 1'b0; + + // don't shift in last bit. It is evaluated directly + // when writing to ram + if(cnt != 23) + sbuf <= { sbuf[13:0], sdi}; + + // count 0-7 8-15 16-23 8-15 16-23 ... + if(cnt < 23) cnt <= cnt + 4'd1; + else cnt <= 4'd8; + + // finished command byte + if(cnt == 7) + cmd <= {sbuf[6:0], sdi}; + + // prepare/end transmission + if((cmd == UIO_FILE_TX) && (cnt == 15)) begin + // prepare + if(sdi) begin + // download rom to address 0 + laddr <= 24'h0 - 24'd1; + downloading_reg <= 1'b1; + end else + downloading_reg <= 1'b0; + end + + // command 0x54: UIO_FILE_TX + if((cmd == UIO_FILE_TX_DAT) && (cnt == 23)) begin + ldata <= {sbuf, sdi}; + laddr <= laddr + 24'd1; + rclk <= 1'b1; + end + + // expose file (menu) index + if((cmd == UIO_FILE_INDEX) && (cnt == 15)) + index <= {sbuf[3:0], sdi}; + end +end + +reg rclkD, rclkD2; +always@(posedge clk) begin + // bring all signals from spi clock domain into local clock domain + rclkD <= rclk; + rclkD2 <= rclkD; + wr <= 1'b0; + + if(rclkD && !rclkD2) begin + addr <= laddr; + data <= ldata; + wr <= 1'b1; + end +end + +endmodule diff --git a/cores/plus_too/debugPanel.v b/cores/plus_too/debugPanel.v new file mode 100644 index 0000000..5764f08 --- /dev/null +++ b/cores/plus_too/debugPanel.v @@ -0,0 +1,218 @@ +module debugPanel( + input clk8, + input [9:0] sw, + input [3:0] key, + input videoBusControl, + input loadNormalPixels, + input loadDebugPixels, + output loadPixelsOut, + input _dtackIn, + input [7:0] cpuAddrHi, + input [23:0] cpuAddr, + input _cpuRW, + input _cpuUDS, + input _cpuLDS, + input [15:0] dataControllerDataOut, + input [15:0] cpuDataOut, + input [21:0] memoryAddr, + output _dtackOut, + output [6:0] hex0, + output [6:0] hex1, + output [6:0] hex2, + output [6:0] hex3, + output driveDebugData, + output [15:0] debugDataOut, + input extraRomReadAck +); + + /* debug interface: + sw0 = run/stop_and_disable_interrupts + sw2-9 = data in + key0 = step + key1 = load breakpoint addr[7:0] + key2 = load breakpoint addr[15:8] + key3 = load breakpoint addr[23:16] + key0+key1 = reset + */ + + wire singleStep = sw[0]; + + // sample dataControllerDataOut only when CPU owns the bus + // use negative edge sample, since that's when the CPU latches data + reg [15:0] dataControllerDataOutSample; + always @(negedge clk8) begin + if (videoBusControl == 0) + dataControllerDataOutSample <= dataControllerDataOut; + end + + // store the previous address, sort of a previous instruction address + reg [23:0] previousAddr; + reg [23:0] currAddr; + always @(negedge clk8) begin + if (videoBusControl == 1'b0 && cpuAddr != currAddr) begin + previousAddr <= currAddr; + currAddr <= cpuAddr; + end + end + + reg [23:0] breakpointAddr = 24'hDABEEF; + always @(negedge clk8) begin + if (singleStep == 1'b1 && key[1] == 1'b0) + breakpointAddr[7:0] <= sw[9:2]; + else if (singleStep == 1'b1 && key[2] == 1'b0) + breakpointAddr[15:8] <= sw[9:2]; + else if (singleStep == 1'b1 && key[3] == 1'b0) + breakpointAddr[23:16] <= sw[9:2]; + end + + // find xy position for debug panel + assign driveDebugData = loadDebugPixels && (memoryAddr[16:0] < 17'h00200); + assign loadPixelsOut = loadNormalPixels | driveDebugData; + wire [4:0] pixX = memoryAddr[5:1]; // 16-bit word: 0 to 31 + wire [2:0] pixY = memoryAddr[8:6]; // row: 0 to 7 + + // decide what characters to display + reg [5:0] char0; + reg [5:0] char1; + always @(*) begin + case (pixX) + 5'h0: begin + char0 = 6'hA; + char1 = 6'h3F; + end + 5'h1: begin + char0 = cpuAddr[23:20]; + char1 = cpuAddr[19:16]; + end + 5'h2: begin + char0 = cpuAddr[15:12]; + char1 = cpuAddr[11:8]; + end + 5'h3: begin + char0 = cpuAddr[7:4]; + char1 = cpuAddr[3:0]; + end + 5'h5: begin + char0 = 6'hD; + char1 = 6'h1; + end + 5'h6: begin + char0 = 6'h3F; + char1 = dataControllerDataOutSample[15:12]; + end + 5'h7: begin + char0 = dataControllerDataOutSample[11:8]; + char1 = dataControllerDataOutSample[7:4]; + end + 5'h8: begin + char0 = dataControllerDataOutSample[3:0]; + char1 = 6'h3F; + end + 5'h9: begin + char0 = 6'h3F; + char1 = 6'hD; + end + 5'hA: begin + char0 = 6'h0; + char1 = 6'h3F; + end + 5'hB: begin + char0 = cpuDataOut[15:12]; + char1 = cpuDataOut[11:8]; + end + 5'hC: begin + char0 = cpuDataOut[7:4]; + char1 = cpuDataOut[3:0]; + end + 5'hD: begin + char0 = 6'h3F; + char1 = _cpuRW ? 6'h1 : 6'h0; + end + 5'hE: begin + char0 = _cpuUDS ? 6'h1 : 6'h0; + char1 = _cpuLDS ? 6'h1 : 6'h0; + end + 5'hF: begin + char0 = 6'h3F; + char1 = 6'hA; + end + 5'h10: begin + char0 = 6'hA; + char1 = 6'h3F; + end + 5'h11: begin + char0 = previousAddr[23:20]; + char1 = previousAddr[19:16]; + end + 5'h12: begin + char0 = previousAddr[15:12]; + char1 = previousAddr[11:8]; + end + 5'h13: begin + char0 = previousAddr[7:4]; + char1 = previousAddr[3:0]; + end + 5'h14: begin + char0 = 6'h3F; + char1 = 6'h3F; + end + 5'h15: begin + char0 = 6'hB; + char1 = 6'h3F; + end + 5'h16: begin + char0 = breakpointAddr[23:20]; + char1 = breakpointAddr[19:16]; + end + 5'h17: begin + char0 = breakpointAddr[15:12]; + char1 = breakpointAddr[11:8]; + end + 5'h18: begin + char0 = breakpointAddr[7:4]; + char1 = breakpointAddr[3:0]; + end + default: begin + char0 = 6'h3F; + char1 = 6'h3F; + end + endcase + end + + // map characters to font data + wire [7:0] font0; + wire [7:0] font1; + fontGen fg0(.char(char0), .row(pixY), .dataOut(font0)); + fontGen fg1(.char(char1), .row(pixY), .dataOut(font1)); + assign debugDataOut = { font0, font1 }; + + // display extra ROM data on 7-segment LEDs + reg [7:0] extraRomData; + always @(posedge clk8) begin + if (extraRomReadAck) begin + extraRomData <= dataControllerDataOut[7:0]; + end + end + + // map the chosen data to the hex display + led7seg ls0(.data(extraRomData[3:0]), .segments(hex0)); + led7seg ls1(.data(extraRomData[7:4]), .segments(hex1)); + led7seg ls2(.data({4'b0000}), .segments(hex2)); + led7seg ls3(.data({4'b0000}), .segments(hex3)); + + // withhold DTACK if stopped and delay timer != 0 + reg [19:0] delayDTACK; + assign _dtackOut = (singleStep == 1'b0 && cpuAddr != breakpointAddr) ? _dtackIn : (_dtackIn | (delayDTACK != 0)); + + // debounce step key and set DTACK delay timer + always @(posedge clk8) begin + if (key[0] == 1'b1) + delayDTACK = 20'hFFFFE; + else + if (delayDTACK != 0 && delayDTACK != 20'hFFFFF) + delayDTACK = delayDTACK - 1'b1; + else if (delayDTACK == 0 && _dtackIn == 0) + delayDTACK = 20'hFFFFF; + end + +endmodule diff --git a/cores/plus_too/floppy.v b/cores/plus_too/floppy.v new file mode 100644 index 0000000..fecc456 --- /dev/null +++ b/cores/plus_too/floppy.v @@ -0,0 +1,353 @@ +/* Synchronous 8-bit replica of 3.5 inch floppy disk drive. + + Differences from the true floppy interace at the Mac's DB-19 port: + True interface has a writeReq control line, only 1-bit readData and writeData, and no clk. + True interface does not have newByteReady signal. Instead the IWM must watch the data in bit and synchronize with it to + determine the timing and framing of bytes. + +*/ + +/* Disk register (read): + State-control lines Register + CA2 CA1 CA0 SEL addressed Information in register + + 0 0 0 0 DIRTN Head step direction (0=toward track 79, 1=toward track 0) + 0 0 0 1 CSTIN Disk in place (0=disk is inserted) + 0 0 1 0 STEP Drive head stepping (setting to 0 performs a step, returns to 1 when step is complete) + 0 0 1 1 WRTPRT Disk locked (0=locked) + 0 1 0 0 MOTORON Drive motor running (0=on, 1=off) + 0 1 0 1 TKO Head at track 0 (0=at track 0) + 0 1 1 0 SWITCHED Disk switched (1=yes?) + 0 1 1 1 TACH Tachometer (produces 60 pulses for each rotation of the drive motor) + 1 0 0 0 RDDATA0 Read data, lower head, side 0 + 1 0 0 1 RDDATA1 Read data, upper head, side 1 + 1 0 1 0 SUPERDR Drive is a Superdrive (0=no, 1=yes) + 1 1 0 0 SIDES Single- or double-sided drive (0=single side, 1=double side) + 1 1 0 1 READY 0 = yes + 1 1 1 0 INSTALLED 0 = yes + 1 1 1 1 DRVIN 400K/800K: Drive installed (0=drive is present), Superdrive: Inserted disk capacity (0=HD, 1=DD) + + Disk registers (write): + Control lines Register + CA1 CA0 SEL addressed Register function + + 0 0 0 DIRTN Set stepping direction (0=toward track 79, 1=toward track 0) + 0 0 1 SWITCHED Reset disk switched flag (writing 1 sets switch flag to 0) + 0 1 0 STEP Step the drive head one track (setting to 0 performs a step, returns to 1 when step is complete) + 1 0 0 MOTORON Turn on/off drive motor (0=on, 1=off) + 1 1 0 EJECT Eject the disk (writing 1 ejects the disk) + +*/ + +`define DRIVE_REG_DIRTN 0 /* R/W: step direction (0=toward track 79, 1=toward track 0) */ +`define DRIVE_REG_CSTIN 1 /* R: disk in place (1 = no disk) */ + /* W: ?? reset disk switch flag ? */ +`define DRIVE_REG_STEP 2 /* R: drive head is stepping (1 = complete) */ + /* W: 0 = step drive head */ +`define DRIVE_REG_WRTPRT 3 /* R: 0 = disk is write-protected */ +`define DRIVE_REG_MOTORON 4 /* R/W: 0 = motor on */ +`define DRIVE_REG_TK0 5 /* R: 0 = head at track 0 */ +`define DRIVE_REG_EJECT 6 /* R: disk switched (1=yes?)*/ + /* W: 1 = eject the disk */ +`define DRIVE_REG_TACH 7 /* R: tach-o-meter */ +`define DRIVE_REG_RDDATA0 8 /* R: activate lower head: side 0 */ +`define DRIVE_REG_RDDATA1 9 /* R: activate upper head: side 1 */ +`define DRIVE_REG_SUPERDR 10 /* R: drive is a superdrive (0=no, 1=yes) */ +`define DRIVE_REG_SIDES 12 /* R: number of sides (0=single, 1=dbl) */ +`define DRIVE_REG_READY 13 /* R: drive ready (head loaded) (0=ready) */ +`define DRIVE_REG_INSTALLED 14 /* R: drive present (0 = yes ??) */ +`define DRIVE_REG_DRVIN 15 /* R: 400K/800k: drive present (0=yes, 1=no), Superdrive: disk capacity (0=HD, 1=DD) */ + +module floppy( + input clk8, + input _reset, + input ca0, // PH0 + input ca1, // PH1 + input ca2, // PH2 + input SEL, // HDSEL from VIA + input lstrb, // aka PH3 + input _enable, + input [7:0] writeData, + output [7:0] readData, + + input useDiskImage, + input advanceDriveHead, // prevents overrun when debugging, does not exist on a real Mac! + output reg newByteReady, + input insertDisk, + output diskInDrive, + + output [21:0] extraRomReadAddr, + input extraRomReadAck, + input [7:0] extraRomReadData +); + + reg [15:0] driveRegs; + reg [6:0] driveTrack; + reg driveSide; + reg [7:0] diskDataIn; // incoming byte from the floppy disk + + // read drive registers + wire [15:0] driveRegsAsRead = { + 1'b0, // DRVIN = yes + 1'b0, // INSTALLED = yes + 1'b0, // READY = yes + 1'b1, // SIDES = double-sided drive + 1'b0, // UNUSED + 1'b0, // SUPERDR + 1'b0, // RDDATA1 + 1'b0, // RDDATA0 + driveRegs[`DRIVE_REG_TACH], // TACH: 60 pules for each rotation of the drive motor + 1'b0, // disk switched? + ~(driveTrack == 7'h00), // TK0: track 0 indicator + driveRegs[`DRIVE_REG_MOTORON], // motor on + 1'b0, // WRTPRT = locked + 1'b1, // STEP = complete + driveRegs[`DRIVE_REG_CSTIN], // disk in drive + driveRegs[`DRIVE_REG_DIRTN] // step direction + }; + + // TODO: auto-detect doubleSidedDisk from image file size + wire doubleSidedDisk = 1'b1; + + // number of bytes in one side of the current track + reg [15:0] diskImageTrackSideLen; + always @(*) begin + case (driveTrack[6:4]) + 3'b000: + diskImageTrackSideLen = 12 * 1024; + 3'b001: + diskImageTrackSideLen = 11 * 1024; + 3'b010: + diskImageTrackSideLen = 10 * 1024; + 3'b011: + diskImageTrackSideLen = 9 * 1024; + 3'b100: + diskImageTrackSideLen = 8 * 1024; + default: + diskImageTrackSideLen = 8 * 1024; + endcase + end + wire [15:0] diskImageTrackLen = doubleSidedDisk ? {diskImageTrackSideLen[14:0], 1'b0 } : diskImageTrackSideLen; + // number of bytes in one side of the track before the current track (used for stepping backwards) + wire [6:0] driveTrackMinus1 = driveTrack - 1'b1; // can't step backward from track 0, so underflow doesn't matter + reg [15:0] diskImageTrackMinus1SideLen; + always @(*) begin + case (driveTrackMinus1[6:4]) + 3'b000: + diskImageTrackMinus1SideLen = 12 * 1024; + 3'b001: + diskImageTrackMinus1SideLen = 11 * 1024; + 3'b010: + diskImageTrackMinus1SideLen = 10 * 1024; + 3'b011: + diskImageTrackMinus1SideLen = 9 * 1024; + 3'b100: + diskImageTrackMinus1SideLen = 8 * 1024; + default: + diskImageTrackMinus1SideLen = 8 * 1024; + endcase + end + wire [15:0] diskImageTrackMinus1Len = doubleSidedDisk ? {diskImageTrackMinus1SideLen[14:0], 1'b0 } : diskImageTrackMinus1SideLen; + + + // offset from the start of the disk image to the start of the current track + reg [21:0] diskImageTrackBase; + + // bytes offset in the current side of the current track, must be less than diskImageTrackSideLen + reg [15:0] diskImageHeadOffset; + + assign extraRomReadAddr = + 22'h020000 + + diskImageTrackBase + + ((driveSide && doubleSidedDisk) ? diskImageTrackSideLen : 0) + + diskImageHeadOffset; + + wire [3:0] driveReadAddr = {ca2,ca1,ca0,SEL}; + + // a byte is read or written every 128 clocks (2 us per bit * 8 bits = 16 us, @ 8 MHz = 128 clocks) + // The CPU must poll for data at least this often, or else an overrun will occur. + reg [6:0] diskDataByteTimer; + reg [7:0] diskImageData; + reg readyToAdvanceHead; + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + diskImageHeadOffset <= 1'b0; + driveSide <= 0; + diskImageData <= 8'h00; + diskDataIn <= 8'hFF; + diskDataByteTimer <= 0; + readyToAdvanceHead <= 1; + end + else begin + // a timer governs when the next disk byte will become available + diskDataByteTimer <= diskDataByteTimer + 1'b1; + + // at time 0, latch a new byte and advance the drive head + if (diskDataByteTimer == 0 && readyToAdvanceHead && diskImageData != 0) begin + diskDataIn <= useDiskImage ? diskImageData : 8'hFF; + newByteReady <= 1'b1; + + if (diskImageHeadOffset + 1'b1 >= diskImageTrackSideLen) + diskImageHeadOffset <= 0; + else + diskImageHeadOffset <= diskImageHeadOffset + 1'b1; + + // clear diskImageData after it's used, so we can tell when we get a new one from the disk + diskImageData <= 0; + + // for debugging, don't advance the head until the IWM says it's ready + readyToAdvanceHead <= 1'b1; // TEMP: treat IWM as always ready + end + else begin + newByteReady <= 1'b0; + + if (extraRomReadAck) begin + // whenever ACK is received, store the data from the current diskImageAddr + diskImageData <= extraRomReadData; + end + + if (advanceDriveHead) begin + readyToAdvanceHead <= 1'b1; + end + end + + // switch drive sides if DRIVE_REG_RDDATA0 or DRIVE_REG_RDDATA1 are read + // TODO: we don't know if this is a true read, since we don't know if IWM is selected or + // could be bad if we use this test to flush a cache of encoded disk data + if (driveReadAddr == `DRIVE_REG_RDDATA0 && lstrb == 1'b0) + driveSide <= 0; + if (driveReadAddr == `DRIVE_REG_RDDATA1 && lstrb == 1'b0) + driveSide <= 1; + end + end + + reg lstrbPrev; + always @(posedge clk8) begin + lstrbPrev <= lstrb; + end + wire lstrbEdge = lstrb == 1'b0 && lstrbPrev == 1'b1; + + assign readData = _enable == 1'b1 ? 8'hZZ : + (driveReadAddr == `DRIVE_REG_RDDATA0 || driveReadAddr == `DRIVE_REG_RDDATA1) ? diskDataIn : + { driveRegsAsRead[driveReadAddr], 7'h00 }; + + // write drive registers + wire [2:0] driveWriteAddr = {ca1,ca0,SEL}; + + // DRIVE_REG_DIRTN 0 /* R/W: step direction (0=toward track 79, 1=toward track 0) */ + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + driveRegs[`DRIVE_REG_DIRTN] <= 1'b0; + end + else if (_enable == 1'b0 && lstrbEdge == 1'b1 && driveWriteAddr == `DRIVE_REG_DIRTN) begin + driveRegs[`DRIVE_REG_DIRTN] <= ca2; + end + end + + + // DRIVE_REG_CSTIN 1 /* R: disk in place (1 = no disk) */ + /* W: ?? reset disk switch flag ? */ + // disk in drive indicators + reg [23:0] ejectIndicatorTimer; + assign diskInDrive = ~driveRegs[`DRIVE_REG_CSTIN] | ejectIndicatorTimer[20]; + + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + driveRegs[`DRIVE_REG_CSTIN] <= 1'b1; + end + else if (_enable == 1'b0 && lstrbEdge == 1'b1 && driveWriteAddr == `DRIVE_REG_EJECT && ca2 == 1'b1) begin + // eject the disk + driveRegs[`DRIVE_REG_CSTIN] <= 1'b1; + ejectIndicatorTimer <= 24'hFFFFFF; + end + else if (insertDisk) begin + // insert a disk + driveRegs[`DRIVE_REG_CSTIN] <= 1'b0; + end + else begin + if (ejectIndicatorTimer != 0) + ejectIndicatorTimer <= ejectIndicatorTimer - 1'b1; + end + end + + //`define DRIVE_REG_STEP 2 /* R: drive head stepping (1 = complete) */ + /* W: 0 = step drive head */ + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + driveTrack <= 0; + diskImageTrackBase <= 0; + end + else if (_enable == 1'b0 && lstrbEdge == 1'b1 && driveWriteAddr == `DRIVE_REG_STEP && ca2 == 1'b0) begin + if (driveRegs[`DRIVE_REG_DIRTN] == 1'b0 && driveTrack != 7'h4F) begin + driveTrack <= driveTrack + 1'b1; + diskImageTrackBase <= diskImageTrackBase + diskImageTrackLen; + end + if (driveRegs[`DRIVE_REG_DIRTN] == 1'b1 && driveTrack != 0) begin + driveTrack <= driveTrack - 1'b1; + diskImageTrackBase <= diskImageTrackBase - diskImageTrackMinus1Len; + end + end + end + + // DRIVE_REG_MOTORON 4 /* R/W: 0 = motor on */ + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + driveRegs[`DRIVE_REG_MOTORON] <= 1'b1; + end + else if (_enable == 1'b0 && lstrbEdge == 1'b1 && driveWriteAddr == `DRIVE_REG_MOTORON) begin + driveRegs[`DRIVE_REG_MOTORON] <= ca2; + end + end + + // DRIVE_REG_TACH 7 Tachometer (produces 60 pulses for each rotation of the drive motor) + /* Data from MESS, sonydriv.c: + Tracks RPM Timing Value + 00-15: 500 timing value $117B (acceptable range {1135-11E9}) + 16-31: 550 timing value $???? (acceptable range {12C6-138A}) + 32-47: 600 timing value $???? (acceptable range {14A7-157F}) + 48-63: 675 timing value $???? (acceptable range {16F2-17E2}) + 64-79: 750 timing value $???? (acceptable range {19D0-1ADE}) + + Experimentally determined toggle rates for Plus Too with 8.125 MHz CPU clock: + TACH Half Period Clocks Resulting Timing Value + 9996 $117B (4475) + 9122 $1328 (4904) + 8292 $1513 (5395) + 7463 $176A (5994) + 6634 $1A56 (6742) + */ + + reg [13:0] driveTachTimer; + reg [13:0] driveTachPeriod; + + always @(*) begin + case (driveTrack[6:4]) + 0: // tracks 0-15 + driveTachPeriod <= 9996; + 1: // tracks 16-31 + driveTachPeriod <= 9122; + 2: // tracks 32-47 + driveTachPeriod <= 8292; + 3: // tracks 48-63 + driveTachPeriod <= 7463; + default: // tracks 64-79 + driveTachPeriod <= 6634; + endcase + end + + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + driveRegs[`DRIVE_REG_TACH] <= 1'b0; + driveTachTimer <= 0; + end + else begin + if (driveTachTimer == driveTachPeriod) begin + driveTachTimer <= 0; + driveRegs[`DRIVE_REG_TACH] <= ~driveRegs[`DRIVE_REG_TACH]; + end + else begin + driveTachTimer <= driveTachTimer + 1'b1; + end + end + end +endmodule diff --git a/cores/plus_too/fontGen.v b/cores/plus_too/fontGen.v new file mode 100644 index 0000000..0c99dbd --- /dev/null +++ b/cores/plus_too/fontGen.v @@ -0,0 +1,173 @@ +module fontGen( + input [5:0] char, + input [2:0] row, + output reg [7:0] dataOut +); + + always @(*) begin + case ( { char, row } ) + // 0 + { 4'h0, 3'h0 }: dataOut = 8'b11111111; + { 4'h0, 3'h1 }: dataOut = 8'b11000011; + { 4'h0, 3'h2 }: dataOut = 8'b10011001; + { 4'h0, 3'h3 }: dataOut = 8'b10010001; + { 4'h0, 3'h4 }: dataOut = 8'b10001001; + { 4'h0, 3'h5 }: dataOut = 8'b10011001; + { 4'h0, 3'h6 }: dataOut = 8'b11000011; + { 4'h0, 3'h7 }: dataOut = 8'b11111111; + + // 1 + { 4'h1, 3'h0 }: dataOut = 8'b11111111; + { 4'h1, 3'h1 }: dataOut = 8'b11100111; + { 4'h1, 3'h2 }: dataOut = 8'b11000111; + { 4'h1, 3'h3 }: dataOut = 8'b11100111; + { 4'h1, 3'h4 }: dataOut = 8'b11100111; + { 4'h1, 3'h5 }: dataOut = 8'b11100111; + { 4'h1, 3'h6 }: dataOut = 8'b10000001; + { 4'h1, 3'h7 }: dataOut = 8'b11111111; + + // 2 + { 4'h2, 3'h0 }: dataOut = 8'b11111111; + { 4'h2, 3'h1 }: dataOut = 8'b11000011; + { 4'h2, 3'h2 }: dataOut = 8'b10011001; + { 4'h2, 3'h3 }: dataOut = 8'b11110011; + { 4'h2, 3'h4 }: dataOut = 8'b11100111; + { 4'h2, 3'h5 }: dataOut = 8'b11001111; + { 4'h2, 3'h6 }: dataOut = 8'b10000001; + { 4'h2, 3'h7 }: dataOut = 8'b11111111; + + // 3 + { 4'h3, 3'h0 }: dataOut = 8'b11111111; + { 4'h3, 3'h1 }: dataOut = 8'b10000001; + { 4'h3, 3'h2 }: dataOut = 8'b11110011; + { 4'h3, 3'h3 }: dataOut = 8'b11100111; + { 4'h3, 3'h4 }: dataOut = 8'b11110011; + { 4'h3, 3'h5 }: dataOut = 8'b10011001; + { 4'h3, 3'h6 }: dataOut = 8'b11000011; + { 4'h3, 3'h7 }: dataOut = 8'b11111111; + + // 4 + { 4'h4, 3'h0 }: dataOut = 8'b11111111; + { 4'h4, 3'h1 }: dataOut = 8'b11110011; + { 4'h4, 3'h2 }: dataOut = 8'b11100011; + { 4'h4, 3'h3 }: dataOut = 8'b11000011; + { 4'h4, 3'h4 }: dataOut = 8'b10010011; + { 4'h4, 3'h5 }: dataOut = 8'b10000001; + { 4'h4, 3'h6 }: dataOut = 8'b11110011; + { 4'h4, 3'h7 }: dataOut = 8'b11111111; + + // 5 + { 4'h5, 3'h0 }: dataOut = 8'b11111111; + { 4'h5, 3'h1 }: dataOut = 8'b10000001; + { 4'h5, 3'h2 }: dataOut = 8'b10011111; + { 4'h5, 3'h3 }: dataOut = 8'b10000011; + { 4'h5, 3'h4 }: dataOut = 8'b11111001; + { 4'h5, 3'h5 }: dataOut = 8'b10011001; + { 4'h5, 3'h6 }: dataOut = 8'b11000011; + { 4'h5, 3'h7 }: dataOut = 8'b11111111; + + // 6 + { 4'h6, 3'h0 }: dataOut = 8'b11111111; + { 4'h6, 3'h1 }: dataOut = 8'b11000011; + { 4'h6, 3'h2 }: dataOut = 8'b10011111; + { 4'h6, 3'h3 }: dataOut = 8'b10000011; + { 4'h6, 3'h4 }: dataOut = 8'b10011001; + { 4'h6, 3'h5 }: dataOut = 8'b10011001; + { 4'h6, 3'h6 }: dataOut = 8'b11000011; + { 4'h6, 3'h7 }: dataOut = 8'b11111111; + + // 7 + { 4'h7, 3'h0 }: dataOut = 8'b11111111; + { 4'h7, 3'h1 }: dataOut = 8'b10000001; + { 4'h7, 3'h2 }: dataOut = 8'b11111001; + { 4'h7, 3'h3 }: dataOut = 8'b11110011; + { 4'h7, 3'h4 }: dataOut = 8'b11100111; + { 4'h7, 3'h5 }: dataOut = 8'b11001111; + { 4'h7, 3'h6 }: dataOut = 8'b11001111; + { 4'h7, 3'h7 }: dataOut = 8'b11111111; + + // 8 + { 4'h8, 3'h0 }: dataOut = 8'b11111111; + { 4'h8, 3'h1 }: dataOut = 8'b11000011; + { 4'h8, 3'h2 }: dataOut = 8'b10011001; + { 4'h8, 3'h3 }: dataOut = 8'b11000011; + { 4'h8, 3'h4 }: dataOut = 8'b10011001; + { 4'h8, 3'h5 }: dataOut = 8'b10011001; + { 4'h8, 3'h6 }: dataOut = 8'b11000011; + { 4'h8, 3'h7 }: dataOut = 8'b11111111; + + // 9 + { 4'h9, 3'h0 }: dataOut = 8'b11111111; + { 4'h9, 3'h1 }: dataOut = 8'b11000011; + { 4'h9, 3'h2 }: dataOut = 8'b10011001; + { 4'h9, 3'h3 }: dataOut = 8'b11000001; + { 4'h9, 3'h4 }: dataOut = 8'b11111001; + { 4'h9, 3'h5 }: dataOut = 8'b11110011; + { 4'h9, 3'h6 }: dataOut = 8'b11000111; + { 4'h9, 3'h7 }: dataOut = 8'b11111111; + + // A + { 4'hA, 3'h0 }: dataOut = 8'b11111111; + { 4'hA, 3'h1 }: dataOut = 8'b11100111; + { 4'hA, 3'h2 }: dataOut = 8'b11000011; + { 4'hA, 3'h3 }: dataOut = 8'b10011001; + { 4'hA, 3'h4 }: dataOut = 8'b10011001; + { 4'hA, 3'h5 }: dataOut = 8'b10000001; + { 4'hA, 3'h6 }: dataOut = 8'b10011001; + { 4'hA, 3'h7 }: dataOut = 8'b11111111; + + // B + { 4'hB, 3'h0 }: dataOut = 8'b11111111; + { 4'hB, 3'h1 }: dataOut = 8'b10000011; + { 4'hB, 3'h2 }: dataOut = 8'b10011001; + { 4'hB, 3'h3 }: dataOut = 8'b10000011; + { 4'hB, 3'h4 }: dataOut = 8'b10011001; + { 4'hB, 3'h5 }: dataOut = 8'b10011001; + { 4'hB, 3'h6 }: dataOut = 8'b10000011; + { 4'hB, 3'h7 }: dataOut = 8'b11111111; + + // C + { 4'hC, 3'h0 }: dataOut = 8'b11111111; + { 4'hC, 3'h1 }: dataOut = 8'b11000011; + { 4'hC, 3'h2 }: dataOut = 8'b10011001; + { 4'hC, 3'h3 }: dataOut = 8'b10011111; + { 4'hC, 3'h4 }: dataOut = 8'b10011111; + { 4'hC, 3'h5 }: dataOut = 8'b10011001; + { 4'hC, 3'h6 }: dataOut = 8'b11000011; + { 4'hC, 3'h7 }: dataOut = 8'b11111111; + + // D + { 4'hD, 3'h0 }: dataOut = 8'b11111111; + { 4'hD, 3'h1 }: dataOut = 8'b10000111; + { 4'hD, 3'h2 }: dataOut = 8'b10010011; + { 4'hD, 3'h3 }: dataOut = 8'b10011001; + { 4'hD, 3'h4 }: dataOut = 8'b10011001; + { 4'hD, 3'h5 }: dataOut = 8'b10010011; + { 4'hD, 3'h6 }: dataOut = 8'b10000111; + { 4'hD, 3'h7 }: dataOut = 8'b11111111; + + // E + { 4'hE, 3'h0 }: dataOut = 8'b11111111; + { 4'hE, 3'h1 }: dataOut = 8'b10000001; + { 4'hE, 3'h2 }: dataOut = 8'b10011111; + { 4'hE, 3'h3 }: dataOut = 8'b10000011; + { 4'hE, 3'h4 }: dataOut = 8'b10011111; + { 4'hE, 3'h5 }: dataOut = 8'b10011111; + { 4'hE, 3'h6 }: dataOut = 8'b10000001; + { 4'hE, 3'h7 }: dataOut = 8'b11111111; + + // F + { 4'hF, 3'h0 }: dataOut = 8'b11111111; + { 4'hF, 3'h1 }: dataOut = 8'b10000001; + { 4'hF, 3'h2 }: dataOut = 8'b10011111; + { 4'hF, 3'h3 }: dataOut = 8'b10000011; + { 4'hF, 3'h4 }: dataOut = 8'b10011111; + { 4'hF, 3'h5 }: dataOut = 8'b10011111; + { 4'hF, 3'h6 }: dataOut = 8'b10011111; + { 4'hF, 3'h7 }: dataOut = 8'b11111111; + + default: dataOut = 8'b11111111; + + endcase + end +endmodule diff --git a/cores/plus_too/iwm.v b/cores/plus_too/iwm.v new file mode 100644 index 0000000..adeac35 --- /dev/null +++ b/cores/plus_too/iwm.v @@ -0,0 +1,275 @@ +/* IWM + + Mapped to $DFE1FF - $DFFFFF + + The 16 IWM one-bit registers are {8'hDF, 8'b111xxxx1, 8'hFF}: + 0 $0 ca0L CA0 off (0) + 1 $200 ca0H CA0 on (1) + 2 $400 ca1L CA1 off (0) + 3 $600 ca1H CA1 on (1) + 4 $800 ca2L CA2 off (0) + 5 $A00 ca2H CA2 on (1) + 6 $C00 ph3L LSTRB off (low) + 7 $E00 ph3H LSTRB on (high) + 8 $1000 mtrOff ENABLE disk enable off + 9 $1200 mtrOn ENABLE disk enable on + 10 $1400 intDrive SELECT select internal drive + 11 $1600 extDrive SELECT select external drive + 12 $1800 q6L Q6 off + 13 $1A00 q6H Q6 on + 14 $1C00 q7L Q7 off, read register + 15 $1E00 q7H Q7 on, write register + + Notes from IWM manual: + Serial data is shifted in/out MSB first, with a bit transferred every 2 microseconds. + When writing data, a 1 is written as a transition on writeData at a bit cell boundary time, and a 0 is written as no transition. + When reading data, a falling transition within a bit cell window is considered to be a 1, and no falling transition is considered a 0. + When reading data, the read data register will latch the shift register when a 1 is shifted into the MSB. + The read data register will be cleared 14 fclk periods (about 2 microseconds) after a valid data read takes place-- a valid data read + being defined as both /DEV being low and D7 (the MSB) outputting a one from the read data register for at least one fclk period. +*/ + +module iwm( + input clk8, + input _reset, + input selectIWM, + input _cpuRW, + input _cpuLDS, + input [15:0] dataIn, + input [3:0] cpuAddrRegHi, + input SEL, // from VIA + output [15:0] dataOut, + input [1:0] insertDisk, + output [1:0] diskInDrive, + + output [21:0] extraRomReadAddr, + input extraRomReadAck, + input [7:0] extraRomReadData +); + + wire [7:0] dataInLo = dataIn[7:0]; + reg [7:0] dataOutLo; + assign dataOut = { 8'hBE, dataOutLo }; + + // IWM state + reg ca0, ca1, ca2, lstrb, selectExternalDrive, q6, q7; + reg ca0Next, ca1Next, ca2Next, lstrbNext, selectExternalDriveNext, q6Next, q7Next; + wire advanceDriveHead; // prevents overrun when debugging, does not exit on a real Mac! + reg [7:0] writeData; + reg [7:0] readDataLatch; + wire _iwmBusy, _writeUnderrun; + assign _iwmBusy = 1'b1; // for writes, a value of 1 here indicates the IWM write buffer is empty + assign _writeUnderrun = 1'b1; + + // floppy disk drives + reg diskEnableExt, diskEnableInt; + reg diskEnableExtNext, diskEnableIntNext; + wire newByteReadyInt; + wire [7:0] readDataInt; + wire senseInt = readDataInt[7]; // bit 7 doubles as the sense line here + wire newByteReadyExt; + wire [7:0] readDataExt; + wire senseExt = readDataExt[7]; // bit 7 doubles as the sense line here + + floppy floppyInt( + .clk8(clk8), + ._reset(_reset), + .ca0(ca0), + .ca1(ca1), + .ca2(ca2), + .SEL(SEL), + .lstrb(lstrb), + ._enable(~diskEnableInt), + .writeData(writeData), + .readData(readDataInt), + .useDiskImage(1'b1), + .advanceDriveHead(advanceDriveHead), + .newByteReady(newByteReadyInt), + .insertDisk(insertDisk[0]), + .diskInDrive(diskInDrive[0]), + .extraRomReadAddr(extraRomReadAddr), + .extraRomReadAck(extraRomReadAck), + .extraRomReadData(extraRomReadData)); + floppy floppyExt( + .clk8(clk8), + ._reset(_reset), + .ca0(ca0), + .ca1(ca1), + .ca2(ca2), + .SEL(SEL), + .lstrb(lstrb), + ._enable(~diskEnableExt), + .writeData(writeData), + .readData(readDataExt), + .useDiskImage(1'b0), + .advanceDriveHead(advanceDriveHead), + .newByteReady(newByteReadyExt), + .insertDisk(insertDisk[1]), + .diskInDrive(diskInDrive[1])); + + wire [7:0] readData = selectExternalDrive ? readDataExt : readDataInt; + wire newByteReady = selectExternalDrive ? newByteReadyExt : newByteReadyInt; + + reg [4:0] iwmMode; + /* IWM mode register: S C M H L + S Clock speed: + 0 = 7 MHz + 1 = 8 MHz + Should always be 1 for Macintosh. + C Bit cell time: + 0 = 4 usec/bit (for 5.25 drives) + 1 = 2 usec/bit (for 3.5 drives) (Macintosh mode) + M Motor-off timer: + 0 = leave drive on for 1 sec after program turns + it off + 1 = no delay (Macintosh mode) + Should be 0 for 5.25 and 1 for 3.5. + H Handshake protocol: + 0 = synchronous (software must supply proper + timing for writing data) + 1 = asynchronous (IWM supplies timing) (Macintosh Mode) + Should be 0 for 5.25 and 1 for 3.5. + L Latch mode: + 0 = read-data stays valid for about 7 usec + 1 = read-data stays valid for full byte time (Macintosh mode) + Should be 0 for 5.25 and 1 for 3.5. + */ + + // any read/write access to IWM bit registers will change their values + always @(*) begin + ca0Next <= ca0; + ca1Next <= ca1; + ca2Next <= ca2; + lstrbNext <= lstrb; + diskEnableExtNext <= diskEnableExt; + diskEnableIntNext <= diskEnableInt; + selectExternalDriveNext <= selectExternalDrive; + q6Next <= q6; + q7Next <= q7; + + if (selectIWM == 1'b1 && _cpuLDS == 1'b0) begin + case (cpuAddrRegHi[3:1]) + 3'h0: // ca0 + ca0Next <= cpuAddrRegHi[0]; + 3'h1: // ca1 + ca1Next <= cpuAddrRegHi[0]; + 3'h2: // ca2 + ca2Next <= cpuAddrRegHi[0]; + 3'h3: // lstrb + lstrbNext <= cpuAddrRegHi[0]; + 3'h4: // disk enable + if (selectExternalDrive) + diskEnableExtNext <= cpuAddrRegHi[0]; + else + diskEnableIntNext <= cpuAddrRegHi[0]; + 3'h5: // external drive + selectExternalDriveNext <= cpuAddrRegHi[0]; + 3'h6: // Q6 + q6Next <= cpuAddrRegHi[0]; + 3'h7: // Q7 + q7Next <= cpuAddrRegHi[0]; + endcase + end + end + + // update IWM bit registers + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + ca0 <= 0; + ca1 <= 0; + ca2 <= 0; + lstrb <= 0; + diskEnableExt <= 0; + diskEnableInt <= 0; + selectExternalDrive <= 0; + q6 <= 0; + q7 <= 0; + end + else begin + ca0 <= ca0Next; + ca1 <= ca1Next; + ca2 <= ca2Next; + lstrb <= lstrbNext; + diskEnableExt <= diskEnableExtNext; + diskEnableInt <= diskEnableIntNext; + selectExternalDrive <= selectExternalDriveNext; + q6 <= q6Next; + q7 <= q7Next; + end + end + + // read IWM state + always @(*) begin + dataOutLo = 8'hEF; + + if (_cpuRW == 1'b1 && selectIWM == 1'b1 && _cpuLDS == 1'b0) begin + // reading any IWM address returns state as selected by Q7 and Q6 + case ({q7Next,q6Next}) + 2'b00: // data-in register (from disk drive) - MSB is 1 when data is valid + dataOutLo <= readDataLatch; + 2'b01: // IWM status register - read only + dataOutLo <= { (selectExternalDriveNext ? senseExt : senseInt), 1'b0, diskEnableExt & diskEnableInt, iwmMode }; + 2'b10: // handshake - read only + dataOutLo <= { _iwmBusy, _writeUnderrun, 6'b000000 }; + 2'b11: // IWM mode register when not enabled (write-only), or (write?) data register when enabled + dataOutLo <= 0; + endcase + end + end + + // write IWM state + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + iwmMode <= 0; + writeData <= 0; + end + else begin + if (_cpuRW == 0 && selectIWM == 1'b1 && _cpuLDS == 1'b0) begin + // writing to any IWM address modifies state as selected by Q7 and Q6 + case ({q7Next,q6Next}) + 2'b11: begin + if (diskEnableExt | diskEnableInt) + writeData <= dataInLo; + else + iwmMode <= dataInLo[4:0]; + end + endcase + end + end + end + + // Manage incoming bytes from the disk drive + wire iwmRead = (_cpuRW == 1'b1 && selectIWM == 1'b1 && _cpuLDS == 1'b0); + reg iwmReadPrev; + reg [3:0] readLatchClearTimer; + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + readDataLatch <= 0; + readLatchClearTimer <= 0; + iwmReadPrev <= 0; + end + else begin + // a countdown timer governs how long after a data latch read before the latch is cleared + if (readLatchClearTimer != 0) begin + readLatchClearTimer <= readLatchClearTimer - 1'b1; + end + + // the conclusion of a valid CPU read from the IWM will start the timer to clear the latch + if (iwmReadPrev && !iwmRead && readDataLatch[7]) begin + readLatchClearTimer <= 4'hD; // clear latch 14 clocks after the conclusion of a valid read + end + + // when the drive indicates that a new byte is ready, latch it + // NOTE: the real IWM must self-synchronize with the incoming data to determine when to latch it + if (newByteReady) begin + readDataLatch <= readData; + end + else if (readLatchClearTimer == 1'b1) begin + readDataLatch <= 0; + end + + iwmReadPrev <= iwmRead; + end + end + assign advanceDriveHead = readLatchClearTimer == 1'b1; // prevents overrun when debugging, does not exist on a real Mac! +endmodule diff --git a/cores/plus_too/led7seg.v b/cores/plus_too/led7seg.v new file mode 100644 index 0000000..38e683c --- /dev/null +++ b/cores/plus_too/led7seg.v @@ -0,0 +1,30 @@ +module led7seg( + input [3:0] data, + output [6:0] segments +); + + reg [6:0] _segments; + assign segments = ~_segments; + + always @(data) begin + case (data) + 4'h0: _segments = 7'b0111111; + 4'h1: _segments = 7'b0000110; + 4'h2: _segments = 7'b1011011; + 4'h3: _segments = 7'b1001111; + 4'h4: _segments = 7'b1100110; + 4'h5: _segments = 7'b1101101; + 4'h6: _segments = 7'b1111101; + 4'h7: _segments = 7'b0000111; + 4'h8: _segments = 7'b1111111; + 4'h9: _segments = 7'b1101111; + 4'hA: _segments = 7'b1110111; + 4'hB: _segments = 7'b1111100; + 4'hC: _segments = 7'b0111001; + 4'hD: _segments = 7'b1011110; + 4'hE: _segments = 7'b1111001; + 4'hF: _segments = 7'b1110001; + endcase + end + +endmodule \ No newline at end of file diff --git a/cores/plus_too/osd.v b/cores/plus_too/osd.v new file mode 100644 index 0000000..a654b40 --- /dev/null +++ b/cores/plus_too/osd.v @@ -0,0 +1,182 @@ +// A simple OSD implementation. Can be hooked up between a cores +// VGA output and the physical VGA pins + +module osd ( + // OSDs pixel clock, should be synchronous to cores pixel clock to + // avoid jitter. + input pclk, + + // SPI interface + input sck, + input ss, + input sdi, + + // VGA signals coming from core + input [5:0] red_in, + input [5:0] green_in, + input [5:0] blue_in, + input hs_in, + input vs_in, + + // VGA signals going to video connector + output [5:0] red_out, + output [5:0] green_out, + output [5:0] blue_out, + output hs_out, + output vs_out +); + +parameter OSD_X_OFFSET = 10'd0; +parameter OSD_Y_OFFSET = 10'd0; +parameter OSD_COLOR = 3'd0; + +localparam OSD_WIDTH = 10'd256; +localparam OSD_HEIGHT = 10'd128; + +// ********************************************************************************* +// spi client +// ********************************************************************************* + +// this core supports only the display related OSD commands +// of the minimig +reg [7:0] sbuf; +reg [7:0] cmd; +reg [4:0] cnt; +reg [10:0] bcnt; +reg osd_enable; + +reg [7:0] osd_buffer [2047:0]; // the OSD buffer itself + +// the OSD has its own SPI interface to the io controller +always@(posedge sck, posedge ss) begin + if(ss == 1'b1) begin + cnt <= 5'd0; + bcnt <= 11'd0; + end else begin + sbuf <= { sbuf[6:0], sdi}; + + // 0:7 is command, rest payload + if(cnt < 15) + cnt <= cnt + 4'd1; + else + cnt <= 4'd8; + + if(cnt == 7) begin + cmd <= {sbuf[6:0], sdi}; + + // lower three command bits are line address + bcnt <= { sbuf[1:0], sdi, 8'h00}; + + // command 0x40: OSDCMDENABLE, OSDCMDDISABLE + if(sbuf[6:3] == 4'b0100) + osd_enable <= sdi; + end + + // command 0x20: OSDCMDWRITE + if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin + osd_buffer[bcnt] <= {sbuf[6:0], sdi}; + bcnt <= bcnt + 11'd1; + end + end +end + +// ********************************************************************************* +// video timing and sync polarity anaylsis +// ********************************************************************************* + +// horizontal counter +reg [9:0] h_cnt; +reg hsD, hsD2; +reg [9:0] hs_low, hs_high; +wire hs_pol = hs_high < hs_low; +wire [9:0] h_dsp_width = hs_pol?hs_low:hs_high; +wire [9:0] h_dsp_ctr = { 1'b0, h_dsp_width[9:1] }; + +always @(posedge pclk) begin + // bring hsync into local clock domain + hsD <= hs_in; + hsD2 <= hsD; + + // falling edge of hs_in + if(!hsD && hsD2) begin + h_cnt <= 10'd0; + hs_high <= h_cnt; + end + + // rising edge of hs_in + else if(hsD && !hsD2) begin + h_cnt <= 10'd0; + hs_low <= h_cnt; + end + + else + h_cnt <= h_cnt + 10'd1; +end + +// vertical counter +reg [9:0] v_cnt; +reg vsD, vsD2; +reg [9:0] vs_low, vs_high; +wire vs_pol = vs_high < vs_low; +wire [9:0] v_dsp_width = vs_pol?vs_low:vs_high; +wire [9:0] v_dsp_ctr = { 1'b0, v_dsp_width[9:1] }; + +always @(posedge hs_in) begin + // bring vsync into local clock domain + vsD <= vs_in; + vsD2 <= vsD; + + // falling edge of vs_in + if(!vsD && vsD2) begin + v_cnt <= 10'd0; + vs_high <= v_cnt; + end + + // rising edge of vs_in + else if(vsD && !vsD2) begin + v_cnt <= 10'd0; + vs_low <= v_cnt; + end + + else + v_cnt <= v_cnt + 10'd1; +end + +// area in which OSD is being displayed +wire [9:0] h_osd_start = h_dsp_ctr + OSD_X_OFFSET - (OSD_WIDTH >> 1); +wire [9:0] h_osd_end = h_dsp_ctr + OSD_X_OFFSET + (OSD_WIDTH >> 1) - 1; +wire [9:0] v_osd_start = v_dsp_ctr + OSD_Y_OFFSET - (OSD_HEIGHT >> 1); +wire [9:0] v_osd_end = v_dsp_ctr + OSD_Y_OFFSET + (OSD_HEIGHT >> 1) - 1; + +reg h_osd_active, v_osd_active; +always @(posedge pclk) begin + if(hs_in != hs_pol) begin + if(h_cnt == h_osd_start) h_osd_active <= 1'b1; + if(h_cnt == h_osd_end) h_osd_active <= 1'b0; + end + if(vs_in != vs_pol) begin + if(v_cnt == v_osd_start) v_osd_active <= 1'b1; + if(v_cnt == v_osd_end) v_osd_active <= 1'b0; + end +end + +wire osd_de = osd_enable && h_osd_active && v_osd_active; + +wire [7:0] osd_hcnt = h_cnt - h_osd_start + 7'd1; // one pixel offset for osd_byte register +wire [6:0] osd_vcnt = v_cnt - v_osd_start; + +wire osd_pixel = osd_byte[osd_vcnt[3:1]]; + +reg [7:0] osd_byte; +always @(posedge pclk) + osd_byte <= osd_buffer[{osd_vcnt[6:4], osd_hcnt}]; + +wire [2:0] osd_color = OSD_COLOR; +assign red_out = !osd_de?red_in: {osd_pixel, osd_pixel, osd_color[2], red_in[5:3] }; +assign green_out = !osd_de?green_in:{osd_pixel, osd_pixel, osd_color[1], green_in[5:3]}; +assign blue_out = !osd_de?blue_in: {osd_pixel, osd_pixel, osd_color[0], blue_in[5:3] }; + +assign hs_out = hs_in; +assign vs_out = vs_in; + +endmodule \ No newline at end of file diff --git a/cores/plus_too/plusToo_top.qsf b/cores/plus_too/plusToo_top.qsf new file mode 100644 index 0000000..48cc914 --- /dev/null +++ b/cores/plus_too/plusToo_top.qsf @@ -0,0 +1,632 @@ +# Copyright (C) 1991-2007 Altera Corporation +# Your use of Altera Corporation's design tools, logic functions +# and other software and tools, and its AMPP partner logic +# functions, and any output files from any of the foregoing +# (including device programming or simulation files), and any +# associated documentation or information are expressly subject +# to the terms and conditions of the Altera Program License +# Subscription Agreement, Altera MegaCore Function License +# Agreement, or other applicable license agreement, including, +# without limitation, that your use is for the sole purpose of +# programming logic devices manufactured by Altera and sold by +# Altera or its authorized distributors. Please refer to the +# applicable agreement for further details. + + +# If this file doesn't exist, and for assignments not listed, see file +# assignment_defaults.qdf + +# Altera recommends that you do not modify this file. This +# file is updated automatically by the Quartus II software +# and any changes you make may be lost or overwritten. + + +set_global_assignment -name FAMILY "Cyclone III" +set_global_assignment -name DEVICE EP3C25E144C8 +set_global_assignment -name TOP_LEVEL_ENTITY plusToo_top +set_global_assignment -name ORIGINAL_QUARTUS_VERSION 7.2 +set_global_assignment -name PROJECT_CREATION_TIME_DATE "22:27:29 OCTOBER 30, 2007" +set_global_assignment -name LAST_QUARTUS_VERSION 13.1 +set_global_assignment -name USE_GENERATED_PHYSICAL_CONSTRAINTS OFF -section_id eda_palace +set_global_assignment -name DEVICE_FILTER_PIN_COUNT 144 +set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR" +set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" +set_global_assignment -name OPTIMIZE_HOLD_TIMING OFF +set_global_assignment -name FITTER_EFFORT "FAST FIT" +set_global_assignment -name STRATIX_CONFIGURATION_DEVICE EPCS4 +set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "AS INPUT TRI-STATED" +set_global_assignment -name CYCLONEIII_CONFIGURATION_SCHEME "PASSIVE SERIAL" +set_global_assignment -name GENERATE_RBF_FILE ON +set_global_assignment -name FORCE_CONFIGURATION_VCCIO ON +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" + +set_location_assignment PIN_7 -to LED +set_location_assignment PIN_22 -to CLOCK_50[0] +set_location_assignment PIN_23 -to CLOCK_50[1] +set_location_assignment PIN_128 -to CLOCK_32[0] +set_location_assignment PIN_129 -to CLOCK_32[1] +set_location_assignment PIN_54 -to CLOCK_27[0] +set_location_assignment PIN_55 -to CLOCK_27[1] +set_location_assignment PIN_144 -to VGA_R[5] +set_location_assignment PIN_143 -to VGA_R[4] +set_location_assignment PIN_142 -to VGA_R[3] +set_location_assignment PIN_141 -to VGA_R[2] +set_location_assignment PIN_137 -to VGA_R[1] +set_location_assignment PIN_135 -to VGA_R[0] +set_location_assignment PIN_133 -to VGA_B[5] +set_location_assignment PIN_132 -to VGA_B[4] +set_location_assignment PIN_125 -to VGA_B[3] +set_location_assignment PIN_121 -to VGA_B[2] +set_location_assignment PIN_120 -to VGA_B[1] +set_location_assignment PIN_115 -to VGA_B[0] +set_location_assignment PIN_114 -to VGA_G[5] +set_location_assignment PIN_113 -to VGA_G[4] +set_location_assignment PIN_112 -to VGA_G[3] +set_location_assignment PIN_111 -to VGA_G[2] +set_location_assignment PIN_110 -to VGA_G[1] +set_location_assignment PIN_106 -to VGA_G[0] +set_location_assignment PIN_136 -to VGA_VS +set_location_assignment PIN_119 -to VGA_HS +set_location_assignment PIN_65 -to AUDIO_L +set_location_assignment PIN_80 -to AUDIO_R +set_location_assignment PIN_46 -to UART_TX +set_location_assignment PIN_31 -to UART_RX +set_location_assignment PIN_105 -to SPI_DO +set_location_assignment PIN_88 -to SPI_DI +set_location_assignment PIN_126 -to SPI_SCK +set_location_assignment PIN_127 -to SPI_SS2 +set_location_assignment PIN_91 -to SPI_SS3 +set_location_assignment PIN_90 -to SPI_SS4 +set_location_assignment PIN_13 -to CONF_DATA0 + +set_location_assignment PIN_49 -to SDRAM_A[0] +set_location_assignment PIN_44 -to SDRAM_A[1] +set_location_assignment PIN_42 -to SDRAM_A[2] +set_location_assignment PIN_39 -to SDRAM_A[3] +set_location_assignment PIN_4 -to SDRAM_A[4] +set_location_assignment PIN_6 -to SDRAM_A[5] +set_location_assignment PIN_8 -to SDRAM_A[6] +set_location_assignment PIN_10 -to SDRAM_A[7] +set_location_assignment PIN_11 -to SDRAM_A[8] +set_location_assignment PIN_28 -to SDRAM_A[9] +set_location_assignment PIN_50 -to SDRAM_A[10] +set_location_assignment PIN_30 -to SDRAM_A[11] +set_location_assignment PIN_32 -to SDRAM_A[12] +set_location_assignment PIN_83 -to SDRAM_DQ[0] +set_location_assignment PIN_79 -to SDRAM_DQ[1] +set_location_assignment PIN_77 -to SDRAM_DQ[2] +set_location_assignment PIN_76 -to SDRAM_DQ[3] +set_location_assignment PIN_72 -to SDRAM_DQ[4] +set_location_assignment PIN_71 -to SDRAM_DQ[5] +set_location_assignment PIN_69 -to SDRAM_DQ[6] +set_location_assignment PIN_68 -to SDRAM_DQ[7] +set_location_assignment PIN_86 -to SDRAM_DQ[8] +set_location_assignment PIN_87 -to SDRAM_DQ[9] +set_location_assignment PIN_98 -to SDRAM_DQ[10] +set_location_assignment PIN_99 -to SDRAM_DQ[11] +set_location_assignment PIN_100 -to SDRAM_DQ[12] +set_location_assignment PIN_101 -to SDRAM_DQ[13] +set_location_assignment PIN_103 -to SDRAM_DQ[14] +set_location_assignment PIN_104 -to SDRAM_DQ[15] +set_location_assignment PIN_58 -to SDRAM_BA[0] +set_location_assignment PIN_51 -to SDRAM_BA[1] +set_location_assignment PIN_85 -to SDRAM_DQMH +set_location_assignment PIN_67 -to SDRAM_DQML +set_location_assignment PIN_60 -to SDRAM_nRAS +set_location_assignment PIN_64 -to SDRAM_nCAS +set_location_assignment PIN_66 -to SDRAM_nWE +set_location_assignment PIN_59 -to SDRAM_nCS +set_location_assignment PIN_33 -to SDRAM_CKE +set_location_assignment PIN_43 -to SDRAM_CLK + +set_global_assignment -name CYCLONEII_OPTIMIZATION_TECHNIQUE BALANCED +set_global_assignment -name SMART_RECOMPILE ON +set_global_assignment -name ENABLE_SIGNALTAP ON +set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp +set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON +set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON +set_global_assignment -name PHYSICAL_SYNTHESIS_EFFORT NORMAL +set_global_assignment -name FMAX_REQUIREMENT "114 MHz" +set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING OFF +set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 +set_global_assignment -name USE_CONFIGURATION_DEVICE ON +set_global_assignment -name TPD_REQUIREMENT "2 ns" +set_global_assignment -name TSU_REQUIREMENT "2 ns" +set_global_assignment -name TCO_REQUIREMENT "2 ns" +set_global_assignment -name ALLOW_POWER_UP_DONT_CARE OFF +set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS OFF +set_global_assignment -name AUTO_RAM_TO_LCELL_CONVERSION OFF +set_global_assignment -name AUTO_RAM_RECOGNITION ON +set_global_assignment -name AUTO_ROM_RECOGNITION ON +set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON +set_global_assignment -name LL_ROOT_REGION ON -section_id "Root Region" +set_global_assignment -name LL_MEMBER_STATE LOCKED -section_id "Root Region" +set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top +set_global_assignment -name PARTITION_COLOR 2147039 -section_id Top +set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top + +set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON +set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA OFF +set_global_assignment -name PHYSICAL_SYNTHESIS_MAP_LOGIC_TO_MEMORY_FOR_AREA OFF + +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY out +set_global_assignment -name PLACEMENT_EFFORT_MULTIPLIER 4.0 +set_global_assignment -name ROUTER_EFFORT_MULTIPLIER 4.0 +set_global_assignment -name CYCLONEII_M4K_COMPATIBILITY OFF + +set_global_assignment -name CRC_ERROR_OPEN_DRAIN OFF +set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -rise +set_global_assignment -name OUTPUT_IO_TIMING_NEAR_END_VMEAS "HALF VCCIO" -fall +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -rise +set_global_assignment -name OUTPUT_IO_TIMING_FAR_END_VMEAS "HALF SIGNAL SWING" -fall +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[2] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[3] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[4] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[5] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[6] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[7] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[8] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[9] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[10] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[11] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[12] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[13] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[14] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQ[15] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[2] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[3] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[4] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[5] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[6] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[7] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[8] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[9] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[10] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[11] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_A[12] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_BA[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQMH +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_DQML +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nRAS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCAS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nWE +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_nCS + +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[0] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[1] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[2] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[3] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[4] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[5] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[6] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[7] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[8] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[9] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[10] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[11] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[12] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[13] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[14] +set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[15] + +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[0] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[1] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[2] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[3] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[4] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[5] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[6] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[7] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[8] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[9] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[10] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[11] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[12] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[13] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[14] +set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[15] + +set_instance_assignment -name GLOBAL_SIGNAL "GLOBAL CLOCK" -to clk_8 +set_instance_assignment -name GLOBAL_SIGNAL "GLOBAL CLOCK" -to clk_128 +set_instance_assignment -name GLOBAL_SIGNAL "GLOBAL CLOCK" -to SDRAM_CLK +set_instance_assignment -name GLOBAL_SIGNAL "GLOBAL CLOCK" -to SPI_SCK +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[6] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[7] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[8] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[9] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[10] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[11] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_A[12] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[6] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[7] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[8] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[9] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[10] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[11] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[12] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[13] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[14] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQ[15] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_BA[0] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_BA[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQML +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_DQMH +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nRAS +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nCAS +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nWE +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_nCS +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_CKE +set_instance_assignment -name CURRENT_STRENGTH_NEW 4MA -to SDRAM_CLK + +set_instance_assignment -name GLOBAL_SIGNAL "GLOBAL CLOCK" -to clk_32 + +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_R[5] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_R[4] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_R[3] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_R[2] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_R[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_R[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_B[5] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_B[4] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_B[3] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_B[2] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_B[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_B[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_G[5] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_G[4] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_G[3] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_G[2] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_G[1] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_G[0] +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_VS +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to VGA_HS + +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to AUDIO_L +set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to AUDIO_R + +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_R[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_R[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_R[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_R[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_R[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_R[0] + +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_G[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_G[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_G[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_G[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_G[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_G[0] + +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_B[5] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_B[4] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_B[3] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_B[2] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_B[1] +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_B[0] + +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_HS +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_VS + +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to AUDIO_L +set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to AUDIO_R + +set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to UART_RX + + +set_global_assignment -name SLD_NODE_CREATOR_ID 110 -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_ENTITY_NAME sld_signaltap -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[0] -to "TG68:m68k|addr[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[1] -to "TG68:m68k|addr[10]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[2] -to "TG68:m68k|addr[11]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[3] -to "TG68:m68k|addr[12]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[4] -to "TG68:m68k|addr[13]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[5] -to "TG68:m68k|addr[14]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[6] -to "TG68:m68k|addr[15]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[7] -to "TG68:m68k|addr[16]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[8] -to "TG68:m68k|addr[17]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[9] -to "TG68:m68k|addr[18]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[10] -to "TG68:m68k|addr[19]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[11] -to "TG68:m68k|addr[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[12] -to "TG68:m68k|addr[20]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[13] -to "TG68:m68k|addr[21]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[14] -to "TG68:m68k|addr[22]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[15] -to "TG68:m68k|addr[23]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[16] -to "TG68:m68k|addr[24]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[17] -to "TG68:m68k|addr[25]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[18] -to "TG68:m68k|addr[26]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[19] -to "TG68:m68k|addr[27]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[20] -to "TG68:m68k|addr[28]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[21] -to "TG68:m68k|addr[29]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[22] -to "TG68:m68k|addr[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[23] -to "TG68:m68k|addr[30]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[24] -to "TG68:m68k|addr[31]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[25] -to "TG68:m68k|addr[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[26] -to "TG68:m68k|addr[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[27] -to "TG68:m68k|addr[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[28] -to "TG68:m68k|addr[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[29] -to "TG68:m68k|addr[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[30] -to "TG68:m68k|addr[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[31] -to "TG68:m68k|addr[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[32] -to "TG68:m68k|as" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[33] -to "TG68:m68k|clk" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[34] -to "TG68:m68k|clkena" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[35] -to "TG68:m68k|data_in[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[36] -to "TG68:m68k|data_in[10]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[37] -to "TG68:m68k|data_in[11]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[38] -to "TG68:m68k|data_in[12]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[39] -to "TG68:m68k|data_in[13]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[40] -to "TG68:m68k|data_in[14]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[41] -to "TG68:m68k|data_in[15]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[42] -to "TG68:m68k|data_in[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[43] -to "TG68:m68k|data_in[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[44] -to "TG68:m68k|data_in[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[45] -to "TG68:m68k|data_in[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[46] -to "TG68:m68k|data_in[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[47] -to "TG68:m68k|data_in[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[48] -to "TG68:m68k|data_in[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[49] -to "TG68:m68k|data_in[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[50] -to "TG68:m68k|data_in[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[51] -to "TG68:m68k|data_out[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[52] -to "TG68:m68k|data_out[10]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[53] -to "TG68:m68k|data_out[11]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[54] -to "TG68:m68k|data_out[12]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[55] -to "TG68:m68k|data_out[13]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[56] -to "TG68:m68k|data_out[14]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[57] -to "TG68:m68k|data_out[15]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[58] -to "TG68:m68k|data_out[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[59] -to "TG68:m68k|data_out[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[60] -to "TG68:m68k|data_out[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[61] -to "TG68:m68k|data_out[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[62] -to "TG68:m68k|data_out[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[63] -to "TG68:m68k|data_out[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[64] -to "TG68:m68k|data_out[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[65] -to "TG68:m68k|data_out[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[66] -to "TG68:m68k|data_out[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[67] -to "TG68:m68k|dtack" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[68] -to "TG68:m68k|lds" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[0] -to "TG68:m68k|addr[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[1] -to "TG68:m68k|addr[10]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[2] -to "TG68:m68k|addr[11]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[3] -to "TG68:m68k|addr[12]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[4] -to "TG68:m68k|addr[13]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[5] -to "TG68:m68k|addr[14]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[6] -to "TG68:m68k|addr[15]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[7] -to "TG68:m68k|addr[16]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[8] -to "TG68:m68k|addr[17]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[9] -to "TG68:m68k|addr[18]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[10] -to "TG68:m68k|addr[19]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[11] -to "TG68:m68k|addr[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[12] -to "TG68:m68k|addr[20]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[13] -to "TG68:m68k|addr[21]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[14] -to "TG68:m68k|addr[22]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[15] -to "TG68:m68k|addr[23]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[16] -to "TG68:m68k|addr[24]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[17] -to "TG68:m68k|addr[25]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[18] -to "TG68:m68k|addr[26]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[19] -to "TG68:m68k|addr[27]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[20] -to "TG68:m68k|addr[28]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[21] -to "TG68:m68k|addr[29]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[22] -to "TG68:m68k|addr[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[23] -to "TG68:m68k|addr[30]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[24] -to "TG68:m68k|addr[31]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[25] -to "TG68:m68k|addr[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[26] -to "TG68:m68k|addr[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[27] -to "TG68:m68k|addr[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[28] -to "TG68:m68k|addr[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[29] -to "TG68:m68k|addr[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[30] -to "TG68:m68k|addr[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[31] -to "TG68:m68k|addr[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[32] -to "TG68:m68k|as" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[33] -to "TG68:m68k|clk" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[34] -to "TG68:m68k|clkena" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[35] -to "TG68:m68k|data_in[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[36] -to "TG68:m68k|data_in[10]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[37] -to "TG68:m68k|data_in[11]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[38] -to "TG68:m68k|data_in[12]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[39] -to "TG68:m68k|data_in[13]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[40] -to "TG68:m68k|data_in[14]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[41] -to "TG68:m68k|data_in[15]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[42] -to "TG68:m68k|data_in[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[43] -to "TG68:m68k|data_in[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[44] -to "TG68:m68k|data_in[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[45] -to "TG68:m68k|data_in[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[46] -to "TG68:m68k|data_in[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[47] -to "TG68:m68k|data_in[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[48] -to "TG68:m68k|data_in[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[49] -to "TG68:m68k|data_in[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[50] -to "TG68:m68k|data_in[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[51] -to "TG68:m68k|data_out[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[52] -to "TG68:m68k|data_out[10]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[53] -to "TG68:m68k|data_out[11]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[54] -to "TG68:m68k|data_out[12]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[55] -to "TG68:m68k|data_out[13]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[56] -to "TG68:m68k|data_out[14]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[57] -to "TG68:m68k|data_out[15]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[58] -to "TG68:m68k|data_out[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[59] -to "TG68:m68k|data_out[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[60] -to "TG68:m68k|data_out[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[61] -to "TG68:m68k|data_out[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[62] -to "TG68:m68k|data_out[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[63] -to "TG68:m68k|data_out[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[64] -to "TG68:m68k|data_out[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[65] -to "TG68:m68k|data_out[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[66] -to "TG68:m68k|data_out[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[67] -to "TG68:m68k|dtack" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[68] -to "TG68:m68k|lds" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_RAM_BLOCK_TYPE=AUTO" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_INFO=805334528" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_POWER_UP_TRIGGER=0" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STORAGE_QUALIFIER_INVERSION_MASK_LENGTH=0" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ATTRIBUTE_MEM_MODE=OFF" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STATE_FLOW_USE_GENERATED=0" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_STATE_BITS=11" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_BUFFER_FULL_STOP=1" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_CURRENT_RESOURCE_WIDTH=1" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_LEVEL=1" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_IN_ENABLED=0" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ADVANCED_TRIGGER_ENTITY=basic,1," -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_LEVEL_PIPELINE=1" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_ENABLE_ADVANCED_TRIGGER=0" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[69] -to "TG68:m68k|reset" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[70] -to "TG68:m68k|rw" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[71] -to "TG68:m68k|uds" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[69] -to "TG68:m68k|reset" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[70] -to "TG68:m68k|rw" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[71] -to "TG68:m68k|uds" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[72] -to "addrController_top:ac0|_memoryLDS" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[73] -to "addrController_top:ac0|_memoryUDS" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[74] -to "addrController_top:ac0|_ramCS" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[75] -to "addrController_top:ac0|_ramOE" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[76] -to "addrController_top:ac0|_ramWE" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[72] -to "addrController_top:ac0|_memoryLDS" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[73] -to "addrController_top:ac0|_memoryUDS" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[74] -to "addrController_top:ac0|_ramCS" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[75] -to "addrController_top:ac0|_ramOE" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[76] -to "addrController_top:ac0|_ramWE" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[77] -to "addrController_top:ac0|_romOE" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[77] -to "addrController_top:ac0|_romOE" -section_id auto_signaltap_0 +set_global_assignment -name VERILOG_FILE data_io.v +set_global_assignment -name VERILOG_FILE user_io.v +set_global_assignment -name VERILOG_FILE osd.v +set_global_assignment -name VERILOG_FILE sdram.v +set_global_assignment -name SDC_FILE plusToo_top.sdc +set_global_assignment -name VERILOG_FILE scc.v +set_global_assignment -name VERILOG_FILE ps2_mouse.v +set_global_assignment -name VERILOG_FILE ps2.v +set_global_assignment -name VERILOG_FILE iwm.v +set_global_assignment -name VERILOG_FILE led7seg.v +set_global_assignment -name VERILOG_TEST_BENCH_FILE testbench.v +set_global_assignment -name VHDL_FILE TG68_fast.vhd +set_global_assignment -name VHDL_FILE TG68.vhd +set_global_assignment -name VERILOG_FILE via.v +set_global_assignment -name VERILOG_FILE addrDecoder.v +set_global_assignment -name VERILOG_FILE addrController_top.v +set_global_assignment -name VERILOG_FILE dataController_top.v +set_global_assignment -name VERILOG_FILE videoTimer.v +set_global_assignment -name VERILOG_FILE videoShifter.v +set_global_assignment -name VERILOG_FILE plusToo_top.v +set_global_assignment -name QIP_FILE clock325MHz.qip +set_global_assignment -name VERILOG_FILE debugPanel.v +set_global_assignment -name VERILOG_FILE fontGen.v +set_global_assignment -name VERILOG_FILE romAdapter.v +set_global_assignment -name VERILOG_FILE floppy.v +set_global_assignment -name SIGNALTAP_FILE stp1.stp +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[78] -to "clock325MHz:cs0|locked" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[78] -to "clock325MHz:cs0|locked" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_SEGMENT_SIZE=1024" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_SAMPLE_DEPTH=1024" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[79] -to "dataController_top:dc0|ps2_mouse:mouse|button" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[79] -to "dataController_top:dc0|ps2_mouse:mouse|button" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_clk -to "dataController_top:dc0|ps2_mouse:mouse|sysclk" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[80] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[81] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[82] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[83] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[84] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[85] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[86] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[87] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[88] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|istrobe" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[89] -to "dataController_top:dc0|ps2_mouse:mouse|state[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[90] -to "dataController_top:dc0|ps2_mouse:mouse|state[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[91] -to "dataController_top:dc0|ps2_mouse:mouse|state[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[92] -to "dataController_top:dc0|ps2_mouse:mouse|x1" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[93] -to "dataController_top:dc0|ps2_mouse:mouse|x2" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[94] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[95] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[96] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[97] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[98] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[99] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[100] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[101] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[102] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[103] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[104] -to "dataController_top:dc0|ps2_mouse:mouse|y1" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[105] -to "dataController_top:dc0|ps2_mouse:mouse|y2" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[106] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[107] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[108] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[109] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[110] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[111] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[112] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[113] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[114] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[115] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[116] -to "sdram:sdram|sd_cas" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[117] -to "sdram:sdram|sd_cs" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[118] -to "sdram:sdram|sd_ras" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_trigger_in[119] -to "sdram:sdram|sd_we" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[80] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[81] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[82] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[83] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[84] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[85] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[86] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[87] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|ibyte[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[88] -to "dataController_top:dc0|ps2_mouse:mouse|ps2:ps20|istrobe" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[89] -to "dataController_top:dc0|ps2_mouse:mouse|state[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[90] -to "dataController_top:dc0|ps2_mouse:mouse|state[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[91] -to "dataController_top:dc0|ps2_mouse:mouse|state[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[92] -to "dataController_top:dc0|ps2_mouse:mouse|x1" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[93] -to "dataController_top:dc0|ps2_mouse:mouse|x2" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[94] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[95] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[96] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[97] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[98] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[99] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[100] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[101] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[102] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[103] -to "dataController_top:dc0|ps2_mouse:mouse|xacc[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[104] -to "dataController_top:dc0|ps2_mouse:mouse|y1" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[105] -to "dataController_top:dc0|ps2_mouse:mouse|y2" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[106] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[0]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[107] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[1]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[108] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[2]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[109] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[3]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[110] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[4]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[111] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[5]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[112] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[6]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[113] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[7]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[114] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[8]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[115] -to "dataController_top:dc0|ps2_mouse:mouse|yacc[9]" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[116] -to "sdram:sdram|sd_cas" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[117] -to "sdram:sdram|sd_cs" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[118] -to "sdram:sdram|sd_ras" -section_id auto_signaltap_0 +set_instance_assignment -name CONNECT_TO_SLD_NODE_ENTITY_PORT acq_data_in[119] -to "sdram:sdram|sd_we" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_DATA_BITS=120" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_TRIGGER_BITS=120" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INVERSION_MASK=000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_INVERSION_MASK_LENGTH=384" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_LOWORD=44178" -section_id auto_signaltap_0 +set_global_assignment -name SLD_NODE_PARAMETER_ASSIGNMENT "SLD_NODE_CRC_HIWORD=27233" -section_id auto_signaltap_0 +set_global_assignment -name SLD_FILE db/stp1_auto_stripped.stp +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/cores/plus_too/plusToo_top.sdc b/cores/plus_too/plusToo_top.sdc new file mode 100644 index 0000000..8691306 --- /dev/null +++ b/cores/plus_too/plusToo_top.sdc @@ -0,0 +1,111 @@ +## Generated SDC file "plusToo_top.sdc" + +## Copyright (C) 1991-2011 Altera Corporation +## Your use of Altera Corporation's design tools, logic functions +## and other software and tools, and its AMPP partner logic +## functions, and any output files from any of the foregoing +## (including device programming or simulation files), and any +## associated documentation or information are expressly subject +## to the terms and conditions of the Altera Program License +## Subscription Agreement, Altera MegaCore Function License +## Agreement, or other applicable license agreement, including, +## without limitation, that your use is for the sole purpose of +## programming logic devices manufactured by Altera and sold by +## Altera or its authorized distributors. Please refer to the +## applicable agreement for further details. + + +## VENDOR "Altera" +## PROGRAM "Quartus II" +## VERSION "Version 11.0 Build 157 04/27/2011 SJ Web Edition" + +## DATE "Thu Sep 22 12:58:58 2011" + +## +## DEVICE "EP2C20F484C7" +## + + +#************************************************************** +# Time Information +#************************************************************** + +set_time_format -unit ns -decimal_places 3 + + + +#************************************************************** +# Create Clock +#************************************************************** + +create_clock -name {altera_reserved_tck} -period 100.000 -waveform { 0.000 50.000 } [get_ports {altera_reserved_tck}] +create_clock -name {clk50} -period 20.000 -waveform { 0.000 10.000 } [get_ports {clk50}] +create_clock -name {dataController_top:dc0|clkPhase[1]} -period 123.076 -waveform { 0.000 61.538 } [get_registers { dataController_top:dc0|clkPhase[1] }] + + +#************************************************************** +# Create Generated Clock +#************************************************************** + +create_generated_clock -name {clock325MHz:cs0|altpll:altpll_component|_clk0} -source [get_pins {cs0|altpll_component|pll|inclk[0]}] -duty_cycle 50.000 -multiply_by 13 -divide_by 20 -master_clock {clk50} [get_pins {cs0|altpll_component|pll|clk[0]}] + + +#************************************************************** +# Set Clock Latency +#************************************************************** + + + +#************************************************************** +# Set Clock Uncertainty +#************************************************************** + + + +#************************************************************** +# Set Input Delay +#************************************************************** + + + +#************************************************************** +# Set Output Delay +#************************************************************** + + + +#************************************************************** +# Set Clock Groups +#************************************************************** + +set_clock_groups -asynchronous -group [get_clocks {altera_reserved_tck}] + + +#************************************************************** +# Set False Path +#************************************************************** + + + +#************************************************************** +# Set Multicycle Path +#************************************************************** + + + +#************************************************************** +# Set Maximum Delay +#************************************************************** + + + +#************************************************************** +# Set Minimum Delay +#************************************************************** + + + +#************************************************************** +# Set Input Transition +#************************************************************** + diff --git a/cores/plus_too/plusToo_top.v b/cores/plus_too/plusToo_top.v new file mode 100644 index 0000000..d932df1 --- /dev/null +++ b/cores/plus_too/plusToo_top.v @@ -0,0 +1,416 @@ +// PlusToo_top for the MIST FPGA board + +module plusToo_top( + // clock inputs + input wire [ 2-1:0] CLOCK_27, // 27 MHz + // LED outputs + output wire LED, // LED Yellow + // UART + output wire UART_TX, // UART Transmitter (MIDI out) + input wire UART_RX, // UART Receiver (MIDI in) + // VGA + output wire VGA_HS, // VGA H_SYNC + output wire VGA_VS, // VGA V_SYNC + output wire [ 6-1:0] VGA_R, // VGA Red[5:0] + output wire [ 6-1:0] VGA_G, // VGA Green[5:0] + output wire [ 6-1:0] VGA_B, // VGA Blue[5:0] + // SDRAM + inout wire [ 16-1:0] SDRAM_DQ, // SDRAM Data bus 16 Bits + output wire [ 13-1:0] SDRAM_A, // SDRAM Address bus 13 Bits + output wire SDRAM_DQML, // SDRAM Low-byte Data Mask + output wire SDRAM_DQMH, // SDRAM High-byte Data Mask + output wire SDRAM_nWE, // SDRAM Write Enable + output wire SDRAM_nCAS, // SDRAM Column Address Strobe + output wire SDRAM_nRAS, // SDRAM Row Address Strobe + output wire SDRAM_nCS, // SDRAM Chip Select + output wire [ 2-1:0] SDRAM_BA, // SDRAM Bank Address + output wire SDRAM_CLK, // SDRAM Clock + output wire SDRAM_CKE, // SDRAM Clock Enable + // MINIMIG specific + output wire AUDIO_L, // sigma-delta DAC output left + output wire AUDIO_R, // sigma-delta DAC output right + // SPI + inout wire SPI_DO, + input wire SPI_DI, + input wire SPI_SCK, + input wire SPI_SS2, // fpga + input wire SPI_SS3, // OSD + input wire SPI_SS4, // "sniff" mode + input wire CONF_DATA0 // SPI_SS for user_io + ); + +// include the OSD into the video data path +osd #(10,0,2) osd ( + .pclk ( clk32 ), + + // spi for OSD + .sdi ( SPI_DI ), + .sck ( SPI_SCK ), + .ss ( SPI_SS3 ), + + .red_in ( { red, 2'b00 } ), + .green_in ( { green, 2'b00 } ), + .blue_in ( { blue, 2'b00 } ), + .hs_in ( hsync ), + .vs_in ( vsync ), + + .red_out ( VGA_R ), + .green_out ( VGA_G ), + .blue_out ( VGA_B ), + .hs_out ( VGA_HS ), + .vs_out ( VGA_VS ) +); + +// ------------------------------------------------------------------------- +// ------------------------------ data_io ---------------------------------- +// ------------------------------------------------------------------------- + +// include ROM download helper +wire dio_download; +wire dio_write; +wire [23:0] dio_addr; +wire [4:0] dio_index; +wire [15:0] dio_data; + +// disk image is being stored right after os rom at word offset 0x10000 +wire [20:0] dio_a = (dio_index == 0)?dio_addr[20:0]:{21'h10000 + dio_addr[20:0]}; + +data_io data_io ( + // io controller spi interface + .sck ( SPI_SCK ), + .ss ( SPI_SS2 ), + .sdi ( SPI_DI ), + + .downloading ( dio_download ), // signal indicating an active rom download + .index ( dio_index ), // 0=rom download, 1=disk image + + // external ram interface + .clk ( clk8 ), + .wr ( dio_write ), + .addr ( dio_addr ), + .data ( dio_data ) +); + +// keys and switches are dummies as the mist doesn't have any ... +wire [9:0] sw = 10'd0; +wire [3:0] key = 4'd0; + +// the macs video signals. To be fed into the MiSTs OSD overlay and then +// send to the VGA +wire hsync; +wire vsync; +wire [3:0] red; +wire [3:0] green; +wire [3:0] blue; + +// various debug signals for the DE1/DE2. These don't exist on the MIST +// and will be optimized away ... +wire [6:0] hex0; +wire [6:0] hex1; +wire [6:0] hex2; +wire [6:0] hex3; +wire [7:0] ledg; + +// ps2 interface for mouse, to be mapped into user_io +wire mouseClk; +wire mouseData; + + // NO REAL LOGIC SHOULD GO IN THIS MODULE! + // It may not exist in the hand-built Plus Too. + // Only interconnections and interfaces specific to the dev board should go here + + // synthesize a 32.5 MHz clock + wire clk32; + wire clk128; + wire pll_locked; + clock325MHz cs0( + .inclk0 ( CLOCK_27[0] ), + .c0 ( clk32 ), + .c1 ( clk128 ), + .c2 ( SDRAM_CLK ), + .locked ( pll_locked ) + ); + + // generate ~16kHz for ps2 + wire ps2_clk = ps2_clk_div[10]; + reg [10:0] ps2_clk_div; + always @(posedge clk8) + ps2_clk_div <= ps2_clk_div + 11'd1; + + // set the real-world inputs to sane defaults + localparam keyClk = 1'b0, + keyData = 1'b0, + serialIn = 1'b0, + interruptButton = 1'b0, + configROMSize = 1'b1, // 128K ROM + configRAMSize = 2'b01; // 512K RAM + + // interconnects + // CPU + wire clk8, _cpuReset, _cpuAS, _cpuUDS, _cpuLDS, _cpuRW, _cpuDTACK, cpuDriveData; + wire [2:0] _cpuIPL; + wire [7:0] cpuAddrHi; + wire [23:0] cpuAddr; + wire [15:0] cpuDataOut; + + // RAM/ROM + wire _romCS, _romOE; + wire _ramCS, _ramOE, _ramWE; + wire _memoryUDS, _memoryLDS; + wire videoBusControl; + wire [21:0] memoryAddr; + wire [15:0] memoryDataOut; + wire memoryDriveData; + wire [15:0] memoryDataInMux; + + // peripherals + wire loadSound, loadNormalPixels, loadDebugPixels, pixelOut, _hblank, _vblank; + wire memoryOverlayOn, selectSCC, selectIWM, selectVIA, selectInterruptVectors; + wire [15:0] dataControllerDataOut; + wire dataControllerDriveData; + + // debug panel + wire _debugDTACK, driveDebugData, loadPixels, extraRomReadAck; + wire [15:0] debugDataOut; + wire [21:0] extraRomReadAddr; + + // LED debug lights + assign ledg = { 2'b00, diskInDrive[1], diskInDrive[1], diskInDrive[0], diskInDrive[0], 2'b00 }; + + // convert 1-bit pixel data to 4:4:4 RGB + // force pixels in debug area to appear green + assign red[3:0] = _vblank == 1'b0 ? 4'h0 : { pixelOut, pixelOut, pixelOut, pixelOut }; + assign green[3:0] = { pixelOut, pixelOut, pixelOut, pixelOut }; + assign blue[3:0] = _vblank == 1'b0 ? 4'h0 : { pixelOut, pixelOut, pixelOut, pixelOut }; + + // memory-side data input mux + // In a hand-built system, both RAM and ROM data will be on the same physical pins, + // making this mux unnecessary + assign memoryDataInMux = driveDebugData ? debugDataOut : + sdram_do; + + // the configuration string is returned to the io controller to allow + // it to control the menu on the OSD + parameter CONF_STR = { + "PLUS_TOO;;", + "F1,BIN;", + "T2,Reset" + }; + + parameter CONF_STR_LEN = 10+7+8; + + // the status register is controlled by the on screen display (OSD) + wire [7:0] status; + wire [1:0] buttons; + + // include user_io module for arm controller communication + user_io #(.STRLEN(CONF_STR_LEN)) user_io ( + .conf_str ( CONF_STR ), + + .SPI_CLK ( SPI_SCK ), + .SPI_SS_IO ( CONF_DATA0 ), + .SPI_MISO ( SPI_DO ), + .SPI_MOSI ( SPI_DI ), + + .status ( status ), + .buttons ( buttons ), + + // ps2 interface + .ps2_clk ( ps2_clk ), + .ps2_kbd_clk ( ), + .ps2_kbd_data ( ), + .ps2_mouse_clk ( mouseClk ), + .ps2_mouse_data( mouseData ) + ); + + + debugPanel dp( + .clk8(clk8), + .sw(sw), + .key(key), + .videoBusControl(videoBusControl), + .loadNormalPixels(loadNormalPixels), + .loadDebugPixels(loadDebugPixels), + .loadPixelsOut(loadPixels), + ._dtackIn(_cpuDTACK), + .cpuAddrHi(cpuAddrHi), + .cpuAddr(cpuAddr), + ._cpuRW(_cpuRW), + ._cpuUDS(_cpuUDS), + ._cpuLDS(_cpuLDS), + .dataControllerDataOut(dataControllerDataOut), + .cpuDataOut(cpuDataOut), + .memoryAddr(memoryAddr), + ._dtackOut(_debugDTACK), + .hex0(hex0), + .hex1(hex1), + .hex2(hex2), + .hex3(hex3), + .driveDebugData(driveDebugData), + .debugDataOut(debugDataOut), + .extraRomReadAck(extraRomReadAck)); + + wire [2:0] _debugIPL = sw[0] == 1'b1 ? 3'b111 : _cpuIPL; // suppress interrupts when sw0 on + + TG68 m68k( + .clk(clk8), + .reset(_cpuReset), + .clkena_in(1'b1), + .data_in(dataControllerDataOut), + .IPL(_debugIPL), + .dtack(_debugDTACK), + .addr({cpuAddrHi, cpuAddr}), + .data_out(cpuDataOut), + .as(_cpuAS), + .uds(_cpuUDS), + .lds(_cpuLDS), + .rw(_cpuRW), + .drive_data(cpuDriveData)); + + addrController_top ac0( + .clk8(clk8), + .cpuAddr(cpuAddr), + ._cpuAS(_cpuAS), + ._cpuUDS(_cpuUDS), + ._cpuLDS(_cpuLDS), + ._cpuRW(_cpuRW), + ._cpuDTACK(_cpuDTACK), + .configROMSize(configROMSize), + .configRAMSize(configRAMSize), + .memoryAddr(memoryAddr), + ._memoryUDS(_memoryUDS), + ._memoryLDS(_memoryLDS), + ._romCS(_romCS), + ._romOE(_romOE), + ._ramCS(_ramCS), + ._ramOE(_ramOE), + ._ramWE(_ramWE), + .videoBusControl(videoBusControl), + .selectSCC(selectSCC), + .selectIWM(selectIWM), + .selectVIA(selectVIA), + .selectInterruptVectors(selectInterruptVectors), + .hsync(hsync), + .vsync(vsync), + ._hblank(_hblank), + ._vblank(_vblank), + .loadNormalPixels(loadNormalPixels), + .loadDebugPixels(loadDebugPixels), + .loadSound(loadSound), + .memoryOverlayOn(memoryOverlayOn), + + .extraRomReadAddr(extraRomReadAddr), + .extraRomReadAck(extraRomReadAck)); + + wire [1:0] diskInDrive; + + // addional ~8ms delay in reset + wire n_reset = (rst_cnt == 0); + reg [15:0] rst_cnt; + always @(posedge clk8) begin + // various source can reset the mac + if(!pll_locked || status[0] || status[2] || buttons[1] || dio_download) + rst_cnt <= 16'd65535; + else if(rst_cnt != 0) + rst_cnt <= rst_cnt - 16'd1; + end + + dataController_top dc0( + .clk32(clk32), + .clk8out(clk8), + .clk8(clk8), + ._systemReset(n_reset), + ._cpuReset(_cpuReset), + ._cpuIPL(_cpuIPL), + ._cpuUDS(_cpuUDS), + ._cpuLDS(_cpuLDS), + ._cpuRW(_cpuRW), + .cpuDataIn(cpuDataOut), + .cpuDataOut(dataControllerDataOut), + .cpuDriveData(dataControllerDriveData), + .cpuAddrRegHi(cpuAddr[12:9]), + .cpuAddrRegLo(cpuAddr[2:1]), + .selectSCC(selectSCC), + .selectIWM(selectIWM), + .selectVIA(selectVIA), + .selectInterruptVectors(selectInterruptVectors), + .videoBusControl(videoBusControl), + .memoryDataOut(memoryDataOut), + .memoryDataIn(memoryDataInMux), + .memoryDriveData(memoryDriveData), + .keyClk(keyClk), + .keyData(keyData), + .mouseClk(mouseClk), + .mouseData(mouseData), + .serialIn(serialIn), + ._hblank(_hblank), + ._vblank(_vblank), + .pixelOut(pixelOut), + .loadPixels(loadPixels), + .loadSound(loadSound), + .interruptButton(1'b1), + .memoryOverlayOn(memoryOverlayOn), + .insertDisk( 2'b01 ), + .diskInDrive(diskInDrive), + + .extraRomReadAddr(extraRomReadAddr), + .extraRomReadAck(extraRomReadAck)); + + // ram/rom maps directly into 68k address space + +// multiplex sdram between mac and the rom downloader +// 4MB RAM +// wire [24:0] sdram_addr = dio_download?{ 3'b001, dio_a[20:0] }:{ 2'b00, ~_romOE, memoryAddr[21:1] }; + +wire [20:0] memoryAddrEx = + extraRomReadAck?memoryAddr[21:1]: // full access to floppy image +// memoryAddr[21:1]; // CPU access not masked giving 4MB ram + { 3'b000, memoryAddr[18:1]} ; // CPU access masked for 512k ram + +wire [24:0] sdram_addr = dio_download?{ 4'b0001, dio_a[20:0] }:{ 3'b000, ~_romOE, memoryAddrEx }; + +wire [15:0] sdram_din = dio_download?dio_data:memoryDataOut; +wire [1:0] sdram_ds = dio_download?2'b11:{ !_memoryUDS, !_memoryLDS }; +wire sdram_we = dio_download?dio_write:!_ramWE; +wire sdram_oe = dio_download?1'b0:(!_ramOE || !_romOE); + + +// during rom/disk download ffff is returned so the screen is black during download +// "extra rom" is used to hold the disk image. It's expected to be byte wide and +// we thus need to properly demultiplex the word returned from sdram in that case +wire [15:0] extra_rom_data_demux = memoryAddr[0]? + {sdram_out[7:0],sdram_out[7:0]}:{sdram_out[15:8],sdram_out[15:8]}; +wire [15:0] sdram_do = dio_download?16'hffff: + extraRomReadAck?extra_rom_data_demux: + sdram_out; +wire [15:0] sdram_out; + +assign SDRAM_CKE = 1'b1; + +sdram sdram ( + // interface to the MT48LC16M16 chip + .sd_data ( SDRAM_DQ ), + .sd_addr ( SDRAM_A ), + .sd_dqm ( {SDRAM_DQMH, SDRAM_DQML} ), + .sd_cs ( SDRAM_nCS ), + .sd_ba ( SDRAM_BA ), + .sd_we ( SDRAM_nWE ), + .sd_ras ( SDRAM_nRAS ), + .sd_cas ( SDRAM_nCAS ), + + // system interface + .clk_128 ( clk128 ), + .clk_8 ( clk8 ), + .init ( !pll_locked ), + + // cpu/chipset interface + // map rom to sdram word address $200000 - $20ffff + .din ( sdram_din ), + .addr ( sdram_addr ), + .ds ( sdram_ds ), + .we ( sdram_we ), + .oe ( sdram_oe ), + .dout ( sdram_out ) +); + +endmodule diff --git a/cores/plus_too/ps2.v b/cores/plus_too/ps2.v new file mode 100644 index 0000000..5c8aa7f --- /dev/null +++ b/cores/plus_too/ps2.v @@ -0,0 +1,172 @@ +`timescale 1ns / 100ps + +/* + * Generic PS2 interface module + * + * istrobe, oreq, oack and timeout are all 1-clk strobes, + * ibyte must be latched on that strobe, obyte is latched + * as oreq is detected, oreq is ignore while already + * sending. + * + * we ignore bad parity on input for now + */ + +module ps2(input sysclk, + input reset, + +// inout ps2dat, +// inout ps2clk, + input ps2dat, + input ps2clk, + + output istrobe, + output [7:0] ibyte, + + input oreq, + input [7:0] obyte, + output oack, + + output timeout, + + output[1:0] dbg_state + ); + + reg [7:0] clkbuf; + reg [7:0] datbuf; + reg clksync; + reg clkprev; + reg datsync; + reg [10:0] shiftreg; + reg [3:0] shiftcnt; + wire shiftend; + reg [1:0] state; + wire datout; + reg [23:0] timecnt; + wire clkdown; + wire opar; + + /* State machine */ + localparam ps2_state_idle = 0; + localparam ps2_state_ring = 1; + localparam ps2_state_send = 2; + localparam ps2_state_recv = 3; + + always@(posedge sysclk or posedge reset) begin + if (reset) + state <= ps2_state_idle; + else begin + if (timeout && !oreq) + state <= ps2_state_idle; + else + case(state) + ps2_state_idle: begin + if (oreq) + state <= ps2_state_ring; + else if (clkdown) + state <= ps2_state_recv; + end + ps2_state_ring: begin + if (timecnt[12]) + state <= ps2_state_send; + end + ps2_state_send: begin + if (shiftend) + state <= ps2_state_idle; + end + ps2_state_recv: begin + if (oreq) + state <= ps2_state_ring; + else if (shiftend) + state <= ps2_state_idle; + end + endcase + end + end + assign dbg_state = state; + + /* Tristate control of clk & data */ + assign datout = state == ps2_state_ring || state == ps2_state_send; +// assign ps2dat = (datout & ~shiftreg[0]) ? 1'b0 : 1'bz; +// assign ps2clk = (state == ps2_state_ring) ? 1'b0 : 1'bz; + + /* Bit counter */ + always@(posedge sysclk or posedge reset) begin + if (reset) + shiftcnt <= 10; + else begin + if (state == ps2_state_idle) + shiftcnt <= 10; + else if (state == ps2_state_ring) + shiftcnt <= 11; + else if (clkdown && state != ps2_state_ring) + shiftcnt <= shiftcnt - 1'b1; + end + end + + /* Shift register, ticks on falling edge of ps2 clock */ + always@(posedge sysclk or posedge reset) begin + if (reset) + shiftreg <= 0; + else begin + if (oreq) + shiftreg <= { 1'b1, opar, obyte, 1'b0 }; + else if (clkdown && state != ps2_state_ring) + shiftreg <= { datsync, shiftreg[10:1] }; + end + end + + + /* Ack/strobe logic */ + assign shiftend = shiftcnt == 0; + assign oack = (state == ps2_state_send && shiftend); + assign istrobe = (state == ps2_state_recv && shiftend); + assign ibyte = shiftreg[8:1]; + + /* Filters/synchronizers on PS/2 clock */ + always@(posedge sysclk or posedge reset) begin + if (reset) begin + clkbuf <= 0; + clksync <= 0; + clkprev <= 0; + end else begin + clkprev <= clksync; + clkbuf <= { clkbuf[6:0], ps2clk }; + if (clkbuf[7:2] == 6'b000000) + clksync <= 0; + if (clkbuf[7:2] == 6'b111111) + clksync <= 1; + end + end + assign clkdown = clkprev & ~clksync; + + /* Filters/synchronizers on PS/2 data */ + always@(posedge sysclk or posedge reset) begin + if (reset) begin + datbuf <= 0; + datsync <= 0; + end else begin + datbuf <= { datbuf[6:0], ps2dat }; + if (datbuf[7:2] == 6'b000000) + datsync <= 0; + if (datbuf[7:2] == 6'b111111) + datsync <= 1; + end + end + + /* Parity for output byte */ + assign opar = ~(obyte[0] ^ obyte[1] ^ obyte[2] ^ obyte[3] ^ + obyte[4] ^ obyte[5] ^ obyte[6] ^ obyte[7]); + + /* Timeout logic */ + always@(posedge sysclk or posedge reset) begin + if (reset) + timecnt <= 0; + else begin + if (clkdown | oreq) + timecnt <= 0; + else + timecnt <= timecnt + 1'b1; + end + end + assign timeout = (timecnt == 24'hff_ffff); +endmodule diff --git a/cores/plus_too/ps2_mouse.v b/cores/plus_too/ps2_mouse.v new file mode 100644 index 0000000..3474f66 --- /dev/null +++ b/cores/plus_too/ps2_mouse.v @@ -0,0 +1,250 @@ +`timescale 1ns / 100ps + +/* + * PS2 mouse protocol + * Bit 7 6 5 4 3 2 1 0 + * Byte 0: YOVR XOVR YSGN XSGN 1 MBUT RBUT LBUT + * Byte 1: XMOVE + * Byte 2: YMOVE + */ + +/* + * PS2 Mouse to Mac interface module + */ +module ps2_mouse(input sysclk, + input reset, + + input ps2dat, + input ps2clk, + + output reg x1, + output reg y1, + output reg x2, + output reg y2, + output reg button, + + output reg [15:0] debug +); + wire istrobe; + wire [7:0] ibyte; + wire timeout; + wire oack; + reg [7:0] obyte; + reg oreq; + reg [2:0] state; + reg [2:0] next; + reg [7:0] nbyte; + reg nreq; + reg [9:0] xacc; + reg [9:0] yacc; + reg xsign; + reg ysign; + reg [12:0] clkdiv; + wire tick; + wire[1:0] dbg_lowstate; + + ps2 ps20(.sysclk(sysclk), + .reset(reset), + .ps2dat(ps2dat), + .ps2clk(ps2clk), + .istrobe(istrobe), + .ibyte(ibyte), + .oreq(oreq), + .obyte(obyte), + .oack(oack), + .timeout(timeout), + .dbg_state(dbg_lowstate)); + + /* State machine: + * + * - at state_init: wait for BAT reply + * * 0xaa -> state_id + * * 0xfa -> send 0xff -> state_init + * * bad reply -> send 0xff -> state_init + * * timeout -> send 0xff -> state_init + * + * - at state_id: wait for device_id + * * 0x00 -> send 0xf4 -> state_setup + * * bad reply -> send 0xff -> state_init + * * timeout -> send 0xff -> state_init + * + * - at state_setup: wait for enable data reporting ack + * * 0xfa -> state_byte0 + * * bad reply -> send 0xff -> state_init + * * timeout -> send 0xff -> state_init + * + * - at state_byte0: wait for data byte 0 + * * data -> state_byte1 + * * data -> state_byte1 + * * timeout -> send 0xff -> state_init + * + * - at state_byte1: wait for data byte 1 + * * data -> state_byte2 + * * timeout -> send 0xff -> state_init + * + * - at state_byte2: wait for data byte 2 + * * data -> state_byte0 + * * timeout -> send 0xff -> state_init + */ + localparam ps2m_state_init = 3'h0; + localparam ps2m_state_id = 3'h1; + localparam ps2m_state_setup = 3'h2; + localparam ps2m_state_byte0 = 3'h3; + localparam ps2m_state_byte1 = 3'h4; + localparam ps2m_state_byte2 = 3'h5; + + /* Unlike my other modules, here I'll play with a big fat + * combo logic. The outputs are: + * - oreq : triggers sending of a byte. Set based on either + * timeout or istrobe, and as such only set for a + * clock. + * - next : next state + * - obyte : next byte to send + */ + always@(timeout or state or istrobe or ibyte) begin + nreq = 0; + next = state; + nbyte = 8'hff; +// if (timeout) begin +// next = ps2m_state_byte0; // ps2m_state_init +// nreq = 1; +// end else + if (istrobe) + case(state) + ps2m_state_init: begin + if (ibyte == 8'haa) + next = ps2m_state_id; + else if (ibyte != 8'hfa) + nreq = 1; + end + ps2m_state_id: begin + nreq = 1; + if (ibyte == 8'h00) begin + nbyte = 8'hf4; + next = ps2m_state_setup; + end else + next = ps2m_state_init; + end + ps2m_state_setup: begin + if (ibyte == 8'hfa) + next = ps2m_state_byte0; + else begin + nreq = 1; + next = ps2m_state_init; + end + end + ps2m_state_byte0: next = ps2m_state_byte1; + ps2m_state_byte1: next = ps2m_state_byte2; + ps2m_state_byte2: next = ps2m_state_byte0; + default: // shouldn't ever get into these states + next = ps2m_state_init; + endcase + end + + /* State related latches. We latch oreq and obyte, we don't + * necessarily have to but that avoids back to back + * receive/send at the low level which can upset things + */ + always@(posedge sysclk or posedge reset) + if (reset) + state <= ps2m_state_byte0; // ps2m_state_init + else + state <= next; + always@(posedge sysclk or posedge reset) + if (reset) + oreq <= 0; + else + oreq <= nreq; + always@(posedge sysclk or posedge reset) + if (reset) + obyte <= 0; + else + obyte <= nbyte; + + /* Capture button state */ + always@(posedge sysclk or posedge reset) + if (reset) + button <= 1; + else if (istrobe && state == ps2m_state_byte0) + button <= ~ibyte[0]; + + /* Clock divider to flush accumulators */ + always@(posedge sysclk or posedge reset) + if (reset) + clkdiv <= 0; + else + clkdiv <= clkdiv + 1'b1; + assign tick = clkdiv == 0; + + /* Toggle output lines base on accumulator */ + always@(posedge sysclk or posedge reset) begin + if (reset) begin + x1 <= 0; + x2 <= 0; + end else if (tick && xacc != 0) begin + x1 <= ~x1; + x2 <= ~x1 ^ ~xacc[9]; + end + end + always@(posedge sysclk or posedge reset) begin + if (reset) begin + y1 <= 0; + y2 <= 0; + end else if (tick && yacc != 0) begin + y1 <= ~y1; + y2 <= ~y1 ^ ~yacc[9]; + end + end + + /* Capture sign bits */ + always@(posedge sysclk or posedge reset) begin + if (reset) begin + xsign <= 0; + ysign <= 0; + end else if (istrobe && state == ps2m_state_byte0) begin + xsign <= ibyte[4]; + ysign <= ibyte[5]; + end + end + + /* Movement accumulators. Needs tuning ! */ + always@(posedge sysclk or posedge reset) begin + if (reset) + xacc <= 0; + else begin + /* Add movement, convert to a 10-bit number if not over */ + if (istrobe && state == ps2m_state_byte1 && xacc[8] == xacc[9]) + xacc <= xacc + { xsign, xsign, ibyte }; + else + /* Decrement */ + if (tick && xacc != 0) + xacc <= xacc + { {9{~xsign}}, 1'b1 }; + end + end + + always@(posedge sysclk or posedge reset) begin + if (reset) + yacc <= 0; + else begin + /* Add movement, convert to a 10-bit number if not over*/ + if (istrobe && state == ps2m_state_byte2 && yacc[8] == yacc[9]) + yacc <= yacc + { ysign, ysign, ibyte }; + else + /* Decrement */ + if (tick && yacc != 0) + yacc <= yacc + { {9{~ysign}}, 1'b1 }; + end + end + + /* Some debug signals for my own sanity */ + always@(posedge sysclk or posedge reset) begin + if (reset) + debug <= 0; + else begin + if (istrobe) + debug[15:8] <= ibyte; + debug[7:0] <= { ps2clk, ps2dat, dbg_lowstate, 1'b0, + state }; + end + end +endmodule diff --git a/cores/plus_too/ramAdapter.v b/cores/plus_too/ramAdapter.v new file mode 100644 index 0000000..452a977 --- /dev/null +++ b/cores/plus_too/ramAdapter.v @@ -0,0 +1,18 @@ +module ramAdapter( + // CPU interface + input clk8, + input [20:0] addr, // word address + output [15:0] dataOut, + input _OE, + input _CS, + input _UDS, + input _LDS, + + // external interface to 8-bit Flash + output [21:0] flashAddr, // byte address + input [7:0] flashData, + output flashCE, + output flashOE +); + +endmodule diff --git a/cores/plus_too/readme.md b/cores/plus_too/readme.md new file mode 100644 index 0000000..dc6e0cd --- /dev/null +++ b/cores/plus_too/readme.md @@ -0,0 +1,23 @@ +Plus Too for MiST +================= + +This is the source code of the MiST port of the Plus Too project. The +original files can be founf at: + +http://www.bigmessowires.com/2012/12/15/plus-too-files/ + +Changes +------- + +All changes made to the original source code are due to the porting process +itself. No functional changes have been made (yet). Major changes were: + +- Use of SDRAM for RAM as well as ROM and floppy image buffer + - SDRAM clocking at 130 MHz + - ROM upload using the MISTs IO controller + - Floppy image upload using the MISTs IO controller +- Use of MiSTs on screen display for floppy image selection +- Use of MiSTS PS2 mouse emulation + - Need to disable all parts dealing with mouse inialization + +Binaries are available at https://github.com/mist-devel/mist-binaries/tree/master/cores/plustoo. diff --git a/cores/plus_too/scc.v b/cores/plus_too/scc.v new file mode 100644 index 0000000..70e9fee --- /dev/null +++ b/cores/plus_too/scc.v @@ -0,0 +1,688 @@ +`timescale 1ns / 100ps + +/* + * Zilog 8530 SCC module for minimigmac. + * + * Located on high data bus, but writes are done at odd addresses as + * LDS is used as WR signals or something like that on a Mac Plus. + * + * We don't care here and just ignore which side was used. + * + * NOTE: We don't implement the 85C30 or ESCC additions such as WR7' + * for now, it's all very simplified + */ + +module scc(input sysclk, + input reset_hw, + + /* Bus interface. 2-bit address, to be wired + * appropriately upstream (to A1..A2). + */ + input cs, + input we, + input [1:0] rs, /* [1] = data(1)/ctl [0] = a_side(1)/b_side */ + input [7:0] wdata, + output [7:0] rdata, + output _irq, + + /* A single serial port on Minimig */ + input rxd, + output txd, + input cts, /* normally wired to device DTR output + * on Mac cables. That same line is also + * connected to the TRxC input of the SCC + * to do fast clocking but we don't do that + * here + */ + output rts, /* on a real mac this activates line + * drivers when low */ + + /* DCD for both ports are hijacked by mouse interface */ + input dcd_a, /* We don't synchronize those inputs */ + input dcd_b, + + /* Write request */ + output wreq + ); + + /* Register access is semi-insane */ + reg [3:0] rindex; + wire wreg_a; + wire wreg_b; + wire wdata_a; + wire wdata_b; + wire rdata_a; + wire rdata_b; + + /* Resets via WR9, one clk pulses */ + wire reset_a; + wire reset_b; + wire reset; + + /* Data registers */ + reg [7:0] data_a = 0; + reg [7:0] data_b = 0; + + /* Read registers */ + wire [7:0] rr0_a; + wire [7:0] rr0_b; + wire [7:0] rr1_a; + wire [7:0] rr1_b; + wire [7:0] rr2_b; + wire [7:0] rr3_a; + wire [7:0] rr10_a; + wire [7:0] rr10_b; + wire [7:0] rr15_a; + wire [7:0] rr15_b; + + /* Write registers. Only some are implemented, + * some result in actions on write and don't + * store anything + */ + reg [7:0] wr1_a; + reg [7:0] wr1_b; + reg [7:0] wr2; + reg [7:0] wr3_a; + reg [7:0] wr3_b; + reg [7:0] wr4_a; + reg [7:0] wr4_b; + reg [7:0] wr5_a; + reg [7:0] wr5_b; + reg [7:0] wr6_a; + reg [7:0] wr6_b; + reg [7:0] wr7_a; + reg [7:0] wr7_b; + reg [7:0] wr8_a; + reg [7:0] wr8_b; + reg [5:0] wr9; + reg [7:0] wr10_a; + reg [7:0] wr10_b; + reg [7:0] wr11_a; + reg [7:0] wr11_b; + reg [7:0] wr12_a; + reg [7:0] wr12_b; + reg [7:0] wr13_a; + reg [7:0] wr13_b; + reg [7:0] wr14_a; + reg [7:0] wr14_b; + reg [7:0] wr15_a; + reg [7:0] wr15_b; + + /* Status latches */ + reg latch_open_a; + reg latch_open_b; + reg dcd_latch_a; + reg dcd_latch_b; + wire dcd_ip_a; + wire dcd_ip_b; + wire do_latch_a; + wire do_latch_b; + wire do_extreset_a; + wire do_extreset_b; + + /* IRQ stuff */ + wire rx_irq_pend_a; + wire rx_irq_pend_b; + wire tx_irq_pend_a; + wire tx_irq_pend_b; + wire ex_irq_pend_a; + wire ex_irq_pend_b; + reg ex_irq_ip_a; + reg ex_irq_ip_b; + wire [2:0] rr2_vec_stat; + + /* Register/Data access helpers */ + assign wreg_a = cs & we & (~rs[1]) & rs[0]; + assign wreg_b = cs & we & (~rs[1]) & ~rs[0]; + assign wdata_a = cs & we & (rs[1] | (rindex == 8)) & rs[0]; + assign wdata_b = cs & we & (rs[1] | (rindex == 8)) & ~rs[0]; + assign rdata_a = cs & (~we) & (rs[1] | (rindex == 8)) & rs[0]; + assign rdata_b = cs & (~we) & (rs[1] | (rindex == 8)) & ~rs[0]; + + /* Register index is set by a write to WR0 and reset + * after any subsequent write. We ignore the side + */ + always@(posedge sysclk or posedge reset) begin + if (reset) + rindex <= 0; + else if (cs && !rs[1]) begin + /* Default, reset index */ + rindex <= 0; + + /* Write to WR0 */ + if (we && rindex == 0) begin + /* Get low index bits */ + rindex[2:0] <= wdata[2:0]; + + /* Add point high */ + rindex[3] <= (wdata[5:3] == 3'b001); + end + end + end + + /* Reset logic (write to WR9 cmd) + * + * Note about resets: Some bits are documented as unchanged/undefined on + * HW reset by the doc. We apply this to channel and soft resets, however + * we _do_ reset every bit on an external HW reset in this implementation + * to make the FPGA & synthesis tools happy. + */ + assign reset = ((wreg_a | wreg_b) & (rindex == 9) & (wdata[7:6] == 2'b11)) | reset_hw; + assign reset_a = ((wreg_a | wreg_b) & (rindex == 9) & (wdata[7:6] == 2'b10)) | reset; + assign reset_b = ((wreg_a | wreg_b) & (rindex == 9) & (wdata[7:6] == 2'b01)) | reset; + + /* WR1 + * Reset: bit 5 and 2 unchanged */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr1_a <= 0; + else begin + if (reset_a) + wr1_a <= { 2'b00, wr1_a[5], 2'b00, wr1_a[2], 2'b00 }; + else if (wreg_a && rindex == 1) + wr1_a <= wdata; + end + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr1_b <= 0; + else begin + if (reset_b) + wr1_b <= { 2'b00, wr1_b[5], 2'b00, wr1_b[2], 2'b00 }; + else if (wreg_b && rindex == 1) + wr1_b <= wdata; + end + end + + /* WR2 + * Reset: unchanged + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr2 <= 0; + else if ((wreg_a || wreg_b) && rindex == 2) + wr2 <= wdata; + end + + /* WR3 + * Reset: bit 0 to 0, otherwise unchanged. + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr3_a <= 0; + else begin + if (reset_a) + wr3_a[0] <= 0; + else if (wreg_a && rindex == 3) + wr3_a <= wdata; + end + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr3_b <= 0; + else begin + if (reset_b) + wr3_b[0] <= 0; + else if (wreg_b && rindex == 3) + wr3_b <= wdata; + end + end + + /* WR4 + * Reset: Bit 2 to 1, otherwise unchanged + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr4_a <= 0; + else begin + if (reset_a) + wr4_a[2] <= 1; + else if (wreg_a && rindex == 4) + wr4_a <= wdata; + end + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr4_b <= 0; + else begin + if (reset_b) + wr4_b[2] <= 1; + else if (wreg_b && rindex == 4) + wr4_b <= wdata; + end + end + + /* WR5 + * Reset: Bits 7,4,3,2,1 to 0 + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr5_a <= 0; + else begin + if (reset_a) + wr5_a <= { 1'b0, wr5_a[6:5], 4'b0000, wr5_a[0] }; + else if (wreg_a && rindex == 5) + wr5_a <= wdata; + end + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr5_b <= 0; + else begin + if (reset_b) + wr5_b <= { 1'b0, wr5_b[6:5], 4'b0000, wr5_b[0] }; + else if (wreg_b && rindex == 5) + wr5_b <= wdata; + end + end + + /* WR6 + * Reset: Unchanged. + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr6_a <= 0; + else if (wreg_a && rindex == 6) + wr6_a <= wdata; + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr6_b <= 0; + else if (wreg_b && rindex == 6) + wr6_b <= wdata; + end + + /* WR7 + * Reset: Unchanged. + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr7_a <= 0; + else if (wreg_a && rindex == 7) + wr7_a <= wdata; + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr7_b <= 0; + else if (wreg_b && rindex == 7) + wr7_b <= wdata; + end + + /* WR9. Special: top bits are reset, handled separately, bottom + * bits are only reset by a hw reset + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr9 <= 0; + else if ((wreg_a || wreg_b) && rindex == 9) + wr9 <= wdata[5:0]; + end + + /* WR10 + * Reset: all 0, except chanel reset retains 6 and 5 + */ + always@(posedge sysclk or posedge reset) begin + if (reset) + wr10_a <= 0; + else begin + if (reset_a) + wr10_a <= { 1'b0, wr10_a[6:5], 5'b00000 }; + else if (wreg_a && rindex == 10) + wr10_a <= wdata; + end + end + always@(posedge sysclk or posedge reset) begin + if (reset) + wr10_b <= 0; + else begin + if (reset_b) + wr10_b <= { 1'b0, wr10_b[6:5], 5'b00000 }; + else if (wreg_b && rindex == 10) + wr10_b <= wdata; + end + end + + /* WR11 + * Reset: On full reset only, not channel reset + */ + always@(posedge sysclk or posedge reset) begin + if (reset) + wr11_a <= 8'b00001000; + else if (wreg_a && rindex == 11) + wr11_a <= wdata; + end + always@(posedge sysclk or posedge reset) begin + if (reset) + wr11_b <= 8'b00001000; + else if (wreg_b && rindex == 11) + wr11_b <= wdata; + end + + /* WR12 + * Reset: Unchanged + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr12_a <= 0; + else if (wreg_a && rindex == 12) + wr12_a <= wdata; + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr12_b <= 0; + else if (wreg_b && rindex == 12) + wr12_b <= wdata; + end + + /* WR13 + * Reset: Unchanged + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr13_a <= 0; + else if (wreg_a && rindex == 13) + wr13_a <= wdata; + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr13_b <= 0; + else if (wreg_b && rindex == 13) + wr13_b <= wdata; + end + + /* WR14 + * Reset: Full reset maintains top 2 bits, + * Chan reset also maitains bottom 2 bits, bit 4 also + * reset to a different value + */ + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr14_a <= 0; + else begin + if (reset) + wr14_a <= { wr14_a[7:6], 6'b110000 }; + else if (reset_a) + wr14_a <= { wr14_a[7:6], 4'b1000, wr14_a[1:0] }; + else if (wreg_a && rindex == 14) + wr14_a <= wdata; + end + end + always@(posedge sysclk or posedge reset_hw) begin + if (reset_hw) + wr14_b <= 0; + else begin + if (reset) + wr14_b <= { wr14_b[7:6], 6'b110000 }; + else if (reset_b) + wr14_b <= { wr14_b[7:6], 4'b1000, wr14_b[1:0] }; + else if (wreg_b && rindex == 14) + wr14_b <= wdata; + end + end + + /* WR15 */ + always@(posedge sysclk or posedge reset) begin + if (reset) + wr15_a <= 8'b11111000; + else if (wreg_a && rindex == 15) + wr15_a <= wdata; + end + always@(posedge sysclk or posedge reset) begin + if (reset) + wr15_b <= 8'b11111000; + else if (wreg_b && rindex == 15) + wr15_b <= wdata; + end + + /* Read data mux */ + assign rdata = rs[1] && rs[0] ? data_a : + rs[1] ? data_b : + rindex == 0 && rs[0] ? rr0_a : + rindex == 0 ? rr0_b : + rindex == 1 && rs[0] ? rr1_a : + rindex == 1 ? rr1_b : + rindex == 2 && rs[0] ? wr2 : + rindex == 2 ? rr2_b : + rindex == 3 && rs[0] ? rr3_a : + rindex == 3 ? 8'h00 : + rindex == 4 && rs[0] ? rr0_a : + rindex == 4 ? rr0_b : + rindex == 5 && rs[0] ? rr1_a : + rindex == 5 ? rr1_b : + rindex == 6 && rs[0] ? wr2 : + rindex == 6 ? rr2_b : + rindex == 7 && rs[0] ? rr3_a : + rindex == 7 ? 8'h00 : + + rindex == 8 && rs[0] ? data_a : + rindex == 8 ? data_b : + rindex == 9 && rs[0] ? wr13_a : + rindex == 9 ? wr13_b : + rindex == 10 && rs[0] ? rr10_a : + rindex == 10 ? rr10_b : + rindex == 11 && rs[0] ? rr15_a : + rindex == 11 ? rr15_b : + rindex == 12 && rs[0] ? wr12_a : + rindex == 12 ? wr12_b : + rindex == 13 && rs[0] ? wr13_a : + rindex == 13 ? wr13_b : + rindex == 14 && rs[0] ? rr10_a : + rindex == 14 ? rr10_b : + rindex == 15 && rs[0] ? rr15_a : + rindex == 15 ? rr15_b : 8'hff; + + /* RR0 */ + assign rr0_a = { 1'b0, /* Break */ + 1'b1, /* Tx Underrun/EOM */ + 1'b0, /* CTS */ + 1'b0, /* Sync/Hunt */ + wr15_a[3] ? dcd_latch_a : dcd_a, /* DCD */ + 1'b1, /* Tx Empty */ + 1'b0, /* Zero Count */ + 1'b0 /* Rx Available */ + }; + assign rr0_b = { 1'b0, /* Break */ + 1'b1, /* Tx Underrun/EOM */ + 1'b0, /* CTS */ + 1'b0, /* Sync/Hunt */ + wr15_b[3] ? dcd_latch_b : dcd_b, /* DCD */ + 1'b1, /* Tx Empty */ + 1'b0, /* Zero Count */ + 1'b0 /* Rx Available */ + }; + + /* RR1 */ + assign rr1_a = { 1'b0, /* End of frame */ + 1'b0, /* CRC/Framing error */ + 1'b0, /* Rx Overrun error */ + 1'b0, /* Parity error */ + 1'b0, /* Residue code 0 */ + 1'b1, /* Residue code 1 */ + 1'b1, /* Residue code 2 */ + 1'b1 /* All sent */ + }; + + assign rr1_b = { 1'b0, /* End of frame */ + 1'b0, /* CRC/Framing error */ + 1'b0, /* Rx Overrun error */ + 1'b0, /* Parity error */ + 1'b0, /* Residue code 0 */ + 1'b1, /* Residue code 1 */ + 1'b1, /* Residue code 2 */ + 1'b1 /* All sent */ + }; + + /* RR2 (Chan B only, A is just WR2) */ + assign rr2_b = { wr2[7], + wr9[4] ? rr2_vec_stat[0] : wr2[6], + wr9[4] ? rr2_vec_stat[1] : wr2[5], + wr9[4] ? rr2_vec_stat[2] : wr2[4], + wr9[4] ? wr2[3] : rr2_vec_stat[2], + wr9[4] ? wr2[2] : rr2_vec_stat[1], + wr9[4] ? wr2[1] : rr2_vec_stat[0], + wr2[0] + }; + + + /* RR3 (Chan A only) */ + assign rr3_a = { 2'b0, + rx_irq_pend_a, /* Rx interrupt pending */ + tx_irq_pend_a, /* Tx interrupt pending */ + ex_irq_pend_a, /* Status/Ext interrupt pending */ + rx_irq_pend_b, + tx_irq_pend_b, + ex_irq_pend_b + }; + + /* RR10 */ + assign rr10_a = { 1'b0, /* One clock missing */ + 1'b0, /* Two clocks missing */ + 1'b0, + 1'b0, /* Loop sending */ + 1'b0, + 1'b0, + 1'b0, /* On Loop */ + 1'b0 + }; + assign rr10_b = { 1'b0, /* One clock missing */ + 1'b0, /* Two clocks missing */ + 1'b0, + 1'b0, /* Loop sending */ + 1'b0, + 1'b0, + 1'b0, /* On Loop */ + 1'b0 + }; + + /* RR15 */ + assign rr15_a = { wr15_a[7], + wr15_a[6], + wr15_a[5], + wr15_a[4], + wr15_a[3], + 1'b0, + wr15_a[1], + 1'b0 + }; + + assign rr15_b = { wr15_b[7], + wr15_b[6], + wr15_b[5], + wr15_b[4], + wr15_b[3], + 1'b0, + wr15_b[1], + 1'b0 + }; + + /* Interrupts. Simplified for now + * + * Need to add latches. Tx irq is latched when buffer goes from full->empty, + * it's not a permanent state. For now keep it clear. Will have to fix that. + */ + assign rx_irq_pend_a = 0; + assign tx_irq_pend_a = 0 /*& wr1_a[1]*/; /* Tx always empty for now */ + assign ex_irq_pend_a = ex_irq_ip_a; + assign rx_irq_pend_b = 0; + assign tx_irq_pend_b = 0 /*& wr1_b[1]*/; /* Tx always empty for now */ + assign ex_irq_pend_b = ex_irq_ip_b; + + assign _irq = ~(wr9[3] & (rx_irq_pend_a | + rx_irq_pend_b | + tx_irq_pend_a | + tx_irq_pend_b | + ex_irq_pend_a | + ex_irq_pend_b)); + + /* XXX Verify that... also missing special receive condition */ + assign rr2_vec_stat = rx_irq_pend_a ? 3'b110 : + tx_irq_pend_a ? 3'b100 : + ex_irq_pend_a ? 3'b101 : + rx_irq_pend_b ? 3'b010 : + tx_irq_pend_b ? 3'b000 : + ex_irq_pend_b ? 3'b001 : 3'b011; + + /* External/Status interrupt & latch logic */ + assign do_extreset_a = wreg_a & (rindex == 0) & (wdata[5:3] == 3'b010); + assign do_extreset_b = wreg_b & (rindex == 0) & (wdata[5:3] == 3'b010); + + /* Internal IP bit set if latch different from source and + * corresponding interrupt is enabled in WR15 + */ + assign dcd_ip_a = (dcd_a != dcd_latch_a) & wr15_a[3]; + assign dcd_ip_b = (dcd_b != dcd_latch_b) & wr15_b[3]; + + /* Latches close when an enabled IP bit is set and latches + * are currently open + */ + assign do_latch_a = latch_open_a & (dcd_ip_a /* | cts... */); + assign do_latch_b = latch_open_b & (dcd_ip_b /* | cts... */); + + /* "Master" interrupt, set when latch close & WR1[0] is set */ + always@(posedge sysclk or posedge reset) begin + if (reset) + ex_irq_ip_a <= 0; + else if (do_extreset_a) + ex_irq_ip_a <= 0; + else if (do_latch_a && wr1_a[0]) + ex_irq_ip_a <= 1; + end + always@(posedge sysclk or posedge reset) begin + if (reset) + ex_irq_ip_b <= 0; + else if (do_extreset_b) + ex_irq_ip_b <= 0; + else if (do_latch_b && wr1_b[0]) + ex_irq_ip_b <= 1; + end + + /* Latch open/close control */ + always@(posedge sysclk or posedge reset) begin + if (reset) + latch_open_a <= 1; + else begin + if (do_extreset_a) + latch_open_a <= 1; + else if (do_latch_a) + latch_open_a <= 0; + end + end + always@(posedge sysclk or posedge reset) begin + if (reset) + latch_open_b <= 1; + else begin + if (do_extreset_b) + latch_open_b <= 1; + else if (do_latch_b) + latch_open_b <= 0; + end + end + + /* Latches proper */ + always@(posedge sysclk or posedge reset) begin + if (reset) begin + dcd_latch_a <= 0; + /* cts ... */ + end else begin + if (do_latch_a) + dcd_latch_a <= dcd_a; + /* cts ... */ + end + end + always@(posedge sysclk or posedge reset) begin + if (reset) begin + dcd_latch_b <= 0; + /* cts ... */ + end else begin + if (do_latch_b) + dcd_latch_b <= dcd_b; + /* cts ... */ + end + end + + /* NYI */ + assign txd = 1; + assign rts = 1; + + assign wreq = 1; +endmodule diff --git a/cores/plus_too/sdcard.v b/cores/plus_too/sdcard.v new file mode 100644 index 0000000..070cd3d --- /dev/null +++ b/cores/plus_too/sdcard.v @@ -0,0 +1,27 @@ +module sdcard( + input clk8, + input _reset, + input selectIWM +); + + spiMaster sdcard_intf( + // host interface + .clk_i(clk8), + .rst_i(), + .address_i(), // input [7:0] + .data_i(), // input [7:0] + .data_o(), // output [7:0] + .strobe_i(), // input + .we_i(), // input + .ack_o(), // output + + // SPI logic clock + spiSysClk(), + + //SPI bus + spiClkOut(), + spiDataIn(), + spiDataOut(), + spiCS_n()); + +endmodule diff --git a/cores/plus_too/sdram.v b/cores/plus_too/sdram.v new file mode 100644 index 0000000..69ea0a9 --- /dev/null +++ b/cores/plus_too/sdram.v @@ -0,0 +1,173 @@ +// +// sdram.v +// +// sdram controller implementation for the MiST board +// +// Copyright (c) 2015 Till Harbaum +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +module sdram ( + + // interface to the MT48LC16M16 chip + inout [15:0] sd_data, // 16 bit bidirectional data bus + output reg [12:0] sd_addr, // 13 bit multiplexed address bus + output reg [1:0] sd_dqm, // two byte masks + output reg [1:0] sd_ba, // two banks + output sd_cs, // a single chip select + output sd_we, // write enable + output sd_ras, // row address select + output sd_cas, // columns address select + + // cpu/chipset interface + input init, // init signal after FPGA config to initialize RAM + input clk_128, // sdram is accessed at 128MHz + input clk_8, // 8MHz chipset clock to which sdram state machine is synchonized + + input [15:0] din, // data input from chipset/cpu + output [15:0] dout, // data output to chipset/cpu + input [23:0] addr, // 24 bit word address + input [1:0] ds, // upper/lower data strobe + input oe, // cpu/chipset requests read + input we // cpu/chipset requests write +); + +localparam RASCAS_DELAY = 3'd3; // tRCD=20ns -> 3 cycles@128MHz +localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8 +localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved +localparam CAS_LATENCY = 3'd3; // 2/3 allowed +localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed +localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write + +localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH}; + + +// --------------------------------------------------------------------- +// ------------------------ cycle state machine ------------------------ +// --------------------------------------------------------------------- + +// The state machine runs at 128Mhz synchronous to the 8 Mhz chipset clock. +// It wraps from T15 to T0 on the rising edge of clk_8 + +localparam STATE_FIRST = 4'd0; // first state in cycle +localparam STATE_CMD_START = 4'd1; // state in which a new command can be started +localparam STATE_CMD_CONT = STATE_CMD_START + RASCAS_DELAY; // command can be continued +localparam STATE_READ = STATE_CMD_CONT + CAS_LATENCY + 4'd1; +localparam STATE_LAST = 4'd15; // last state in cycle + +reg [3:0] t; +always @(posedge clk_128) begin + // 128Mhz counter synchronous to 8 Mhz clock + // force counter to pass state 0 exactly after the rising edge of clk_8 + if(((t == STATE_LAST) && ( clk_8 == 0)) || + ((t == STATE_FIRST) && ( clk_8 == 1)) || + ((t != STATE_LAST) && (t != STATE_FIRST))) + t <= t + 4'd1; +end + +// --------------------------------------------------------------------- +// --------------------------- startup/reset --------------------------- +// --------------------------------------------------------------------- + +// wait 1ms (32 8Mhz cycles) after FPGA config is done before going +// into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0) +reg [4:0] reset; +always @(posedge clk_128) begin + if(init) reset <= 5'h1f; + else if((t == STATE_LAST) && (reset != 0)) + reset <= reset - 5'd1; +end + +// --------------------------------------------------------------------- +// ------------------ generate ram control signals --------------------- +// --------------------------------------------------------------------- + +// all possible commands +localparam CMD_INHIBIT = 4'b1111; +localparam CMD_NOP = 4'b0111; +localparam CMD_ACTIVE = 4'b0011; +localparam CMD_READ = 4'b0101; +localparam CMD_WRITE = 4'b0100; +localparam CMD_BURST_TERMINATE = 4'b0110; +localparam CMD_PRECHARGE = 4'b0010; +localparam CMD_AUTO_REFRESH = 4'b0001; +localparam CMD_LOAD_MODE = 4'b0000; + +reg [3:0] sd_cmd; // current command sent to sd ram + +// drive control signals according to current command +assign sd_cs = sd_cmd[3]; +assign sd_ras = sd_cmd[2]; +assign sd_cas = sd_cmd[1]; +assign sd_we = sd_cmd[0]; + +// drive ram data lines when writing, set them as inputs otherwise +assign sd_data = we?din:16'bZZZZZZZZZZZZZZZZ; +assign dout = sd_data; + +always @(posedge clk_128) begin + sd_cmd <= CMD_INHIBIT; // default: idle + + if(reset != 0) begin + // initialization takes place at the end of the reset phase + if(t == STATE_CMD_START) begin + + if(reset == 13) begin + sd_cmd <= CMD_PRECHARGE; + sd_addr[10] <= 1'b1; // precharge all banks + end + + if(reset == 2) begin + sd_cmd <= CMD_LOAD_MODE; + sd_addr <= MODE; + end + + end + end else begin + // normal operation + + // ------------------- cpu/chipset read/write ---------------------- + if(we || oe) begin + + // RAS phase + if(t == STATE_CMD_START) begin + sd_cmd <= CMD_ACTIVE; + sd_addr <= { 1'b0, addr[19:8] }; + sd_ba <= addr[21:20]; + + // always return both bytes in a read. The cpu may not + // need it, but the caches need to be able to store everything + if(!we) sd_dqm <= 2'b00; + else sd_dqm <= ~ds; + end + + // CAS phase + if(t == STATE_CMD_CONT) begin + sd_cmd <= we?CMD_WRITE:CMD_READ; + sd_addr <= { 4'b0010, addr[22], addr[7:0] }; // auto precharge + end + end + + // ------------------------ no access -------------------------- + else begin + if(t == STATE_CMD_START) + sd_cmd <= CMD_AUTO_REFRESH; + end + end +end + + + +endmodule diff --git a/cores/plus_too/testbench.v b/cores/plus_too/testbench.v new file mode 100644 index 0000000..d1aa265 --- /dev/null +++ b/cores/plus_too/testbench.v @@ -0,0 +1,81 @@ +`timescale 1ns / 1ps + +//////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 14:54:22 09/05/2011 +// Design Name: plusToo_top +// Module Name: C:/Users/steve/Documents/PlusToo/Verilog/testbench.v +// Project Name: plusToo +// Target Device: +// Tool versions: +// Description: +// +// Verilog Test Fixture created by ISE for module: plusToo_top +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +//////////////////////////////////////////////////////////////////////////////// + +`define VIA_A_Data 24'hEFFFFE +`define VIA_A_Dir 24'hEFE9FE + +module testbench; + + // Inputs + reg clk50; + + // Outputs + wire hsync; + wire vsync; + wire [3:0] red; + wire [3:0] green; + wire [3:0] blue; + + // Instantiate the Unit Under Test (UUT) + plusToo_top uut ( + .clk50(clk50), + .hsync(hsync), + .vsync(vsync), + .red(red), + .green(green), + .blue(blue) + ); + + initial begin + clk50 = 1'b1; + uut.ac0.busCycle = 0; + uut.ac0.vt.xpos = 0; + uut.ac0.vt.ypos = 0; + uut.dc0.clkPhase = 0; + end + + always + #10 clk50 = ~clk50; + + always @(posedge uut.clk32) begin + if (uut.cpuAddr == `VIA_A_Data || + uut.cpuAddr == `VIA_A_Dir) begin + $display($time, " memory reference to VIA"); + end + if (uut.loadPixels == 1'b1 && uut.memoryDataInMux == 16'hBEEF) begin + $display($time, " loading bad pixel data"); + end + if (uut.cpuAddr == 24'h4001B8) begin + $display($time, " critical error"); + end + if (uut._cpuAS == 0 && + uut.cpuAddr >= 24'h402000 && + uut.cpuAddr < 24'h800000) begin + $display($time, " memory reference unimplemented ROM"); + $stop(); + end + end + +endmodule + diff --git a/cores/plus_too/user_io.v b/cores/plus_too/user_io.v new file mode 100644 index 0000000..3118588 --- /dev/null +++ b/cores/plus_too/user_io.v @@ -0,0 +1,412 @@ +// +// user_io.v +// +// user_io for the MiST board +// http://code.google.com/p/mist-board/ +// +// Copyright (c) 2014 Till Harbaum +// +// This source file is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +// parameter STRLEN and the actual length of conf_str have to match + +module user_io #(parameter STRLEN=0) ( + input [(8*STRLEN)-1:0] conf_str, + + input SPI_CLK, + input SPI_SS_IO, + output reg SPI_MISO, + input SPI_MOSI, + + output reg [7:0] joystick_0, + output reg [7:0] joystick_1, + output reg [15:0] joystick_analog_0, + output reg [15:0] joystick_analog_1, + output [1:0] buttons, + output [1:0] switches, + + output reg [7:0] status, + + // connection to sd card emulation + input [31:0] sd_lba, + input sd_rd, + input sd_wr, + output reg sd_ack, + input sd_conf, + input sd_sdhc, + output [7:0] sd_dout, // valid on rising edge of sd_dout_strobe + output reg sd_dout_strobe, + input [7:0] sd_din, + output reg sd_din_strobe, + + + // ps2 keyboard emulation + input ps2_clk, // 12-16khz provided by core + output ps2_kbd_clk, + output reg ps2_kbd_data, + output ps2_mouse_clk, + output reg ps2_mouse_data, + + // serial com port + input [7:0] serial_data, + input serial_strobe +); + +reg [6:0] sbuf; +reg [7:0] cmd; +reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... +reg [7:0] byte_cnt; // counts bytes +reg [5:0] joystick0; +reg [5:0] joystick1; +reg [3:0] but_sw; +reg [2:0] stick_idx; + +assign buttons = but_sw[1:0]; +assign switches = but_sw[3:2]; +assign sd_dout = { sbuf, SPI_MOSI}; + +// this variant of user_io is for 8 bit cores (type == a4) only +wire [7:0] core_type = 8'ha4; + +// command byte read by the io controller +wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd }; + +// filter spi clock. the 8 bit gate delay is ~2.5ns in total +wire [7:0] spi_sck_D = { spi_sck_D[6:0], SPI_CLK } /* synthesis keep */; +wire spi_sck = (spi_sck && spi_sck_D != 8'h00) || (!spi_sck && spi_sck_D == 8'hff); + +// drive MISO only when transmitting core id +always@(negedge spi_sck or posedge SPI_SS_IO) begin + if(SPI_SS_IO == 1) begin + SPI_MISO <= 1'bZ; + end else begin + + // first byte returned is always core type, further bytes are + // command dependent + if(byte_cnt == 0) begin + SPI_MISO <= core_type[~bit_cnt]; + + end else begin + // reading serial fifo + if(cmd == 8'h1b) begin + // send alternating flag byte and data + if(byte_cnt[0]) SPI_MISO <= serial_out_status[~bit_cnt]; + else SPI_MISO <= serial_out_byte[~bit_cnt]; + end + + // reading config string + else if(cmd == 8'h14) begin + // returning a byte from string + if(byte_cnt < STRLEN + 1) + SPI_MISO <= conf_str[{STRLEN - byte_cnt,~bit_cnt}]; + else + SPI_MISO <= 1'b0; + end + + // reading sd card status + else if(cmd == 8'h16) begin + if(byte_cnt == 1) + SPI_MISO <= sd_cmd[~bit_cnt]; + else if((byte_cnt >= 2) && (byte_cnt < 6)) + SPI_MISO <= sd_lba[{5-byte_cnt, ~bit_cnt}]; + else + SPI_MISO <= 1'b0; + end + + // reading sd card write data + else if(cmd == 8'h18) + SPI_MISO <= sd_din[~bit_cnt]; + + else + SPI_MISO <= 1'b0; + end + end +end + +// ---------------- PS2 --------------------- + +// 8 byte fifos to store ps2 bytes +localparam PS2_FIFO_BITS = 3; + +// keyboard +reg [7:0] ps2_kbd_fifo [(2**PS2_FIFO_BITS)-1:0]; +reg [PS2_FIFO_BITS-1:0] ps2_kbd_wptr; +reg [PS2_FIFO_BITS-1:0] ps2_kbd_rptr; + +// ps2 transmitter state machine +reg [3:0] ps2_kbd_tx_state; +reg [7:0] ps2_kbd_tx_byte; +reg ps2_kbd_parity; + +assign ps2_kbd_clk = ps2_clk || (ps2_kbd_tx_state == 0); + +// ps2 transmitter +// Takes a byte from the FIFO and sends it in a ps2 compliant serial format. +reg ps2_kbd_r_inc; +always@(posedge ps2_clk) begin + ps2_kbd_r_inc <= 1'b0; + + if(ps2_kbd_r_inc) + ps2_kbd_rptr <= ps2_kbd_rptr + 1; + + // transmitter is idle? + if(ps2_kbd_tx_state == 0) begin + // data in fifo present? + if(ps2_kbd_wptr != ps2_kbd_rptr) begin + // load tx register from fifo + ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr]; + ps2_kbd_r_inc <= 1'b1; + + // reset parity + ps2_kbd_parity <= 1'b1; + + // start transmitter + ps2_kbd_tx_state <= 4'd1; + + // put start bit on data line + ps2_kbd_data <= 1'b0; // start bit is 0 + end + end else begin + + // transmission of 8 data bits + if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin + ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits + ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down + if(ps2_kbd_tx_byte[0]) + ps2_kbd_parity <= !ps2_kbd_parity; + end + + // transmission of parity + if(ps2_kbd_tx_state == 9) + ps2_kbd_data <= ps2_kbd_parity; + + // transmission of stop bit + if(ps2_kbd_tx_state == 10) + ps2_kbd_data <= 1'b1; // stop bit is 1 + + // advance state machine + if(ps2_kbd_tx_state < 11) + ps2_kbd_tx_state <= ps2_kbd_tx_state + 4'd1; + else + ps2_kbd_tx_state <= 4'd0; + + end +end + +// mouse +reg [7:0] ps2_mouse_fifo [(2**PS2_FIFO_BITS)-1:0]; +reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr; +reg [PS2_FIFO_BITS-1:0] ps2_mouse_rptr; + +// ps2 transmitter state machine +reg [3:0] ps2_mouse_tx_state; +reg [7:0] ps2_mouse_tx_byte; +reg ps2_mouse_parity; + +assign ps2_mouse_clk = ps2_clk || (ps2_mouse_tx_state == 0); + +// ps2 transmitter +// Takes a byte from the FIFO and sends it in a ps2 compliant serial format. +reg ps2_mouse_r_inc; +always@(posedge ps2_clk) begin + ps2_mouse_r_inc <= 1'b0; + + if(ps2_mouse_r_inc) + ps2_mouse_rptr <= ps2_mouse_rptr + 1; + + // transmitter is idle? + if(ps2_mouse_tx_state == 0) begin + // data in fifo present? + if(ps2_mouse_wptr != ps2_mouse_rptr) begin + // load tx register from fifo + ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr]; + ps2_mouse_r_inc <= 1'b1; + + // reset parity + ps2_mouse_parity <= 1'b1; + + // start transmitter + ps2_mouse_tx_state <= 4'd1; + + // put start bit on data line + ps2_mouse_data <= 1'b0; // start bit is 0 + end + end else begin + + // transmission of 8 data bits + if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin + ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits + ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down + if(ps2_mouse_tx_byte[0]) + ps2_mouse_parity <= !ps2_mouse_parity; + end + + // transmission of parity + if(ps2_mouse_tx_state == 9) + ps2_mouse_data <= ps2_mouse_parity; + + // transmission of stop bit + if(ps2_mouse_tx_state == 10) + ps2_mouse_data <= 1'b1; // stop bit is 1 + + // advance state machine + if(ps2_mouse_tx_state < 11) + ps2_mouse_tx_state <= ps2_mouse_tx_state + 4'd1; + else + ps2_mouse_tx_state <= 4'd0; + + end +end + +// fifo to receive serial data from core to be forwarded to io controller + +// 16 byte fifo to store serial bytes +localparam SERIAL_OUT_FIFO_BITS = 6; +reg [7:0] serial_out_fifo [(2**SERIAL_OUT_FIFO_BITS)-1:0]; +reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_wptr; +reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_rptr; + +wire serial_out_data_available = serial_out_wptr != serial_out_rptr; +wire [7:0] serial_out_byte = serial_out_fifo[serial_out_rptr] /* synthesis keep */; +wire [7:0] serial_out_status = { 7'b1000000, serial_out_data_available}; + +// status[0] is reset signal from io controller and is thus used to flush +// the fifo +always @(posedge serial_strobe or posedge status[0]) begin + if(status[0] == 1) begin + serial_out_wptr <= 0; + end else begin + serial_out_fifo[serial_out_wptr] <= serial_data; + serial_out_wptr <= serial_out_wptr + 1; + end +end + +always@(negedge spi_sck or posedge status[0]) begin + if(status[0] == 1) begin + serial_out_rptr <= 0; + end else begin + if((byte_cnt != 0) && (cmd == 8'h1b)) begin + // read last bit -> advance read pointer + if((bit_cnt == 7) && !byte_cnt[0] && serial_out_data_available) + serial_out_rptr <= serial_out_rptr + 1; + end + end +end + +// SPI receiver +always@(posedge spi_sck or posedge SPI_SS_IO) begin + + if(SPI_SS_IO == 1) begin + bit_cnt <= 3'd0; + byte_cnt <= 8'd0; + sd_ack <= 1'b0; + sd_dout_strobe <= 1'b0; + sd_din_strobe <= 1'b0; + end else begin + sd_dout_strobe <= 1'b0; + sd_din_strobe <= 1'b0; + + if(bit_cnt != 7) + sbuf[6:0] <= { sbuf[5:0], SPI_MOSI }; + + bit_cnt <= bit_cnt + 3'd1; + if((bit_cnt == 7)&&(byte_cnt != 8'd255)) + byte_cnt <= byte_cnt + 8'd1; + + // finished reading command byte + if(bit_cnt == 7) begin + if(byte_cnt == 0) begin + cmd <= { sbuf, SPI_MOSI}; + + // fetch first byte when sectore FPGA->IO command has been seen + if({ sbuf, SPI_MOSI} == 8'h18) + sd_din_strobe <= 1'b1; + + if(({ sbuf, SPI_MOSI} == 8'h17) || ({ sbuf, SPI_MOSI} == 8'h18)) + sd_ack <= 1'b1; + + end else begin + + // buttons and switches + if(cmd == 8'h01) + but_sw <= { sbuf[2:0], SPI_MOSI }; + + if(cmd == 8'h02) + joystick_0 <= { sbuf, SPI_MOSI }; + + if(cmd == 8'h03) + joystick_1 <= { sbuf, SPI_MOSI }; + + if(cmd == 8'h04) begin + // store incoming ps2 mouse bytes + ps2_mouse_fifo[ps2_mouse_wptr] <= { sbuf, SPI_MOSI }; + ps2_mouse_wptr <= ps2_mouse_wptr + 1; + end + + if(cmd == 8'h05) begin + // store incoming ps2 keyboard bytes + ps2_kbd_fifo[ps2_kbd_wptr] <= { sbuf, SPI_MOSI }; + ps2_kbd_wptr <= ps2_kbd_wptr + 1; + end + + if(cmd == 8'h15) + status <= { sbuf[6:0], SPI_MOSI }; + + // send sector IO -> FPGA + if(cmd == 8'h17) begin + // flag that download begins +// sd_dout <= { sbuf, SPI_MOSI}; + sd_dout_strobe <= 1'b1; + end + + // send sector FPGA -> IO + if(cmd == 8'h18) + sd_din_strobe <= 1'b1; + + // send SD config IO -> FPGA + if(cmd == 8'h19) begin + // flag that download begins +// sd_dout <= { sbuf, SPI_MOSI}; + // sd card knows data is config if sd_dout_strobe is asserted + // with sd_ack still being inactive (low) + sd_dout_strobe <= 1'b1; + end + + // joystick analog + if(cmd == 8'h1a) begin + // first byte is joystick indes + if(byte_cnt == 1) + stick_idx <= { sbuf[1:0], SPI_MOSI }; + else if(byte_cnt == 2) begin + // second byte is x axis + if(stick_idx == 0) + joystick_analog_0[15:8] <= { sbuf, SPI_MOSI }; + else if(stick_idx == 1) + joystick_analog_1[15:8] <= { sbuf, SPI_MOSI }; + end else if(byte_cnt == 3) begin + // third byte is y axis + if(stick_idx == 0) + joystick_analog_0[7:0] <= { sbuf, SPI_MOSI }; + else if(stick_idx == 1) + joystick_analog_1[7:0] <= { sbuf, SPI_MOSI }; + end + end + + end + end + end +end + +endmodule diff --git a/cores/plus_too/via.v b/cores/plus_too/via.v new file mode 100644 index 0000000..1ab8583 --- /dev/null +++ b/cores/plus_too/via.v @@ -0,0 +1,303 @@ +/* VIA + + This implementation assumes the I/O data directions and PCR edge triggers used in the Macintosh, + and ignores most writes to the VIA data direction registers and the PCR. + + The 16 VIA registers are mapped to addresses {8'hEF, 8'b111xxxx1, 8'hFE}: + 0 $0 vBufB register B + 1 $200 ????? register A (controls handshake) + 2 $400 vDirB register B direction register + 3 $600 vDirA register A direction register + 4 $800 vT1C timer 1 counter (low-order byte) - for sound? + 5 $A00 vT1CH timer 1 counter (high-order byte) + 6 $C00 vT1L timer 1 latch (low-order byte) + 7 $E00 vT1LH timer 1 latch (high-order byte) + 8 $1000 vT2C timer 2 counter (low-order byte) - W: writes T2L-L R: read T2C-L and clear interrupt flag + 9 $1200 vT2CH timer 2 counter (high-order byte) - W: write T2C-H, transfer T2L-L to T2C-L, clear interrupt flag R: read T2C-H + 10 $1400 vSR shift register (keyboard) + 11 $1600 vACR auxiliary control register + 12 $1800 vPCR peripheral control register + 13 $1A00 vIFR interrupt flag register + 14 $1C00 vIER interrupt enable register + 15 $1E00 vBufA register A (no handshake) + + Register A: + Bit(s) Name Dir Description + + 7 vSCCWReq in SCC wait/request + 6 vPage2 out Alternate screen buffer (1 = main buffer) + 5 vHeadSel out Disk SEL line + 4 vOverlay out ROM low-memory overlay (1 = overlay on) + 3 vSndPg2 out Alternate sound buffer (1 = main buffer) + 0-2 vSound (mask) out Sound volume + + Register B: + Bit Name Dir Description + + 7 vSndEnb out Sound enable/disable + 6 vH4 in Horizontal blanking + 5 vY2 in Mouse Y2 + 4 vX2 in Mouse X2 + 3 vSW in Mouse switch + 2 rTCEnb out Real-time clock serial enable (active low I think) + 1 rTCClk out Real-time clock data-clock line + 0 rTCData in/out Real-time clock serial data + + Interrupt flag and enable registers: + IFR bit 7: remains set (and the IRQ line to the processor is held low) as long as any enabled VIA + interrupt is occurring. + IER bit 7: "enable/disable": If bit 7 is a 1, each 1 in bits 0-6 enables the corresponding interrupt; + if bit 7 is a 0, each 1 in bits 0-6 disables that interrupt. In either case, 0's in bits 0-6 do not + change the status of those interrupts. Bit 7 is always read as a 1. + + Bit Interrupting device + + 7 IRQ (IFR) or enable (IER) + 6 Timer 1 timeout + 5 Timer 2 timeout + 4 Keyboard clock (CB1) + 3 Keyboard data bit (CB2) + 2 Keyboard data ready (completion of 8 shifts) (SR) + 1 Vertical blanking interrupt (CA1) + 0 One-second interrupt (CA2) + + Peripheral control register: + Bit Description + + 5-7 CB2 control (keyboard data bit) + 4 CB1 control (keyboard clock) + 1-3 CA2 control (one-second interrupt) + 0 CA1 control (vertical blanking interrupt) + + 1-bit controls: 0 = negative edge trigger (normal Macintosh mode), 1 = positive edge trigger + 3-bit controls: + 000 set IFR on negative edge, clear IFR on read/write from register A/B. Normal Macintosh mode. + 001 set IFR on negative edge + 010 set IFR on positive edge, clear IFR on read/write from register A/B + 011 set IFR on positive edge + 100-111 not used in Macintosh (output mode) + + Auxiliary control register: + Bit Description + 6-7 T1 control, 00 = one-shot mode, output to PB7 disabled, 11 = free running mode, output to PB7 enabled + 5 T2 control, 0 = interval timer in one-shot mode (Mac mode), 1 = counts a predetermined number of pulses on pin PB6 (not used) + 2-4 shift register control + 1 PB latch enable + 0 PA latch enable + + Timer 2: + For Macintosh, always operates as a one-shot inerval timer. + 8 $1000 vT2C W: write T2L-L R: read T2C-L and clear interrupt flag + 9 $1200 vT2CH W: write T2C-H, transfer T2L-L to T2C-L, clear interrupt, arms timer flag R: read T2C-H +*/ + +`define INT_ONESEC 0 +`define INT_VBLANK 1 +`define INT_KEYREADY 2 +`define INT_KEYBIT 3 +`define INT_KEYCLK 4 +`define INT_T2 5 +`define INT_T1 6 + +module via( + input clk8, + input _reset, + input selectVIA, + input _cpuRW, + input _cpuUDS, + input [15:0] dataIn, + input [3:0] cpuAddrRegHi, + input _hblank, + input _vblank, + input mouseY2, + input mouseX2, + input mouseButton, + input rtcData, + input sccWReq, + output _irq, + output [15:0] dataOut, + output memoryOverlayOn, + output SEL // to IWM +); + + wire [7:0] dataInHi = dataIn[15:8]; + reg [7:0] dataOutHi; + assign dataOut = { dataOutHi, 8'hEF }; + + reg [7:0] viaADataOut; + reg [7:0] viaBDataOut; + reg viaB0DDR; + reg [6:0] viaIFR; + reg [6:0] viaIER; + reg [7:0] viaACR; + reg [15:0] viaTimer1Count; + reg [15:0] viaTimer1Latch; + reg [15:0] viaTimer2Count; + reg [7:0] viaTimer2LatchLow; + reg viaTimer2Armed; + + // divide by 10 clock divider for the VIA timers: 0.78336 MHz + reg [3:0] clkDiv; + always @(posedge clk8) begin + if (clkDiv == 4'h9) + clkDiv <= 0; + else + clkDiv <= clkDiv + 1'b1; + end + wire timerStrobe = (clkDiv == 0); + + // store previous vblank value, for edge detection + reg _lastVblank; + always @(posedge clk8) begin + _lastVblank <= _vblank; + end + + // count vblanks, and set 1 second interrupt after 60 vblanks + reg [5:0] vblankCount; + always @(posedge clk8) begin + if (_vblank == 1'b0 && _lastVblank == 1'b1) begin + if (vblankCount != 59) begin + vblankCount <= vblankCount + 1'b1; + end + else begin + vblankCount <= 6'h0; + end + end + end + assign _irq = (viaIFR & viaIER) == 0 ? 1'b1 : 1'b0; + + // register write + wire loadT2 = selectVIA == 1'b1 && _cpuUDS == 1'b0 && _cpuRW == 1'b0 && cpuAddrRegHi == 4'h9; + always @(posedge clk8 or negedge _reset) begin + if (_reset == 1'b0) begin + viaB0DDR <= 1'b1; + viaADataOut <= 8'b01111111; + viaBDataOut <= 8'b11111111; + viaIFR <= 7'b0000000; + viaIER <= 7'b0000000; + viaACR <= 8'b00000000; + viaTimer1Count <= 16'h0000; + viaTimer1Latch <= 16'h0000; + viaTimer2Count <= 16'h0000; + viaTimer2LatchLow <= 8'h00; + viaTimer2Armed <= 0; + end + else begin + if (selectVIA == 1'b1 && _cpuUDS == 1'b0) begin + if (_cpuRW == 1'b0) begin + // normal register writes + case (cpuAddrRegHi) + 4'h0: // B + viaBDataOut <= dataInHi; + 4'h2: // B DDR + viaB0DDR <= dataInHi[0]; + // 4'h3: ignore A DDR + 4'h4: // timer 1 count low + viaTimer1Count[7:0] <= dataInHi; + 4'h5: // timer 1 count high + viaTimer1Count[15:8] <= dataInHi; + 4'h6: // timer 1 latch low + viaTimer1Latch[7:0] <= dataInHi; + 4'h7: // timer 1 latch high + viaTimer1Latch[15:8] <= dataInHi; + 4'h8: // timer 2 latch low + viaTimer2LatchLow <= dataInHi; + 4'h9: begin // timer 2 count high + viaTimer2Count[15:8] <= dataInHi; + viaTimer2Count[7:0] <= viaTimer2LatchLow; + viaTimer2Armed = 1'b1; + viaIFR[`INT_T2] <= 1'b0; + end + 4'hB: // Aux control register + viaACR <= dataInHi; + // 4'hC: ignore PCR + 4'hD: // IFR + viaIFR <= viaIFR & ~dataInHi[6:0]; + 4'hE: // IER + if (dataInHi[7]) + viaIER <= viaIER | dataInHi[6:0]; + else + viaIER <= viaIER & ~dataInHi[6:0]; + 4'hF: // A + viaADataOut <= dataInHi; + endcase + end + else begin + // interrupt flag modifications due to register reads + case (cpuAddrRegHi) + 4'h0: begin // reading (and writing?) register B clears KEYCLK and KEYBIT interrupt flags + viaIFR[`INT_KEYCLK] <= 1'b0; + viaIFR[`INT_KEYBIT] <= 1'b0; + end + 4'h8: // reading T2C-L clears the T2 interrupt flag + viaIFR[`INT_T2] <= 1'b0; + 4'hF: begin // reading (and writing?) register A clears VBLANK and ONESEC interrupt flags + viaIFR[`INT_ONESEC] <= 1'b0; + viaIFR[`INT_VBLANK] <= 1'b0; + end + endcase + end + end + // external interrupts + if (_vblank == 1'b0 && _lastVblank == 1'b1) begin + viaIFR[`INT_VBLANK] <= 1'b1; // set vblank interrupt + if (vblankCount == 59) + viaIFR[`INT_ONESEC] <= 1'b1; // set one second interrupt after 60 vblanks + end + // timer 2 + if (timerStrobe && !loadT2) begin + if (viaTimer2Armed && viaTimer2Count == 0) begin + viaIFR[`INT_T2] <= 1'b1; + viaTimer2Armed <= 0; + end + viaTimer2Count <= viaTimer2Count - 1'b1; + end + end + end + + // register read + always @(*) begin + dataOutHi = 8'hBE; + + if (_cpuRW == 1'b1 && selectVIA == 1'b1 && _cpuUDS == 1'b0) begin + case (cpuAddrRegHi) + 4'h0: // B + // TODO: clear CB1 and CB2 interrupts + dataOutHi = { viaBDataOut[7], ~_hblank, mouseY2, mouseX2, mouseButton, viaBDataOut[2:1], viaB0DDR == 1'b1 ? viaBDataOut[0] : rtcData }; + 4'h2: // B DDR + dataOutHi = { 7'b1000011, viaB0DDR }; + 4'h3: // A DDR + dataOutHi = 8'b01111111; + 4'h4: // timer 1 count low + dataOutHi = viaTimer1Count[7:0]; + 4'h5: // timer 1 count high + dataOutHi = viaTimer1Count[15:8]; + 4'h6: // timer 1 latch low + dataOutHi = viaTimer1Latch[7:0]; + 4'h7: // timer 1 latch high + dataOutHi = viaTimer1Latch[15:8]; + 4'h8: // timer 2 count low + dataOutHi = viaTimer2Count[7:0]; + 4'h9: // timer 2 count high + dataOutHi = viaTimer2Count[15:8]; + 4'hB: // Aux control register + dataOutHi = viaACR; + 4'hC: // PCR + dataOutHi = 0; + 4'hD: // IFR + dataOutHi = { viaIFR & viaIER == 0 ? 1'b0 : 1'b1, viaIFR }; + 4'hE: // IER + dataOutHi = { 1'b1, viaIER }; + 4'hF: // A + // TODO: clear CA1 and CA2 interrupts + dataOutHi = { sccWReq, viaADataOut[6:0] }; + default: + dataOutHi = 8'hBE; + endcase + end + end + + assign memoryOverlayOn = viaADataOut[4]; + assign SEL = viaADataOut[5]; + +endmodule diff --git a/cores/plus_too/videoShifter.v b/cores/plus_too/videoShifter.v new file mode 100644 index 0000000..6b2338a --- /dev/null +++ b/cores/plus_too/videoShifter.v @@ -0,0 +1,26 @@ +module videoShifter( + input clk32, + input [1:0] clkPhase, + input [15:0] dataIn, + input loadPixels, + output pixelOut + ); + + reg [15:0] shiftRegister; + + // a 0 bit is white, and a 1 bit is black + // data is shifted out MSB first + assign pixelOut = ~shiftRegister[15]; + + always @(posedge clk32) begin + // loadPixels is generated by a module running on the 8 MHz CPU clock. Therefore this module + // only honors loadPixels when clkPhase is 1, indicating the last quarter of the 8 MHz clock cycle. + if (loadPixels && clkPhase == 2'b01) begin + shiftRegister <= dataIn; + end + else begin + shiftRegister <= { shiftRegister[14:0], 1'b1 }; + end + end + +endmodule diff --git a/cores/plus_too/videoTimer.v b/cores/plus_too/videoTimer.v new file mode 100644 index 0000000..3cf7e75 --- /dev/null +++ b/cores/plus_too/videoTimer.v @@ -0,0 +1,77 @@ +// generates 1024x768 (actually 512x768) @ 60Hz, from a 32.5MHz input clock +module videoTimer( + input clk8, + input [1:0] busCycle, + output [21:0] videoAddr, + output reg hsync, + output reg vsync, + output _hblank, + output _vblank, + output loadNormalPixels, + output loadDebugPixels, + output loadSound +); + + // timing data from http://tinyvga.com/vga-timing/1024x768@60Hz + localparam kVisibleWidth = 128, // (1024/2)/4 + kTotalWidth = 168, // (1344/2)/4 + kVisibleHeightStart = 42, + kVisibleHeightEnd = 725, + kTotalHeight = 806, + kHsyncStart = 131, // (1048/2)/4 + kHsyncEnd = 147, // (1184/2)/4-1 + kVsyncStart = 771, + kVsyncEnd = 776, + kPixelLatency = 1; // number of clk8 cycles from xpos==0 to when pixel data actually exits the video shift register + + // use screen buffer address for a 4MB RAM layout-- it will wrap + // around to the proper address for 1MB, 512K, and 128K layouts + localparam kScreenBufferBase = 22'h3FA700; + + reg [7:0] xpos; + reg [9:0] ypos; + + wire endline = (xpos == kTotalWidth-1); + + always @(posedge clk8) begin + if (endline) + xpos <= 0; + else if (xpos == 0 && busCycle != 0) + // hold xpos at 0, until xpos and busCycle are in phase + xpos <= 0; + else + xpos <= xpos + 1'b1; + end + + always @(posedge clk8) begin + if (endline) begin + if (ypos == kTotalHeight-1) + ypos <= 0; + else + ypos <= ypos + 1'b1; + end + end + + always @(posedge clk8) begin + hsync <= ~(xpos >= kHsyncStart+kPixelLatency && xpos <= kHsyncEnd+kPixelLatency); + vsync <= ~(ypos >= kVsyncStart && ypos <= kVsyncEnd); + end + + assign _hblank = ~(xpos >= kVisibleWidth); + assign _vblank = ~(ypos < kVisibleHeightStart || ypos > kVisibleHeightEnd); + + // The 0,0 address actually starts below kScreenBufferBase, because the Mac screen buffer is + // not displayed beginning at 0,0, but at 0,kVisibleHeightStart. + // kVisibleHeightStart divided by 2 to account for vertical pixel doubling. + // kVisibleWidth divided by 2 because it's the 8MHz visible width times 4 to get actual number of pixels, + // then divided by 8 bits per byte + assign videoAddr = kScreenBufferBase - + (kVisibleHeightStart/2 * kVisibleWidth/2) + + { ypos[9:1], xpos[6:2], 1'b0 }; + + assign loadNormalPixels = _vblank == 1'b1 && _hblank == 1'b1 && busCycle == 2'b00; + assign loadDebugPixels = _vblank == 1'b0 && _hblank == 1'b1 && busCycle == 2'b00; + + assign loadSound = 1'b0; + +endmodule