diff --git a/common/CPU/T80/README b/common/CPU/T80/README new file mode 100644 index 00000000..16297f14 --- /dev/null +++ b/common/CPU/T80/README @@ -0,0 +1,53 @@ +-------------------------------------------------------------------------------- +-- **** +-- T80(c) core. Attempt to finish all undocumented features and provide +-- accurate timings. +-- Version 350. +-- Copyright (c) 2018 Sorgelig +-- Test passed: ZEXDOC, ZEXALL, Z80Full(*), Z80memptr +-- (*) Currently only SCF and CCF instructions aren't passed X/Y flags check as +-- correct implementation is still unclear. +-- +-- **** +-- T80(b) core. In an effort to merge and maintain bug fixes .... +-- +-- Ver 303 add undocumented DDCB and FDCB opcodes by TobiFlex 20.04.2010 +-- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle +-- Ver 300 started tidyup. +-- +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- +-- **** +-- Z80 compatible microprocessor core +-- +-- Version : 0247 +-- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- diff --git a/common/CPU/T80/T80.vhd b/common/CPU/T80/T80.vhd index 391394df..d7745b16 100644 --- a/common/CPU/T80/T80.vhd +++ b/common/CPU/T80/T80.vhd @@ -79,8 +79,7 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use IEEE.STD_LOGIC_UNSIGNED.all; - -use work.all; +use work.T80_Pack.all; entity T80 is generic( @@ -128,136 +127,6 @@ entity T80 is end T80; architecture rtl of T80 is - component T80_MCode - generic( - Mode : integer := 0; - Flag_C : integer := 0; - Flag_N : integer := 1; - Flag_P : integer := 2; - Flag_X : integer := 3; - Flag_H : integer := 4; - Flag_Y : integer := 5; - Flag_Z : integer := 6; - Flag_S : integer := 7 - ); - port( - IR : in std_logic_vector(7 downto 0); - ISet : in std_logic_vector(1 downto 0); - MCycle : in std_logic_vector(2 downto 0); - F : in std_logic_vector(7 downto 0); - NMICycle : in std_logic; - IntCycle : in std_logic; - XY_State : in std_logic_vector(1 downto 0); - MCycles : out std_logic_vector(2 downto 0); - TStates : out std_logic_vector(2 downto 0); - Prefix : out std_logic_vector(1 downto 0); -- None,CB,ED,DD/FD - Inc_PC : out std_logic; - Inc_WZ : out std_logic; - IncDec_16 : out std_logic_vector(3 downto 0); -- BC,DE,HL,SP 0 is inc - Read_To_Reg : out std_logic; - Read_To_Acc : out std_logic; - Set_BusA_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI/DB,A,SP(L),SP(M),0,F - Set_BusB_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI,A,SP(L),SP(M),1,F,PC(L),PC(M),0 - ALU_Op : out std_logic_vector(3 downto 0); - -- ADD, ADC, SUB, SBC, AND, XOR, OR, CP, ROT, BIT, SET, RES, DAA, RLD, RRD, None - Save_ALU : out std_logic; - PreserveC : out std_logic; - Arith16 : out std_logic; - Set_Addr_To : out std_logic_vector(2 downto 0); -- aNone,aXY,aIOA,aSP,aBC,aDE,aZI - IORQ : out std_logic; - Jump : out std_logic; - JumpE : out std_logic; - JumpXY : out std_logic; - Call : out std_logic; - RstP : out std_logic; - LDZ : out std_logic; - LDW : out std_logic; - LDSPHL : out std_logic; - Special_LD : out std_logic_vector(2 downto 0); -- A,I;A,R;I,A;R,A;None - ExchangeDH : out std_logic; - ExchangeRp : out std_logic; - ExchangeAF : out std_logic; - ExchangeRS : out std_logic; - I_DJNZ : out std_logic; - I_CPL : out std_logic; - I_CCF : out std_logic; - I_SCF : out std_logic; - I_RETN : out std_logic; - I_BT : out std_logic; - I_BC : out std_logic; - I_BTR : out std_logic; - I_RLD : out std_logic; - I_RRD : out std_logic; - I_INRC : out std_logic; - SetWZ : out std_logic_vector(1 downto 0); - SetDI : out std_logic; - SetEI : out std_logic; - IMode : out std_logic_vector(1 downto 0); - Halt : out std_logic; - NoRead : out std_logic; - Write : out std_logic; - XYbit_undoc : out std_logic - ); - end component; - - component T80_ALU - generic( - Mode : integer := 0; - Flag_C : integer := 0; - Flag_N : integer := 1; - Flag_P : integer := 2; - Flag_X : integer := 3; - Flag_H : integer := 4; - Flag_Y : integer := 5; - Flag_Z : integer := 6; - Flag_S : integer := 7 - ); - port( - Arith16 : in std_logic; - Z16 : in std_logic; - WZ : in std_logic_vector(15 downto 0); - XY_State : in std_logic_vector(1 downto 0); - ALU_Op : in std_logic_vector(3 downto 0); - IR : in std_logic_vector(5 downto 0); - ISet : in std_logic_vector(1 downto 0); - BusA : in std_logic_vector(7 downto 0); - BusB : in std_logic_vector(7 downto 0); - F_In : in std_logic_vector(7 downto 0); - Q : out std_logic_vector(7 downto 0); - F_Out : out std_logic_vector(7 downto 0) - ); - end component; - - component T80_Reg - port( - Clk : in std_logic; - CEN : in std_logic; - WEH : in std_logic; - WEL : in std_logic; - AddrA : in std_logic_vector(2 downto 0); - AddrB : in std_logic_vector(2 downto 0); - AddrC : in std_logic_vector(2 downto 0); - DIH : in std_logic_vector(7 downto 0); - DIL : in std_logic_vector(7 downto 0); - DOAH : out std_logic_vector(7 downto 0); - DOAL : out std_logic_vector(7 downto 0); - DOBH : out std_logic_vector(7 downto 0); - DOBL : out std_logic_vector(7 downto 0); - DOCH : out std_logic_vector(7 downto 0); - DOCL : out std_logic_vector(7 downto 0); - DOR : out std_logic_vector(127 downto 0); - DIRSet : in std_logic; - DIR : in std_logic_vector(127 downto 0) - ); - end component; - - constant aNone : std_logic_vector(2 downto 0) := "111"; - constant aBC : std_logic_vector(2 downto 0) := "000"; - constant aDE : std_logic_vector(2 downto 0) := "001"; - constant aXY : std_logic_vector(2 downto 0) := "010"; - constant aIOA : std_logic_vector(2 downto 0) := "100"; - constant aSP : std_logic_vector(2 downto 0) := "101"; - constant aZI : std_logic_vector(2 downto 0) := "110"; -- Registers signal ACC, F : std_logic_vector(7 downto 0); @@ -294,8 +163,8 @@ architecture rtl of T80 is signal IntE_FF1 : std_logic; signal IntE_FF2 : std_logic; signal Halt_FF : std_logic; - signal BusReq_s : std_logic; - signal BusAck : std_logic; + signal BusReq_s : std_logic := '0'; + signal BusAck : std_logic := '0'; signal ClkEn : std_logic; signal NMI_s : std_logic; signal IStatus : std_logic_vector(1 downto 0); @@ -1168,7 +1037,7 @@ begin TS <= std_logic_vector(TState); DI_Reg <= DI; HALT_n <= not Halt_FF; - BUSAK_n <= not BusAck; + BUSAK_n <= not (BusAck and RESET_n); IntCycle_n <= not IntCycle; IntE <= IntE_FF1; IORQ <= IORQ_i; @@ -1187,7 +1056,7 @@ begin TState <= "000"; Pre_XY_F_M <= "000"; Halt_FF <= '0'; - BusAck <= '0'; + --BusAck <= '0'; NMICycle <= '0'; IntCycle <= '0'; IntE_FF1 <= '0'; @@ -1196,7 +1065,7 @@ begin Auto_Wait_t1 <= '0'; Auto_Wait_t2 <= '0'; M1_n <= '1'; - BusReq_s <= '0'; + --BusReq_s <= '0'; NMI_s <= '0'; elsif rising_edge(CLK_n) then @@ -1295,5 +1164,5 @@ begin end if; end process; - Auto_Wait <= '1' when IntCycle = '1' and MCycle = "001" else '0'; + Auto_Wait <= '1' when (IntCycle = '1' or NMICycle = '1') and MCycle = "001" else '0'; end; diff --git a/common/CPU/T80/T80_MCode.vhd b/common/CPU/T80/T80_MCode.vhd index f5312bd6..9fc1af7b 100644 --- a/common/CPU/T80/T80_MCode.vhd +++ b/common/CPU/T80/T80_MCode.vhd @@ -74,6 +74,7 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; +use work.T80_Pack.all; entity T80_MCode is generic( @@ -149,14 +150,6 @@ end T80_MCode; architecture rtl of T80_MCode is - constant aNone : std_logic_vector(2 downto 0) := "111"; - constant aBC : std_logic_vector(2 downto 0) := "000"; - constant aDE : std_logic_vector(2 downto 0) := "001"; - constant aXY : std_logic_vector(2 downto 0) := "010"; - constant aIOA : std_logic_vector(2 downto 0) := "100"; - constant aSP : std_logic_vector(2 downto 0) := "101"; - constant aZI : std_logic_vector(2 downto 0) := "110"; - function is_cc_true( F : std_logic_vector(7 downto 0); cc : bit_vector(2 downto 0) diff --git a/common/CPU/T80/T80_Pack.vhd b/common/CPU/T80/T80_Pack.vhd index 199f6dd1..fc6a5a93 100644 --- a/common/CPU/T80/T80_Pack.vhd +++ b/common/CPU/T80/T80_Pack.vhd @@ -84,7 +84,7 @@ package T80_Pack is port( RESET_n : in std_logic; CLK_n : in std_logic; - CEN : in std_logic; + CEN : in std_logic; WAIT_n : in std_logic; INT_n : in std_logic; NMI_n : in std_logic; @@ -96,35 +96,42 @@ package T80_Pack is RFSH_n : out std_logic; HALT_n : out std_logic; BUSAK_n : out std_logic; - A : out std_logic_vector(15 downto 0); + A : out std_logic_vector(15 downto 0); DInst : in std_logic_vector(7 downto 0); - DI : in std_logic_vector(7 downto 0); - DO : out std_logic_vector(7 downto 0); - MC : out std_logic_vector(2 downto 0); - TS : out std_logic_vector(2 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0); + MC : out std_logic_vector(2 downto 0); + TS : out std_logic_vector(2 downto 0); IntCycle_n : out std_logic; IntE : out std_logic; - Stop : out std_logic + Stop : out std_logic; + out0 : in std_logic := '0'; -- 0 => OUT(C),0, 1 => OUT(C),255 + REG : out std_logic_vector(211 downto 0); -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A + DIRSet : in std_logic := '0'; + DIR : in std_logic_vector(211 downto 0) := (others => '0') -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A ); end component; component T80_Reg port( - Clk : in std_logic; - CEN : in std_logic; - WEH : in std_logic; - WEL : in std_logic; + Clk : in std_logic; + CEN : in std_logic; + WEH : in std_logic; + WEL : in std_logic; AddrA : in std_logic_vector(2 downto 0); AddrB : in std_logic_vector(2 downto 0); AddrC : in std_logic_vector(2 downto 0); - DIH : in std_logic_vector(7 downto 0); - DIL : in std_logic_vector(7 downto 0); + DIH : in std_logic_vector(7 downto 0); + DIL : in std_logic_vector(7 downto 0); DOAH : out std_logic_vector(7 downto 0); DOAL : out std_logic_vector(7 downto 0); DOBH : out std_logic_vector(7 downto 0); DOBL : out std_logic_vector(7 downto 0); DOCH : out std_logic_vector(7 downto 0); - DOCL : out std_logic_vector(7 downto 0) + DOCL : out std_logic_vector(7 downto 0); + DOR : out std_logic_vector(127 downto 0); + DIRSet : in std_logic; + DIR : in std_logic_vector(127 downto 0) ); end component; @@ -173,8 +180,6 @@ package T80_Pack is LDZ : out std_logic; LDW : out std_logic; LDSPHL : out std_logic; - LDHLSP : out std_logic; - ADDSPdd : out std_logic; Special_LD : out std_logic_vector(2 downto 0); -- A,I;A,R;I,A;R,A;None ExchangeDH : out std_logic; ExchangeRp : out std_logic; @@ -191,6 +196,7 @@ package T80_Pack is I_RLD : out std_logic; I_RRD : out std_logic; I_INRC : out std_logic; + SetWZ : out std_logic_vector(1 downto 0); SetDI : out std_logic; SetEI : out std_logic; IMode : out std_logic_vector(1 downto 0); @@ -216,6 +222,8 @@ package T80_Pack is port( Arith16 : in std_logic; Z16 : in std_logic; + WZ : in std_logic_vector(15 downto 0); + XY_State : in std_logic_vector(1 downto 0); ALU_Op : in std_logic_vector(3 downto 0); IR : in std_logic_vector(5 downto 0); ISet : in std_logic_vector(1 downto 0); diff --git a/common/CPU/T80/T80pa.vhd b/common/CPU/T80/T80pa.vhd index 436dc4d6..98e5c3a1 100644 --- a/common/CPU/T80/T80pa.vhd +++ b/common/CPU/T80/T80pa.vhd @@ -56,6 +56,7 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; +use work.T80_Pack.all; entity T80pa is generic( @@ -89,50 +90,7 @@ entity T80pa is end T80pa; architecture rtl of T80pa is - component T80 - generic( - Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB - IOWait : integer := 0; -- 0 => Single cycle I/O, 1 => Std I/O cycle - Flag_C : integer := 0; - Flag_N : integer := 1; - Flag_P : integer := 2; - Flag_X : integer := 3; - Flag_H : integer := 4; - Flag_Y : integer := 5; - Flag_Z : integer := 6; - Flag_S : integer := 7 - ); - port( - RESET_n : in std_logic; - CLK_n : in std_logic; - CEN : in std_logic; - WAIT_n : in std_logic; - INT_n : in std_logic; - NMI_n : in std_logic; - BUSRQ_n : in std_logic; - M1_n : out std_logic; - IORQ : out std_logic; - NoRead : out std_logic; - Write : out std_logic; - RFSH_n : out std_logic; - HALT_n : out std_logic; - BUSAK_n : out std_logic; - A : out std_logic_vector(15 downto 0); - DInst : in std_logic_vector(7 downto 0); - DI : in std_logic_vector(7 downto 0); - DO : out std_logic_vector(7 downto 0); - MC : out std_logic_vector(2 downto 0); - TS : out std_logic_vector(2 downto 0); - IntCycle_n : out std_logic; - IntE : out std_logic; - Stop : out std_logic; - out0 : in std_logic := '0'; -- 0 => OUT(C),0, 1 => OUT(C),255 - REG : out std_logic_vector(211 downto 0); -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A - DIRSet : in std_logic := '0'; - DIR : in std_logic_vector(211 downto 0) := (others => '0') -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A - ); - end component; signal IntCycle_n : std_logic; signal IntCycleD_n : std_logic_vector(1 downto 0); signal IORQ : std_logic; diff --git a/common/CPU/T80/T80s.vhd b/common/CPU/T80/T80s.vhd index a2d8c448..6967292c 100644 --- a/common/CPU/T80/T80s.vhd +++ b/common/CPU/T80/T80s.vhd @@ -69,6 +69,7 @@ library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use IEEE.STD_LOGIC_UNSIGNED.all; +use work.T80_Pack.all; entity T80s is generic( @@ -100,50 +101,6 @@ entity T80s is end T80s; architecture rtl of T80s is - component T80 - generic( - Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB - IOWait : integer := 0; -- 0 => Single cycle I/O, 1 => Std I/O cycle - Flag_C : integer := 0; - Flag_N : integer := 1; - Flag_P : integer := 2; - Flag_X : integer := 3; - Flag_H : integer := 4; - Flag_Y : integer := 5; - Flag_Z : integer := 6; - Flag_S : integer := 7 - ); - port( - RESET_n : in std_logic; - CLK_n : in std_logic; - CEN : in std_logic; - WAIT_n : in std_logic; - INT_n : in std_logic; - NMI_n : in std_logic; - BUSRQ_n : in std_logic; - M1_n : out std_logic; - IORQ : out std_logic; - NoRead : out std_logic; - Write : out std_logic; - RFSH_n : out std_logic; - HALT_n : out std_logic; - BUSAK_n : out std_logic; - A : out std_logic_vector(15 downto 0); - DInst : in std_logic_vector(7 downto 0); - DI : in std_logic_vector(7 downto 0); - DO : out std_logic_vector(7 downto 0); - MC : out std_logic_vector(2 downto 0); - TS : out std_logic_vector(2 downto 0); - IntCycle_n : out std_logic; - IntE : out std_logic; - Stop : out std_logic; - out0 : in std_logic := '0'; -- 0 => OUT(C),0, 1 => OUT(C),255 - REG : out std_logic_vector(211 downto 0); -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A - - DIRSet : in std_logic := '0'; - DIR : in std_logic_vector(211 downto 0) := (others => '0') -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A - ); - end component; signal IntCycle_n : std_logic; signal NoRead : std_logic; diff --git a/common/IO/Z80CTC/ctc_counter.vhd b/common/IO/Z80CTC/ctc_counter.vhd index da17d608..d0192526 100644 --- a/common/IO/Z80CTC/ctc_counter.vhd +++ b/common/IO/Z80CTC/ctc_counter.vhd @@ -41,6 +41,7 @@ architecture struct of ctc_counter is signal clk_trg_in : std_logic; signal clk_trg_r : std_logic; signal trigger : std_logic; + signal trigger_clk : std_logic; signal count_ena : std_logic; signal load_data_r : std_logic; -- make sure load_data toggles to get one new data @@ -52,7 +53,6 @@ prescale_max <= X"FF"; -- timer mode prescale 256 clk_trg_in <= clk_trg xor control_word(4); -trigger <= '1' when clk_trg_in = '0' and clk_trg_r = '1' else '0'; d_out <= count_in(7 downto 0); @@ -74,8 +74,11 @@ begin else if rising_edge(clock) then if clock_ena = '1' then - - clk_trg_r <= clk_trg_in; + trigger <= '0'; + trigger_clk <= '0'; + if trigger_clk = '0' and trigger = '1' then + trigger_clk <= '1'; + end if; load_data_r <= load_data; if (restart_on_next_trigger = '1' and trigger = '1') or (restart_on_next_clock = '1') then @@ -128,7 +131,7 @@ begin -- counter zc_to_in <= '0'; - if ((control_word(6) = '1' and trigger = '1' ) or + if ((control_word(6) = '1' and trigger_clk = '0' and trigger = '1') or -- rising edge of trigger_clk (control_word(6) = '0' and count_ena = '1') ) and time_constant_loaded = '1' then if prescale_in = 0 then prescale_in <= prescale_max; @@ -144,6 +147,14 @@ begin end if; end if; + + -- detecting of trg input is asynchronous, + -- but eventually it's synchronized to the timer clock (clock_ena) via trigger_clk + clk_trg_r <= clk_trg_in; + if clk_trg_in = '0' and clk_trg_r = '1' then + trigger <= '1'; + end if; + end if; end if; end process; diff --git a/common/IO/Z80CTC/z80ctc.qip b/common/IO/Z80CTC/z80ctc.qip index 6a3ed4fd..56c05534 100644 --- a/common/IO/Z80CTC/z80ctc.qip +++ b/common/IO/Z80CTC/z80ctc.qip @@ -1,4 +1,3 @@ set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) z80ctc_top.vhd ] set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ctc_controler.vhd ] set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ctc_counter.vhd ] -set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) z80ctc_top.vhd ] diff --git a/common/IO/Z80CTC/z80ctc_top.vhd b/common/IO/Z80CTC/z80ctc_top.vhd index b9efaca9..b6c094ec 100644 --- a/common/IO/Z80CTC/z80ctc_top.vhd +++ b/common/IO/Z80CTC/z80ctc_top.vhd @@ -37,6 +37,7 @@ end z80ctc_top; architecture struct of z80ctc_top is signal cpu_int_ack_n : std_logic; + signal ctc_int_n : std_logic; signal ctc_controler_we : std_logic; signal ctc_controler_do : std_logic_vector(7 downto 0); @@ -87,13 +88,15 @@ ctc_counter_1_we <= '1' when ce_n = '0' and iorq_n = '0' and m1_n = '1' and rd_n ctc_counter_2_we <= '1' when ce_n = '0' and iorq_n = '0' and m1_n = '1' and rd_n = '1' and cs = "10" else '0'; ctc_counter_3_we <= '1' when ce_n = '0' and iorq_n = '0' and m1_n = '1' and rd_n = '1' and cs = "11" else '0'; -dout <= ctc_controler_do when cpu_int_ack_n = '0' else - ctc_counter_0_do when iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "00" else - ctc_counter_1_do when iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "01" else - ctc_counter_2_do when iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "10" else - ctc_counter_3_do when iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "11" else +dout <= ctc_controler_do when cpu_int_ack_n = '0' and ctc_int_n = '0' else + ctc_counter_0_do when ce_n = '0' and iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "00" else + ctc_counter_1_do when ce_n = '0' and iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "01" else + ctc_counter_2_do when ce_n = '0' and iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "10" else + ctc_counter_3_do when ce_n = '0' and iorq_n = '0' and m1_n = '1' and rd_n = '0' and cs = "11" else x"FF"; +int_n <= ctc_int_n; + -- CTC interrupt controler Z80-CTC (MK3882) ctc_controler : entity work.ctc_controler port map( @@ -112,7 +115,7 @@ port map( int_pulse_3 => ctc_counter_3_int, d_out => ctc_controler_do, - int_n => int_n + int_n => ctc_int_n ); ctc_counter_0 : entity work.ctc_counter diff --git a/common/Sound/ym2149/YM2149.vhd b/common/Sound/ym2149/YM2149.vhd index b5e463cc..ae14e63e 100644 --- a/common/Sound/ym2149/YM2149.vhd +++ b/common/Sound/ym2149/YM2149.vhd @@ -62,7 +62,7 @@ library ieee; entity YM2149 is generic ( - MIXER_VOLTABLE : std_logic := '0' + MIXER_VOLTABLE : std_logic := '0' ); port ( -- data bus @@ -586,11 +586,12 @@ begin vol_r <= vol_r + dac_amp; when "00" => -- Channel A if I_STEREO = '0' then - vol_mixer_l <= vol_l + dac_amp; - else - vol_mixer_l <= vol_l; + vol_r <= vol_r + dac_amp; end if; - vol_mixer_r <= vol_r + dac_amp; + vol_l <= vol_l + dac_amp; + when "11" => + vol_mixer_l <= vol_l; + vol_mixer_r <= vol_r; when others => null; end case; end if; @@ -667,12 +668,12 @@ begin ADDR_B => vol_table_in_r, DATA_B => vol_table_out_r ); - end generate; -- VOLTABLE + end generate; -- VOLTABLE NO_VOLTABLE: if MIXER_VOLTABLE = '0' generate vol_table_out_l <= (others => '0'); vol_table_out_r <= (others => '0'); - end generate; + end generate; -- mixed audio output diff --git a/common/mist/README.md b/common/mist/README.md new file mode 100644 index 00000000..588d54cd --- /dev/null +++ b/common/mist/README.md @@ -0,0 +1,33 @@ +Common components for MiST board +================================ + +This repository contains common components, which should be used by almost all cores. +The modules: + +- user_io.v - communicating with the IO controller. +- data_io.v - handling file uploads from the IO controller. +- mist_video.v - a video pipeline, which gives an optional scandoubler, OSD and rgb2ypbpr conversion. +- osd.v, scandoubler.v, rgb2ypbpr.sv, cofi.sv - these are used in mist_video, but can be used separately, too. +- sd_card.v - gives an SPI interface with SD-Card commands towards the IO-Controller, accessing .VHD and other mounted files. +- dac.vhd - a simple sigma-delta DAC for audio output. +- arcade_inputs.v - mostly for arcade-style games, gives access to the joysticks with MAME-style keyboard mapping. +- mist.vhd - VHDL component declarations for user_io and mist_video. +- mist_core.qip - collects the core components, which are needed in almost every case. + +Usage hints +=========== + +All of these components should be clocked by a synchronous clock to the core. The data between the external SPI +interface and this internal clock are synchronized. However to make Quartus' job easier, you have to tell it to +don't try to optimize paths between the SPI and the system clock domain. Also you have to define the incoming +27 MHz and the SPI clocks. These lines in the .sdc file do that: + +``` +set sys_clk "your_system_clock" + +create_clock -name {clk_27} -period 37.037 -waveform { 0.000 18.500 } [get_ports {CLOCK_27[0]}] +create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}] +set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks $sys_clk] +``` + +Replace "your_system_clock" with the name of the pll clock, like "pll|altpll_component|auto_generated|pll1|clk[0]". diff --git a/common/mist/data_io.v b/common/mist/data_io.v index aaf67786..8941fe45 100644 --- a/common/mist/data_io.v +++ b/common/mist/data_io.v @@ -35,6 +35,8 @@ module data_io // ARM -> FPGA download output reg ioctl_download = 0, // signal indicating an active download output reg [7:0] ioctl_index, // menu index used to upload the file ([7:6] - extension index, [5:0] - menu index) + // Note: this is also set for user_io mounts. + // Valid when ioctl_download = 1 or when img_mounted strobe is active in user_io. output reg ioctl_wr, // strobe indicating ioctl_dout valid output reg [24:0] ioctl_addr, output reg [7:0] ioctl_dout, @@ -53,7 +55,6 @@ reg rclk = 0; reg rclk2 = 0; reg addr_reset = 0; reg downloading_reg = 0; -reg [7:0] index_reg = 0; localparam DIO_FILE_TX = 8'h53; localparam DIO_FILE_TX_DAT = 8'h54; @@ -101,7 +102,7 @@ always@(posedge SPI_SCK, posedge SPI_SS2) begin : SPI_RECEIVER end // expose file (menu) index - if((cmd == DIO_FILE_INDEX) && (cnt == 15)) index_reg <= {sbuf, SPI_DI}; + if((cmd == DIO_FILE_INDEX) && (cnt == 15)) ioctl_index <= {sbuf, SPI_DI}; // receiving FAT directory entry (mist-firmware/fat.h - DIRENTRY) if((cmd == DIO_FILE_INFO) && (cnt == 15)) begin @@ -193,7 +194,6 @@ always@(posedge clk_sys) begin : DATA_OUT if(addr_resetD ^ addr_resetD2) begin addr <= START_ADDR; filepos <= 0; - ioctl_index <= index_reg; ioctl_download <= 1; end diff --git a/common/mist/mist_video.v b/common/mist/mist_video.v index 219d78c3..a0142aba 100644 --- a/common/mist/mist_video.v +++ b/common/mist/mist_video.v @@ -51,6 +51,7 @@ parameter OSD_Y_OFFSET = 10'd0; parameter SD_HCNT_WIDTH = 9; parameter COLOR_DEPTH = 6; // 1-6 parameter OSD_AUTO_CE = 1'b1; +parameter SYNC_AND = 1'b0; // 0 - XOR, 1 - AND wire [5:0] SD_R_O; wire [5:0] SD_G_O; @@ -181,7 +182,7 @@ assign VGA_R = ypbpr?pr:cofi_r; assign VGA_G = ypbpr? y:cofi_g; assign VGA_B = ypbpr?pb:cofi_b; -wire cs = ~(cofi_hs ^ cofi_vs); +wire cs = SYNC_AND ? (cofi_hs & cofi_vs) : ~(cofi_hs ^ cofi_vs); wire hs = cofi_hs; wire vs = cofi_vs; diff --git a/common/mist/osd.v b/common/mist/osd.v index 4efbbe61..6f0b84ba 100644 --- a/common/mist/osd.v +++ b/common/mist/osd.v @@ -102,8 +102,8 @@ wire doublescan = (dsp_height>350); reg auto_ce_pix; always @(posedge clk_sys) begin reg [15:0] cnt = 0; - reg [1:0] pixsz; - reg [1:0] pixcnt; + reg [2:0] pixsz; + reg [2:0] pixcnt; reg hs; cnt <= cnt + 1'd1; @@ -118,7 +118,9 @@ always @(posedge clk_sys) begin if(cnt <= OSD_WIDTH_PADDED * 2) pixsz <= 0; else if(cnt <= OSD_WIDTH_PADDED * 3) pixsz <= 1; else if(cnt <= OSD_WIDTH_PADDED * 4) pixsz <= 2; - else pixsz <= 3; + else if(cnt <= OSD_WIDTH_PADDED * 5) pixsz <= 3; + else if(cnt <= OSD_WIDTH_PADDED * 6) pixsz <= 4; + else pixsz <= 5; pixcnt <= 0; auto_ce_pix <= 1; @@ -155,13 +157,15 @@ always @(posedge clk_sys) begin // falling edge of VSync if(!VSync && vsD) begin v_cnt <= 0; - vs_high <= v_cnt; + // if the difference is only one line, that might be interlaced picture + if (vs_high != v_cnt + 1'd1) vs_high <= v_cnt; end // rising edge of VSync else if(VSync && !vsD) begin v_cnt <= 0; - vs_low <= v_cnt; + // if the difference is only one line, that might be interlaced picture + if (vs_low != v_cnt + 1'd1) vs_low <= v_cnt; end end end diff --git a/common/mist/user_io.v b/common/mist/user_io.v index 67dcfed4..609f6d49 100644 --- a/common/mist/user_io.v +++ b/common/mist/user_io.v @@ -146,7 +146,7 @@ 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 clk_sys) begin +always@(posedge clk_sys) begin : ps2_kbd reg ps2_clkD; ps2_clkD <= ps2_clk; @@ -215,7 +215,7 @@ 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 clk_sys) begin +always@(posedge clk_sys) begin : ps2_mouse reg ps2_clkD; ps2_clkD <= ps2_clk; @@ -283,7 +283,7 @@ 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 +always @(posedge serial_strobe or posedge status[0]) begin : serial_out if(status[0] == 1) begin serial_out_wptr <= 0; end else begin @@ -292,7 +292,7 @@ always @(posedge serial_strobe or posedge status[0]) begin end end -always@(negedge spi_sck or posedge status[0]) begin +always@(negedge spi_sck or posedge status[0]) begin : serial_in if(status[0] == 1) begin serial_out_rptr <= 0; end else begin @@ -306,7 +306,7 @@ end // SPI bit and byte counters -always@(posedge spi_sck or posedge SPI_SS_IO) begin +always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_counter if(SPI_SS_IO == 1) begin bit_cnt <= 0; byte_cnt <= 0; @@ -321,7 +321,7 @@ end // SPI transmitter FPGA -> IO reg [7:0] spi_byte_out; -always@(negedge spi_sck or posedge SPI_SS_IO) begin +always@(negedge spi_sck or posedge SPI_SS_IO) begin : spi_byteout if(SPI_SS_IO == 1) begin SPI_MISO <= 1'bZ; end else begin @@ -329,7 +329,7 @@ always@(negedge spi_sck or posedge SPI_SS_IO) begin end end -always@(posedge spi_sck or posedge SPI_SS_IO) begin +always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_transmitter reg [31:0] sd_lba_r; reg [7:0] drive_sel_r; @@ -357,10 +357,12 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin // reading sd card write data 8'h18: spi_byte_out <= sd_din; + 8'h1b: // send alternating flag byte and data if(byte_cnt[0]) spi_byte_out <= serial_out_status; else spi_byte_out <= serial_out_byte; + endcase end end @@ -373,7 +375,7 @@ reg spi_transfer_end_r = 1; reg [7:0] spi_byte_in; // Read at spi_sck clock domain, assemble bytes for transferring to clk_sys -always@(posedge spi_sck or posedge SPI_SS_IO) begin +always@(posedge spi_sck or posedge SPI_SS_IO) begin : spi_receiver if(SPI_SS_IO == 1) begin spi_transfer_end_r <= 1; @@ -392,7 +394,7 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin end // Process bytes from SPI at the clk_sys domain -always @(posedge clk_sys) begin +always @(posedge clk_sys) begin : cmd_block reg spi_receiver_strobe; reg spi_transfer_end; @@ -417,7 +419,7 @@ always @(posedge clk_sys) begin key_strobe <= 0; mouse_strobe <= 0; - if (~spi_transfer_endD & spi_transfer_end) begin + if (spi_transfer_end) begin abyte_cnt <= 8'd0; end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin @@ -436,12 +438,12 @@ always @(posedge clk_sys) begin 8'h63: if (abyte_cnt < 5) joystick_3[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; 8'h64: if (abyte_cnt < 5) joystick_4[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; 8'h70,8'h71: begin - // store incoming ps2 mouse bytes - if (~acmd[0]) begin - // PS2 serial protocol for the first mouse only + // store incoming ps2 mouse bytes + if (abyte_cnt < 4) begin ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in; ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; end + if (abyte_cnt == 1) mouse_flags_r <= spi_byte_in; else if (abyte_cnt == 2) mouse_x_r <= spi_byte_in; else if (abyte_cnt == 3) mouse_y_r <= spi_byte_in; @@ -451,8 +453,8 @@ always @(posedge clk_sys) begin mouse_x <= { mouse_flags_r[4], mouse_x_r }; mouse_y <= { mouse_flags_r[5], mouse_y_r }; mouse_z <= spi_byte_in[3:0]; - mouse_strobe <= 1; mouse_idx <= acmd[0]; + mouse_strobe <= 1; end end 8'h05: begin @@ -466,7 +468,7 @@ always @(posedge clk_sys) begin if (spi_byte_in == 8'he0) key_extended_r <= 1'b1; else if (spi_byte_in == 8'hf0) key_pressed_r <= 1'b0; else begin - key_extended <= key_extended_r; + key_extended <= key_extended_r && abyte_cnt != 1; key_pressed <= key_pressed_r || abyte_cnt == 1; key_code <= spi_byte_in; key_strobe <= 1'b1; @@ -506,8 +508,9 @@ always @(posedge clk_sys) begin end end + // Process SD-card related bytes from SPI at the clk_sd domain -always @(posedge clk_sd) begin +always @(posedge clk_sd) begin : sd_block reg spi_receiver_strobe; reg spi_transfer_end; @@ -538,7 +541,7 @@ always @(posedge clk_sd) begin img_mounted <= 0; - if (~spi_transfer_endD & spi_transfer_end) begin + if (spi_transfer_end) begin abyte_cnt <= 8'd0; sd_ack <= 1'b0; sd_ack_conf <= 1'b0; @@ -558,6 +561,8 @@ always @(posedge clk_sd) begin if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; end + if(spi_byte_in == 8'h19) + sd_ack_conf <= 1'b1; if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18)) sd_ack <= 1'b1; @@ -565,7 +570,9 @@ always @(posedge clk_sd) begin case(acmd) // send sector IO -> FPGA - 8'h17: begin + 8'h17, + // send SD config IO -> FPGA + 8'h19: begin // flag that download begins sd_dout_strobe <= 1'b1; sd_dout <= spi_byte_in; @@ -579,14 +586,6 @@ always @(posedge clk_sd) begin end end - // send SD config IO -> FPGA - 8'h19: begin - // flag that download begins - sd_dout_strobe <= 1'b1; - sd_ack_conf <= 1'b1; - sd_dout <= spi_byte_in; - end - 8'h1c: img_mounted[spi_byte_in[0]] <= 1; // send image info