Update sys. Re-organize the sources.

This commit is contained in:
sorgelig
2020-05-11 23:17:53 +08:00
parent 0c1cb37dba
commit 5a66d5ec1c
102 changed files with 1996 additions and 1364 deletions

6
rtl/T80/T80.qip Normal file
View File

@ -0,0 +1,6 @@
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80s.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80pa.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80_Reg.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80_MCode.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80_ALU.vhd ]
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) T80.vhd ]

1167
rtl/T80/T80.vhd Normal file

File diff suppressed because it is too large Load Diff

376
rtl/T80/T80_ALU.vhd Normal file
View File

@ -0,0 +1,376 @@
--------------------------------------------------------------------------------
-- ****
-- 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 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.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- http://www.opencores.org/cvsweb.shtml/t80/
--
-- Limitations :
--
-- File history :
--
-- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test
-- 0238 : Fixed zero flag for 16 bit SBC and ADC
-- 0240 : Added GB operations
-- 0242 : Cleanup
-- 0247 : Cleanup
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity T80_ALU is
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 T80_ALU;
architecture rtl of T80_ALU is
procedure AddSub(A : std_logic_vector;
B : std_logic_vector;
Sub : std_logic;
Carry_In : std_logic;
signal Res : out std_logic_vector;
signal Carry : out std_logic) is
variable B_i : unsigned(A'length - 1 downto 0);
variable Res_i : unsigned(A'length + 1 downto 0);
begin
if Sub = '1' then
B_i := not unsigned(B);
else
B_i := unsigned(B);
end if;
Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1");
Carry <= Res_i(A'length + 1);
Res <= std_logic_vector(Res_i(A'length downto 1));
end;
-- AddSub variables (temporary signals)
signal UseCarry : std_logic;
signal Carry7_v : std_logic;
signal Overflow_v : std_logic;
signal HalfCarry_v : std_logic;
signal Carry_v : std_logic;
signal Q_v : std_logic_vector(7 downto 0);
signal BitMask : std_logic_vector(7 downto 0);
begin
with IR(5 downto 3) select BitMask <= "00000001" when "000",
"00000010" when "001",
"00000100" when "010",
"00001000" when "011",
"00010000" when "100",
"00100000" when "101",
"01000000" when "110",
"10000000" when others;
UseCarry <= not ALU_Op(2) and ALU_Op(0);
AddSub(BusA(3 downto 0), BusB(3 downto 0), ALU_Op(1), ALU_Op(1) xor (UseCarry and F_In(Flag_C)), Q_v(3 downto 0), HalfCarry_v);
AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v);
AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v);
-- bug fix - parity flag is just parity for 8080, also overflow for Z80
process (Carry_v, Carry7_v, Q_v)
begin
if(Mode=2) then
OverFlow_v <= not (Q_v(0) xor Q_v(1) xor Q_v(2) xor Q_v(3) xor
Q_v(4) xor Q_v(5) xor Q_v(6) xor Q_v(7)); else
OverFlow_v <= Carry_v xor Carry7_v;
end if;
end process;
process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16, WZ, XY_State)
variable Q_t : std_logic_vector(7 downto 0);
variable DAA_Q : unsigned(8 downto 0);
begin
Q_t := "--------";
F_Out <= F_In;
DAA_Q := "---------";
case ALU_Op is
when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" | "0110" | "0111" =>
F_Out(Flag_N) <= '0';
F_Out(Flag_C) <= '0';
case ALU_OP(2 downto 0) is
when "000" | "001" => -- ADD, ADC
Q_t := Q_v;
F_Out(Flag_C) <= Carry_v;
F_Out(Flag_H) <= HalfCarry_v;
F_Out(Flag_P) <= OverFlow_v;
when "010" | "011" | "111" => -- SUB, SBC, CP
Q_t := Q_v;
F_Out(Flag_N) <= '1';
F_Out(Flag_C) <= not Carry_v;
F_Out(Flag_H) <= not HalfCarry_v;
F_Out(Flag_P) <= OverFlow_v;
when "100" => -- AND
Q_t(7 downto 0) := BusA and BusB;
F_Out(Flag_H) <= '1';
when "101" => -- XOR
Q_t(7 downto 0) := BusA xor BusB;
F_Out(Flag_H) <= '0';
when others => -- OR "110"
Q_t(7 downto 0) := BusA or BusB;
F_Out(Flag_H) <= '0';
end case;
if ALU_Op(2 downto 0) = "111" then -- CP
F_Out(Flag_X) <= BusB(3);
F_Out(Flag_Y) <= BusB(5);
else
F_Out(Flag_X) <= Q_t(3);
F_Out(Flag_Y) <= Q_t(5);
end if;
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
if Z16 = '1' then
F_Out(Flag_Z) <= F_In(Flag_Z); -- 16 bit ADC,SBC
end if;
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_S) <= Q_t(7);
case ALU_Op(2 downto 0) is
when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP
when others =>
F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
end case;
if Arith16 = '1' then
F_Out(Flag_S) <= F_In(Flag_S);
F_Out(Flag_Z) <= F_In(Flag_Z);
F_Out(Flag_P) <= F_In(Flag_P);
end if;
when "1100" =>
-- DAA
F_Out(Flag_H) <= F_In(Flag_H);
F_Out(Flag_C) <= F_In(Flag_C);
DAA_Q(7 downto 0) := unsigned(BusA);
DAA_Q(8) := '0';
if F_In(Flag_N) = '0' then
-- After addition
-- Alow > 9 or H = 1
if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
if (DAA_Q(3 downto 0) > 9) then
F_Out(Flag_H) <= '1';
else
F_Out(Flag_H) <= '0';
end if;
DAA_Q := DAA_Q + 6;
end if;
-- new Ahigh > 9 or C = 1
if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then
DAA_Q := DAA_Q + 96; -- 0x60
end if;
else
-- After subtraction
if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then
if DAA_Q(3 downto 0) > 5 then
F_Out(Flag_H) <= '0';
end if;
DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6;
end if;
if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then
DAA_Q := DAA_Q - 352; -- 0x160
end if;
end if;
F_Out(Flag_X) <= DAA_Q(3);
F_Out(Flag_Y) <= DAA_Q(5);
F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8);
Q_t := std_logic_vector(DAA_Q(7 downto 0));
if DAA_Q(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_S) <= DAA_Q(7);
F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor
DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7));
when "1101" | "1110" =>
-- RLD, RRD
Q_t(7 downto 4) := BusA(7 downto 4);
if ALU_Op(0) = '1' then
Q_t(3 downto 0) := BusB(7 downto 4);
else
Q_t(3 downto 0) := BusB(3 downto 0);
end if;
F_Out(Flag_H) <= '0';
F_Out(Flag_N) <= '0';
F_Out(Flag_X) <= Q_t(3);
F_Out(Flag_Y) <= Q_t(5);
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_S) <= Q_t(7);
F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
when "1001" =>
-- BIT
Q_t(7 downto 0) := BusB and BitMask;
F_Out(Flag_S) <= Q_t(7);
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
F_Out(Flag_P) <= '1';
else
F_Out(Flag_Z) <= '0';
F_Out(Flag_P) <= '0';
end if;
F_Out(Flag_H) <= '1';
F_Out(Flag_N) <= '0';
if IR(2 downto 0) = "110" or XY_State /= "00" then
F_Out(Flag_X) <= WZ(11);
F_Out(Flag_Y) <= WZ(13);
else
F_Out(Flag_X) <= BusB(3);
F_Out(Flag_Y) <= BusB(5);
end if;
when "1010" =>
-- SET
Q_t(7 downto 0) := BusB or BitMask;
when "1011" =>
-- RES
Q_t(7 downto 0) := BusB and not BitMask;
when "1000" =>
-- ROT
case IR(5 downto 3) is
when "000" => -- RLC
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := BusA(7);
F_Out(Flag_C) <= BusA(7);
when "010" => -- RL
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := F_In(Flag_C);
F_Out(Flag_C) <= BusA(7);
when "001" => -- RRC
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := BusA(0);
F_Out(Flag_C) <= BusA(0);
when "011" => -- RR
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := F_In(Flag_C);
F_Out(Flag_C) <= BusA(0);
when "100" => -- SLA
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := '0';
F_Out(Flag_C) <= BusA(7);
when "110" => -- SLL (Undocumented) / SWAP
if Mode = 3 then
Q_t(7 downto 4) := BusA(3 downto 0);
Q_t(3 downto 0) := BusA(7 downto 4);
F_Out(Flag_C) <= '0';
else
Q_t(7 downto 1) := BusA(6 downto 0);
Q_t(0) := '1';
F_Out(Flag_C) <= BusA(7);
end if;
when "101" => -- SRA
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := BusA(7);
F_Out(Flag_C) <= BusA(0);
when others => -- SRL
Q_t(6 downto 0) := BusA(7 downto 1);
Q_t(7) := '0';
F_Out(Flag_C) <= BusA(0);
end case;
F_Out(Flag_H) <= '0';
F_Out(Flag_N) <= '0';
F_Out(Flag_X) <= Q_t(3);
F_Out(Flag_Y) <= Q_t(5);
F_Out(Flag_S) <= Q_t(7);
if Q_t(7 downto 0) = "00000000" then
F_Out(Flag_Z) <= '1';
else
F_Out(Flag_Z) <= '0';
end if;
F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor
Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7));
if ISet = "00" then
F_Out(Flag_P) <= F_In(Flag_P);
F_Out(Flag_S) <= F_In(Flag_S);
F_Out(Flag_Z) <= F_In(Flag_Z);
end if;
when others =>
null;
end case;
Q <= Q_t;
end process;
end;

2037
rtl/T80/T80_MCode.vhd Normal file

File diff suppressed because it is too large Load Diff

126
rtl/T80/T80_Reg.vhd Normal file
View File

@ -0,0 +1,126 @@
--------------------------------------------------------------------------------
-- ****
-- 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 300 started tidyup
-- MikeJ March 2005
-- Latest version from www.fpgaarcade.com (original www.opencores.org)
--
-- ****
--
-- T80 Registers, technology independent
--
-- Version : 0244
--
-- Copyright (c) 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.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- http://www.opencores.org/cvsweb.shtml/t51/
--
-- Limitations :
--
-- File history :
--
-- 0242 : Initial release
--
-- 0244 : Changed to single register file
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity T80_Reg is
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)
);
end T80_Reg;
architecture rtl of T80_Reg is
type Register_Image is array (natural range <>) of std_logic_vector(7 downto 0);
signal RegsH : Register_Image(0 to 7);
signal RegsL : Register_Image(0 to 7);
begin
process (Clk)
begin
if rising_edge(Clk) then
if CEN = '1' then
if WEH = '1' then
RegsH(to_integer(unsigned(AddrA))) <= DIH;
end if;
if WEL = '1' then
RegsL(to_integer(unsigned(AddrA))) <= DIL;
end if;
end if;
end if;
end process;
DOAH <= RegsH(to_integer(unsigned(AddrA)));
DOAL <= RegsL(to_integer(unsigned(AddrA)));
DOBH <= RegsH(to_integer(unsigned(AddrB)));
DOBL <= RegsL(to_integer(unsigned(AddrB)));
DOCH <= RegsH(to_integer(unsigned(AddrC)));
DOCL <= RegsL(to_integer(unsigned(AddrC)));
DOR <= RegsH(7) & RegsL(7) & RegsH(6) & RegsL(6) & RegsH(5) & RegsL(5) & RegsH(4) & RegsL(4) & RegsH(3) & RegsL(3) & RegsH(2) & RegsL(2) & RegsH(1) & RegsL(1) & RegsH(0) & RegsL(0);
end;

212
rtl/T80/T80pa.vhd Normal file
View File

@ -0,0 +1,212 @@
--
-- Z80 compatible microprocessor core, preudo-asynchronous top level (by Sorgelig)
--
-- 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.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- http://www.opencores.org/cvsweb.shtml/t80/
--
-- File history :
--
-- v1.0: convert to preudo-asynchronous model with original Z80 timings.
--
-- v2.0: rewritten for more precise timings.
-- support for both CEN_n and CEN_p set to 1. Effective clock will be CLK/2.
--
-- v2.1: Output Address 0 during non-bus MCycle (fix ZX contention)
--
-- v2.2: Interrupt acknowledge cycle has been corrected
-- WAIT_n is broken in T80.vhd. Simulate correct WAIT_n locally.
--
-- v2.3: Output last used Address during non-bus MCycle seems more correct.
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity T80pa is
generic(
Mode : integer := 0 -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
);
port(
RESET_n : in std_logic;
CLK : in std_logic;
CEN_p : in std_logic := '1';
CEN_n : in std_logic := '1';
WAIT_n : in std_logic := '1';
INT_n : in std_logic := '1';
NMI_n : in std_logic := '1';
BUSRQ_n : in std_logic := '1';
M1_n : out std_logic;
MREQ_n : out std_logic;
IORQ_n : out std_logic;
RD_n : out std_logic;
WR_n : out std_logic;
RFSH_n : out std_logic;
HALT_n : out std_logic;
BUSAK_n : out std_logic;
OUT0 : in std_logic := '0'; -- 0 => OUT(C),0, 1 => OUT(C),255
A : out std_logic_vector(15 downto 0);
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0);
REG : out std_logic_vector(207 downto 0) -- IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A
);
end T80pa;
architecture rtl of T80pa is
signal IntCycle_n : std_logic;
signal IntCycleD_n : std_logic_vector(1 downto 0);
signal IORQ : std_logic;
signal NoRead : std_logic;
signal Write : std_logic;
signal BUSAK : std_logic;
signal DI_Reg : std_logic_vector (7 downto 0); -- Input synchroniser
signal MCycle : std_logic_vector(2 downto 0);
signal TState : std_logic_vector(2 downto 0);
signal CEN_pol : std_logic;
signal A_int : std_logic_vector(15 downto 0);
signal A_last : std_logic_vector(15 downto 0);
begin
A <= A_int when NoRead = '0' or Write = '1' else A_last;
BUSAK_n <= BUSAK;
u0 : work.T80
generic map(
Mode => Mode,
IOWait => 1
)
port map(
CEN => CEN_p and not CEN_pol,
M1_n => M1_n,
IORQ => IORQ,
NoRead => NoRead,
Write => Write,
RFSH_n => RFSH_n,
HALT_n => HALT_n,
WAIT_n => '1',
INT_n => INT_n,
NMI_n => NMI_n,
RESET_n => RESET_n,
BUSRQ_n => BUSRQ_n,
BUSAK_n => BUSAK,
CLK_n => CLK,
A => A_int,
DInst => DI, -- valid at beginning of T3
DI => DI_Reg, -- latched at middle of T3
DO => DO,
REG => REG,
MC => MCycle,
TS => TState,
OUT0 => OUT0,
IntCycle_n => IntCycle_n
);
process(CLK)
begin
if rising_edge(CLK) then
if RESET_n = '0' then
WR_n <= '1';
RD_n <= '1';
IORQ_n <= '1';
MREQ_n <= '1';
DI_Reg <= "00000000";
CEN_pol <= '0';
elsif CEN_p = '1' and CEN_pol = '0' then
CEN_pol <= '1';
if MCycle = "001" then
if TState = "010" then
IORQ_n <= '1';
MREQ_n <= '1';
RD_n <= '1';
end if;
else
if TState = "001" and IORQ = '1' then
WR_n <= not Write;
RD_n <= Write;
IORQ_n <= '0';
end if;
end if;
elsif CEN_n = '1' and CEN_pol = '1' then
if TState = "010" then
CEN_pol <= not WAIT_n;
else
CEN_pol <= '0';
end if;
if TState = "011" and BUSAK = '1' then
DI_Reg <= DI;
end if;
if MCycle = "001" then
if TState = "001" then
IntCycleD_n <= IntCycleD_n(0) & IntCycle_n;
RD_n <= not IntCycle_n;
MREQ_n <= not IntCycle_n;
IORQ_n <= IntCycleD_n(1);
A_last <= A_int;
end if;
if TState = "011" then
IntCycleD_n <= "11";
RD_n <= '1';
MREQ_n <= '0';
end if;
if TState = "100" then
MREQ_n <= '1';
end if;
else
if NoRead = '0' and IORQ = '0' then
if TState = "001" then
RD_n <= Write;
MREQ_n <= '0';
A_last <= A_int;
end if;
end if;
if TState = "010" then
WR_n <= not Write;
end if;
if TState = "011" then
WR_n <= '1';
RD_n <= '1';
IORQ_n <= '1';
MREQ_n <= '1';
end if;
end if;
end if;
end if;
end process;
end;

192
rtl/T80/T80s.vhd Normal file
View File

@ -0,0 +1,192 @@
--
-- Z80 compatible microprocessor core, synchronous top level
-- Different timing than the original z80
-- Inputs needs to be synchronous and outputs may glitch
--
-- Version : 0242
--
-- 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.
--
-- Please report bugs to the author, but before you do so, please
-- make sure that this is not a derivative work and that
-- you have the latest version of this file.
--
-- The latest version of this file can be found at:
-- http://www.opencores.org/cvsweb.shtml/t80/
--
-- Limitations :
--
-- File history :
--
-- 0208 : First complete release
--
-- 0210 : Fixed read with wait
--
-- 0211 : Fixed interrupt cycle
--
-- 0235 : Updated for T80 interface change
--
-- 0236 : Added T2Write generic
--
-- 0237 : Fixed T2Write with wait state
--
-- 0238 : Updated for T80 interface change
--
-- 0240 : Updated for T80 interface change
--
-- 0242 : Updated for T80 interface change
--
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
entity T80s is
generic(
Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB
T2Write : integer := 1; -- 0 => WR_n active in T3, /=0 => WR_n active in T2
IOWait : integer := 1 -- 0 => Single cycle I/O, 1 => Std I/O cycle
);
port(
RESET_n : in std_logic;
CLK : in std_logic;
CEN : in std_logic := '1';
WAIT_n : in std_logic := '1';
INT_n : in std_logic := '1';
NMI_n : in std_logic := '1';
BUSRQ_n : in std_logic := '1';
M1_n : out std_logic;
MREQ_n : out std_logic;
IORQ_n : out std_logic;
RD_n : out std_logic;
WR_n : out std_logic;
RFSH_n : out std_logic;
HALT_n : out std_logic;
BUSAK_n : out std_logic;
OUT0 : in std_logic := '0'; -- 0 => OUT(C),0, 1 => OUT(C),255
A : out std_logic_vector(15 downto 0);
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0)
);
end T80s;
architecture rtl of T80s is
signal IntCycle_n : std_logic;
signal NoRead : std_logic;
signal Write : std_logic;
signal IORQ : std_logic;
signal DI_Reg : std_logic_vector(7 downto 0);
signal MCycle : std_logic_vector(2 downto 0);
signal TState : std_logic_vector(2 downto 0);
begin
u0 : work.T80
generic map(
Mode => Mode,
IOWait => IOWait)
port map(
CEN => CEN,
M1_n => M1_n,
IORQ => IORQ,
NoRead => NoRead,
Write => Write,
RFSH_n => RFSH_n,
HALT_n => HALT_n,
WAIT_n => Wait_n,
INT_n => INT_n,
NMI_n => NMI_n,
RESET_n => RESET_n,
BUSRQ_n => BUSRQ_n,
BUSAK_n => BUSAK_n,
CLK_n => CLK,
A => A,
DInst => DI,
DI => DI_Reg,
DO => DO,
MC => MCycle,
TS => TState,
OUT0 => OUT0,
IntCycle_n => IntCycle_n
);
process (RESET_n, CLK)
begin
if RESET_n = '0' then
RD_n <= '1';
WR_n <= '1';
IORQ_n <= '1';
MREQ_n <= '1';
DI_Reg <= "00000000";
elsif rising_edge(CLK) then
if CEN = '1' then
RD_n <= '1';
WR_n <= '1';
IORQ_n <= '1';
MREQ_n <= '1';
if MCycle = 1 then
if TState = 1 or (TState = 2 and Wait_n = '0') then
RD_n <= not IntCycle_n;
MREQ_n <= not IntCycle_n;
IORQ_n <= IntCycle_n;
end if;
if TState = 3 then
MREQ_n <= '0';
end if;
else
if (TState = 1 or (TState = 2 and Wait_n = '0')) and NoRead = '0' and Write = '0' then
RD_n <= '0';
IORQ_n <= not IORQ;
MREQ_n <= IORQ;
end if;
if T2Write = 0 then
if TState = 2 and Write = '1' then
WR_n <= '0';
IORQ_n <= not IORQ;
MREQ_n <= IORQ;
end if;
else
if (TState = 1 or (TState = 2 and Wait_n = '0')) and Write = '1' then
WR_n <= '0';
IORQ_n <= not IORQ;
MREQ_n <= IORQ;
end if;
end if;
end if;
if TState = 2 and Wait_n = '1' then
DI_Reg <= DI;
end if;
end if;
end if;
end process;
end;

33
rtl/clock.v Normal file
View File

@ -0,0 +1,33 @@
// This module receives 28 MHz as input clock
// and strobes strobes for all clocked parts
// clk|-__--__--__--__-| period = 28 duty = 50% phase = 0
// cnt|< 0>< 1>< 2>< 3>|
// f0 |----____----____| period = 14 duty = 50% phase = 0
// f1 |____----____----| period = 14 duty = 50% phase = 180
// h0 |--------________| period = 7 duty = 50% phase = 0
// h1 |________--------| period = 7 duty = 50% phase = 180
// c0 |----____________| period = 7 duty = 25% phase = 0
// c1 |____----________| period = 7 duty = 25% phase = 90
// c2 |________----____| period = 7 duty = 25% phase = 180
// c3 |____________----| period = 7 duty = 25% phase = 270
module clock
(
input wire clk,
output reg f0, f1,
output reg h0, h1,
output reg c0, c1, c2, c3
);
reg [1:0] cnt;
always @(posedge clk) begin
cnt <= cnt + 2'b1;
{f1, f0} <= 2'b1 << cnt[0];
{h1, h0} <= 2'b1 << cnt[1];
{c3, c2, c1, c0} <= 4'b1 << cnt;
end
endmodule

106
rtl/common/zclock.v Normal file
View File

@ -0,0 +1,106 @@
// PentEvo project (c) NedoPC 2008-2011
//
// Z80 clocking module, also contains some wait-stating when 14MHz
//
// IDEAL:
// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________
// clock phasing:
// c3 must be zpos for 7mhz, therefore c1 - zneg
// for 3.5 mhz, c3 is both zpos and zneg (alternating)
// 14MHz rulez:
// 1. do variable stalls for memory access.
// 2. do fallback on 7mhz for external IO accesses
// 3. clock switch 14-7-3.5 only at RFSH
module zclock
(
input clk,
output zclk_out,
input c0, c2, f0, f1,
input iorq_s,
input external_port,
output reg zpos,
output reg zneg,
// stall enables and triggers
input cpu_stall,
input ide_stall,
input dos_on,
input vdos_off,
input [1:0] turbo // 2'b00 - 3.5 MHz
// 2'b01 - 7.0 MHz
// 2'b1x - 14.0 MHz
);
assign zclk_out = ~zclk_o;
reg zclk_o;
wire [1:0] turbo_int = turbo;
// wait generator
wire dos_io_stall = stall_start || !stall_count_end;
wire stall_start = dos_stall || io_stall;
wire dos_stall = dos_on || vdos_off;
wire io_stall = iorq_s && external_port && turbo_int[1];
wire stall_count_end = stall_count[3];
reg [3:0] stall_count;
always @(posedge clk) begin
if (stall_start) begin
if (dos_stall) stall_count <= 4; // 4 tacts 28MHz (1 tact 7MHz)
else if (io_stall) stall_count <= 0; // 8 tacts 28MHz (1 tact 3.5MHz)
end
else if (!stall_count_end) stall_count <= stall_count + 3'd1;
end
// Z80 clocking pre-strobes
wire pre_zpos = turbo_int[1] ? pre_zpos_140 : (turbo_int[0] ? pre_zpos_70 : pre_zpos_35);
wire pre_zneg = turbo_int[1] ? pre_zneg_140 : (turbo_int[0] ? pre_zneg_70 : pre_zneg_35);
wire pre_zpos_140 = f1;
wire pre_zneg_140 = f0;
wire pre_zpos_70 = c2;
wire pre_zneg_70 = c0;
wire pre_zpos_35 = c2_cnt && c2;
wire pre_zneg_35 = !c2_cnt && c2;
reg c2_cnt;
always @(posedge clk) if (c2) c2_cnt <= ~c2_cnt;
// Z80 clocking strobes
wire stall = cpu_stall || dos_io_stall || ide_stall;
always @(posedge clk) begin
zpos <= !stall && pre_zpos && zclk_o;
zneg <= !stall && pre_zneg && !zclk_o;
end
// make Z80 clock: account for external inversion and make some leading of clock
// 9.5 ns propagation delay: from clk posedge to zclk returned back any edge
// (1/28)/2=17.9ns half a clock lead
// 2.6ns lag because of non-output register emitting of zclk_o
// total: 5.8 ns lead of any edge of zclk relative to posedge of clk => ACCOUNT FOR THIS WHEN DOING INTER-CLOCK DATA TRANSFERS
// Z80 clocking
always @(negedge clk) begin
if (zpos) zclk_o <= 0;
if (zneg) zclk_o <= 1;
end
endmodule

71
rtl/common/zint.v Normal file
View File

@ -0,0 +1,71 @@
module zint
(
input wire clk,
input wire zpos,
input wire res,
input wire int_start_frm,
input wire int_start_lin,
input wire int_start_dma,
input wire vdos,
input wire intack,
input wire [7:0] intmask,
output reg [7:0] im2vect,
output wire int_n
);
// In VDOS INTs are focibly disabled.
// For Frame, Line INT its generation is blocked, it will be lost.
// For DMA INT only its output is blocked, so DMA ISR will will be processed as soon as returned from VDOS.
assign int_n = ~(int_frm || int_lin || int_dma) | vdos;
wire dis_int_frm = !intmask[0];
wire dis_int_lin = !intmask[1];
wire dis_int_dma = !intmask[2];
wire intack_s = intack && !intack_r;
reg intack_r;
always @(posedge clk) intack_r <= intack;
reg [1:0] int_sel;
always @(posedge clk) begin
if (intack_s) begin
if (int_frm) im2vect <= 8'hFF; // priority 0
else if (int_lin) im2vect <= 8'hFD; // priority 1
else if (int_dma) im2vect <= 8'hFB; // priority 2
end
end
// ~INT generating
reg int_frm;
always @(posedge clk) begin
if (res || dis_int_frm) int_frm <= 0;
else if (int_start_frm) int_frm <= 1;
else if (intack_s || intctr_fin) int_frm <= 0; // priority 0
end
reg int_lin;
always @(posedge clk) begin
if (res || dis_int_lin) int_lin <= 0;
else if (int_start_lin) int_lin <= 1;
else if (intack_s && !int_frm) int_lin <= 0; // priority 1
end
reg int_dma;
always @(posedge clk) begin
if (res || dis_int_dma) int_dma <= 0;
else if (int_start_dma) int_dma <= 1;
else if (intack_s && !int_frm && !int_lin) int_dma <= 0; // priority 2
end
// ~INT counter
reg [5:0] intctr;
wire intctr_fin = intctr[5]; // 32 clks
always @(posedge clk, posedge int_start_frm) begin
if (int_start_frm) intctr <= 0;
else if (zpos && !intctr_fin && !vdos) intctr <= intctr + 1'b1;
end
endmodule

56
rtl/common/zmaps.v Normal file
View File

@ -0,0 +1,56 @@
// This module maps z80 memory accesses into FPGA RAM and ports
module zmaps
(
// Z80 controls
input wire clk,
input wire memwr_s,
input wire [15:0] a,
input wire [7:0] d,
// config data
input wire [4:0] fmaddr,
// FPRAM data
output wire [15:0] zmd,
output wire [7:0] zma,
// DMA
input wire [15:0] dma_data,
input wire [7:0] dma_wraddr,
input wire dma_cram_we,
input wire dma_sfile_we,
// write strobes
output wire cram_we,
output wire sfile_we,
output wire regs_we
);
// addresses of files withing zmaps
localparam CRAM = 3'b000;
localparam SFYS = 3'b001;
localparam REGS = 4'b0100;
// control signals
wire hit = (a[15:12] == fmaddr[3:0]) && fmaddr[4] && memwr_s;
// write enables
assign cram_we = dma_req ? dma_cram_we : (a[11:9] == CRAM) && a[0] && hit;
assign sfile_we = dma_req ? dma_sfile_we : (a[11:9] == SFYS) && a[0] && hit;
assign regs_we = (a[11:8] == REGS) && hit;
// LSB fetching
assign zma = dma_req ? dma_wraddr : a[8:1];
assign zmd = dma_req ? dma_data : {d, zmd0};
reg [7:0] zmd0;
always @(posedge clk) if (!a[0] && hit) zmd0 <= d;
// DMA
wire dma_req = dma_cram_we || dma_sfile_we;
endmodule

228
rtl/common/zmem.v Normal file
View File

@ -0,0 +1,228 @@
// PentEvo project (c) NedoPC 2008-2009
//
// Z80 memory manager: routes ROM/RAM accesses, makes wait-states for 14MHz or stall condition, etc.
//
//
// clk _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
// zclk /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
// zpos `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
// | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
// zneg _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________
module zmem
(
input clk,
input c0, c1, c2, c3,
input zneg, // strobes which show positive and negative edges of zclk
input zpos,
// Z80
input rst,
input [15:0] za,
output [ 7:0] zd_out, // output to Z80 bus
output zd_ena, // output to Z80 bus enable
input opfetch,
input opfetch_s,
input mreq,
input memrd,
input memwr,
input memwr_s,
input [ 1:0] turbo, // 2'b00 - 3.5,
// 2'b01 - 7.0,
// 2'b1x - 14.0
input [3:0] cache_en,
input [3:0] memconf,
input [31:0] xt_page,
output [4:0] rompg,
output csrom,
output romoe_n,
output romwe_n,
output dos,
output dos_on,
output dos_off,
output vdos,
output reg pre_vdos,
input vdos_on,
input vdos_off,
// DRAM
output cpu_req,
output [20:0] cpu_addr,
output cpu_wrbsel,
input [15:0] cpu_rddata,
input cpu_next,
input cpu_strobe,
input cpu_latch,
output cpu_stall // for zclock
);
// controls
wire rom128 = memconf[0];
wire w0_we = memconf[1];
wire w0_map_n = memconf[2];
wire w0_ram = memconf[3];
// pager
wire [1:0] win = za[15:14];
wire win0 = ~|win;
wire ramwr_en = !win0 || w0_we || vdos;
wire rom_n_ram = win0 && !w0_ram && !vdos;
wire [7:0] page = xtpage[win];
wire [7:0] xtpage[0:3];
assign xtpage[0] = vdos ? 8'hFF : {xt_page[7:2], w0_map_n ? xt_page[1:0] : {~dos, rom128}};
assign xtpage[1] = xt_page[15:8];
assign xtpage[2] = xt_page[23:16];
assign xtpage[3] = xt_page[31:24];
// ROM chip
assign csrom = rom_n_ram;
assign romoe_n = !memrd;
assign romwe_n = !(memwr && w0_we);
assign rompg = xtpage[0][4:0];
// RAM
assign zd_ena = !rom_n_ram && memrd;
wire ramreq = !rom_n_ram && ((memrd && !cache_hit_en) || (memwr && ramwr_en));
// DOS signal control
assign dos_on = win0 && opfetch_s && (za[13:8]==6'h3D) && rom128 && !w0_map_n;
assign dos_off = !win0 && opfetch_s && !vdos;
assign dos = (dos_on || dos_off) ^^ dos_r; // to make dos appear 1 clock earlier than dos_r
reg dos_r;
always @(posedge clk) begin
if (rst) dos_r <= 0;
else if (dos_off) dos_r <= 0;
else if (dos_on) dos_r <= 1;
end
// VDOS signal control
// vdos turn on/off is delayed till next opfetch due to INIR that writes right after iord cycle
assign vdos = opfetch ? pre_vdos : vdos_r; // vdos appears as soon as first opfetch
reg vdos_r;
always @(posedge clk) begin
if (rst || vdos_off) begin
pre_vdos <= 0;
vdos_r <= 0;
end
else if (vdos_on) pre_vdos <= 1;
else if (opfetch_s) vdos_r <= pre_vdos;
end
// address, data in and data out
assign cpu_wrbsel = za[0];
assign cpu_addr[20:0] = {page, za[13:1]};
wire [15:0] mem_d = cpu_latch ? cpu_rddata : cache_d;
assign zd_out = ~cpu_wrbsel ? mem_d[7:0] : mem_d[15:8];
// Z80 controls
assign cpu_req = turbo14 ? cpureq_14 : cpureq_357;
assign cpu_stall = turbo14 ? stall14 : stall357;
wire turbo14 = turbo[1];
// 7/3.5MHz support
wire cpureq_357 = ramreq && !ramreq_r;
wire stall357 = cpureq_357 && !cpu_next;
reg ramreq_r;
always @(posedge clk) if (c3 && !cpu_stall) ramreq_r <= ramreq;
// 14MHz support
// wait tables:
//
// M1 opcode fetch, dram_beg concurs with:
// c3: +3
// c2: +4
// c1: +5
// c0: +6
//
// memory read, dram_beg concurs with:
// c3: +2
// c2: +3
// c1: +4
// c0: +5
//
// memory write: no wait
//
// special case: if dram_beg pulses 1 when cpu_next is 0,
// unconditional wait has to be performed until cpu_next is 1, and
// then wait as if dram_beg would concur with c0
// memrd, opfetch - wait till c3 && cpu_next,
// memwr - wait till cpu_next
wire cpureq_14 = dram_beg || pending_cpu_req;
wire stall14 = stall14_ini || stall14_cyc || stall14_fin;
wire dram_beg = ramreq && !pre_ramreq_r && zneg;
reg pre_ramreq_r;
always @(posedge clk) if (zneg) pre_ramreq_r <= ramreq;
reg pending_cpu_req;
always @(posedge clk) begin
if (rst) pending_cpu_req <= 0;
else if (cpu_next && c3) pending_cpu_req <= 0;
else if (dram_beg) pending_cpu_req <= 1;
end
wire stall14_ini = dram_beg && (!cpu_next || opfetch || memrd); // no wait at all in write cycles, if next dram cycle is available
wire stall14_cyc = memrd ? stall14_cycrd : !cpu_next;
reg stall14_cycrd;
always @(posedge clk) begin
if (rst) stall14_cycrd <= 0;
else if (cpu_next && c3) stall14_cycrd <= 0;
else if (dram_beg && (!c3 || !cpu_next) && (opfetch || memrd)) stall14_cycrd <= 1;
end
reg stall14_fin;
always @(posedge clk) begin
if (rst) stall14_fin <= 0;
else if (stall14_fin && ((opfetch && c1) || (memrd && c2))) stall14_fin <= 0;
else if (cpu_next && c3 && cpu_req && (opfetch || memrd)) stall14_fin <= 1;
end
// cache
// wire cache_hit = (ch_addr[7:2] != 6'b011100) && (cpu_hi_addr == cache_a) && cache_v; // debug for BM
wire cache_hit = (cpu_hi_addr == cache_a) && cache_v; // asynchronous signal meaning that address requested by CPU is cached and valid
wire cache_hit_en = cache_hit && cache_en[win];
wire cache_inv = cache_hit && !rom_n_ram && memwr_s && ramwr_en; // cache invalidation should be only performed if write happens to cached address
wire [12:0] cpu_hi_addr = {page[7:0], za[13:9]};
wire [12:0] cache_a;
wire [7:0] ch_addr = cpu_addr[7:0];
wire [15:0] cache_d;
wire cache_v;
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) cache_data
(
.clock(clk),
.address_a(ch_addr),
.data_a(cpu_rddata),
.wren_a(cpu_strobe),
.address_b(ch_addr),
.q_b(cache_d)
);
dpram #(.DATAWIDTH(14), .ADDRWIDTH(8)) cache_addr
(
.clock(clk),
.address_a(ch_addr),
.data_a({!cache_inv, cpu_hi_addr}),
.wren_a(cpu_strobe || cache_inv),
.address_b(ch_addr),
.q_b({cache_v, cache_a})
);
endmodule

469
rtl/common/zports.v Normal file
View File

@ -0,0 +1,469 @@
// PentEvo project (c) NedoPC 2008-2010
module zports
(
input clk,
input [7:0] din,
output reg [7:0] dout,
output dataout,
input [15:0] a,
input rst, // system reset
input opfetch,
input rd,
input wr,
input rdwr,
input iorq,
input iorq_s,
input iord,
input iord_s,
input iowr,
input iowr_s,
input iordwr,
input iordwr_s,
output porthit, // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
output external_port, // asserts for AY and VG93 accesses
output zborder_wr,
output border_wr,
output zvpage_wr,
output vpage_wr,
output vconf_wr,
output gx_offsl_wr,
output gx_offsh_wr,
output gy_offsl_wr,
output gy_offsh_wr,
output t0x_offsl_wr,
output t0x_offsh_wr,
output t0y_offsl_wr,
output t0y_offsh_wr,
output t1x_offsl_wr,
output t1x_offsh_wr,
output t1y_offsl_wr,
output t1y_offsh_wr,
output tsconf_wr,
output palsel_wr,
output tmpage_wr,
output t0gpage_wr,
output t1gpage_wr,
output sgpage_wr,
output hint_beg_wr ,
output vint_begl_wr,
output vint_begh_wr,
output [31:0] xt_page,
output reg [4:0] fmaddr,
input regs_we,
output reg [7:0] sysconf,
output reg [7:0] memconf,
output reg [3:0] cacheconf,
output reg [7:0] fddvirt,
output [8:0] dmaport_wr,
input dma_act,
output reg [1:0] dmawpdev,
output reg [7:0] intmask,
input dos,
input vdos,
output vdos_on,
output vdos_off,
output ay_bdir,
output ay_bc1,
output covox_wr,
output beeper_wr,
input tape_read,
input [4:0] keys_in, // keys (port FE)
input [7:0] mus_in, // mouse (xxDF)
input [5:0] kj_in,
input vg_intrq,
input vg_drq, // from vg93 module - drq + irq read
output vg_cs_n,
output vg_wrFF,
output [1:0] drive_sel, // disk drive selection
// SPI
output sdcs_n,
output sd_start,
output [7:0] sd_datain,
input [7:0] sd_dataout,
// WAIT-ports related
output reg [7:0] wait_addr,
output wait_start_gluclock, // begin wait from some ports
output wait_start_comport, //
output reg [7:0] wait_write,
input [7:0] wait_read
);
assign sdcs_n = spi_cs_n[0];
localparam FDR_VER = 1'b0;
localparam VDAC_VER = 3'h3;
localparam PORTFE = 8'hFE;
localparam PORTFD = 8'hFD;
localparam PORTXT = 8'hAF;
localparam PORTF7 = 8'hF7;
localparam COVOX = 8'hFB;
localparam VGCOM = 8'h1F;
localparam VGTRK = 8'h3F;
localparam VGSEC = 8'h5F;
localparam VGDAT = 8'h7F;
localparam VGSYS = 8'hFF;
localparam KJOY = 8'h1F;
localparam KMOUSE = 8'hDF;
localparam SDCFG = 8'h77;
localparam SDDAT = 8'h57;
localparam COMPORT = 8'hEF; // F8EF..FFEF - rs232 ports
wire [7:0] loa = a[7:0];
wire [7:0] hoa = regs_we ? a[7:0] : a[15:8];
assign porthit = ((loa==PORTFE) || (loa==PORTXT) || (loa==PORTFD) || (loa==COVOX))
|| ((loa==PORTF7) && !dos)
|| ((vg_port || vgsys_port) && (dos || open_vg))
|| ((loa==KJOY) && !dos && !open_vg)
|| (loa==KMOUSE)
|| (((loa==SDCFG) || (loa==SDDAT)) && (!dos || vdos))
|| (loa==COMPORT);
wire vg_port = (loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT);
wire vgsys_port = (loa==VGSYS);
assign external_port = ((loa==PORTFD) && a[15]) // AY
|| (((loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT)) && (dos || open_vg));
assign dataout = porthit && iord && (~external_port);
reg iowr_reg;
reg iord_reg;
reg port_wr;
reg port_rd;
always @(posedge clk) begin
iowr_reg <= iowr;
port_wr <= (!iowr_reg && iowr);
iord_reg <= iord;
port_rd <= (!iord_reg && iord);
end
// reading ports
always @(*) begin
case (loa)
PORTFE:
dout = {1'b1, tape_read, 1'b0, keys_in};
PORTXT:
begin
case (hoa)
XSTAT:
dout = {1'b0, pwr_up_reg, FDR_VER, 2'b0, VDAC_VER};
DMASTAT:
dout = {dma_act, 7'b0};
RAMPAGE + 8'd2, RAMPAGE + 8'd3:
dout = rampage[hoa[1:0]];
default:
dout = 8'hFF;
endcase
end
VGSYS:
dout = {vg_intrq, vg_drq, 6'b111111};
KJOY:
dout = {2'b00, kj_in};
KMOUSE:
dout = mus_in;
SDCFG:
dout = 8'h00; // always SD inserted, SD is in R/W mode
SDDAT:
dout = sd_dataout;
PORTF7:
begin
if (!a[14] && (a[8] ^ dos) && gluclock_on) dout = wait_read; // $BFF7 - data i/o
else dout = 8'hFF; // any other $xxF7 port
end
COMPORT:
dout = wait_read; // $F8EF..$FFEF
default:
dout = 8'hFF;
endcase
end
// power-up
// This bit is loaded as 1 while FPGA is configured
// and automatically reset to 0 after STATUS port reading
reg pwr_up_reg;
reg pwr_up = 1;
always @(posedge clk) begin
if (iord_s & (loa == PORTXT) & (hoa == XSTAT)) begin
pwr_up_reg <= pwr_up;
pwr_up <= 1'b0;
end
end
// writing ports
//#nnAF
localparam VCONF = 8'h00;
localparam VPAGE = 8'h01;
localparam GXOFFSL = 8'h02;
localparam GXOFFSH = 8'h03;
localparam GYOFFSL = 8'h04;
localparam GYOFFSH = 8'h05;
localparam TSCONF = 8'h06;
localparam PALSEL = 8'h07;
localparam XBORDER = 8'h0F;
localparam T0XOFFSL = 8'h40;
localparam T0XOFFSH = 8'h41;
localparam T0YOFFSL = 8'h42;
localparam T0YOFFSH = 8'h43;
localparam T1XOFFSL = 8'h44;
localparam T1XOFFSH = 8'h45;
localparam T1YOFFSL = 8'h46;
localparam T1YOFFSH = 8'h47;
localparam RAMPAGE = 8'h10; // this covers #10-#13
localparam FMADDR = 8'h15;
localparam TMPAGE = 8'h16;
localparam T0GPAGE = 8'h17;
localparam T1GPAGE = 8'h18;
localparam SGPAGE = 8'h19;
localparam DMASADDRL = 8'h1A;
localparam DMASADDRH = 8'h1B;
localparam DMASADDRX = 8'h1C;
localparam DMADADDRL = 8'h1D;
localparam DMADADDRH = 8'h1E;
localparam DMADADDRX = 8'h1F;
localparam SYSCONF = 8'h20;
localparam MEMCONF = 8'h21;
localparam HSINT = 8'h22;
localparam VSINTL = 8'h23;
localparam VSINTH = 8'h24;
localparam DMAWPD = 8'h25;
localparam DMALEN = 8'h26;
localparam DMACTRL = 8'h27;
localparam DMANUM = 8'h28;
localparam FDDVIRT = 8'h29;
localparam INTMASK = 8'h2A;
localparam CACHECONF = 8'h2B;
localparam DMAWPA = 8'h2D;
localparam XSTAT = 8'h00;
localparam DMASTAT = 8'h27;
assign dmaport_wr[0] = portxt_wr && (hoa == DMASADDRL);
assign dmaport_wr[1] = portxt_wr && (hoa == DMASADDRH);
assign dmaport_wr[2] = portxt_wr && (hoa == DMASADDRX);
assign dmaport_wr[3] = portxt_wr && (hoa == DMADADDRL);
assign dmaport_wr[4] = portxt_wr && (hoa == DMADADDRH);
assign dmaport_wr[5] = portxt_wr && (hoa == DMADADDRX);
assign dmaport_wr[6] = portxt_wr && (hoa == DMALEN);
assign dmaport_wr[7] = portxt_wr && (hoa == DMACTRL);
assign dmaport_wr[8] = portxt_wr && (hoa == DMANUM);
assign zborder_wr = portfe_wr;
assign border_wr = (portxt_wr && (hoa == XBORDER));
assign zvpage_wr = p7ffd_wr;
assign vpage_wr = (portxt_wr && (hoa == VPAGE ));
assign vconf_wr = (portxt_wr && (hoa == VCONF ));
assign gx_offsl_wr = (portxt_wr && (hoa == GXOFFSL));
assign gx_offsh_wr = (portxt_wr && (hoa == GXOFFSH));
assign gy_offsl_wr = (portxt_wr && (hoa == GYOFFSL));
assign gy_offsh_wr = (portxt_wr && (hoa == GYOFFSH));
assign t0x_offsl_wr = (portxt_wr && (hoa == T0XOFFSL));
assign t0x_offsh_wr = (portxt_wr && (hoa == T0XOFFSH));
assign t0y_offsl_wr = (portxt_wr && (hoa == T0YOFFSL));
assign t0y_offsh_wr = (portxt_wr && (hoa == T0YOFFSH));
assign t1x_offsl_wr = (portxt_wr && (hoa == T1XOFFSL));
assign t1x_offsh_wr = (portxt_wr && (hoa == T1XOFFSH));
assign t1y_offsl_wr = (portxt_wr && (hoa == T1YOFFSL));
assign t1y_offsh_wr = (portxt_wr && (hoa == T1YOFFSH));
assign tsconf_wr = (portxt_wr && (hoa == TSCONF));
assign palsel_wr = (portxt_wr && (hoa == PALSEL));
assign tmpage_wr = (portxt_wr && (hoa == TMPAGE));
assign t0gpage_wr = (portxt_wr && (hoa == T0GPAGE));
assign t1gpage_wr = (portxt_wr && (hoa == T1GPAGE));
assign sgpage_wr = (portxt_wr && (hoa == SGPAGE));
assign hint_beg_wr = (portxt_wr && (hoa == HSINT ));
assign vint_begl_wr = (portxt_wr && (hoa == VSINTL));
assign vint_begh_wr = (portxt_wr && (hoa == VSINTH));
assign beeper_wr = portfe_wr;
wire portfe_wr = (loa==PORTFE) && iowr_s;
assign covox_wr = (loa==COVOX) && iowr_s;
wire portxt_wr = ((loa==PORTXT) && iowr_s) || regs_we;
reg [7:0] rampage[0:3];
assign xt_page = {rampage[3], rampage[2], rampage[1], rampage[0]};
wire lock128 = lock128_3 ? 1'b0 : (lock128_2 ? m1_lock128 : memconf[6]);
wire lock128_2 = memconf[7:6] == 2'b10; // mode 2
wire lock128_3 = memconf[7:6] == 2'b11; // mode 3
reg m1_lock128;
always @(posedge clk) if (opfetch) m1_lock128 <= !(din[7] ^ din[6]);
always @(posedge clk) begin
if (rst) begin
fmaddr[4] <= 1'b0;
intmask <= 8'b1;
fddvirt <= 8'b0;
sysconf <= 8'h00; // 3.5 MHz
memconf <= 8'h04; // no map
cacheconf <= 4'h0; // no cache
rampage[0]<= 8'h00;
rampage[1]<= 8'h05;
rampage[2]<= 8'h02;
rampage[3]<= 8'h00;
end
else if (p7ffd_wr) begin
memconf[0] <= din[4];
rampage[3] <= {2'b0, lock128_3 ? {din[5], din[7:6]} : ({1'b0, lock128 ? 2'b0 : din[7:6]}), din[2:0]};
end
else if (portxt_wr) begin
if (hoa[7:2] == RAMPAGE[7:2]) rampage[hoa[1:0]] <= din;
if (hoa == FMADDR) fmaddr <= din[4:0];
if (hoa == SYSCONF) begin
sysconf <= din;
cacheconf <= {4{din[2]}};
end
if (hoa == DMAWPD) dmawpdev <= din[1:0];
if (hoa == CACHECONF) cacheconf <= din[3:0];
if (hoa == MEMCONF) memconf <= din;
if (hoa == FDDVIRT) fddvirt <= din;
if (hoa == INTMASK) intmask <= din;
end
end
// 7FFD port
wire p7ffd_wr = !a[15] && (loa==PORTFD) && iowr_s && !lock48;
reg lock48;
always @(posedge clk) begin
if (rst) lock48 <= 1'b0;
else if (p7ffd_wr && !lock128_3) lock48 <= din[5];
end
// AY control
wire ay_hit = (loa==PORTFD) & a[15];
assign ay_bc1 = ay_hit & a[14] & iordwr;
assign ay_bdir = ay_hit & iowr;
// VG93
wire [3:0] fddvrt = fddvirt[3:0];
wire virt_vg = fddvrt[drive_sel_raw];
wire open_vg = fddvirt[7];
assign drive_sel = {drive_sel_raw[1], drive_sel_raw[0]};
wire vg_wen = (dos || open_vg) && !vdos && !virt_vg;
assign vg_cs_n = !(iordwr && vg_port && vg_wen);
assign vg_wrFF = iowr_s && vgsys_port && vg_wen;
wire vg_wrDS = iowr_s && vgsys_port && (dos || open_vg);
assign vdos_on = iordwr_s && (vg_port || vgsys_port) && dos && !vdos && virt_vg;
assign vdos_off = iordwr_s && vg_port && vdos;
// write drive number
reg [1:0] drive_sel_raw;
always @(posedge clk) if (vg_wrDS) drive_sel_raw <= din[1:0];
// SD card (Z-controller compatible)
wire sdcfg_wr;
wire sddat_wr;
wire sddat_rd;
reg [1:0] spi_cs_n;
assign sdcfg_wr = ((loa==SDCFG) && iowr_s && (!dos || vdos));
assign sddat_wr = ((loa==SDDAT) && iowr_s && (!dos || vdos));
assign sddat_rd = ((loa==SDDAT) && iord_s);
// SDCFG write - sdcs_n control
always @(posedge clk) begin
if (rst) spi_cs_n <= 2'b11;
else if (sdcfg_wr) spi_cs_n <= {~din[2], din[1]};
end
// start signal for SPI module with resyncing to fclk
assign sd_start = sddat_wr || sddat_rd;
// data for SPI module
assign sd_datain = wr ? din : 8'hFF;
// xxF7
wire portf7_wr = ((loa==PORTF7) && (a[8]==1'b1) && port_wr && (!dos || vdos));
wire portf7_rd = ((loa==PORTF7) && (a[8]==1'b1) && port_rd && (!dos || vdos));
// EFF7 port
reg [7:0] peff7;
always @(posedge clk) begin
if (rst) peff7 <= 8'h00;
else if (!a[12] && portf7_wr && !dos) peff7 <= din; // #EEF7 in dos is not accessible
end
// gluclock ports
wire gluclock_on = peff7[7] || dos; // in dos mode EEF7 is not accessible, gluclock access is ON in dos mode.
// comports
wire comport_wr = ((loa == COMPORT) && port_wr);
wire comport_rd = ((loa == COMPORT) && port_rd);
// write to wait registers
always @(posedge clk) begin
// gluclocks
if (gluclock_on && portf7_wr) begin
if (!a[14]) wait_write <= din; // $BFF7 - data reg
if (!a[13]) wait_addr <= din; // $DFF7 - addr reg
end
// com ports
if (comport_wr) wait_write <= din; // $xxEF
if (comport_wr || comport_rd) wait_addr <= a[15:8];
if ((loa==PORTXT) && (hoa == DMAWPA)) wait_addr <= din;
end
// wait from wait registers
// ACHTUNG!!!! here portxx_wr are ON Z80 CLOCK! logic must change when moving to clk strobes
assign wait_start_gluclock = (gluclock_on && !a[14] && (portf7_rd || portf7_wr)); // $BFF7 - gluclock r/w
assign wait_start_comport = (comport_rd || comport_wr);
endmodule

85
rtl/common/zsignals.v Normal file
View File

@ -0,0 +1,85 @@
// Decoding and strobing of z80 signals
module zsignals
(
// clocks
input wire clk,
// z80 interface input
input wire iorq_n,
input wire mreq_n,
input wire m1_n,
input wire rfsh_n,
input wire rd_n,
input wire wr_n,
// Z80 signals
output wire m1,
output wire rfsh,
output wire rd,
output wire wr,
output wire iorq,
output wire mreq,
output wire rdwr,
output wire iord,
output wire iowr,
output wire iorw,
output wire memrd,
output wire memwr,
output wire memrw,
output wire opfetch,
output wire intack,
// Z80 signals strobes, at fclk
output wire iorq_s,
output wire mreq_s,
output wire iord_s,
output wire iowr_s,
output wire iorw_s,
output wire memrd_s,
output wire memwr_s,
output wire memrw_s,
output wire opfetch_s
);
// invertors
assign m1 = !m1_n;
assign rfsh = !rfsh_n;
assign rd = !rd_n;
assign wr = !wr_n;
// requests
assign iorq = !iorq_n && m1_n; // this is masked by ~M1 to avoid port decoding on INT ack
assign mreq = !mreq_n && rfsh_n; // this is masked by ~RFSH to ignore refresh cycles as memory requests
// combined
assign rdwr = rd || wr;
assign iord = iorq && rd;
assign iowr = iorq && wr;
assign iorw = iorq && rdwr;
assign memrd = mreq && rd;
assign memwr = mreq && !rd;
assign memrw = mreq && rdwr;
assign opfetch = memrd && m1;
assign intack = !iorq_n && m1; // NOT masked by M1
// strobed
assign iorq_s = iorq_r[0] && !iorq_r[1];
assign mreq_s = mreq_r[0] && !mreq_r[1];
assign iord_s = iorq_s && rd;
assign iowr_s = iorq_s && wr;
assign iorw_s = iorq_s && rdwr;
assign memrd_s = mreq_s && rd;
assign memwr_s = mreq_s && !rd;
assign memrw_s = mreq_s && rdwr;
assign opfetch_s = memrd_s && m1;
// latch inputs on FPGA clock
reg [1:0] iorq_r, mreq_r;
always @(posedge clk) begin
iorq_r <= {iorq_r[0], iorq};
mreq_r <= {mreq_r[0], mreq};
end
endmodule

66
rtl/kempston_mouse.v Normal file
View File

@ -0,0 +1,66 @@
////////////////////////////////////////////////////////////////////////////////
//
// PS2-to-Kempston Mouse v2
// (C) 2017,2018 Sorgelig
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
////////////////////////////////////////////////////////////////////////////////
module kempston_mouse
(
input clk_sys,
input reset,
input [24:0] ps2_mouse,
input [2:0] addr,
output sel,
output [7:0] dout
);
assign dout = data;
assign sel = port_sel;
reg [11:0] dx;
reg [11:0] dy;
reg [7:0] data;
reg port_sel;
always @* begin
port_sel = 1;
casex(addr)
3'b011: data = dx[7:0];
3'b111: data = dy[7:0];
3'bX10: data = ~{5'b00000,ps2_mouse[2], ps2_mouse[0], ps2_mouse[1]} ;
default: {port_sel,data} = 8'hFF;
endcase
end
always @(posedge clk_sys) begin
reg old_status;
old_status <= ps2_mouse[24];
if(reset) begin
dx <= 128; // dx != dy for better mouse detection
dy <= 0;
end
else if(old_status != ps2_mouse[24]) begin
dx <= dx + {{4{ps2_mouse[4]}},ps2_mouse[15:8]};
dy <= dy + {{4{ps2_mouse[5]}},ps2_mouse[23:16]};
end
end
endmodule

170
rtl/keyboard.vhd Normal file
View File

@ -0,0 +1,170 @@
-------------------------------------------------------------------[28.07.2014]
-- KEYBOARD CONTROLLER USB HID scancode to Spectrum matrix conversion
-------------------------------------------------------------------------------
-- V0.1 05.10.2011 первая версия
-- V0.2 16.03.2014 измененмия в key_f (активная клавиша теперь устанавливается в '1')
-- V1.0 24.07.2014 доработан под USB HID Keyboard
-- V1.1 28.07.2014 добавлены спец клавиши
-- WXEDA 10.03.2015 добавлен контроллер ps/2
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity keyboard is
port (
CLK : in std_logic;
RESET : in std_logic;
A : in std_logic_vector(7 downto 0);
KEYB : out std_logic_vector(4 downto 0);
KEY_RESET: out std_logic;
SCANCODE : out std_logic_vector(7 downto 0);
PS2_KEY : in std_logic_vector(10 downto 0)
);
end keyboard;
architecture rtl of keyboard is
-- Internal signals
type key_matrix is array (7 downto 0) of std_logic_vector(4 downto 0);
signal keys : key_matrix;
signal row0, row1, row2, row3, row4, row5, row6, row7 : std_logic_vector(4 downto 0);
signal flg : std_logic;
begin
-- Output addressed row to ULA
row0 <= keys(0) when A(0) = '0' else (others => '1');
row1 <= keys(1) when A(1) = '0' else (others => '1');
row2 <= keys(2) when A(2) = '0' else (others => '1');
row3 <= keys(3) when A(3) = '0' else (others => '1');
row4 <= keys(4) when A(4) = '0' else (others => '1');
row5 <= keys(5) when A(5) = '0' else (others => '1');
row6 <= keys(6) when A(6) = '0' else (others => '1');
row7 <= keys(7) when A(7) = '0' else (others => '1');
KEYB <= row0 and row1 and row2 and row3 and row4 and row5 and row6 and row7;
process (CLK) begin
if rising_edge(CLK) then
flg <= ps2_key(10);
if RESET = '1' then
keys(0) <= (others => '1');
keys(1) <= (others => '1');
keys(2) <= (others => '1');
keys(3) <= (others => '1');
keys(4) <= (others => '1');
keys(5) <= (others => '1');
keys(6) <= (others => '1');
keys(7) <= (others => '1');
KEY_RESET <= '0';
SCANCODE <= (others => '0');
else
if flg /= ps2_key(10) then
if (ps2_key(9) = '1') then
SCANCODE <= ps2_key(7 downto 0);
else
SCANCODE <= (others => '1');
end if;
case ps2_key(7 downto 0) is
when X"12" => keys(0)(0) <= not ps2_key(9); -- Left shift (CAPS SHIFT)
when X"59" => keys(0)(0) <= not ps2_key(9); -- Right shift (CAPS SHIFT)
when X"1a" => keys(0)(1) <= not ps2_key(9); -- Z
when X"22" => keys(0)(2) <= not ps2_key(9); -- X
when X"21" => keys(0)(3) <= not ps2_key(9); -- C
when X"2a" => keys(0)(4) <= not ps2_key(9); -- V
when X"1c" => keys(1)(0) <= not ps2_key(9); -- A
when X"1b" => keys(1)(1) <= not ps2_key(9); -- S
when X"23" => keys(1)(2) <= not ps2_key(9); -- D
when X"2b" => keys(1)(3) <= not ps2_key(9); -- F
when X"34" => keys(1)(4) <= not ps2_key(9); -- G
when X"15" => keys(2)(0) <= not ps2_key(9); -- Q
when X"1d" => keys(2)(1) <= not ps2_key(9); -- W
when X"24" => keys(2)(2) <= not ps2_key(9); -- E
when X"2d" => keys(2)(3) <= not ps2_key(9); -- R
when X"2c" => keys(2)(4) <= not ps2_key(9); -- T
when X"16" => keys(3)(0) <= not ps2_key(9); -- 1
when X"1e" => keys(3)(1) <= not ps2_key(9); -- 2
when X"26" => keys(3)(2) <= not ps2_key(9); -- 3
when X"25" => keys(3)(3) <= not ps2_key(9); -- 4
when X"2e" => keys(3)(4) <= not ps2_key(9); -- 5
when X"45" => keys(4)(0) <= not ps2_key(9); -- 0
when X"46" => keys(4)(1) <= not ps2_key(9); -- 9
when X"3e" => keys(4)(2) <= not ps2_key(9); -- 8
when X"3d" => keys(4)(3) <= not ps2_key(9); -- 7
when X"36" => keys(4)(4) <= not ps2_key(9); -- 6
when X"4d" => keys(5)(0) <= not ps2_key(9); -- P
when X"44" => keys(5)(1) <= not ps2_key(9); -- O
when X"43" => keys(5)(2) <= not ps2_key(9); -- I
when X"3c" => keys(5)(3) <= not ps2_key(9); -- U
when X"35" => keys(5)(4) <= not ps2_key(9); -- Y
when X"5a" => keys(6)(0) <= not ps2_key(9); -- ENTER
when X"4b" => keys(6)(1) <= not ps2_key(9); -- L
when X"42" => keys(6)(2) <= not ps2_key(9); -- K
when X"3b" => keys(6)(3) <= not ps2_key(9); -- J
when X"33" => keys(6)(4) <= not ps2_key(9); -- H
when X"29" => keys(7)(0) <= not ps2_key(9); -- SPACE
when X"14" => keys(7)(1) <= not ps2_key(9); -- CTRL (Symbol Shift)
when X"3a" => keys(7)(2) <= not ps2_key(9); -- M
when X"31" => keys(7)(3) <= not ps2_key(9); -- N
when X"32" => keys(7)(4) <= not ps2_key(9); -- B
-- Cursor keys
when X"6b" => keys(0)(0) <= not ps2_key(9); -- Left (CAPS 5)
keys(3)(4) <= not ps2_key(9);
when X"72" => keys(0)(0) <= not ps2_key(9); -- Down (CAPS 6)
keys(4)(4) <= not ps2_key(9);
when X"75" => keys(0)(0) <= not ps2_key(9); -- Up (CAPS 7)
keys(4)(3) <= not ps2_key(9);
when X"74" => keys(0)(0) <= not ps2_key(9); -- Right (CAPS 8)
keys(4)(2) <= not ps2_key(9);
-- Other special keys sent to the ULA as key combinations
when X"66" => keys(0)(0) <= not ps2_key(9); -- Backspace (CAPS 0)
keys(4)(0) <= not ps2_key(9);
when X"58" => keys(0)(0) <= not ps2_key(9); -- Caps lock (CAPS 2)
keys(3)(1) <= not ps2_key(9);
when X"0d" => keys(0)(0) <= not ps2_key(9); -- Tab (CAPS SPACE)
keys(7)(0) <= not ps2_key(9);
when X"49" => keys(7)(2) <= not ps2_key(9); -- .
keys(7)(1) <= not ps2_key(9);
when X"4e" => keys(6)(3) <= not ps2_key(9); -- -
keys(7)(1) <= not ps2_key(9);
when X"0e" => keys(3)(0) <= not ps2_key(9); -- ` (EDIT)
keys(0)(0) <= not ps2_key(9);
when X"41" => keys(7)(3) <= not ps2_key(9); -- ,
keys(7)(1) <= not ps2_key(9);
when X"4c" => keys(5)(1) <= not ps2_key(9); -- ;
keys(7)(1) <= not ps2_key(9);
when X"52" => keys(5)(0) <= not ps2_key(9); -- "
keys(7)(1) <= not ps2_key(9);
when X"5d" => keys(0)(1) <= not ps2_key(9); -- :
keys(7)(1) <= not ps2_key(9);
when X"55" => keys(6)(1) <= not ps2_key(9); -- =
keys(7)(1) <= not ps2_key(9);
when X"54" => keys(4)(2) <= not ps2_key(9); -- (
keys(7)(1) <= not ps2_key(9);
when X"5b" => keys(4)(1) <= not ps2_key(9); -- )
keys(7)(1) <= not ps2_key(9);
when X"4a" => keys(0)(3) <= not ps2_key(9); -- ?
keys(7)(1) <= not ps2_key(9);
--------------------------------------------
when X"78" => KEY_RESET <= ps2_key(9); -- F11
when others => null;
end case;
end if;
end if;
end if;
end process;
end architecture;

233
rtl/memory/arbiter.v Normal file
View File

@ -0,0 +1,233 @@
// PentEvo project (c) NedoPC 2008-2011
//
// DRAM arbiter. Shares DRAM between CPU, video data fetcher and other devices
//
// Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks.
// During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or 8 accesses.
// All spare cycles can be used by CPU or other devices. If no device uses memory in the given cycle, refresh cycle is performed.
//
// In each access block, videodata accesses are spreaded all over the block so that CPU receives cycle
// as fast as possible, until there is absolute need to fetch remaining video data.
//
// Examples:
//
// | access block | 4 video accesses during block, no processor accesses. video accesses are done
// | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones
//
// | access block | 4 video accesses during block, processor requests access every other cycle
// | vid | prc | vid | prc | vid | prc | vid | prc |
//
// | access block | 4 video accesses, processor begins requesting cycles continously from second one
// | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor
// can't access mem until the end of access block and stalls
//
// | access block | 8 video accesses, processor stalls, if it is requesting cycles
// | vid | vid | vid | vid | vid | vid | vid | vid |
//
// | access block | 2 video accesses, single processor request, other cycles are refresh ones
// | vid | vid | ref | ref | cpu | ref | ref | ref |
//
// | access block | 4 video accesses, single processor request, other cycles are refresh ones
// | vid | vid | cpu | vid | vid | ref | ref | ref |
//
// access block begins at any dram cycle, then blocks go back-to-back
//
// key signals are go and XXX_req, sampled at the end of each dram cycle. Must be set to the module at c3 clock cycle.
// CPU can have either normal or lower access priority to the DRAM.
// At the INT active (32 of 3.5MHz clocks) the priority is raised to normal, so that CPU won't miss its interrupt.
// This should be considered if dummy RAM access used for waiting for the end of DMA operation instead of status bit polling.
//
// DRAM access priority:
// Z80 normal Z80 low
// - VIDEO - VIDEO
// - CPU - TS
// - TM - TM
// - TS - DMA
// - DMA - CPU
module arbiter
(
input clk,
input c0,
input c1,
input c2,
input c3,
// dram.v interface
output [20:0] dram_addr, // address for dram access
output dram_req, // dram request
output dram_rnw, // Read-NotWrite
output [ 1:0] dram_bsel, // byte select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0]
output [15:0] dram_wrdata, // data to be written
// video
input [20:0] video_addr, // during access block, only when video_strobe==1
input go, // start video access blocks
input [ 4:0] video_bw, // [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
// [2:0] - need cycles
output video_pre_next, // (c1)
output video_next, // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe
output video_strobe, // (c3) one-cycle strobe meaning that video_data is available
output video_next_strobe, // (c3) one-cycle strobe meaning that video_data is available
output next_vid, // used for TM prefetch
// CPU
input [20:0] cpu_addr,
input [ 7:0] cpu_wrdata,
input cpu_req,
input cpu_rnw,
input cpu_wrbsel,
output reg cpu_next, // next cycle is allowed to be used by CPU
output reg cpu_strobe, // c2 strobe
output reg cpu_latch, // c2-c3 strobe
output curr_cpu_o,
// DMA
input [20:0] dma_addr,
input [15:0] dma_wrdata,
input dma_req,
input dma_rnw,
output dma_next,
// TS
input [20:0] ts_addr,
input ts_req,
output ts_pre_next,
output ts_next,
// TM
input [20:0] tm_addr,
input tm_req,
output tm_next
);
assign curr_cpu_o = curr_cpu;
localparam CYCLES = 5;
localparam CYC_CPU = 5'b00001;
localparam CYC_VID = 5'b00010;
localparam CYC_TS = 5'b00100;
localparam CYC_TM = 5'b01000;
localparam CYC_DMA = 5'b10000;
localparam CYC_FREE = 5'b00000;
localparam CPU = 0;
localparam VIDEO = 1;
localparam TS = 2;
localparam TM = 3;
localparam DMA = 4;
reg [CYCLES-1:0] curr_cycle; // type of the cycle in progress
reg [CYCLES-1:0] next_cycle; // type of the next cycle
wire next_cpu = next_cycle[CPU];
assign next_vid = next_cycle[VIDEO];
wire next_ts = next_cycle[TS];
wire next_tm = next_cycle[TM];
wire next_dma = next_cycle[DMA];
wire curr_cpu = curr_cycle[CPU];
wire curr_vid = curr_cycle[VIDEO];
wire curr_ts = curr_cycle[TS];
wire curr_tm = curr_cycle[TM];
wire curr_dma = curr_cycle[DMA];
// track blk_rem counter:
// how many cycles left to the end of block (7..0)
wire [2:0] blk_nrem = (video_start && go) ? {video_bw[4:3], 1'b1} : (video_start ? 3'd0 : (blk_rem - 3'd1));
wire bw_full = ~|{video_bw[4] & video_bw[2], video_bw[3] & video_bw[1], video_bw[0]}; // stall when 000/00/0
wire video_start = ~|blk_rem;
wire video_only = stall || (vid_rem == blk_rem);
wire video_idle = ~|vid_rem;
reg [2:0] blk_rem; // remaining accesses in a block (7..0)
reg stall;
always @(posedge clk) begin
if (c3) begin
blk_rem <= blk_nrem;
if (video_start) stall <= bw_full & go;
end
end
// track vid_rem counter
// how many video cycles left to the end of block (7..0)
wire [2:0] vid_nrem = (go && video_start) ? vid_nrem_start : (next_vid ? vid_nrem_next : vid_rem);
wire [2:0] vid_nrem_start = (cpu_req && !dev_over_cpu) ? vidmax : (vidmax - 3'd1);
wire [2:0] vid_nrem_next = video_idle ? 3'd0 : (vid_rem - 3'd1);
wire [2:0] vidmax = {video_bw[2:0]}; // number of cycles for video access
reg [2:0] vid_rem; // remaining video accesses in block
always @(posedge clk) if (c3) vid_rem <= vid_nrem;
// next cycle decision
wire [CYCLES-1:0] cyc_dev = tm_req ? CYC_TM : (ts_req ? CYC_TS : CYC_DMA);
wire dev_req = ts_req || tm_req || dma_req;
// wire dev_over_cpu = (((ts_req || tm_req) && ts_z80_lp) || (dma_req && dma_z80_lp)) && int_n; // CPU gets higher priority to acknowledge the INT
wire dev_over_cpu = 0;
always @* begin
if (video_start) begin // video burst start
if (go) begin // video active line - 38us-ON, 26us-ON
cpu_next = dev_over_cpu ? 1'b0 : !bw_full;
next_cycle = dev_over_cpu ? CYC_VID : (bw_full ? CYC_VID : (cpu_req ? CYC_CPU : CYC_VID));
end
else begin // video idle
cpu_next = !dev_over_cpu;
next_cycle = dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (dev_req ? cyc_dev : CYC_FREE));
end
end
else begin // video burst in progress
cpu_next = dev_over_cpu ? 1'b0 : !video_only;
next_cycle = video_only ? CYC_VID : (dev_over_cpu ? cyc_dev : (cpu_req ? CYC_CPU : (!video_idle ? CYC_VID : (dev_req ? cyc_dev : CYC_FREE))));
end
end
always @(posedge clk) if (c3) curr_cycle <= next_cycle;
// DRAM interface
assign dram_wrdata= curr_dma ? dma_wrdata : {cpu_wrdata,cpu_wrdata}; // write data has to be clocked at c0 in dram.v
assign dram_bsel = {cpu_wrbsel | next_dma, ~cpu_wrbsel | next_dma};
assign dram_req = |next_cycle;
assign dram_rnw = next_cpu ? cpu_rnw : ~next_dma | dma_rnw;
assign dram_addr = {21{next_cpu}} & cpu_addr
| {21{next_vid}} & video_addr
| {21{next_ts }} & ts_addr
| {21{next_tm }} & tm_addr
| {21{next_dma}} & dma_addr;
reg cpu_rnw_r;
always @(posedge clk) if (c3) cpu_rnw_r <= cpu_rnw;
// generation of read strobes: for video and cpu
always @(posedge clk) begin
if (c1) begin
cpu_strobe <= curr_cpu && cpu_rnw_r;
cpu_latch <= curr_cpu && cpu_rnw_r;
end
else if (c2) cpu_strobe <= 1'b0;
else if (c3) cpu_latch <= 1'b0;
end
assign video_pre_next = curr_vid & c1;
assign video_next = curr_vid & c2;
assign video_strobe = curr_vid && c3;
assign video_next_strobe = next_vid && c3;
assign ts_pre_next = curr_ts & c1;
assign ts_next = curr_ts & c2;
assign tm_next = curr_tm & c2;
assign dma_next = curr_dma & c2;
endmodule

124
rtl/memory/ddram.sv Normal file
View File

@ -0,0 +1,124 @@
//
// ddram.v
//
// DE10-nano DDR3 memory interface
//
// Copyright (c) 2017 Sorgelig
//
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ------------------------------------------
//
// 8-bit version
module ddram
(
input reset,
input DDRAM_CLK,
input DDRAM_BUSY,
output [7:0] DDRAM_BURSTCNT,
output [28:0] DDRAM_ADDR,
input [63:0] DDRAM_DOUT,
input DDRAM_DOUT_READY,
output DDRAM_RD,
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
input [27:0] addr, // 256MB at the end of 1GB
output [7:0] dout, // data output to cpu
input [7:0] din, // data input from cpu
input we, // cpu requests write
input rd, // cpu requests read
output ready // dout is valid. Ready to accept new read/write.
);
assign DDRAM_BURSTCNT = 1;
assign DDRAM_BE = (8'd1<<ram_address[2:0]) | {8{ram_read}};
assign DDRAM_ADDR = {4'b0011, ram_address[27:3]}; // RAM at 0x30000000
assign DDRAM_RD = ram_read;
assign DDRAM_DIN = ram_cache;
assign DDRAM_WE = ram_write;
assign dout = ram_q;
assign ready = ~busy;
reg [7:0] ram_q;
reg [27:0] ram_address;
reg ram_read;
reg [63:0] ram_cache;
reg ram_write;
reg [7:0] cached;
reg busy;
always @(posedge DDRAM_CLK)
begin
reg old_rd, old_we;
reg old_reset;
reg state;
old_reset <= reset;
if(old_reset && ~reset) begin
busy <= 0;
state <= 0;
cached <= 0;
end
if(!DDRAM_BUSY)
begin
ram_write <= 0;
ram_read <= 0;
if(state) begin
if(DDRAM_DOUT_READY) begin
ram_q <= DDRAM_DOUT[{ram_address[2:0], 3'b000} +:8];
ram_cache <= DDRAM_DOUT;
cached <= 8'hFF;
state <= 0;
busy <= 0;
end
end
else begin
old_rd <= rd;
old_we <= we;
busy <= 0;
if(~old_we && we) begin
ram_cache[{addr[2:0], 3'b000} +:8] <= din;
ram_address <= addr;
busy <= 1;
ram_write <= 1;
cached <= ((ram_address[27:3] == addr[27:3]) ? cached : 8'h00) | (8'd1<<addr[2:0]);
end
if(~old_rd && rd) begin
if((ram_address[27:3] == addr[27:3]) && (cached & (8'd1<<addr[2:0]))) begin
ram_q <= ram_cache[{addr[2:0], 3'b000} +:8];
end
else begin
ram_address <= addr;
ram_read <= 1;
state <= 1;
cached <= 0;
busy <= 1;
end
end
end
end
end
endmodule

337
rtl/memory/dma.v Normal file
View File

@ -0,0 +1,337 @@
// This module serves direct DRAM-to-device data transfer
// to do
// - probably add the extra 8 bit counter for number of bursts
module dma
(
// clocks
input wire clk,
input wire c2,
input wire reset,
// interface
input wire [8:0] dmaport_wr,
output wire dma_act,
output reg [15:0] data,
output wire [ 7:0] wraddr,
output wire int_start,
// Z80
input wire [7:0] zdata,
// DRAM interface
output wire [20:0] dram_addr,
input wire [15:0] dram_rddata,
output wire [15:0] dram_wrdata,
output wire dram_req,
output wire dram_rnw,
input wire dram_next,
// SPI interface
input wire [7:0] spi_rddata,
output wire [7:0] spi_wrdata,
output wire spi_req,
input wire spi_stb,
// IDE interface
input wire [15:0] ide_in,
output wire [15:0] ide_out,
output wire ide_req,
output wire ide_rnw,
input wire ide_stb,
// CRAM interface
output wire cram_we,
// SFILE interface
output wire sfile_we
);
// mode:
// 0 - device to RAM (read from device)
// 1 - RAM to device (write to device)
assign wraddr = d_addr[7:0];
wire dma_saddrl = dmaport_wr[0];
wire dma_saddrh = dmaport_wr[1];
wire dma_saddrx = dmaport_wr[2];
wire dma_daddrl = dmaport_wr[3];
wire dma_daddrh = dmaport_wr[4];
wire dma_daddrx = dmaport_wr[5];
wire dma_len = dmaport_wr[6];
wire dma_launch = dmaport_wr[7];
wire dma_num = dmaport_wr[8];
// DRAM
assign dram_addr = state_rd ? ((!dv_blt || !phase_blt) ? s_addr : d_addr) : d_addr;
assign dram_wrdata = data;
assign dram_req = dma_act && state_mem;
assign dram_rnw = state_rd;
// devices
localparam DEV_RAM = 3'b0001;
localparam DEV_BLT1 = 4'b1001;
localparam DEV_BLT2 = 4'b0110;
localparam DEV_FIL = 4'b0100;
localparam DEV_SPI = 3'b010;
localparam DEV_IDE = 3'b011;
localparam DEV_CRM = 4'b1100;
localparam DEV_SFL = 4'b1101;
localparam DEV_FDD = 4'b0101;
wire [2:0] dev_bid = device[2:0]; // bidirectional
wire [3:0] dev_uni = device[3:0]; // unidirectional
wire dma_wnr = device[3]; // 0 - device to RAM / 1 - RAM to device
wire dv_ram = (dev_uni == DEV_RAM) || (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2) || (dev_uni == DEV_FIL);
wire dv_blt = (dev_uni == DEV_BLT1) || (dev_uni == DEV_BLT2);
wire dv_fil = (dev_uni == DEV_FIL);
wire dv_spi = (dev_bid == DEV_SPI);
wire dv_ide = (dev_bid == DEV_IDE);
wire dv_crm = (dev_uni == DEV_CRM);
wire dv_sfl = (dev_uni == DEV_SFL);
wire dev_req = dma_act && state_dev;
wire dev_stb = cram_we || sfile_we || ide_int_stb || (spi_int_stb && bsel && dma_act);
assign cram_we = dev_req && dv_crm && state_wr;
assign sfile_we = dev_req && dv_sfl && state_wr;
// SPI
wire spi_int_stb = dv_spi && spi_stb;
assign spi_wrdata = {8{state_rd}} | (bsel ? data[15:8] : data[7:0]); // send FF on read cycles
assign spi_req = dev_req && dv_spi;
// IDE
wire ide_int_stb = dv_ide && ide_stb;
assign ide_out = data;
assign ide_req = dev_req && dv_ide;
assign ide_rnw = state_rd;
// blitter
wire [15:0] blt_rddata = (dev_uni == DEV_BLT1) ? blt1_rddata : blt2_rddata;
// Mode 1
wire [15:0] blt1_rddata = {blt1_data_h, blt1_data_l};
wire [7:0] blt1_data_h = dma_asz ? blt1_data32 : {blt1_data3, blt1_data2};
wire [7:0] blt1_data_l = dma_asz ? blt1_data10 : {blt1_data1, blt1_data0};
wire [7:0] blt1_data32 = |data[15:8] ? data[15:8] : dram_rddata[15:8];
wire [7:0] blt1_data10 = |data[7:0] ? data[7:0] : dram_rddata[7:0];
wire [3:0] blt1_data3 = |data[15:12] ? data[15:12] : dram_rddata[15:12];
wire [3:0] blt1_data2 = |data[11:8] ? data[11:8] : dram_rddata[11:8];
wire [3:0] blt1_data1 = |data[7:4] ? data[7:4] : dram_rddata[7:4];
wire [3:0] blt1_data0 = |data[3:0] ? data[3:0] : dram_rddata[3:0];
// Mode 2
wire [15:0] blt2_rddata = {blt2_data_1, blt2_data_0};
wire [7:0] blt2_data_1 = dma_asz ? blt2_8_data1 : {blt2_4_data3, blt2_4_data2};
wire [7:0] blt2_data_0 = dma_asz ? blt2_8_data0 : {blt2_4_data1, blt2_4_data0};
localparam msk = 8'd255;
wire [8:0] sum80 = data[7:0] + dram_rddata[7:0];
wire [8:0] sum81 = data[15:8] + dram_rddata[15:8];
wire [4:0] sum40 = data[3:0] + dram_rddata[3:0];
wire [4:0] sum41 = data[7:4] + dram_rddata[7:4];
wire [4:0] sum42 = data[11:8] + dram_rddata[11:8];
wire [4:0] sum43 = data[15:12] + dram_rddata[15:12];
wire [7:0] blt2_8_data0 = ((sum80 > msk) && dma_opt) ? msk : sum80[7:0];
wire [7:0] blt2_8_data1 = ((sum81 > msk) && dma_opt) ? msk : sum81[7:0];
wire [3:0] blt2_4_data0 = ((sum40 > msk[3:0]) && dma_opt) ? msk[3:0] : sum40[3:0];
wire [3:0] blt2_4_data1 = ((sum41 > msk[3:0]) && dma_opt) ? msk[3:0] : sum41[3:0];
wire [3:0] blt2_4_data2 = ((sum42 > msk[3:0]) && dma_opt) ? msk[3:0] : sum42[3:0];
wire [3:0] blt2_4_data3 = ((sum43 > msk[3:0]) && dma_opt) ? msk[3:0] : sum43[3:0];
// data aquiring
always @(posedge clk)
if (state_rd)
begin
if (dram_next)
data <= (dv_blt && phase_blt) ? blt_rddata : dram_rddata;
if (ide_int_stb)
data <= ide_in;
if (spi_int_stb)
begin
if (bsel)
data[15:8] <= spi_rddata;
else
data[7:0] <= spi_rddata;
end
end
// states
wire state_rd = ~phase;
wire state_wr = phase;
wire state_dev = !dv_ram && (dma_wnr ^ !phase);
wire state_mem = dv_ram || (dma_wnr ^ phase);
// states processing
wire phase_end = phase_end_ram || phase_end_dev;
wire phase_end_ram = state_mem && dram_next && !blt_hook;
wire phase_end_dev = state_dev && dev_stb;
wire blt_hook = dv_blt && !phase_blt && !phase;
wire fil_hook = dv_fil && phase;
wire phase_blt_end = state_mem && dram_next && !phase;
// blitter cycles:
// phase phase_blt blt_hook activity
// 0 0 1 read src
// 0 1 0 read dst
// 1 1 0 write dst
reg [3:0] device;
reg dma_salgn;
reg dma_dalgn;
reg dma_asz;
reg phase; // 0 - read / 1 - write
reg phase_blt; // 0 - source / 1 - destination
reg bsel; // 0 - lsb / 1 - msb
reg dma_opt;
always @(posedge clk)
if (dma_launch) // write to DMACtrl - launch of DMA burst
begin
dma_opt <= zdata[6];
dma_salgn <= zdata[5];
dma_dalgn <= zdata[4];
dma_asz <= zdata[3];
device <= {zdata[7], zdata[2:0]};
phase <= 1'b0;
phase_blt <= 1'b0;
bsel <= 1'b0;
end
else
begin
if (phase_end && !fil_hook)
phase <= ~phase;
if (phase_blt_end)
phase_blt <= ~phase_blt;
if (spi_int_stb)
bsel <= ~bsel;
end
// counter processing
reg [7:0] b_len; // length of burst
reg [7:0] b_num; // number of bursts
reg [8:0] n_ctr; // counter for bursts
wire [8:0] n_ctr_dec = n_ctr - next_burst;
assign dma_act = !n_ctr[8];
reg [7:0] b_ctr; // counter for cycles in burst
wire [7:0] b_ctr_next = next_burst ? b_len : b_ctr_dec[7:0];
wire [8:0] b_ctr_dec = {1'b0, b_ctr[7:0]} - 9'b1;
wire next_burst = b_ctr_dec[8];
always @(posedge clk)
if (reset)
n_ctr[8] <= 1'b1;
else if (dma_launch)
begin
b_ctr <= b_len;
n_ctr <= {1'b0, b_num};
end
else if (phase && phase_end) // cycle processed
begin
b_ctr <= b_ctr_next;
n_ctr <= n_ctr_dec;
end
// loading of burst parameters
always @(posedge clk)
begin
if (dma_len)
b_len <= zdata;
if (dma_num)
b_num <= zdata;
end
// address processing
// source
wire [20:0] s_addr_next = {s_addr_next_h[13:1], s_addr_next_m, s_addr_next_l[6:0]};
wire [13:0] s_addr_next_h = s_addr[20:7] + s_addr_add_h;
wire [1:0] s_addr_add_h = dma_salgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {s_addr_inc_l[8], 1'b0};
wire s_addr_next_m = dma_salgn ? (dma_asz ? s_addr_next_l[7] : s_addr_next_h[0]) : s_addr_inc_l[7];
wire [7:0] s_addr_next_l = (dma_salgn && next_burst) ? s_addr_r : s_addr_inc_l[7:0];
wire [8:0] s_addr_inc_l = {1'b0, s_addr[7:0]} + 9'b1;
reg [20:0] s_addr; // current source address
reg [7:0] s_addr_r; // source lower address
always @(posedge clk)
if ((dram_next || dev_stb) && state_rd && (!dv_blt || !phase_blt)) // increment RAM source addr
s_addr <= s_addr_next;
else
begin
if (dma_saddrl)
begin
s_addr[6:0] <= zdata[7:1];
s_addr_r[6:0] <= zdata[7:1];
end
if (dma_saddrh)
begin
s_addr[12:7] <= zdata[5:0];
s_addr_r[7] <= zdata[0];
end
if (dma_saddrx)
s_addr[20:13] <= zdata;
end
// destination
wire [20:0] d_addr_next = {d_addr_next_h[13:1], d_addr_next_m, d_addr_next_l[6:0]};
wire [13:0] d_addr_next_h = d_addr[20:7] + d_addr_add_h;
wire [1:0] d_addr_add_h = dma_dalgn ? {next_burst && dma_asz, next_burst && !dma_asz} : {d_addr_inc_l[8], 1'b0};
wire d_addr_next_m = dma_dalgn ? (dma_asz ? d_addr_next_l[7] : d_addr_next_h[0]) : d_addr_inc_l[7];
wire [7:0] d_addr_next_l = (dma_dalgn && next_burst) ? d_addr_r : d_addr_inc_l[7:0];
wire [8:0] d_addr_inc_l = {1'b0, d_addr[7:0]} + 9'b1;
reg [20:0] d_addr; // current dest address
reg [7:0] d_addr_r; // dest lower address
always @(posedge clk)
if ((dram_next || dev_stb) && state_wr) // increment RAM dest addr
d_addr <= d_addr_next;
else
begin
if (dma_daddrl)
begin
d_addr[6:0] <= zdata[7:1];
d_addr_r[6:0] <= zdata[7:1];
end
if (dma_daddrh)
begin
d_addr[12:7] <= zdata[5:0];
d_addr_r[7] <= zdata[0];
end
if (dma_daddrx)
d_addr[20:13] <= zdata;
end
// INT generation
reg dma_act_r;
always @(posedge clk)
dma_act_r <= dma_act && ~reset;
assign int_start = !dma_act && dma_act_r;
endmodule

72
rtl/memory/dpram.v Normal file
View File

@ -0,0 +1,72 @@
module dpram #(parameter DATAWIDTH=8, ADDRWIDTH=8, NUMWORDS=1<<ADDRWIDTH, MEM_INIT_FILE="")
(
input clock,
input [ADDRWIDTH-1:0] address_a,
input [DATAWIDTH-1:0] data_a,
input wren_a,
output [DATAWIDTH-1:0] q_a,
input [ADDRWIDTH-1:0] address_b,
input [DATAWIDTH-1:0] data_b,
input wren_b,
output [DATAWIDTH-1:0] q_b
);
altsyncram altsyncram_component (
.address_a (address_a),
.address_b (address_b),
.clock0 (clock),
.data_a (data_a),
.data_b (data_b),
.wren_a (wren_a),
.wren_b (wren_b),
.q_a (q_a),
.q_b (q_b),
.aclr0 (1'b0),
.aclr1 (1'b0),
.addressstall_a (1'b0),
.addressstall_b (1'b0),
.byteena_a (1'b1),
.byteena_b (1'b1),
.clock1 (1'b1),
.clocken0 (1'b1),
.clocken1 (1'b1),
.clocken2 (1'b1),
.clocken3 (1'b1),
.eccstatus (),
.rden_a (1'b1),
.rden_b (1'b1));
defparam
altsyncram_component.wrcontrol_wraddress_reg_b = "CLOCK0",
altsyncram_component.address_reg_b = "CLOCK0",
altsyncram_component.indata_reg_b = "CLOCK0",
altsyncram_component.numwords_a = NUMWORDS,
altsyncram_component.numwords_b = NUMWORDS,
altsyncram_component.widthad_a = ADDRWIDTH,
altsyncram_component.widthad_b = ADDRWIDTH,
altsyncram_component.width_a = DATAWIDTH,
altsyncram_component.width_b = DATAWIDTH,
altsyncram_component.width_byteena_a = 1,
altsyncram_component.width_byteena_b = 1,
altsyncram_component.init_file = MEM_INIT_FILE,
altsyncram_component.clock_enable_input_a = "BYPASS",
altsyncram_component.clock_enable_input_b = "BYPASS",
altsyncram_component.clock_enable_output_a = "BYPASS",
altsyncram_component.clock_enable_output_b = "BYPASS",
altsyncram_component.intended_device_family = "Cyclone V",
altsyncram_component.lpm_type = "altsyncram",
altsyncram_component.operation_mode = "BIDIR_DUAL_PORT",
altsyncram_component.outdata_aclr_a = "NONE",
altsyncram_component.outdata_aclr_b = "NONE",
altsyncram_component.outdata_reg_a = "UNREGISTERED",
altsyncram_component.outdata_reg_b = "UNREGISTERED",
altsyncram_component.power_up_uninitialized = "FALSE",
altsyncram_component.read_during_write_mode_mixed_ports = "DONT_CARE",
altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
altsyncram_component.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ";
endmodule

146
rtl/memory/sdram.v Normal file
View File

@ -0,0 +1,146 @@
module sdram
(
// Memory port
input clk,
input cyc,
input curr_cpu,
input [1:0] bsel, // Active HI
input [23:0] A,
input [15:0] DI,
output reg [15:0] DO,
output reg [15:0] DO_cpu,
input REQ,
input RNW,
// SDRAM Pin
inout reg [15:0] SDRAM_DQ,
output reg [12:0] SDRAM_A,
output reg [1:0] SDRAM_BA,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nCS,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nWE,
output SDRAM_CKE,
output SDRAM_CLK
);
reg [2:0] sdr_cmd;
localparam SdrCmd_xx = 3'b111; // no operation
localparam SdrCmd_ac = 3'b011; // activate
localparam SdrCmd_rd = 3'b101; // read
localparam SdrCmd_wr = 3'b100; // write
localparam SdrCmd_pr = 3'b010; // precharge all
localparam SdrCmd_re = 3'b001; // refresh
localparam SdrCmd_ms = 3'b000; // mode regiser set
always @(posedge clk) begin
reg [4:0] state;
reg rd;
reg [8:0] col;
reg [1:0] dqm;
SDRAM_DQ <= 16'hZZZZ;
case (state)
// Init
'h00: begin
sdr_cmd <= SdrCmd_pr; // PRECHARGE
SDRAM_A <= 0;
SDRAM_BA <= 0;
state <= state + 1'd1;
end
// REFRESH
'h03, 'h0A: begin
sdr_cmd <= SdrCmd_re;
state <= state + 1'd1;
end
// LOAD MODE REGISTER
'h11: begin
sdr_cmd <= SdrCmd_ms;
SDRAM_A <= {3'b000, 1'b1, 2'b00, 3'b010, 1'b0, 3'b000};
state <= state + 1'd1;
end
// Idle
'h18: begin
rd <= 0;
if (rd) begin
DO <= SDRAM_DQ;
if (curr_cpu) DO_cpu <= SDRAM_DQ;
end
if(cyc) begin
if (REQ) begin
sdr_cmd <= SdrCmd_ac; // ACTIVE
{SDRAM_A,SDRAM_BA,col} <= A;
dqm <= RNW ? 2'b00 : ~bsel;
rd <= RNW;
state <= state + 1'd1;
end else begin
sdr_cmd <= SdrCmd_re; // REFRESH
state <= 'h13;
end
end
end
// Single read/write - with auto precharge
'h1A: begin
SDRAM_A <= {dqm, 2'b10, col}; // A10 = 1 enable auto precharge; A9..0 = column
state <= 'h16;
if (rd) sdr_cmd <= SdrCmd_rd; // READ
else begin
sdr_cmd <= SdrCmd_wr; // WRITE
SDRAM_DQ <= DI;
end
end
// NOP
default:
begin
sdr_cmd <= SdrCmd_xx;
state <= state + 1'd1;
end
endcase
end
assign SDRAM_CKE = 1;
assign SDRAM_nCS = 0;
assign SDRAM_nRAS = sdr_cmd[2];
assign SDRAM_nCAS = sdr_cmd[1];
assign SDRAM_nWE = sdr_cmd[0];
assign SDRAM_DQML = SDRAM_A[11];
assign SDRAM_DQMH = SDRAM_A[12];
altddio_out
#(
.extend_oe_disable("OFF"),
.intended_device_family("Cyclone V"),
.invert_output("OFF"),
.lpm_hint("UNUSED"),
.lpm_type("altddio_out"),
.oe_reg("UNREGISTERED"),
.power_up_high("OFF"),
.width(1)
)
sdramclk_ddr
(
.datain_h(1'b0),
.datain_l(1'b1),
.outclock(clk),
.dataout(SDRAM_CLK),
.aclr(1'b0),
.aset(1'b0),
.oe(1'b1),
.outclocken(1'b1),
.sclr(1'b0),
.sset(1'b0)
);
endmodule

337
rtl/pll.qip Normal file
View File

@ -0,0 +1,337 @@
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_ENV "mwpim"
set_global_assignment -library "pll" -name MISC_FILE [file join $::quartus(qip_path) "pll.cmp"]
set_global_assignment -entity "pll" -library "pll" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V"
set_global_assignment -entity "pll" -library "pll" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}"
set_global_assignment -entity "pll" -library "pll" -name IP_QSYS_MODE "UNKNOWN"
set_global_assignment -name SYNTHESIS_ONLY_QIP ON
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_NAME "cGxs"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA=="
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "pll" -library "pll" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_NAME "cGxsXzAwMDI="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_REPORT_HIERARCHY "Off"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_INTERNAL "Off"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_VERSION "MTcuMA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIChBTFRFUkFfUExMKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZGVidWdfcHJpbnRfb3V0cHV0::ZmFsc2U=::ZGVidWdfcHJpbnRfb3V0cHV0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k::ZmFsc2U=::ZGVidWdfdXNlX3JiY190YWZfbWV0aG9k"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZGV2aWNl::NUNFQkEyRjE3QTc=::ZGV2aWNl"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9tb2Rl::RnJhY3Rpb25hbC1OIFBMTA==::UExMIE1vZGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg==::dHJ1ZQ==::ZnJhY3Rpb25hbF92Y29fbXVsdGlwbGllcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmVyZW5jZV9jbG9ja19mcmVxdWVuY3k=::NTAuMA==::UmVmZXJlbmNlIENsb2NrIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ==::NTAuMCBNSHo=::cmVmZXJlbmNlX2Nsb2NrX2ZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2NoYW5uZWxfc3BhY2luZw==::MC4w::Q2hhbm5lbCBTcGFjaW5n"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX29wZXJhdGlvbl9tb2Rl::ZGlyZWN0::T3BlcmF0aW9uIE1vZGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2ZlZWRiYWNrX2Nsb2Nr::R2xvYmFsIENsb2Nr::RmVlZGJhY2sgQ2xvY2s="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWN0aW9uYWxfY291dA==::MzI=::RnJhY3Rpb25hbCBjYXJyeSBvdXQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RzbV9vdXRfc2Vs::MXN0X29yZGVy::RFNNIE9yZGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3BlcmF0aW9uX21vZGU=::ZGlyZWN0::b3BlcmF0aW9uX21vZGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3VzZV9sb2NrZWQ=::ZmFsc2U=::RW5hYmxlIGxvY2tlZCBvdXRwdXQgcG9ydA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Fkdl9wYXJhbXM=::ZmFsc2U=::RW5hYmxlIHBoeXNpY2FsIG91dHB1dCBjbG9jayBwYXJhbWV0ZXJz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX251bWJlcl9vZl9jbG9ja3M=::Mg==::TnVtYmVyIE9mIENsb2Nrcw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "bnVtYmVyX29mX2Nsb2Nrcw==::Mg==::bnVtYmVyX29mX2Nsb2Nrcw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX211bHRpcGx5X2ZhY3Rvcg==::MQ==::TXVsdGlwbHkgRmFjdG9yIChNLUNvdW50ZXIp"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2ZyYWNfbXVsdGlwbHlfZmFjdG9y::MQ==::RnJhY3Rpb25hbCBNdWx0aXBseSBGYWN0b3IgKEsp"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3Jfbg==::MQ==::RGl2aWRlIEZhY3RvciAoTi1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjA=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kw::ODQuMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzA=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iw::MTA=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjA=::MzQzNTk3Mzg0::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMA==::Ng==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzA=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDA=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUw::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kx::NTYuMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Ix::MTA=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE=::MzQzNTk3Mzg0::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMQ==::OQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE=::MTgwLjA=::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUx::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjI=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3ky::NTYuMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzI=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iy::MTA=::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjI=::MzQzNTk3Mzg0::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMg==::OQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mg==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mg==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzI=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDI=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUy::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjM=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kz::MjguMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzM=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3Iz::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjM=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMw==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Mw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMw==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Mw==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzM=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDM=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUz::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjQ=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k0::MjEuMA==::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzQ=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I0::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjQ=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNA==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzQ=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDQ=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU0::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjU=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k1::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzU=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I1::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjU=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5NQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0NQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzU=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDU=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU1::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjY=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k2::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzY=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I2::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjY=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNg==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Ng==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNg==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Ng==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzY=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDY=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU2::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjc=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k3::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzc=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I3::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjc=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yNw==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5Nw==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzNw==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0Nw==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzc=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDc=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU3::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjg=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k4::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzg=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I4::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjg=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOA==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OA==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOA==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OA==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzg=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDg=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU4::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjk=::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3k5::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzk=::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3I5::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3Rvcjk=::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yOQ==::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5OQ==::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzOQ==::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0OQ==::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzk=::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDk=::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGU5::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEw::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEw::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEw::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTA=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTA=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTA=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTA=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEw::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEw::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMA==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEx::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEx::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEx::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTE=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTE=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTE=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTE=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEx::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEx::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMQ==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEy::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEy::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEy::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTI=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTI=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTI=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTI=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEy::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEy::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMg==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjEz::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxMw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzEz::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxMw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjEz::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTM=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTM=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTM=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTM=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzEz::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDEz::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxMw==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE0::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNA==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE0::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNA==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE0::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTQ=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTQ=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTQ=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTQ=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE0::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE0::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNA==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE1::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNQ==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE1::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNQ==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE1::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTU=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTU=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTU=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTU=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE1::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE1::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNQ==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE2::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNg==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE2::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNg==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE2::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTY=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTY=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTY=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTY=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE2::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE2::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNg==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Nhc2NhZGVfY291bnRlcjE3::ZmFsc2U=::TWFrZSB0aGlzIGEgY2FzY2FkZSBjb3VudGVy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX291dHB1dF9jbG9ja19mcmVxdWVuY3kxNw==::MTAwLjA=::RGVzaXJlZCBGcmVxdWVuY3k="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2RpdmlkZV9mYWN0b3JfYzE3::MQ==::RGl2aWRlIEZhY3RvciAoQy1Db3VudGVyKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9tdWx0aXBseV9mYWN0b3IxNw==::MQ==::QWN0dWFsIE11bHRpcGx5IEZhY3Rvcg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9mcmFjX211bHRpcGx5X2ZhY3RvcjE3::MQ==::QWN0dWFsIEZyYWN0aW9uYWwgTXVsdGlwbHkgRmFjdG9yIChLKQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9kaXZpZGVfZmFjdG9yMTc=::MQ==::QWN0dWFsIERpdmlkZSBGYWN0b3I="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9vdXRwdXRfY2xvY2tfZnJlcXVlbmN5MTc=::MCBNSHo=::QWN0dWFsIEZyZXF1ZW5jeQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BzX3VuaXRzMTc=::cHM=::UGhhc2UgU2hpZnQgdW5pdHM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0MTc=::MA==::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BoYXNlX3NoaWZ0X2RlZzE3::MC4w::UGhhc2UgU2hpZnQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2FjdHVhbF9waGFzZV9zaGlmdDE3::MA==::QWN0dWFsIFBoYXNlIFNoaWZ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2R1dHlfY3ljbGUxNw==::NTA=::RHV0eSBDeWNsZQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA=::ODQuMDAwMDAwIE1Ieg==::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTA="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQw::MCBwcw==::cGhhc2Vfc2hpZnQw"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTA=::NTA=::ZHV0eV9jeWNsZTA="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE=::NTYuMDAwMDAwIE1Ieg==::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQx::MCBwcw==::cGhhc2Vfc2hpZnQx"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE=::NTA=::ZHV0eV9jeWNsZTE="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTI="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQy::MCBwcw==::cGhhc2Vfc2hpZnQy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTI=::NTA=::ZHV0eV9jeWNsZTI="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQz::MCBwcw==::cGhhc2Vfc2hpZnQz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTM=::NTA=::ZHV0eV9jeWNsZTM="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ0::MCBwcw==::cGhhc2Vfc2hpZnQ0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTQ=::NTA=::ZHV0eV9jeWNsZTQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ1::MCBwcw==::cGhhc2Vfc2hpZnQ1"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTU=::NTA=::ZHV0eV9jeWNsZTU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTY="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ2::MCBwcw==::cGhhc2Vfc2hpZnQ2"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTY=::NTA=::ZHV0eV9jeWNsZTY="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ3::MCBwcw==::cGhhc2Vfc2hpZnQ3"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTc=::NTA=::ZHV0eV9jeWNsZTc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTg="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ4::MCBwcw==::cGhhc2Vfc2hpZnQ4"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTg=::NTA=::ZHV0eV9jeWNsZTg="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk=::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTk="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQ5::MCBwcw==::cGhhc2Vfc2hpZnQ5"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTk=::NTA=::ZHV0eV9jeWNsZTk="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEw"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMA==::MCBwcw==::cGhhc2Vfc2hpZnQxMA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEw::NTA=::ZHV0eV9jeWNsZTEw"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEx"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMQ==::MCBwcw==::cGhhc2Vfc2hpZnQxMQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEx::NTA=::ZHV0eV9jeWNsZTEx"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMg==::MCBwcw==::cGhhc2Vfc2hpZnQxMg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEy::NTA=::ZHV0eV9jeWNsZTEy"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTEz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxMw==::MCBwcw==::cGhhc2Vfc2hpZnQxMw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTEz::NTA=::ZHV0eV9jeWNsZTEz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNA==::MCBwcw==::cGhhc2Vfc2hpZnQxNA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE0::NTA=::ZHV0eV9jeWNsZTE0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE1"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNQ==::MCBwcw==::cGhhc2Vfc2hpZnQxNQ=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE1::NTA=::ZHV0eV9jeWNsZTE1"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE2"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNg==::MCBwcw==::cGhhc2Vfc2hpZnQxNg=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE2::NTA=::ZHV0eV9jeWNsZTE2"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3::MCBNSHo=::b3V0cHV0X2Nsb2NrX2ZyZXF1ZW5jeTE3"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGhhc2Vfc2hpZnQxNw==::MCBwcw==::cGhhc2Vfc2hpZnQxNw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "ZHV0eV9jeWNsZTE3::NTA=::ZHV0eV9jeWNsZTE3"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9hdXRvX3Jlc2V0::T24=::UExMIEF1dG8gUmVzZXQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BsbF9iYW5kd2lkdGhfcHJlc2V0::QXV0bw==::UExMIEJhbmR3aWR0aCBQcmVzZXQ="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3JlY29uZg==::ZmFsc2U=::RW5hYmxlIGR5bmFtaWMgcmVjb25maWd1cmF0aW9uIG9mIFBMTA=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX2Rwc19wb3J0cw==::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBkeW5hbWljIHBoYXNlIHNoaWZ0IHBvcnRz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuX3Bob3V0X3BvcnRz::ZmFsc2U=::RW5hYmxlIGFjY2VzcyB0byBQTEwgRFBBIG91dHB1dCBwb3J0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGxsX3R5cGU=::R2VuZXJhbA==::UExMIFRZUEU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "cGxsX3N1YnR5cGU=::R2VuZXJhbA==::UExMIFNVQlRZUEU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl9saXN0::TS1Db3VudGVyIEhpIERpdmlkZSxNLUNvdW50ZXIgTG93IERpdmlkZSxOLUNvdW50ZXIgSGkgRGl2aWRlLE4tQ291bnRlciBMb3cgRGl2aWRlLE0tQ291bnRlciBCeXBhc3MgRW5hYmxlLE4tQ291bnRlciBCeXBhc3MgRW5hYmxlLE0tQ291bnRlciBPZGQgRGl2aWRlIEVuYWJsZSxOLUNvdW50ZXIgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTAgSGkgRGl2aWRlLEMtQ291bnRlci0wIExvdyBEaXZpZGUsQy1Db3VudGVyLTAgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0wIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTAgSW5wdXQgU291cmNlLEMtQ291bnRlci0wIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTAgT2RkIERpdmlkZSBFbmFibGUsQy1Db3VudGVyLTEgSGkgRGl2aWRlLEMtQ291bnRlci0xIExvdyBEaXZpZGUsQy1Db3VudGVyLTEgQ29hcnNlIFBoYXNlIFNoaWZ0LEMtQ291bnRlci0xIFZDTyBQaGFzZSBUYXAsQy1Db3VudGVyLTEgSW5wdXQgU291cmNlLEMtQ291bnRlci0xIEJ5cGFzcyBFbmFibGUsQy1Db3VudGVyLTEgT2RkIERpdmlkZSBFbmFibGUsVkNPIFBvc3QgRGl2aWRlIENvdW50ZXIgRW5hYmxlLENoYXJnZSBQdW1wIGN1cnJlbnQgKHVBKSxMb29wIEZpbHRlciBCYW5kd2lkdGggUmVzaXN0b3IgKE9obXMpICxQTEwgT3V0cHV0IFZDTyBGcmVxdWVuY3ksSy1GcmFjdGlvbmFsIERpdmlzaW9uIFZhbHVlIChEU00pLEZlZWRiYWNrIENsb2NrIFR5cGUsRmVlZGJhY2sgQ2xvY2sgTVVYIDEsRmVlZGJhY2sgQ2xvY2sgTVVYIDIsTSBDb3VudGVyIFNvdXJjZSBNVVgsUExMIEF1dG8gUmVzZXQ=::UGFyYW1ldGVyIE5hbWVz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3BhcmFtZXRlcl92YWx1ZXM=::NSw1LDI1NiwyNTYsZmFsc2UsdHJ1ZSxmYWxzZSxmYWxzZSwzLDMsMSwwLHBoX211eF9jbGssZmFsc2UsZmFsc2UsNSw0LDEsMCxwaF9tdXhfY2xrLGZhbHNlLHRydWUsMiwyMCw0MDAwLDUwNC4wIE1IeiwzNDM1OTczODQsbm9uZSxnbGIsbV9jbnQscGhfbXV4X2Nsayx0cnVl::UGFyYW1ldGVyIFZhbHVlcw=="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX21pZl9nZW5lcmF0ZQ==::ZmFsc2U=::R2VuZXJhdGUgTUlGIGZpbGU="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9taWZfZHBz::ZmFsc2U=::RW5hYmxlIER5bmFtaWMgUGhhc2UgU2hpZnQgZm9yIE1JRiBzdHJlYW1pbmc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19jbnRy::QzA=::RFBTIENvdW50ZXIgU2VsZWN0aW9u"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19udW0=::MQ==::TnVtYmVyIG9mIER5bmFtaWMgUGhhc2UgU2hpZnRz"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2Rwc19kaXI=::UG9zaXRpdmU=::RHluYW1pYyBQaGFzZSBTaGlmdCBEaXJlY3Rpb24="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX3JlZmNsa19zd2l0Y2g=::ZmFsc2U=::Q3JlYXRlIGEgc2Vjb25kIGlucHV0IGNsayAncmVmY2xrMSc="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX291dA==::ZmFsc2U=::Q3JlYXRlIGEgJ2Nhc2NhZGVfb3V0JyBzaWduYWwgdG8gY29ubmVjdCB3aXRoIGEgZG93bnN0cmVhbSBQTEw="
set_global_assignment -entity "pll_0002" -library "pll" -name IP_COMPONENT_PARAMETER "Z3VpX2VuYWJsZV9jYXNjYWRlX2lu::ZmFsc2U=::Q3JlYXRlIGFuIGFkanBsbGluIG9yIGNjbGsgc2lnbmFsIHRvIGNvbm5lY3Qgd2l0aCBhbiB1cHN0cmVhbSBQTEw="
set_global_assignment -library "pll" -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"]
set_global_assignment -library "pll" -name VERILOG_FILE [file join $::quartus(qip_path) "pll/pll_0002.v"]
set_global_assignment -library "pll" -name QIP_FILE [file join $::quartus(qip_path) "pll/pll_0002.qip"]
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_NAME "altera_pll"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_VERSION "17.0"
set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_ENV "mwpim"

254
rtl/pll.v Normal file
View File

@ -0,0 +1,254 @@
// megafunction wizard: %Altera PLL v17.0%
// GENERATION: XML
// pll.v
// Generated using ACDS version 17.0 602
`timescale 1 ps / 1 ps
module pll (
input wire refclk, // refclk.clk
input wire rst, // reset.reset
output wire outclk_0, // outclk0.clk
output wire outclk_1 // outclk1.clk
);
pll_0002 pll_inst (
.refclk (refclk), // refclk.clk
.rst (rst), // reset.reset
.outclk_0 (outclk_0), // outclk0.clk
.outclk_1 (outclk_1), // outclk1.clk
.locked () // (terminated)
);
endmodule
// Retrieval info: <?xml version="1.0"?>
//<!--
// Generated by Altera MegaWizard Launcher Utility version 1.0
// ************************************************************
// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
// ************************************************************
// Copyright (C) 1991-2020 Altera Corporation
// Any megafunction design, and related net list (encrypted or decrypted),
// support information, device programming or simulation file, and any other
// associated documentation or information provided by Altera or a partner
// under Altera's Megafunction Partnership Program may be used only to
// program PLD devices (but not masked PLD devices) from Altera. Any other
// use of such megafunction design, net list, support information, device
// programming or simulation file, or any other related documentation or
// information is prohibited for any other purpose, including, but not
// limited to modification, reverse engineering, de-compiling, or use with
// any other silicon devices, unless such use is explicitly licensed under
// a separate agreement with Altera or a megafunction partner. Title to
// the intellectual property, including patents, copyrights, trademarks,
// trade secrets, or maskworks, embodied in any such megafunction design,
// net list, support information, device programming or simulation file, or
// any other related documentation or information provided by Altera or a
// megafunction partner, remains with Altera, the megafunction partner, or
// their respective licensors. No other licenses, including any licenses
// needed under any third party's intellectual property, are provided herein.
//-->
// Retrieval info: <instance entity-name="altera_pll" version="17.0" >
// Retrieval info: <generic name="debug_print_output" value="false" />
// Retrieval info: <generic name="debug_use_rbc_taf_method" value="false" />
// Retrieval info: <generic name="device_family" value="Cyclone V" />
// Retrieval info: <generic name="device" value="5CEBA2F17A7" />
// Retrieval info: <generic name="gui_device_speed_grade" value="2" />
// Retrieval info: <generic name="gui_pll_mode" value="Fractional-N PLL" />
// Retrieval info: <generic name="gui_reference_clock_frequency" value="50.0" />
// Retrieval info: <generic name="gui_channel_spacing" value="0.0" />
// Retrieval info: <generic name="gui_operation_mode" value="direct" />
// Retrieval info: <generic name="gui_feedback_clock" value="Global Clock" />
// Retrieval info: <generic name="gui_fractional_cout" value="32" />
// Retrieval info: <generic name="gui_dsm_out_sel" value="1st_order" />
// Retrieval info: <generic name="gui_use_locked" value="false" />
// Retrieval info: <generic name="gui_en_adv_params" value="false" />
// Retrieval info: <generic name="gui_number_of_clocks" value="2" />
// Retrieval info: <generic name="gui_multiply_factor" value="1" />
// Retrieval info: <generic name="gui_frac_multiply_factor" value="1" />
// Retrieval info: <generic name="gui_divide_factor_n" value="1" />
// Retrieval info: <generic name="gui_cascade_counter0" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency0" value="84.0" />
// Retrieval info: <generic name="gui_divide_factor_c0" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency0" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units0" value="ps" />
// Retrieval info: <generic name="gui_phase_shift0" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg0" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift0" value="0" />
// Retrieval info: <generic name="gui_duty_cycle0" value="50" />
// Retrieval info: <generic name="gui_cascade_counter1" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency1" value="56.0" />
// Retrieval info: <generic name="gui_divide_factor_c1" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency1" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units1" value="ps" />
// Retrieval info: <generic name="gui_phase_shift1" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg1" value="180.0" />
// Retrieval info: <generic name="gui_actual_phase_shift1" value="0" />
// Retrieval info: <generic name="gui_duty_cycle1" value="50" />
// Retrieval info: <generic name="gui_cascade_counter2" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency2" value="56.0" />
// Retrieval info: <generic name="gui_divide_factor_c2" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency2" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units2" value="ps" />
// Retrieval info: <generic name="gui_phase_shift2" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg2" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift2" value="0" />
// Retrieval info: <generic name="gui_duty_cycle2" value="50" />
// Retrieval info: <generic name="gui_cascade_counter3" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency3" value="28.0" />
// Retrieval info: <generic name="gui_divide_factor_c3" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency3" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units3" value="ps" />
// Retrieval info: <generic name="gui_phase_shift3" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg3" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift3" value="0" />
// Retrieval info: <generic name="gui_duty_cycle3" value="50" />
// Retrieval info: <generic name="gui_cascade_counter4" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency4" value="21.0" />
// Retrieval info: <generic name="gui_divide_factor_c4" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency4" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units4" value="ps" />
// Retrieval info: <generic name="gui_phase_shift4" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg4" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift4" value="0" />
// Retrieval info: <generic name="gui_duty_cycle4" value="50" />
// Retrieval info: <generic name="gui_cascade_counter5" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency5" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c5" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency5" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units5" value="ps" />
// Retrieval info: <generic name="gui_phase_shift5" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg5" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift5" value="0" />
// Retrieval info: <generic name="gui_duty_cycle5" value="50" />
// Retrieval info: <generic name="gui_cascade_counter6" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency6" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c6" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency6" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units6" value="ps" />
// Retrieval info: <generic name="gui_phase_shift6" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg6" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift6" value="0" />
// Retrieval info: <generic name="gui_duty_cycle6" value="50" />
// Retrieval info: <generic name="gui_cascade_counter7" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency7" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c7" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency7" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units7" value="ps" />
// Retrieval info: <generic name="gui_phase_shift7" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg7" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift7" value="0" />
// Retrieval info: <generic name="gui_duty_cycle7" value="50" />
// Retrieval info: <generic name="gui_cascade_counter8" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency8" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c8" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency8" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units8" value="ps" />
// Retrieval info: <generic name="gui_phase_shift8" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg8" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift8" value="0" />
// Retrieval info: <generic name="gui_duty_cycle8" value="50" />
// Retrieval info: <generic name="gui_cascade_counter9" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency9" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c9" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency9" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units9" value="ps" />
// Retrieval info: <generic name="gui_phase_shift9" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg9" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift9" value="0" />
// Retrieval info: <generic name="gui_duty_cycle9" value="50" />
// Retrieval info: <generic name="gui_cascade_counter10" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency10" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c10" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency10" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units10" value="ps" />
// Retrieval info: <generic name="gui_phase_shift10" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg10" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift10" value="0" />
// Retrieval info: <generic name="gui_duty_cycle10" value="50" />
// Retrieval info: <generic name="gui_cascade_counter11" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency11" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c11" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency11" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units11" value="ps" />
// Retrieval info: <generic name="gui_phase_shift11" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg11" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift11" value="0" />
// Retrieval info: <generic name="gui_duty_cycle11" value="50" />
// Retrieval info: <generic name="gui_cascade_counter12" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency12" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c12" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency12" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units12" value="ps" />
// Retrieval info: <generic name="gui_phase_shift12" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg12" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift12" value="0" />
// Retrieval info: <generic name="gui_duty_cycle12" value="50" />
// Retrieval info: <generic name="gui_cascade_counter13" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency13" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c13" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency13" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units13" value="ps" />
// Retrieval info: <generic name="gui_phase_shift13" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg13" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift13" value="0" />
// Retrieval info: <generic name="gui_duty_cycle13" value="50" />
// Retrieval info: <generic name="gui_cascade_counter14" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency14" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c14" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency14" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units14" value="ps" />
// Retrieval info: <generic name="gui_phase_shift14" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg14" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift14" value="0" />
// Retrieval info: <generic name="gui_duty_cycle14" value="50" />
// Retrieval info: <generic name="gui_cascade_counter15" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency15" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c15" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency15" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units15" value="ps" />
// Retrieval info: <generic name="gui_phase_shift15" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg15" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift15" value="0" />
// Retrieval info: <generic name="gui_duty_cycle15" value="50" />
// Retrieval info: <generic name="gui_cascade_counter16" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency16" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c16" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency16" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units16" value="ps" />
// Retrieval info: <generic name="gui_phase_shift16" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg16" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift16" value="0" />
// Retrieval info: <generic name="gui_duty_cycle16" value="50" />
// Retrieval info: <generic name="gui_cascade_counter17" value="false" />
// Retrieval info: <generic name="gui_output_clock_frequency17" value="100.0" />
// Retrieval info: <generic name="gui_divide_factor_c17" value="1" />
// Retrieval info: <generic name="gui_actual_output_clock_frequency17" value="0 MHz" />
// Retrieval info: <generic name="gui_ps_units17" value="ps" />
// Retrieval info: <generic name="gui_phase_shift17" value="0" />
// Retrieval info: <generic name="gui_phase_shift_deg17" value="0.0" />
// Retrieval info: <generic name="gui_actual_phase_shift17" value="0" />
// Retrieval info: <generic name="gui_duty_cycle17" value="50" />
// Retrieval info: <generic name="gui_pll_auto_reset" value="On" />
// Retrieval info: <generic name="gui_pll_bandwidth_preset" value="Auto" />
// Retrieval info: <generic name="gui_en_reconf" value="false" />
// Retrieval info: <generic name="gui_en_dps_ports" value="false" />
// Retrieval info: <generic name="gui_en_phout_ports" value="false" />
// Retrieval info: <generic name="gui_phout_division" value="1" />
// Retrieval info: <generic name="gui_mif_generate" value="false" />
// Retrieval info: <generic name="gui_enable_mif_dps" value="false" />
// Retrieval info: <generic name="gui_dps_cntr" value="C0" />
// Retrieval info: <generic name="gui_dps_num" value="1" />
// Retrieval info: <generic name="gui_dps_dir" value="Positive" />
// Retrieval info: <generic name="gui_refclk_switch" value="false" />
// Retrieval info: <generic name="gui_refclk1_frequency" value="100.0" />
// Retrieval info: <generic name="gui_switchover_mode" value="Automatic Switchover" />
// Retrieval info: <generic name="gui_switchover_delay" value="0" />
// Retrieval info: <generic name="gui_active_clk" value="false" />
// Retrieval info: <generic name="gui_clk_bad" value="false" />
// Retrieval info: <generic name="gui_enable_cascade_out" value="false" />
// Retrieval info: <generic name="gui_cascade_outclk_index" value="0" />
// Retrieval info: <generic name="gui_enable_cascade_in" value="false" />
// Retrieval info: <generic name="gui_pll_cascading_mode" value="Create an adjpllin signal to connect with an upstream PLL" />
// Retrieval info: </instance>
// IPFS_FILES : pll.vo
// RELATED_FILES: pll.v, pll_0002.v

4
rtl/pll/pll_0002.qip Normal file
View File

@ -0,0 +1,4 @@
set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_0002*|altera_pll:altera_pll_i*|*"
set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_0002*|altera_pll:altera_pll_i*|*"

90
rtl/pll/pll_0002.v Normal file
View File

@ -0,0 +1,90 @@
`timescale 1ns/10ps
module pll_0002(
// interface 'refclk'
input wire refclk,
// interface 'reset'
input wire rst,
// interface 'outclk0'
output wire outclk_0,
// interface 'outclk1'
output wire outclk_1,
// interface 'locked'
output wire locked
);
altera_pll #(
.fractional_vco_multiplier("true"),
.reference_clock_frequency("50.0 MHz"),
.operation_mode("direct"),
.number_of_clocks(2),
.output_clock_frequency0("84.000000 MHz"),
.phase_shift0("0 ps"),
.duty_cycle0(50),
.output_clock_frequency1("56.000000 MHz"),
.phase_shift1("0 ps"),
.duty_cycle1(50),
.output_clock_frequency2("0 MHz"),
.phase_shift2("0 ps"),
.duty_cycle2(50),
.output_clock_frequency3("0 MHz"),
.phase_shift3("0 ps"),
.duty_cycle3(50),
.output_clock_frequency4("0 MHz"),
.phase_shift4("0 ps"),
.duty_cycle4(50),
.output_clock_frequency5("0 MHz"),
.phase_shift5("0 ps"),
.duty_cycle5(50),
.output_clock_frequency6("0 MHz"),
.phase_shift6("0 ps"),
.duty_cycle6(50),
.output_clock_frequency7("0 MHz"),
.phase_shift7("0 ps"),
.duty_cycle7(50),
.output_clock_frequency8("0 MHz"),
.phase_shift8("0 ps"),
.duty_cycle8(50),
.output_clock_frequency9("0 MHz"),
.phase_shift9("0 ps"),
.duty_cycle9(50),
.output_clock_frequency10("0 MHz"),
.phase_shift10("0 ps"),
.duty_cycle10(50),
.output_clock_frequency11("0 MHz"),
.phase_shift11("0 ps"),
.duty_cycle11(50),
.output_clock_frequency12("0 MHz"),
.phase_shift12("0 ps"),
.duty_cycle12(50),
.output_clock_frequency13("0 MHz"),
.phase_shift13("0 ps"),
.duty_cycle13(50),
.output_clock_frequency14("0 MHz"),
.phase_shift14("0 ps"),
.duty_cycle14(50),
.output_clock_frequency15("0 MHz"),
.phase_shift15("0 ps"),
.duty_cycle15(50),
.output_clock_frequency16("0 MHz"),
.phase_shift16("0 ps"),
.duty_cycle16(50),
.output_clock_frequency17("0 MHz"),
.phase_shift17("0 ps"),
.duty_cycle17(50),
.pll_type("General"),
.pll_subtype("General")
) altera_pll_i (
.rst (rst),
.outclk ({outclk_1, outclk_0}),
.locked (locked),
.fboutclk ( ),
.fbclk (1'b0),
.refclk (refclk)
);
endmodule

BIN
rtl/rtc/CMOS.bin Normal file

Binary file not shown.

71
rtl/rtc/CMOS.mif Normal file
View File

@ -0,0 +1,71 @@
-- Copyright (C) 2017 Intel Corporation. All rights reserved.
-- Your use of Intel 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 Intel Program License
-- Subscription Agreement, the Intel Quartus Prime License Agreement,
-- the Intel 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 Intel and sold by Intel or its
-- authorized distributors. Please refer to the applicable
-- agreement for further details.
-- Quartus Prime generated Memory Initialization File (.mif)
WIDTH=8;
DEPTH=256;
ADDRESS_RADIX=HEX;
DATA_RADIX=HEX;
CONTENT BEGIN
[000..010] : 00;
011 : AA;
[012..0B0] : 00;
0B1 : 01;
0B2 : 00;
0B3 : 01;
0B4 : 03;
[0B5..0B7] : 00;
0B8 : 01;
[0B9..0BA] : 00;
0BB : 02;
[0BC..0CD] : FF;
[0CE..0CF] : 00;
0D0 : 42;
0D1 : 08;
0D2 : 84;
0D3 : 10;
0D4 : C6;
0D5 : 18;
0D6 : 08;
0D7 : 21;
0D8 : 4A;
0D9 : 29;
0DA : 8C;
0DB : 31;
0DC : CE;
0DD : 39;
0DE : 21;
0DF : 04;
0E0 : 63;
0E1 : 0C;
0E2 : A5;
0E3 : 14;
0E4 : E7;
0E5 : 1C;
0E6 : 29;
0E7 : 25;
0E8 : 6B;
0E9 : 2D;
0EA : AD;
0EB : 35;
0EC : EF;
0ED : 3D;
0EE : 6B;
0EF : A2;
[0F0..0FF] : 00;
END;

248
rtl/rtc/mc146818a.v Normal file
View File

@ -0,0 +1,248 @@
//-----------------------------------------------------------------[18.10.2014]
// MC146818A REAL-TIME CLOCK PLUS RAM
//-----------------------------------------------------------------------------
// V0.1 05.10.2011 Initial version
// V0.2 06.09.2014 Added General Purpose RAM
module mc146818a
(
input RESET,
input CLK,
input ENA,
input CS,
input [64:0] RTC,
input [31:0] CMOSCfg,
input [7:0] KEYSCANCODE,
input WR,
input [7:0] A,
input [7:0] DI,
output [7:0] DO
);
reg [18:0] pre_scaler =0;
reg [1:0] leap_reg =0;
reg [7:0] seconds_reg =0; // 00
reg [7:0] seconds_alarm_reg =0; // 01
reg [7:0] minutes_reg =0; // 02
reg [7:0] minutes_alarm_reg = 0;// 03
reg [7:0] hours_reg =0; // 04
reg [7:0] hours_alarm_reg ='hff;// 05
reg [7:0] weeks_reg = 1; // 06
reg [7:0] days_reg = 1; // 07
reg [7:0] month_reg = 1; // 08
reg [7:0] year_reg = 0; // 09
reg [7:0] a_reg; // 0A
reg [7:0] b_reg = 8'b00000010; // 0B
reg [7:0] c_reg; // 0C
wire [7:0] CMOS_Dout;
reg [7:0] Dout;
assign DO = Dout;
always @(*) begin
case (A[7:0])
8'h00 : Dout <= seconds_reg;
8'h01 : Dout <= seconds_alarm_reg;
8'h02 : Dout <= minutes_reg;
8'h03 : Dout <= minutes_alarm_reg;
8'h04 : Dout <= hours_reg;
8'h05 : Dout <= hours_alarm_reg;
8'h06 : Dout <= weeks_reg;
8'h07 : Dout <= days_reg;
8'h08 : Dout <= month_reg;
8'h09 : Dout <= year_reg;
8'h0a : Dout <= a_reg;
8'h0b : Dout <= b_reg;
8'h0c : Dout <= c_reg;
8'h0d : Dout <= 8'b10000000;
8'hb1 : Dout <= CMOSCfg[7:6]; // CPU Speed
8'hb2 : Dout <= 0; // Boot device
8'hb3 : Dout <= CMOSCfg[8]; // CPU Cache
8'hb4 : Dout <= CMOSCfg[13:11]; // F11
8'hb5 : Dout <= CMOSCfg[15:14]; // F11 bank
8'hb6 : Dout <= CMOSCfg[18:16]; // Shift+F11
8'hb7 : Dout <= CMOSCfg[20:19]; // Shift+F11 bank
8'hb8 : Dout <= CMOSCfg[10:9]; // #7FFD
8'hb9 : Dout <= CMOSCfg[23:21]; // ZX Palette
8'hba : Dout <= CMOSCfg[24]; // NGS Reset
8'hbb : Dout <= CMOSCfg[27:25]; // INT offset
8'hf0 : Dout <= KEYSCANCODE;
default: Dout <= CMOS_Dout;
endcase
end
always @(posedge CLK) begin
reg flg;
flg <= RTC[64];
if (flg != RTC[64]) begin
seconds_reg <= RTC[7:0];
minutes_reg <= RTC[15:8];
hours_reg <= RTC[23:16];
days_reg <= RTC[31:24];
month_reg <= RTC[39:32];
year_reg <= RTC[47:40];
weeks_reg <= RTC[55:48] + 1'b1;
b_reg <= 8'b00000010;
end
if (RESET) b_reg <= 8'b00000010;
else if (WR & CS) begin
/*
case (A[7:0])
0 : seconds_reg <= DI;
1 : seconds_alarm_reg <= DI;
2 : minutes_reg <= DI;
3 : minutes_alarm_reg <= DI;
4 : hours_reg <= DI;
5 : hours_alarm_reg <= DI;
6 : weeks_reg <= DI;
7 : days_reg <= DI;
8 : month_reg <= DI;
9 : year_reg <= DI;
11 : begin
b_reg <= DI;
if (b_reg[2] == 1'b0) begin // BCD to BIN convertion
if (DI[4] == 1'b0) leap_reg <= DI[1:0];
else leap_reg <= {~DI[1], DI[0]};
end
else begin
leap_reg <= DI[1:0];
end
end
endcase
*/
end
if (RESET) begin
a_reg <= 8'b00100110;
c_reg <= 0;
end
else if (~b_reg[7] & ENA) begin
if (pre_scaler) begin
pre_scaler <= pre_scaler - 1'd1;
a_reg[7] <= 0;
end
else begin
pre_scaler <= 437500; //(0.4375MHz)
a_reg[7] <= 1;
c_reg[4] <= 1;
// alarm
if ((seconds_reg == seconds_alarm_reg) && (minutes_reg == minutes_alarm_reg) && (hours_reg == hours_alarm_reg)) c_reg[5] <= 1'b1;
if (~b_reg[2]) begin
// DM binary-coded-decimal (BCD) data mode
if (seconds_reg[3:0] != 9) seconds_reg[3:0] <= seconds_reg[3:0] + 1'd1;
else begin
seconds_reg[3:0] <= 0;
if (seconds_reg[6:4] != 5) seconds_reg[6:4] <= seconds_reg[6:4] + 1'd1;
else begin
seconds_reg[6:4] <= 0;
if (minutes_reg[3:0] != 9) minutes_reg[3:0] <= minutes_reg[3:0] + 1'd1;
else begin
minutes_reg[3:0] <= 0;
if (minutes_reg[6:4] != 5) minutes_reg[6:4] <= minutes_reg[6:4] + 1'd1;
else begin
minutes_reg[6:4] <= 0;
if (hours_reg[3:0] == 9) begin
hours_reg[3:0] <= 0;
hours_reg[5:4] <= hours_reg[5:4] + 1'd1;
end
else if ({b_reg[1], hours_reg[7], hours_reg[4:0]} == 7'b0010010) begin
hours_reg[4:0] <= 1;
hours_reg[7] <= ~hours_reg[7];
end
else if (({b_reg[1], hours_reg[7], hours_reg[4:0]} != 7'b0110010) &&
({b_reg[1], hours_reg[5:0]} != 7'b1100011)) hours_reg[3:0] <= hours_reg[3:0] + 1'd1;
else begin
if (~b_reg[1]) hours_reg[7:0] <= 1;
else hours_reg[5:0] <= 0;
if (weeks_reg[2:0] != 7) weeks_reg[2:0] <= weeks_reg[2:0] + 1'd1;
else weeks_reg[2:0] <= 1;
if (({month_reg, days_reg, leap_reg} == {16'h0228, 2'b01}) ||
({month_reg, days_reg, leap_reg} == {16'h0228, 2'b10}) ||
({month_reg, days_reg, leap_reg} == {16'h0228, 2'b11}) ||
({month_reg, days_reg, leap_reg} == {16'h0229, 2'b00}) ||
({month_reg, days_reg} == 16'h0430) ||
({month_reg, days_reg} == 16'h0630) ||
({month_reg, days_reg} == 16'h0930) ||
({month_reg, days_reg} == 16'h1130) ||
(days_reg == 8'h31)) begin
days_reg[5:0] <= 1;
if (month_reg[3:0] == 9) month_reg[4:0] <= 'h10;
else if (month_reg[4:0] != 'h12) month_reg[3:0] <= month_reg[3:0] + 1'd1;
else begin
month_reg[4:0] <= 1;
leap_reg[1:0] <= leap_reg[1:0] + 1'd1;
if (year_reg[3:0] != 9) year_reg[3:0] <= year_reg[3:0] + 1'd1;
else begin
year_reg[3:0] <= 0;
if (year_reg[7:4] != 9) year_reg[7:4] <= year_reg[7:4] + 1'd1;
else year_reg[7:4] <= 0;
end
end
end
else if (days_reg[3:0] != 9) days_reg[3:0] <= days_reg[3:0] + 1'd1;
else begin
days_reg[3:0] <= 0;
days_reg[5:4] <= days_reg[5:4] + 1'd1;
end
end
end
end
end
end
end else begin
// DM binary data mode
if (seconds_reg != 8'h3B) seconds_reg <= seconds_reg + 1'd1;
else begin
seconds_reg <= 0;
if (minutes_reg != 8'h3B) minutes_reg <= minutes_reg + 1'd1;
else begin
minutes_reg <= 0;
if ({b_reg[1], hours_reg[7], hours_reg[3:0]} == 6'b001100) hours_reg[7:0] <= 8'b10000001;
else if (({b_reg[1], hours_reg[7], hours_reg[3:0]} != 6'b011100) & ({b_reg[1], hours_reg[4:0]} != 6'b110111)) hours_reg[4:0] <= hours_reg[4:0] + 1'd1;
else begin
if (b_reg[1] == 1'b0) hours_reg[7:0] <= 1;
else hours_reg <= 0;
if (weeks_reg != 7) weeks_reg <= weeks_reg + 1'd1;
else weeks_reg <= 1; // Sunday = 1
if (({month_reg, days_reg, leap_reg} == {16'h021C, 2'b01}) | ({month_reg, days_reg, leap_reg} == {16'h021C, 2'b10}) | ({month_reg, days_reg, leap_reg} == {16'h021C, 2'b11}) | ({month_reg, days_reg, leap_reg} == {16'h021D, 2'b00}) | ({month_reg, days_reg} == 16'h041E) | ({month_reg, days_reg} == 16'h061E) | ({month_reg, days_reg} == 16'h091E) | ({month_reg, days_reg} == 16'h0B1E) | (days_reg == 8'h1F)) begin
days_reg <= 1;
if (month_reg != 8'h0C) month_reg <= month_reg + 1'd1;
else begin
month_reg <= 1;
leap_reg[1:0] <= leap_reg[1:0] + 1'd1;
if (year_reg != 8'h63) year_reg <= year_reg + 1'd1;
else year_reg <= 0;
end
end else days_reg <= days_reg + 1'd1;
end
end
end
end
end
end
end
// 50 Bytes of General Purpose RAM
dpram #(.DATAWIDTH(8), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/rtc/CMOS.mif")) CMOS
(
.clock (CLK),
.address_a (A),
.data_a (DI),
.wren_a (WR & CS),
.q_a (CMOS_Dout)
);
endmodule

164
rtl/sound/compressor.sv Normal file
View File

@ -0,0 +1,164 @@
//============================================================================
// Audio compressor (signed samples)
//
// Copyright (C) 2018 Sorgelig
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//============================================================================
module compressor
(
input clk,
input [11:0] in1, in2,
output [15:0] out1, out2
);
always @(posedge clk) out1 <= {in1[11], in1[11] ? ~tbl[~in1[10:0]] : tbl[in1[10:0]]};
always @(posedge clk) out2 <= {in2[11], in2[11] ? ~tbl[~in2[10:0]] : tbl[in2[10:0]]};
wire [14:0] tbl[0:2047] =
'{
//sin(x)
15'h0000, 15'h0019, 15'h0032, 15'h004B, 15'h0064, 15'h007D, 15'h0096, 15'h00B0, 15'h00C9, 15'h00E2, 15'h00FB, 15'h0114, 15'h012D, 15'h0146, 15'h0160, 15'h0179,
15'h0192, 15'h01AB, 15'h01C4, 15'h01DD, 15'h01F6, 15'h0210, 15'h0229, 15'h0242, 15'h025B, 15'h0274, 15'h028D, 15'h02A6, 15'h02BF, 15'h02D9, 15'h02F2, 15'h030B,
15'h0324, 15'h033D, 15'h0356, 15'h036F, 15'h0389, 15'h03A2, 15'h03BB, 15'h03D4, 15'h03ED, 15'h0406, 15'h041F, 15'h0439, 15'h0452, 15'h046B, 15'h0484, 15'h049D,
15'h04B6, 15'h04CF, 15'h04E8, 15'h0502, 15'h051B, 15'h0534, 15'h054D, 15'h0566, 15'h057F, 15'h0598, 15'h05B1, 15'h05CB, 15'h05E4, 15'h05FD, 15'h0616, 15'h062F,
15'h0648, 15'h0661, 15'h067A, 15'h0693, 15'h06AD, 15'h06C6, 15'h06DF, 15'h06F8, 15'h0711, 15'h072A, 15'h0743, 15'h075C, 15'h0775, 15'h078E, 15'h07A8, 15'h07C1,
15'h07DA, 15'h07F3, 15'h080C, 15'h0825, 15'h083E, 15'h0857, 15'h0870, 15'h0889, 15'h08A3, 15'h08BC, 15'h08D5, 15'h08EE, 15'h0907, 15'h0920, 15'h0939, 15'h0952,
15'h096B, 15'h0984, 15'h099D, 15'h09B6, 15'h09CF, 15'h09E9, 15'h0A02, 15'h0A1B, 15'h0A34, 15'h0A4D, 15'h0A66, 15'h0A7F, 15'h0A98, 15'h0AB1, 15'h0ACA, 15'h0AE3,
15'h0AFC, 15'h0B15, 15'h0B2E, 15'h0B47, 15'h0B60, 15'h0B79, 15'h0B92, 15'h0BAC, 15'h0BC5, 15'h0BDE, 15'h0BF7, 15'h0C10, 15'h0C29, 15'h0C42, 15'h0C5B, 15'h0C74,
15'h0C8D, 15'h0CA6, 15'h0CBF, 15'h0CD8, 15'h0CF1, 15'h0D0A, 15'h0D23, 15'h0D3C, 15'h0D55, 15'h0D6E, 15'h0D87, 15'h0DA0, 15'h0DB9, 15'h0DD2, 15'h0DEB, 15'h0E04,
15'h0E1D, 15'h0E36, 15'h0E4F, 15'h0E68, 15'h0E81, 15'h0E9A, 15'h0EB3, 15'h0ECC, 15'h0EE5, 15'h0EFE, 15'h0F17, 15'h0F30, 15'h0F49, 15'h0F62, 15'h0F7B, 15'h0F94,
15'h0FAC, 15'h0FC5, 15'h0FDE, 15'h0FF7, 15'h1010, 15'h1029, 15'h1042, 15'h105B, 15'h1074, 15'h108D, 15'h10A6, 15'h10BF, 15'h10D8, 15'h10F1, 15'h110A, 15'h1123,
15'h113B, 15'h1154, 15'h116D, 15'h1186, 15'h119F, 15'h11B8, 15'h11D1, 15'h11EA, 15'h1203, 15'h121C, 15'h1234, 15'h124D, 15'h1266, 15'h127F, 15'h1298, 15'h12B1,
15'h12CA, 15'h12E3, 15'h12FB, 15'h1314, 15'h132D, 15'h1346, 15'h135F, 15'h1378, 15'h1391, 15'h13A9, 15'h13C2, 15'h13DB, 15'h13F4, 15'h140D, 15'h1426, 15'h143E,
15'h1457, 15'h1470, 15'h1489, 15'h14A2, 15'h14BB, 15'h14D3, 15'h14EC, 15'h1505, 15'h151E, 15'h1537, 15'h154F, 15'h1568, 15'h1581, 15'h159A, 15'h15B3, 15'h15CB,
15'h15E4, 15'h15FD, 15'h1616, 15'h162E, 15'h1647, 15'h1660, 15'h1679, 15'h1691, 15'h16AA, 15'h16C3, 15'h16DC, 15'h16F4, 15'h170D, 15'h1726, 15'h173F, 15'h1757,
15'h1770, 15'h1789, 15'h17A1, 15'h17BA, 15'h17D3, 15'h17EC, 15'h1804, 15'h181D, 15'h1836, 15'h184E, 15'h1867, 15'h1880, 15'h1898, 15'h18B1, 15'h18CA, 15'h18E2,
15'h18FB, 15'h1914, 15'h192C, 15'h1945, 15'h195E, 15'h1976, 15'h198F, 15'h19A8, 15'h19C0, 15'h19D9, 15'h19F2, 15'h1A0A, 15'h1A23, 15'h1A3B, 15'h1A54, 15'h1A6D,
15'h1A85, 15'h1A9E, 15'h1AB6, 15'h1ACF, 15'h1AE8, 15'h1B00, 15'h1B19, 15'h1B31, 15'h1B4A, 15'h1B62, 15'h1B7B, 15'h1B94, 15'h1BAC, 15'h1BC5, 15'h1BDD, 15'h1BF6,
15'h1C0E, 15'h1C27, 15'h1C3F, 15'h1C58, 15'h1C70, 15'h1C89, 15'h1CA1, 15'h1CBA, 15'h1CD2, 15'h1CEB, 15'h1D03, 15'h1D1C, 15'h1D34, 15'h1D4D, 15'h1D65, 15'h1D7E,
15'h1D96, 15'h1DAF, 15'h1DC7, 15'h1DE0, 15'h1DF8, 15'h1E10, 15'h1E29, 15'h1E41, 15'h1E5A, 15'h1E72, 15'h1E8B, 15'h1EA3, 15'h1EBB, 15'h1ED4, 15'h1EEC, 15'h1F05,
15'h1F1D, 15'h1F35, 15'h1F4E, 15'h1F66, 15'h1F7F, 15'h1F97, 15'h1FAF, 15'h1FC8, 15'h1FE0, 15'h1FF8, 15'h2011, 15'h2029, 15'h2041, 15'h205A, 15'h2072, 15'h208A,
15'h20A3, 15'h20BB, 15'h20D3, 15'h20EC, 15'h2104, 15'h211C, 15'h2134, 15'h214D, 15'h2165, 15'h217D, 15'h2196, 15'h21AE, 15'h21C6, 15'h21DE, 15'h21F7, 15'h220F,
15'h2227, 15'h223F, 15'h2257, 15'h2270, 15'h2288, 15'h22A0, 15'h22B8, 15'h22D1, 15'h22E9, 15'h2301, 15'h2319, 15'h2331, 15'h2349, 15'h2362, 15'h237A, 15'h2392,
15'h23AA, 15'h23C2, 15'h23DA, 15'h23F3, 15'h240B, 15'h2423, 15'h243B, 15'h2453, 15'h246B, 15'h2483, 15'h249B, 15'h24B3, 15'h24CB, 15'h24E4, 15'h24FC, 15'h2514,
15'h252C, 15'h2544, 15'h255C, 15'h2574, 15'h258C, 15'h25A4, 15'h25BC, 15'h25D4, 15'h25EC, 15'h2604, 15'h261C, 15'h2634, 15'h264C, 15'h2664, 15'h267C, 15'h2694,
15'h26AC, 15'h26C4, 15'h26DC, 15'h26F4, 15'h270C, 15'h2724, 15'h273C, 15'h2754, 15'h276C, 15'h2783, 15'h279B, 15'h27B3, 15'h27CB, 15'h27E3, 15'h27FB, 15'h2813,
15'h282B, 15'h2843, 15'h285A, 15'h2872, 15'h288A, 15'h28A2, 15'h28BA, 15'h28D2, 15'h28EA, 15'h2901, 15'h2919, 15'h2931, 15'h2949, 15'h2961, 15'h2978, 15'h2990,
15'h29A8, 15'h29C0, 15'h29D7, 15'h29EF, 15'h2A07, 15'h2A1F, 15'h2A36, 15'h2A4E, 15'h2A66, 15'h2A7E, 15'h2A95, 15'h2AAD, 15'h2AC5, 15'h2ADC, 15'h2AF4, 15'h2B0C,
15'h2B24, 15'h2B3B, 15'h2B53, 15'h2B6B, 15'h2B82, 15'h2B9A, 15'h2BB1, 15'h2BC9, 15'h2BE1, 15'h2BF8, 15'h2C10, 15'h2C28, 15'h2C3F, 15'h2C57, 15'h2C6E, 15'h2C86,
15'h2C9D, 15'h2CB5, 15'h2CCD, 15'h2CE4, 15'h2CFC, 15'h2D13, 15'h2D2B, 15'h2D42, 15'h2D5A, 15'h2D71, 15'h2D89, 15'h2DA0, 15'h2DB8, 15'h2DCF, 15'h2DE7, 15'h2DFE,
15'h2E16, 15'h2E2D, 15'h2E45, 15'h2E5C, 15'h2E73, 15'h2E8B, 15'h2EA2, 15'h2EBA, 15'h2ED1, 15'h2EE9, 15'h2F00, 15'h2F17, 15'h2F2F, 15'h2F46, 15'h2F5D, 15'h2F75,
15'h2F8C, 15'h2FA3, 15'h2FBB, 15'h2FD2, 15'h2FE9, 15'h3001, 15'h3018, 15'h302F, 15'h3047, 15'h305E, 15'h3075, 15'h308C, 15'h30A4, 15'h30BB, 15'h30D2, 15'h30E9,
15'h3101, 15'h3118, 15'h312F, 15'h3146, 15'h315E, 15'h3175, 15'h318C, 15'h31A3, 15'h31BA, 15'h31D1, 15'h31E9, 15'h3200, 15'h3217, 15'h322E, 15'h3245, 15'h325C,
15'h3273, 15'h328A, 15'h32A2, 15'h32B9, 15'h32D0, 15'h32E7, 15'h32FE, 15'h3315, 15'h332C, 15'h3343, 15'h335A, 15'h3371, 15'h3388, 15'h339F, 15'h33B6, 15'h33CD,
15'h33E4, 15'h33FB, 15'h3412, 15'h3429, 15'h3440, 15'h3457, 15'h346E, 15'h3485, 15'h349C, 15'h34B3, 15'h34CA, 15'h34E1, 15'h34F7, 15'h350E, 15'h3525, 15'h353C,
15'h3553, 15'h356A, 15'h3581, 15'h3597, 15'h35AE, 15'h35C5, 15'h35DC, 15'h35F3, 15'h360A, 15'h3620, 15'h3637, 15'h364E, 15'h3665, 15'h367B, 15'h3692, 15'h36A9,
15'h36C0, 15'h36D6, 15'h36ED, 15'h3704, 15'h371A, 15'h3731, 15'h3748, 15'h375E, 15'h3775, 15'h378C, 15'h37A2, 15'h37B9, 15'h37D0, 15'h37E6, 15'h37FD, 15'h3814,
15'h382A, 15'h3841, 15'h3857, 15'h386E, 15'h3884, 15'h389B, 15'h38B2, 15'h38C8, 15'h38DF, 15'h38F5, 15'h390C, 15'h3922, 15'h3939, 15'h394F, 15'h3966, 15'h397C,
15'h3993, 15'h39A9, 15'h39BF, 15'h39D6, 15'h39EC, 15'h3A03, 15'h3A19, 15'h3A30, 15'h3A46, 15'h3A5C, 15'h3A73, 15'h3A89, 15'h3A9F, 15'h3AB6, 15'h3ACC, 15'h3AE2,
15'h3AF9, 15'h3B0F, 15'h3B25, 15'h3B3C, 15'h3B52, 15'h3B68, 15'h3B7F, 15'h3B95, 15'h3BAB, 15'h3BC1, 15'h3BD7, 15'h3BEE, 15'h3C04, 15'h3C1A, 15'h3C30, 15'h3C47,
15'h3C5D, 15'h3C73, 15'h3C89, 15'h3C9F, 15'h3CB5, 15'h3CCB, 15'h3CE2, 15'h3CF8, 15'h3D0E, 15'h3D24, 15'h3D3A, 15'h3D50, 15'h3D66, 15'h3D7C, 15'h3D92, 15'h3DA8,
15'h3DBE, 15'h3DD4, 15'h3DEA, 15'h3E00, 15'h3E16, 15'h3E2C, 15'h3E42, 15'h3E58, 15'h3E6E, 15'h3E84, 15'h3E9A, 15'h3EB0, 15'h3EC6, 15'h3EDC, 15'h3EF2, 15'h3F08,
15'h3F1D, 15'h3F33, 15'h3F49, 15'h3F5F, 15'h3F75, 15'h3F8B, 15'h3FA1, 15'h3FB6, 15'h3FCC, 15'h3FE2, 15'h3FF8, 15'h400E, 15'h4023, 15'h4039, 15'h404F, 15'h4065,
15'h407A, 15'h4090, 15'h40A6, 15'h40BB, 15'h40D1, 15'h40E7, 15'h40FC, 15'h4112, 15'h4128, 15'h413D, 15'h4153, 15'h4169, 15'h417E, 15'h4194, 15'h41A9, 15'h41BF,
15'h41D5, 15'h41EA, 15'h4200, 15'h4215, 15'h422B, 15'h4240, 15'h4256, 15'h426B, 15'h4281, 15'h4296, 15'h42AC, 15'h42C1, 15'h42D7, 15'h42EC, 15'h4301, 15'h4317,
15'h432C, 15'h4342, 15'h4357, 15'h436C, 15'h4382, 15'h4397, 15'h43AC, 15'h43C2, 15'h43D7, 15'h43EC, 15'h4402, 15'h4417, 15'h442C, 15'h4442, 15'h4457, 15'h446C,
15'h4481, 15'h4497, 15'h44AC, 15'h44C1, 15'h44D6, 15'h44EB, 15'h4501, 15'h4516, 15'h452B, 15'h4540, 15'h4555, 15'h456A, 15'h4580, 15'h4595, 15'h45AA, 15'h45BF,
15'h45D4, 15'h45E9, 15'h45FE, 15'h4613, 15'h4628, 15'h463D, 15'h4652, 15'h4667, 15'h467C, 15'h4691, 15'h46A6, 15'h46BB, 15'h46D0, 15'h46E5, 15'h46FA, 15'h470F,
15'h4724, 15'h4739, 15'h474D, 15'h4762, 15'h4777, 15'h478C, 15'h47A1, 15'h47B6, 15'h47CB, 15'h47DF, 15'h47F4, 15'h4809, 15'h481E, 15'h4833, 15'h4847, 15'h485C,
15'h4871, 15'h4885, 15'h489A, 15'h48AF, 15'h48C4, 15'h48D8, 15'h48ED, 15'h4902, 15'h4916, 15'h492B, 15'h4940, 15'h4954, 15'h4969, 15'h497D, 15'h4992, 15'h49A6,
15'h49BB, 15'h49D0, 15'h49E4, 15'h49F9, 15'h4A0D, 15'h4A22, 15'h4A36, 15'h4A4B, 15'h4A5F, 15'h4A74, 15'h4A88, 15'h4A9C, 15'h4AB1, 15'h4AC5, 15'h4ADA, 15'h4AEE,
15'h4B02, 15'h4B17, 15'h4B2B, 15'h4B40, 15'h4B54, 15'h4B68, 15'h4B7C, 15'h4B91, 15'h4BA5, 15'h4BB9, 15'h4BCE, 15'h4BE2, 15'h4BF6, 15'h4C0A, 15'h4C1F, 15'h4C33,
15'h4C47, 15'h4C5B, 15'h4C6F, 15'h4C84, 15'h4C98, 15'h4CAC, 15'h4CC0, 15'h4CD4, 15'h4CE8, 15'h4CFC, 15'h4D10, 15'h4D24, 15'h4D38, 15'h4D4C, 15'h4D61, 15'h4D75,
15'h4D89, 15'h4D9D, 15'h4DB1, 15'h4DC5, 15'h4DD8, 15'h4DEC, 15'h4E00, 15'h4E14, 15'h4E28, 15'h4E3C, 15'h4E50, 15'h4E64, 15'h4E78, 15'h4E8C, 15'h4E9F, 15'h4EB3,
15'h4EC7, 15'h4EDB, 15'h4EEF, 15'h4F03, 15'h4F16, 15'h4F2A, 15'h4F3E, 15'h4F52, 15'h4F65, 15'h4F79, 15'h4F8D, 15'h4FA0, 15'h4FB4, 15'h4FC8, 15'h4FDB, 15'h4FEF,
15'h5003, 15'h5016, 15'h502A, 15'h503E, 15'h5051, 15'h5065, 15'h5078, 15'h508C, 15'h509F, 15'h50B3, 15'h50C6, 15'h50DA, 15'h50ED, 15'h5101, 15'h5114, 15'h5128,
15'h513B, 15'h514F, 15'h5162, 15'h5175, 15'h5189, 15'h519C, 15'h51B0, 15'h51C3, 15'h51D6, 15'h51EA, 15'h51FD, 15'h5210, 15'h5223, 15'h5237, 15'h524A, 15'h525D,
15'h5270, 15'h5284, 15'h5297, 15'h52AA, 15'h52BD, 15'h52D1, 15'h52E4, 15'h52F7, 15'h530A, 15'h531D, 15'h5330, 15'h5343, 15'h5356, 15'h5369, 15'h537D, 15'h5390,
15'h53A3, 15'h53B6, 15'h53C9, 15'h53DC, 15'h53EF, 15'h5402, 15'h5415, 15'h5428, 15'h543B, 15'h544D, 15'h5460, 15'h5473, 15'h5486, 15'h5499, 15'h54AC, 15'h54BF,
15'h54D2, 15'h54E4, 15'h54F7, 15'h550A, 15'h551D, 15'h5530, 15'h5542, 15'h5555, 15'h5568, 15'h557B, 15'h558D, 15'h55A0, 15'h55B3, 15'h55C5, 15'h55D8, 15'h55EB,
15'h55FD, 15'h5610, 15'h5622, 15'h5635, 15'h5648, 15'h565A, 15'h566D, 15'h567F, 15'h5692, 15'h56A4, 15'h56B7, 15'h56C9, 15'h56DC, 15'h56EE, 15'h5701, 15'h5713,
15'h5726, 15'h5738, 15'h574A, 15'h575D, 15'h576F, 15'h5781, 15'h5794, 15'h57A6, 15'h57B8, 15'h57CB, 15'h57DD, 15'h57EF, 15'h5802, 15'h5814, 15'h5826, 15'h5838,
15'h584A, 15'h585D, 15'h586F, 15'h5881, 15'h5893, 15'h58A5, 15'h58B7, 15'h58CA, 15'h58DC, 15'h58EE, 15'h5900, 15'h5912, 15'h5924, 15'h5936, 15'h5948, 15'h595A,
15'h596C, 15'h597E, 15'h5990, 15'h59A2, 15'h59B4, 15'h59C6, 15'h59D8, 15'h59EA, 15'h59FC, 15'h5A0D, 15'h5A1F, 15'h5A31, 15'h5A43, 15'h5A55, 15'h5A67, 15'h5A78,
15'h5A8A, 15'h5A9C, 15'h5AAE, 15'h5ABF, 15'h5AD1, 15'h5AE3, 15'h5AF5, 15'h5B06, 15'h5B18, 15'h5B2A, 15'h5B3B, 15'h5B4D, 15'h5B5E, 15'h5B70, 15'h5B82, 15'h5B93,
15'h5BA5, 15'h5BB6, 15'h5BC8, 15'h5BD9, 15'h5BEB, 15'h5BFC, 15'h5C0E, 15'h5C1F, 15'h5C31, 15'h5C42, 15'h5C54, 15'h5C65, 15'h5C76, 15'h5C88, 15'h5C99, 15'h5CAB,
15'h5CBC, 15'h5CCD, 15'h5CDE, 15'h5CF0, 15'h5D01, 15'h5D12, 15'h5D24, 15'h5D35, 15'h5D46, 15'h5D57, 15'h5D68, 15'h5D7A, 15'h5D8B, 15'h5D9C, 15'h5DAD, 15'h5DBE,
15'h5DCF, 15'h5DE0, 15'h5DF2, 15'h5E03, 15'h5E14, 15'h5E25, 15'h5E36, 15'h5E47, 15'h5E58, 15'h5E69, 15'h5E7A, 15'h5E8B, 15'h5E9C, 15'h5EAD, 15'h5EBD, 15'h5ECE,
15'h5EDF, 15'h5EF0, 15'h5F01, 15'h5F12, 15'h5F23, 15'h5F33, 15'h5F44, 15'h5F55, 15'h5F66, 15'h5F77, 15'h5F87, 15'h5F98, 15'h5FA9, 15'h5FB9, 15'h5FCA, 15'h5FDB,
15'h5FEB, 15'h5FFC, 15'h600D, 15'h601D, 15'h602E, 15'h603E, 15'h604F, 15'h6060, 15'h6070, 15'h6081, 15'h6091, 15'h60A2, 15'h60B2, 15'h60C3, 15'h60D3, 15'h60E4,
15'h60F4, 15'h6104, 15'h6115, 15'h6125, 15'h6135, 15'h6146, 15'h6156, 15'h6166, 15'h6177, 15'h6187, 15'h6197, 15'h61A8, 15'h61B8, 15'h61C8, 15'h61D8, 15'h61E9,
15'h61F9, 15'h6209, 15'h6219, 15'h6229, 15'h6239, 15'h6249, 15'h625A, 15'h626A, 15'h627A, 15'h628A, 15'h629A, 15'h62AA, 15'h62BA, 15'h62CA, 15'h62DA, 15'h62EA,
15'h62FA, 15'h630A, 15'h631A, 15'h6329, 15'h6339, 15'h6349, 15'h6359, 15'h6369, 15'h6379, 15'h6389, 15'h6398, 15'h63A8, 15'h63B8, 15'h63C8, 15'h63D7, 15'h63E7,
15'h63F7, 15'h6407, 15'h6416, 15'h6426, 15'h6436, 15'h6445, 15'h6455, 15'h6464, 15'h6474, 15'h6484, 15'h6493, 15'h64A3, 15'h64B2, 15'h64C2, 15'h64D1, 15'h64E1,
15'h64F0, 15'h6500, 15'h650F, 15'h651F, 15'h652E, 15'h653D, 15'h654D, 15'h655C, 15'h656B, 15'h657B, 15'h658A, 15'h6599, 15'h65A9, 15'h65B8, 15'h65C7, 15'h65D6,
15'h65E6, 15'h65F5, 15'h6604, 15'h6613, 15'h6622, 15'h6631, 15'h6641, 15'h6650, 15'h665F, 15'h666E, 15'h667D, 15'h668C, 15'h669B, 15'h66AA, 15'h66B9, 15'h66C8,
15'h66D7, 15'h66E6, 15'h66F5, 15'h6704, 15'h6713, 15'h6722, 15'h6731, 15'h673F, 15'h674E, 15'h675D, 15'h676C, 15'h677B, 15'h678A, 15'h6798, 15'h67A7, 15'h67B6,
15'h67C5, 15'h67D3, 15'h67E2, 15'h67F1, 15'h67FF, 15'h680E, 15'h681D, 15'h682B, 15'h683A, 15'h6848, 15'h6857, 15'h6866, 15'h6874, 15'h6883, 15'h6891, 15'h68A0,
15'h68AE, 15'h68BD, 15'h68CB, 15'h68D9, 15'h68E8, 15'h68F6, 15'h6905, 15'h6913, 15'h6921, 15'h6930, 15'h693E, 15'h694C, 15'h695B, 15'h6969, 15'h6977, 15'h6985,
15'h6994, 15'h69A2, 15'h69B0, 15'h69BE, 15'h69CC, 15'h69DA, 15'h69E9, 15'h69F7, 15'h6A05, 15'h6A13, 15'h6A21, 15'h6A2F, 15'h6A3D, 15'h6A4B, 15'h6A59, 15'h6A67,
15'h6A75, 15'h6A83, 15'h6A91, 15'h6A9F, 15'h6AAD, 15'h6ABB, 15'h6AC8, 15'h6AD6, 15'h6AE4, 15'h6AF2, 15'h6B00, 15'h6B0E, 15'h6B1B, 15'h6B29, 15'h6B37, 15'h6B45,
15'h6B52, 15'h6B60, 15'h6B6E, 15'h6B7B, 15'h6B89, 15'h6B97, 15'h6BA4, 15'h6BB2, 15'h6BBF, 15'h6BCD, 15'h6BDA, 15'h6BE8, 15'h6BF6, 15'h6C03, 15'h6C11, 15'h6C1E,
15'h6C2B, 15'h6C39, 15'h6C46, 15'h6C54, 15'h6C61, 15'h6C6E, 15'h6C7C, 15'h6C89, 15'h6C96, 15'h6CA4, 15'h6CB1, 15'h6CBE, 15'h6CCC, 15'h6CD9, 15'h6CE6, 15'h6CF3,
15'h6D00, 15'h6D0E, 15'h6D1B, 15'h6D28, 15'h6D35, 15'h6D42, 15'h6D4F, 15'h6D5C, 15'h6D69, 15'h6D76, 15'h6D83, 15'h6D90, 15'h6D9D, 15'h6DAA, 15'h6DB7, 15'h6DC4,
15'h6DD1, 15'h6DDE, 15'h6DEB, 15'h6DF8, 15'h6E05, 15'h6E12, 15'h6E1E, 15'h6E2B, 15'h6E38, 15'h6E45, 15'h6E52, 15'h6E5E, 15'h6E6B, 15'h6E78, 15'h6E84, 15'h6E91,
15'h6E9E, 15'h6EAA, 15'h6EB7, 15'h6EC4, 15'h6ED0, 15'h6EDD, 15'h6EE9, 15'h6EF6, 15'h6F02, 15'h6F0F, 15'h6F1B, 15'h6F28, 15'h6F34, 15'h6F41, 15'h6F4D, 15'h6F5A,
15'h6F66, 15'h6F72, 15'h6F7F, 15'h6F8B, 15'h6F97, 15'h6FA4, 15'h6FB0, 15'h6FBC, 15'h6FC8, 15'h6FD5, 15'h6FE1, 15'h6FED, 15'h6FF9, 15'h7006, 15'h7012, 15'h701E,
15'h702A, 15'h7036, 15'h7042, 15'h704E, 15'h705A, 15'h7066, 15'h7072, 15'h707E, 15'h708A, 15'h7096, 15'h70A2, 15'h70AE, 15'h70BA, 15'h70C6, 15'h70D2, 15'h70DE,
15'h70EA, 15'h70F5, 15'h7101, 15'h710D, 15'h7119, 15'h7125, 15'h7130, 15'h713C, 15'h7148, 15'h7153, 15'h715F, 15'h716B, 15'h7176, 15'h7182, 15'h718E, 15'h7199,
15'h71A5, 15'h71B0, 15'h71BC, 15'h71C7, 15'h71D3, 15'h71DE, 15'h71EA, 15'h71F5, 15'h7201, 15'h720C, 15'h7218, 15'h7223, 15'h722E, 15'h723A, 15'h7245, 15'h7250,
15'h725C, 15'h7267, 15'h7272, 15'h727E, 15'h7289, 15'h7294, 15'h729F, 15'h72AA, 15'h72B6, 15'h72C1, 15'h72CC, 15'h72D7, 15'h72E2, 15'h72ED, 15'h72F8, 15'h7303,
15'h730E, 15'h7319, 15'h7324, 15'h732F, 15'h733A, 15'h7345, 15'h7350, 15'h735B, 15'h7366, 15'h7371, 15'h737B, 15'h7386, 15'h7391, 15'h739C, 15'h73A7, 15'h73B1,
15'h73BC, 15'h73C7, 15'h73D2, 15'h73DC, 15'h73E7, 15'h73F2, 15'h73FC, 15'h7407, 15'h7412, 15'h741C, 15'h7427, 15'h7431, 15'h743C, 15'h7446, 15'h7451, 15'h745B,
15'h7466, 15'h7470, 15'h747B, 15'h7485, 15'h7490, 15'h749A, 15'h74A4, 15'h74AF, 15'h74B9, 15'h74C3, 15'h74CE, 15'h74D8, 15'h74E2, 15'h74EC, 15'h74F7, 15'h7501,
15'h750B, 15'h7515, 15'h751F, 15'h7529, 15'h7533, 15'h753E, 15'h7548, 15'h7552, 15'h755C, 15'h7566, 15'h7570, 15'h757A, 15'h7584, 15'h758E, 15'h7598, 15'h75A2,
15'h75AB, 15'h75B5, 15'h75BF, 15'h75C9, 15'h75D3, 15'h75DD, 15'h75E6, 15'h75F0, 15'h75FA, 15'h7604, 15'h760D, 15'h7617, 15'h7621, 15'h762B, 15'h7634, 15'h763E,
15'h7647, 15'h7651, 15'h765B, 15'h7664, 15'h766E, 15'h7677, 15'h7681, 15'h768A, 15'h7694, 15'h769D, 15'h76A7, 15'h76B0, 15'h76B9, 15'h76C3, 15'h76CC, 15'h76D6,
15'h76DF, 15'h76E8, 15'h76F2, 15'h76FB, 15'h7704, 15'h770D, 15'h7717, 15'h7720, 15'h7729, 15'h7732, 15'h773B, 15'h7744, 15'h774E, 15'h7757, 15'h7760, 15'h7769,
15'h7772, 15'h777B, 15'h7784, 15'h778D, 15'h7796, 15'h779F, 15'h77A8, 15'h77B1, 15'h77BA, 15'h77C2, 15'h77CB, 15'h77D4, 15'h77DD, 15'h77E6, 15'h77EF, 15'h77F7,
15'h7800, 15'h7809, 15'h7812, 15'h781A, 15'h7823, 15'h782C, 15'h7834, 15'h783D, 15'h7845, 15'h784E, 15'h7857, 15'h785F, 15'h7868, 15'h7870, 15'h7879, 15'h7881,
15'h788A, 15'h7892, 15'h789B, 15'h78A3, 15'h78AB, 15'h78B4, 15'h78BC, 15'h78C4, 15'h78CD, 15'h78D5, 15'h78DD, 15'h78E6, 15'h78EE, 15'h78F6, 15'h78FE, 15'h7906,
15'h790F, 15'h7917, 15'h791F, 15'h7927, 15'h792F, 15'h7937, 15'h793F, 15'h7947, 15'h794F, 15'h7957, 15'h795F, 15'h7967, 15'h796F, 15'h7977, 15'h797F, 15'h7987,
15'h798F, 15'h7997, 15'h799F, 15'h79A7, 15'h79AE, 15'h79B6, 15'h79BE, 15'h79C6, 15'h79CD, 15'h79D5, 15'h79DD, 15'h79E4, 15'h79EC, 15'h79F4, 15'h79FB, 15'h7A03,
15'h7A0B, 15'h7A12, 15'h7A1A, 15'h7A21, 15'h7A29, 15'h7A30, 15'h7A38, 15'h7A3F, 15'h7A47, 15'h7A4E, 15'h7A55, 15'h7A5D, 15'h7A64, 15'h7A6C, 15'h7A73, 15'h7A7A,
15'h7A81, 15'h7A89, 15'h7A90, 15'h7A97, 15'h7A9E, 15'h7AA6, 15'h7AAD, 15'h7AB4, 15'h7ABB, 15'h7AC2, 15'h7AC9, 15'h7AD0, 15'h7AD8, 15'h7ADF, 15'h7AE6, 15'h7AED,
15'h7AF4, 15'h7AFB, 15'h7B02, 15'h7B09, 15'h7B0F, 15'h7B16, 15'h7B1D, 15'h7B24, 15'h7B2B, 15'h7B32, 15'h7B39, 15'h7B3F, 15'h7B46, 15'h7B4D, 15'h7B54, 15'h7B5A,
15'h7B61, 15'h7B68, 15'h7B6E, 15'h7B75, 15'h7B7C, 15'h7B82, 15'h7B89, 15'h7B8F, 15'h7B96, 15'h7B9D, 15'h7BA3, 15'h7BAA, 15'h7BB0, 15'h7BB7, 15'h7BBD, 15'h7BC3,
15'h7BCA, 15'h7BD0, 15'h7BD7, 15'h7BDD, 15'h7BE3, 15'h7BE9, 15'h7BF0, 15'h7BF6, 15'h7BFC, 15'h7C03, 15'h7C09, 15'h7C0F, 15'h7C15, 15'h7C1B, 15'h7C21, 15'h7C28,
15'h7C2E, 15'h7C34, 15'h7C3A, 15'h7C40, 15'h7C46, 15'h7C4C, 15'h7C52, 15'h7C58, 15'h7C5E, 15'h7C64, 15'h7C6A, 15'h7C70, 15'h7C75, 15'h7C7B, 15'h7C81, 15'h7C87,
15'h7C8D, 15'h7C93, 15'h7C98, 15'h7C9E, 15'h7CA4, 15'h7CA9, 15'h7CAF, 15'h7CB5, 15'h7CBB, 15'h7CC0, 15'h7CC6, 15'h7CCB, 15'h7CD1, 15'h7CD6, 15'h7CDC, 15'h7CE2,
15'h7CE7, 15'h7CED, 15'h7CF2, 15'h7CF7, 15'h7CFD, 15'h7D02, 15'h7D08, 15'h7D0D, 15'h7D12, 15'h7D18, 15'h7D1D, 15'h7D22, 15'h7D28, 15'h7D2D, 15'h7D32, 15'h7D37,
15'h7D3D, 15'h7D42, 15'h7D47, 15'h7D4C, 15'h7D51, 15'h7D56, 15'h7D5B, 15'h7D60, 15'h7D65, 15'h7D6A, 15'h7D70, 15'h7D74, 15'h7D79, 15'h7D7E, 15'h7D83, 15'h7D88,
15'h7D8D, 15'h7D92, 15'h7D97, 15'h7D9C, 15'h7DA1, 15'h7DA5, 15'h7DAA, 15'h7DAF, 15'h7DB4, 15'h7DB8, 15'h7DBD, 15'h7DC2, 15'h7DC6, 15'h7DCB, 15'h7DD0, 15'h7DD4,
15'h7DD9, 15'h7DDE, 15'h7DE2, 15'h7DE7, 15'h7DEB, 15'h7DF0, 15'h7DF4, 15'h7DF9, 15'h7DFD, 15'h7E01, 15'h7E06, 15'h7E0A, 15'h7E0F, 15'h7E13, 15'h7E17, 15'h7E1C,
15'h7E20, 15'h7E24, 15'h7E28, 15'h7E2D, 15'h7E31, 15'h7E35, 15'h7E39, 15'h7E3D, 15'h7E42, 15'h7E46, 15'h7E4A, 15'h7E4E, 15'h7E52, 15'h7E56, 15'h7E5A, 15'h7E5E,
15'h7E62, 15'h7E66, 15'h7E6A, 15'h7E6E, 15'h7E72, 15'h7E76, 15'h7E7A, 15'h7E7D, 15'h7E81, 15'h7E85, 15'h7E89, 15'h7E8D, 15'h7E90, 15'h7E94, 15'h7E98, 15'h7E9C,
15'h7E9F, 15'h7EA3, 15'h7EA6, 15'h7EAA, 15'h7EAE, 15'h7EB1, 15'h7EB5, 15'h7EB8, 15'h7EBC, 15'h7EBF, 15'h7EC3, 15'h7EC6, 15'h7ECA, 15'h7ECD, 15'h7ED1, 15'h7ED4,
15'h7ED7, 15'h7EDB, 15'h7EDE, 15'h7EE2, 15'h7EE5, 15'h7EE8, 15'h7EEB, 15'h7EEF, 15'h7EF2, 15'h7EF5, 15'h7EF8, 15'h7EFB, 15'h7EFF, 15'h7F02, 15'h7F05, 15'h7F08,
15'h7F0B, 15'h7F0E, 15'h7F11, 15'h7F14, 15'h7F17, 15'h7F1A, 15'h7F1D, 15'h7F20, 15'h7F23, 15'h7F26, 15'h7F29, 15'h7F2B, 15'h7F2E, 15'h7F31, 15'h7F34, 15'h7F37,
15'h7F39, 15'h7F3C, 15'h7F3F, 15'h7F42, 15'h7F44, 15'h7F47, 15'h7F4A, 15'h7F4C, 15'h7F4F, 15'h7F51, 15'h7F54, 15'h7F57, 15'h7F59, 15'h7F5C, 15'h7F5E, 15'h7F61,
15'h7F63, 15'h7F65, 15'h7F68, 15'h7F6A, 15'h7F6D, 15'h7F6F, 15'h7F71, 15'h7F74, 15'h7F76, 15'h7F78, 15'h7F7B, 15'h7F7D, 15'h7F7F, 15'h7F81, 15'h7F83, 15'h7F86,
15'h7F88, 15'h7F8A, 15'h7F8C, 15'h7F8E, 15'h7F90, 15'h7F92, 15'h7F94, 15'h7F96, 15'h7F98, 15'h7F9A, 15'h7F9C, 15'h7F9E, 15'h7FA0, 15'h7FA2, 15'h7FA4, 15'h7FA6,
15'h7FA7, 15'h7FA9, 15'h7FAB, 15'h7FAD, 15'h7FAF, 15'h7FB0, 15'h7FB2, 15'h7FB4, 15'h7FB6, 15'h7FB7, 15'h7FB9, 15'h7FBA, 15'h7FBC, 15'h7FBE, 15'h7FBF, 15'h7FC1,
15'h7FC2, 15'h7FC4, 15'h7FC5, 15'h7FC7, 15'h7FC8, 15'h7FCA, 15'h7FCB, 15'h7FCD, 15'h7FCE, 15'h7FCF, 15'h7FD1, 15'h7FD2, 15'h7FD3, 15'h7FD4, 15'h7FD6, 15'h7FD7,
15'h7FD8, 15'h7FD9, 15'h7FDB, 15'h7FDC, 15'h7FDD, 15'h7FDE, 15'h7FDF, 15'h7FE0, 15'h7FE1, 15'h7FE2, 15'h7FE3, 15'h7FE4, 15'h7FE5, 15'h7FE6, 15'h7FE7, 15'h7FE8,
15'h7FE9, 15'h7FEA, 15'h7FEB, 15'h7FEC, 15'h7FED, 15'h7FED, 15'h7FEE, 15'h7FEF, 15'h7FF0, 15'h7FF1, 15'h7FF1, 15'h7FF2, 15'h7FF3, 15'h7FF3, 15'h7FF4, 15'h7FF5,
15'h7FF5, 15'h7FF6, 15'h7FF6, 15'h7FF7, 15'h7FF7, 15'h7FF8, 15'h7FF8, 15'h7FF9, 15'h7FF9, 15'h7FFA, 15'h7FFA, 15'h7FFB, 15'h7FFB, 15'h7FFB, 15'h7FFC, 15'h7FFC,
15'h7FFC, 15'h7FFD, 15'h7FFD, 15'h7FFD, 15'h7FFD, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFE, 15'h7FFF
};
endmodule

253
rtl/sound/gs.v Normal file
View File

@ -0,0 +1,253 @@
/*
-----------------------------------------------------------------------------
General Sound
-----------------------------------------------------------------------------
18.08.2018 Reworked first verilog version
19.08.2018 Produce proper signed output
20.08.2018 Use external SDR/DDR RAM for page 2 and up
CPU: Z80 @ 28MHz
ROM: 32K
RAM: up to 4096KB
INT: 37.5KHz
#xxBB Command register - регистр команд, доступный для записи
#xxBB Status register - регистр состояния, доступный для чтения
bit 7 флаг данных
bit <6:1> Не определен
bit 0 флаг команд. Этот регистр позволяет определить состояние GS, в частности можно ли прочитать или записать очередной байт данных, или подать очередную команду, и т.п.
#xxB3 Data register - регистр данных, доступный для записи. В этот регистр Спектрум записывает данные, например, это могут быть аргументы команд.
#xxB3 Output register - регистр вывода, доступный для чтения. Из этого регистра Спектрум читает данные, идущие от GS
Внутренние порта:
#xx00 "расширенная память" - регистр доступный для записи
bit <3:0> переключают страницы по 32Kb, страница 0 - ПЗУ
bit <7:0> не используются
порты 1 - 5 "обеспечивают связь с SPECTRUM'ом"
#xx01 чтение команды General Sound'ом
bit <7:0> код команды
#xx02 чтение данных General Sound'ом
bit <7:0> данные
#xx03 запись данных General Sound'ом для SPECTRUM'a
bit <7:0> данные
#xx04 чтение слова состояния General Sound'ом
bit 0 флаг команд
bit 7 флаг данных
#xx05 сбрасывает бит D0 (флаг команд) слова состояния
порты 6 - 9 "регулировка громкости" в каналах 1 - 4
#xx06 "регулировка громкости" в канале 1
bit <5:0> громкость
bit <7:6> не используются
#xx07 "регулировка громкости" в канале 2
bit <5:0> громкость
bit <7:6> не используются
#xx08 "регулировка громкости" в канале 3
bit <5:0> громкость
bit <7:6> не используются
#xx09 "регулировка громкости" в канале 4
bit <5:0> громкость
bit <7:6> не используются
#xx0A устанавливает бит 7 слова состояния не равным биту 0 порта #xx00
#xx0B устанавливает бит 0 слова состояния равным биту 5 порта #xx06
Распределение памяти
#0000 - #3FFF - первые 16Kb ПЗУ
#4000 - #7FFF - первые 16Kb первой страницы ОЗУ
#8000 - #FFFF - листаемые страницы по 32Kb
страница 0 - ПЗУ,
страница 1 - первая страница ОЗУ
страницы 2... ОЗУ
Данные в каналы заносятся при чтении процессором ОЗУ по адресам #6000 - #7FFF автоматически.
*/
module gs #(parameter ROMFILE="gs105b.mif")
(
input RESET,
input CLK,
input CE,
input A,
input [7:0] DI,
output [7:0] DO,
input CS_n,
input WR_n,
input RD_n,
output [20:0] MEM_ADDR,
output [7:0] MEM_DI,
input [7:0] MEM_DO,
output MEM_RD,
output MEM_WR,
input MEM_WAIT,
output [14:0] OUTL,
output [14:0] OUTR
);
// port #xxBB : #xxB3
assign DO = A ? {bit7, 6'b111111, bit0} : port_03;
// CPU
reg int_n;
wire cpu_m1_n;
wire cpu_mreq_n;
wire cpu_iorq_n;
wire cpu_rd_n;
wire cpu_wr_n;
wire [15:0] cpu_a_bus;
wire [7:0] cpu_do_bus;
T80pa cpu
(
.RESET_n(~RESET),
.CLK(CLK),
.CEN_p(CE & ~MEM_WAIT),
.INT_n(int_n),
.M1_n(cpu_m1_n),
.MREQ_n(cpu_mreq_n),
.IORQ_n(cpu_iorq_n),
.RD_n(cpu_rd_n),
.WR_n(cpu_wr_n),
.A(cpu_a_bus),
.DO(cpu_do_bus),
.DI(cpu_di_bus)
);
// INT#
always @(posedge CLK) begin
reg [9:0] cnt;
if(CE) begin
cnt <= cnt + 1'b1;
if (cnt == 746) begin // 37.48kHz
cnt <= 0;
int_n <= 0;
end
end
if (~cpu_iorq_n & ~cpu_m1_n) int_n <= 1;
end
reg bit7;
reg bit0;
always @(posedge CLK) begin
if (~cpu_iorq_n & cpu_m1_n) begin
case(cpu_a_bus[3:0])
'h2: bit7 <= 0;
'h3: bit7 <= 1;
'h5: bit0 <= 0;
'hA: bit7 <= ~port_00[0];
'hB: bit0 <= port_09[5];
endcase
end
else if (~CS_n) begin
if (~A & ~RD_n) bit7 <= 0;
if (~A & ~WR_n) bit7 <= 1;
if ( A & ~WR_n) bit0 <= 1;
end
end
reg [7:0] port_BB;
reg [7:0] port_B3;
always @(posedge CLK) begin
if (RESET) begin
port_BB <= 0;
port_B3 <= 0;
end
else if (~CS_n && ~WR_n) begin
if(A) port_BB <= DI;
else port_B3 <= DI;
end
end
reg [5:0] port_00;
reg [7:0] port_03;
reg signed [6:0] port_06, port_07, port_08, port_09;
reg signed [7:0] ch_a, ch_b, ch_c, ch_d;
always @(posedge CLK) begin
if (RESET) begin
port_00 <= 0;
port_03 <= 0;
end
else begin
if (~cpu_iorq_n & ~cpu_wr_n) begin
case(cpu_a_bus[3:0])
0: port_00 <= cpu_do_bus[5:0];
3: port_03 <= cpu_do_bus;
6: port_06 <= cpu_do_bus[5:0];
7: port_07 <= cpu_do_bus[5:0];
8: port_08 <= cpu_do_bus[5:0];
9: port_09 <= cpu_do_bus[5:0];
endcase
end
if (~cpu_mreq_n && ~cpu_rd_n && cpu_a_bus[15:13] == 3) begin
case(cpu_a_bus[9:8])
0: ch_a <= {~mem_do[7],mem_do[6:0]};
1: ch_b <= {~mem_do[7],mem_do[6:0]};
2: ch_c <= {~mem_do[7],mem_do[6:0]};
3: ch_d <= {~mem_do[7],mem_do[6:0]};
endcase
end
end
end
wire [7:0] cpu_di_bus =
(~cpu_mreq_n && ~cpu_rd_n && !page_addr[5:1]) ? mem_do :
(~cpu_mreq_n && ~cpu_rd_n) ? MEM_DO :
(~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus[3:0] == 1) ? port_BB :
(~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus[3:0] == 2) ? port_B3 :
(~cpu_iorq_n && ~cpu_rd_n && cpu_a_bus[3:0] == 4) ? {bit7, 6'b111111, bit0} :
8'hFF;
wire mem_wr = ~cpu_wr_n & ~cpu_mreq_n & |page_addr;
wire mem_rd = ~cpu_rd_n & ~cpu_mreq_n;
wire [5:0] page_addr = cpu_a_bus[15] ? port_00 : cpu_a_bus[14];
assign MEM_ADDR = {page_addr, &cpu_a_bus[15:14], cpu_a_bus[13:0]};
assign MEM_RD = mem_rd && |page_addr[5:1];
assign MEM_WR = mem_wr && |page_addr[5:1];
assign MEM_DI = cpu_do_bus;
wire [7:0] mem_do;
dpram #(.ADDRWIDTH(16), .MEM_INIT_FILE(ROMFILE)) mem
(
.clock(CLK),
.address_a(MEM_ADDR[15:0]),
.wren_a(mem_wr && !page_addr[5:1]),
.data_a(cpu_do_bus),
.q_a(mem_do)
);
reg signed [14:0] out_a,out_b,out_c,out_d;
always @(posedge CLK) begin
if(CE) begin
out_a <= ch_a * port_06;
out_b <= ch_b * port_07;
out_c <= ch_c * port_08;
out_d <= ch_d * port_09;
end
end
reg signed [14:0] outl, outr;
always @(posedge CLK) begin
if(CE) begin
outl <= out_a + out_b;
outr <= out_c + out_d;
end
end
assign OUTL = outl;
assign OUTR = outr;
endmodule

1383
rtl/sound/gs105b.mif Normal file

File diff suppressed because it is too large Load Diff

21
rtl/sound/jt12/jt12.qip Normal file
View File

@ -0,0 +1,21 @@
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_acc.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_clksync.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_eg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_exprom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_kon.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_lfo.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_limitamp.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mmr.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_mod.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_op.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_opram.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_pg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_phrom.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_reg.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh_rst.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sh24.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_sumch.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_syn.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jt12_timers.v ]

116
rtl/sound/jt12/jt12.v Normal file
View File

@ -0,0 +1,116 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Based on information provided by
Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Nemesis reports, based on measurements
Comparisons with real hardware lent by Mikes (Va de retro)
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 1-4-2017
Use tab = 4 spaces
*/
// syn_clk "1.285714"
module jt12(
input rst,
// CPU interface
input cpu_clk,
input [7:0] cpu_din,
input [1:0] cpu_addr,
input cpu_cs_n,
input cpu_wr_n,
input cpu_limiter_en,
output [7:0] cpu_dout,
output cpu_irq_n,
// Synthesizer clock domain
input syn_clk,
// combined output
output signed [11:0] syn_snd_right,
output signed [11:0] syn_snd_left,
output syn_snd_sample,
// multiplexed output
output signed [8:0] syn_mux_right,
output signed [8:0] syn_mux_left,
output syn_mux_sample
);
// Timers
wire syn_flag_A, syn_flag_B;
wire [7:0] syn_din;
wire [1:0] syn_addr;
wire syn_write, syn_limiter_en, syn_busy;
wire syn_rst, syn_irq_n;
jt12_clksync u_clksync(
.rst ( rst ),
.cpu_clk ( cpu_clk ),
.syn_clk ( syn_clk ),
// CPU interface
.cpu_din ( cpu_din ),
.cpu_addr ( cpu_addr ),
.cpu_dout ( cpu_dout ),
.cpu_cs_n ( cpu_cs_n ),
.cpu_wr_n ( cpu_wr_n ),
.cpu_irq_n ( cpu_irq_n ),
.cpu_limiter_en( cpu_limiter_en ),
// Synthesizer interface
.syn_rst ( syn_rst ),
.syn_write ( syn_write ),
.syn_din ( syn_din ),
.syn_addr ( syn_addr ),
.syn_limiter_en( syn_limiter_en ),
.syn_busy ( syn_busy ),
.syn_flag_A ( syn_flag_A),
.syn_flag_B ( syn_flag_B),
.syn_irq_n ( syn_irq_n )
);
jt12_syn u_syn(
.rst ( syn_rst ),
.clk ( syn_clk ),
.din ( syn_din ),
.addr ( syn_addr ),
.busy ( syn_busy ),
.flag_A ( syn_flag_A),
.flag_B ( syn_flag_B),
.write ( syn_write ),
.limiter_en ( syn_limiter_en),
.irq_n ( syn_irq_n ),
// Mixed sound
.snd_right ( syn_snd_right ),
.snd_left ( syn_snd_left ),
.snd_sample ( syn_snd_sample),
// Multiplexed sound
.mux_right ( syn_mux_right ),
.mux_left ( syn_mux_left ),
.mux_sample ( syn_mux_sample)
);
endmodule

178
rtl/sound/jt12/jt12_acc.v Normal file
View File

@ -0,0 +1,178 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
Each channel can use the full range of the DAC as they do not
get summed in the real chip.
*/
`timescale 1ns / 1ps
module jt12_acc
(
input rst,
input clk,
input signed [8:0] op_result,
input [ 1:0] rl,
input limiter_en, // enables the limiter on
// the accumulator to prevent overfow.
// I reckon that:
// YM2612 had a limiter
// YM3438 did not
// note that the order changes to deal
// with the operator pipeline delay
input s1_enters,
input s2_enters,
input s3_enters,
input s4_enters,
input ch6op,
input [2:0] alg,
input pcm_en, // only enabled for channel 6
input [8:0] pcm,
// combined output
output reg signed [11:0] left,
output reg signed [11:0] right,
output sample,
// multiplexed output
output reg signed [8:0] mux_left,
output reg signed [8:0] mux_right,
output reg mux_sample
);
reg signed [11:0] pre_left, pre_right;
wire signed [8:0] total;
reg sum_en;
always @(*) begin
case ( alg )
default: sum_en <= s4_enters;
3'd4: sum_en <= s2_enters | s4_enters;
3'd5,3'd6: sum_en <= ~s1_enters;
3'd7: sum_en <= 1'b1;
endcase
end
reg sum_all;
assign sample = ~sum_all;
wire [8:0] buffer;
reg [8:0] buffer2;
reg [8:0] buf_mux;
reg [1:0] rl2,rl3;
reg last_s1;
reg [1:0] mux_cnt;
wire signed [11:0] total_signext = { {3{total[8]}}, total };
always @(posedge clk) begin : mux_dac_input
buffer2 <= buffer;
rl2 <= rl;
last_s1 <= s1_enters;
mux_cnt <= last_s1 && s3_enters ? 2'd01 : mux_cnt + 1'b1;
if( mux_cnt==2'b11 ) begin
if( s1_enters || s3_enters ) begin
buf_mux <= buffer2;
rl3 <= rl2;
end
else begin
buf_mux <= buffer;
rl3 <= rl;
end
end
if( mux_cnt==2'd0 ) begin
mux_left <= rl3[1] ? buf_mux : 9'd0;
mux_right<= rl3[0] ? buf_mux : 9'd0;
mux_sample <= 1'b1;
end
else
mux_sample <= 1'b0;
end
always @(posedge clk) begin
if( rst ) begin
sum_all <= 1'b0;
end
else begin
if( s3_enters ) begin
sum_all <= 1'b1;
if( !sum_all ) begin
pre_right <= rl[0] ? total_signext : 12'd0;
pre_left <= rl[1] ? total_signext : 12'd0;
end
else begin
pre_right <= pre_right + (rl[0] ? total_signext : 12'd0);
pre_left <= pre_left + (rl[1] ? total_signext : 12'd0);
end
end
if( s2_enters ) begin
sum_all <= 1'b0;
left <= pre_left;
right <= pre_right;
`ifdef DUMPSOUND
$strobe("%d\t%d", left, right);
`endif
end
end
end
reg signed [8:0] next, opsum, prev;
wire signed [9:0] opsum10 = next+total;
always @(*) begin
next <= sum_en ? op_result : 9'd0;
if( s3_enters )
opsum <= (ch6op && pcm_en) ? { ~pcm[8], pcm[7:0] } : next;
else begin
if( sum_en && !(ch6op && pcm_en) )
if( limiter_en ) begin
if( opsum10[9]==opsum10[8] )
opsum <= opsum10[8:0];
else begin
opsum <= opsum10[9] ? 9'h100 : 9'h0ff;
end
end
else begin
// MSB is discarded according to
// YM3438 application notes
opsum <= opsum10[8:0];
end
else
opsum <= total;
end
end
jt12_sh #(.width(9),.stages(6)) u_acc(
.clk ( clk ),
.din ( opsum ),
.drop ( total )
);
jt12_sh #(.width(9),.stages(6)) u_buffer(
.clk ( clk ),
.din ( s3_enters ? total : buffer ),
.drop ( buffer )
);
endmodule

View File

@ -0,0 +1,106 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2017
*/
module jt12_clksync(
input rst,
input cpu_clk,
input syn_clk,
// CPU interface
input [7:0] cpu_din,
input [1:0] cpu_addr,
output[7:0] cpu_dout,
input cpu_cs_n,
input cpu_wr_n,
output cpu_irq_n,
input cpu_limiter_en,
// Synthesizer interface
output reg [7:0] syn_din,
output reg [1:0] syn_addr,
output reg syn_rst,
output reg syn_write,
output syn_limiter_en,
input syn_busy,
input syn_flag_A,
input syn_flag_B,
input syn_irq_n
);
// reset generation
reg rst_aux;
assign syn_limiter_en = cpu_limiter_en;
always @(negedge syn_clk or posedge rst)
if( rst ) begin
syn_rst <= 1'b1;
rst_aux <= 1'b1;
end
else begin
syn_rst <= rst_aux;
rst_aux <= 1'b0;
end
reg cpu_busy;
wire cpu_flag_B, cpu_flag_A;
assign cpu_dout = cpu_cs_n ? 8'hFF : { cpu_busy, 5'h0, cpu_flag_B, cpu_flag_A };
wire write_raw = !cpu_cs_n && !cpu_wr_n;
reg [1:0]busy_sh;
always @(posedge cpu_clk) begin
busy_sh <= { busy_sh[0], syn_busy };
end
jt12_sh #(.width(3),.stages(2) ) u_syn2cpu(
.clk ( cpu_clk ),
.din ( { syn_flag_B, syn_flag_A, syn_irq_n } ),
.drop ( { cpu_flag_B, cpu_flag_A, cpu_irq_n } )
);
always @(posedge cpu_clk) begin
reg old_write;
old_write <= write_raw;
if( rst ) begin
cpu_busy <= 1'b0;
end
else begin
if( ~old_write & write_raw ) begin
cpu_busy <= 1;
syn_write <= ~syn_write;
syn_addr <= cpu_addr;
syn_din <= cpu_din;
end
if(cpu_busy && busy_sh==2'b10) cpu_busy <= 0;
end
end
endmodule

621
rtl/sound/jt12/jt12_eg.v Normal file
View File

@ -0,0 +1,621 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2017
The non SSG-EG section is basically that of JT51's jt51_envelope.v
adapted to 6 channels, instead of the eight.
The SSG-EG is based on the works of Nemesis, published on
http://gendev.spritesmind.net/forum/search.php?st=0&sk=t&sd=d&sr=posts&keywords=SSG-EG&t=386&sf=msgonly&ch=-1&start=15
This module tries to replicate exactly the original YM2612 waveforms.
Nonetheless, the verilog code is not a replica of the original circuit
as there is no reverse engineering description of it.
Questions:
-I latch the SSG enable bit on keyon. I have to do this in order to ignore the inversion bit before the keyon
-If SSG enable is set to 0 by software before issueing a keyoff it will be ignored
-However, the other SSG bits will have an effect if changed in the meantime between keyon and keyoff
-Was YM2612 like that?
*/
`timescale 1ns / 1ps
/*
tab size 4
*/
module jt12_eg (
`ifdef TEST_SUPPORT
input test_eg,
`endif
input rst,
input clk,
input zero,
input eg_stop,
// envelope configuration
input [4:0] keycode_III,
input [4:0] arate_II, // attack rate
input [4:0] rate1_II, // decay rate
input [4:0] rate2_II, // sustain rate
input [3:0] rrate_II, // release rate
input [3:0] d1l, // sustain level
input [1:0] ks_III, // key scale
// SSG operation
input ssg_en_II,
input [2:0] ssg_eg_II,
// envelope operation
input keyon_II,
// envelope number
input [6:0] am,
input [6:0] tl_VII,
input [1:0] ams_VII,
input amsen_VII,
output reg [9:0] eg_IX,
output reg pg_rst_III
);
// eg[9:6] -> direct attenuation (divide by 2)
// eg[5:0] -> mantisa attenuation (uses LUT)
// 1 LSB of eg is -0.09257 dB
wire ssg_inv_II = ssg_eg_II[2] & ssg_en_II;
wire ssg_alt_II = ssg_eg_II[1] & ssg_en_II;
wire ssg_hold_II = ssg_eg_II[0] & ssg_en_II;
parameter ATTACK=3'd0, DECAY1=3'd1, DECAY2=3'd2, RELEASE=3'd7, HOLD=3'd3;
reg [4:0] d1level_II;
reg [9:0] eg_III, eg_IV, eg_V;
wire [9:0] eg_II;
reg step_V;
reg sum_up;
reg [5:0] rate_V;
// remember: { log_msb, pow_addr } <= log_val[11:0] + { tl, 5'd0 } + { eg, 2'd0 };
reg [1:0] eg_cnt_base;
reg [14:0] eg_cnt;
always @(posedge clk) begin : envelope_counter
if( rst ) begin
eg_cnt_base <= 2'd0;
eg_cnt <=15'd0;
end
else begin
if( zero ) begin
// envelope counter increases every 3 output samples,
// there is one sample every 32 clock ticks
if( eg_cnt_base == 2'd2 ) begin
eg_cnt <= eg_cnt + 1'b1;
eg_cnt_base <= 2'd0;
end
else eg_cnt_base <= eg_cnt_base + 1'b1;
end
end
end
wire cnt_out; // = all_cnt_last[3*31-1:3*30];
reg [7:0] step_idx;
reg [2:0] state_III, state_IV, state_V, state_VI, state_VII, state_VIII;
wire [2:0] state_II;
wire ar_off_VI;
reg ar_off_III;
// Register Cycle I
always @(posedge clk) begin
if( d1l == 4'd15 )
d1level_II <= 5'h1f; // 93dB
else
d1level_II <= d1l;
end
// Register Cycle II
wire ssg_invertion_II, ssg_invertion_VIII;
reg ssg_invertion_III;
reg [4:0] cfg_III;
wire ssg_pg_rst = eg_II>=10'h200 && ssg_en_II &&
!( ssg_alt_II || ssg_hold_II );
wire ssg_en_out;
wire keyon_last_II;
reg ssg_en_in_II;
always @(*) begin
if( state_II==RELEASE )
ssg_en_in_II <= 1'b0;
else
ssg_en_in_II <= keyon_II ? ssg_en_II : ssg_en_out;
end
wire ar_off_II = arate_II == 5'h1f;
wire keyon_now_II = !keyon_last_II && keyon_II;
wire keyoff_now_II = keyon_last_II && !keyon_II;
always @(posedge clk) begin
// ar_off_III <= arate_II == 5'h1f;
// trigger release
if( keyoff_now_II ) begin
cfg_III <= { rrate_II, 1'b1 };
state_III <= RELEASE;
pg_rst_III <= 1'b0;
ar_off_III <= 1'b0;
end
else begin
// trigger 1st decay
if( keyon_now_II ) begin
cfg_III <= arate_II;
state_III <= ATTACK;
pg_rst_III <= 1'b1;
ar_off_III <= ar_off_II;
end
else begin : sel_rate
pg_rst_III <= (eg_II==10'h3FF) ||ssg_pg_rst;
if( (state_II==DECAY1 ||state_II==DECAY2) && ssg_en_II && eg_II >= 10'h200 ) begin
ssg_invertion_III <= ssg_alt_II ^ ssg_invertion_II;
if( ssg_hold_II ) begin
cfg_III <= 5'd0;
state_III <= HOLD; // repeats!
ar_off_III <= 1'b0;
end
else begin
cfg_III <= rate2_II;
state_III <= ATTACK; // repeats!
ar_off_III <= 1'b1;
end
end
else begin
ssg_invertion_III <= state_II==RELEASE ? 1'b0 : ssg_invertion_II;
case ( state_II )
ATTACK: begin
if( eg_II==10'd0 ) begin
state_III <= DECAY1;
cfg_III <= rate1_II;
end
else begin
state_III <= state_II; // attack
cfg_III <= arate_II;
end
ar_off_III <= 1'b0;
end
DECAY1: begin
if( eg_II[9:5] >= d1level_II ) begin
cfg_III <= rate2_II;
state_III <= DECAY2;
end
else begin
cfg_III <= rate1_II;
state_III <= state_II; // decay1
end
ar_off_III <= 1'b0;
end
DECAY2:
begin
cfg_III <= rate2_II;
state_III <= state_II; // decay2
ar_off_III <= 1'b0;
end
RELEASE: begin
cfg_III <= { rrate_II, 1'b1 };
state_III <= state_II; // release
ar_off_III <= 1'b0;
end
HOLD: begin
cfg_III <= 5'd0;
state_III <= HOLD; // repeats!
ar_off_III <= 1'b0;
end
endcase
end
end
end
eg_III <= eg_II;
end
///////////////////////////////////////////////////////////////////
// Register Cycle III
reg [6:0] pre_rate_III;
reg [5:0] rate_IV;
always @(*) begin : pre_rate_calc
if( cfg_III == 5'd0 )
pre_rate_III <= 6'd0;
else
case( ks_III )
2'd3: pre_rate_III <= { cfg_III, 1'b0 } + keycode_III;
2'd2: pre_rate_III <= { cfg_III, 1'b0 } + { 1'b0, keycode_III[4:1] };
2'd1: pre_rate_III <= { cfg_III, 1'b0 } + { 2'b0, keycode_III[4:2] };
2'd0: pre_rate_III <= { cfg_III, 1'b0 } + { 3'b0, keycode_III[4:3] };
endcase
end
always @(posedge clk) begin
if( rst ) begin
state_IV <= RELEASE;
eg_IV <= 10'h3ff;
rate_IV <= 5'h1F;
end
else begin
state_IV <= state_III;
eg_IV <= eg_III;
rate_IV <= pre_rate_III[6] ? 6'd63 : pre_rate_III[5:0];
end
end
///////////////////////////////////////////////////////////////////
// Register Cycle IV
reg [2:0] cnt_V;
always @(posedge clk) begin
if( rst ) begin
state_V <= RELEASE;
rate_V <= 5'h1f;
eg_V <= 10'h3ff;
//cnt_V<= 3'd0;
end
else begin
state_V <= state_IV;
rate_V <= rate_IV;
eg_V <= eg_IV;
if( state_IV == ATTACK )
case( rate_IV[5:2] )
4'h0: cnt_V <= eg_cnt[13:11];
4'h1: cnt_V <= eg_cnt[12:10];
4'h2: cnt_V <= eg_cnt[11: 9];
4'h3: cnt_V <= eg_cnt[10: 8];
4'h4: cnt_V <= eg_cnt[ 9: 7];
4'h5: cnt_V <= eg_cnt[ 8: 6];
4'h6: cnt_V <= eg_cnt[ 7: 5];
4'h7: cnt_V <= eg_cnt[ 6: 4];
4'h8: cnt_V <= eg_cnt[ 5: 3];
4'h9: cnt_V <= eg_cnt[ 4: 2];
4'ha: cnt_V <= eg_cnt[ 3: 1];
default: cnt_V <= eg_cnt[ 2: 0];
endcase
else
case( rate_IV[5:2] )
4'h0: cnt_V <= eg_cnt[14:12];
4'h1: cnt_V <= eg_cnt[13:11];
4'h2: cnt_V <= eg_cnt[12:10];
4'h3: cnt_V <= eg_cnt[11: 9];
4'h4: cnt_V <= eg_cnt[10: 8];
4'h5: cnt_V <= eg_cnt[ 9: 7];
4'h6: cnt_V <= eg_cnt[ 8: 6];
4'h7: cnt_V <= eg_cnt[ 7: 5];
4'h8: cnt_V <= eg_cnt[ 6: 4];
4'h9: cnt_V <= eg_cnt[ 5: 3];
4'ha: cnt_V <= eg_cnt[ 4: 2];
4'hb: cnt_V <= eg_cnt[ 3: 1];
default: cnt_V <= eg_cnt[ 2: 0];
endcase
end
end
//////////////////////////////////////////////////////////////
// Register Cycle V
always @(*) begin : rate_step
if( rate_V[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x
if( rate_V[5:2]==4'hf && state_V == ATTACK)
step_idx <= 8'b11111111; // Maximum attack speed, rates 60&61
else
case( rate_V[1:0] )
2'd0: step_idx <= 8'b00000000;
2'd1: step_idx <= 8'b10001000; // 2
2'd2: step_idx <= 8'b10101010; // 4
2'd3: step_idx <= 8'b11101110; // 6
endcase
end
else begin
if( rate_V[5:2]==4'd0 && state_V != ATTACK)
step_idx <= 8'b11111110; // limit slowest decay rate_IV
else
case( rate_V[1:0] )
2'd0: step_idx <= 8'b10101010; // 4
2'd1: step_idx <= 8'b11101010; // 5
2'd2: step_idx <= 8'b11101110; // 6
2'd3: step_idx <= 8'b11111110; // 7
endcase
end
// a rate_IV of zero keeps the level still
step_V <= rate_V[5:1]==5'd0 ? 1'b0 : step_idx[ cnt_V ];
end
reg [5:1] rate_VI;
reg [9:0] eg_VI;
reg step_VI;
always @(posedge clk) begin
if( rst ) begin
state_VI <= RELEASE;
rate_VI <= 5'd1;
eg_VI <= 10'h3ff;
sum_up <= 1'b0;
step_VI <= 1'b0;
end
else begin
state_VI <= state_V;
rate_VI <= rate_V[5:1];
eg_VI <= eg_V;
sum_up <= cnt_V[0] != cnt_out;
step_VI <= step_V;
end
end
//////////////////////////////////////////////////////////////
// Register cycle VI
reg [3:0] preatt_VI;
reg [5:0] att_VI;
wire ssg_en_VI;
reg [9:0] eg_VII, eg_stopped_VII;
reg [10:0] egatt_VI;
always @(*) begin
case( rate_VI[5:2] )
4'b1100: preatt_VI <= { step_VI, ~step_VI }; // 12
4'b1101: preatt_VI <= { step_VI, ~step_VI, 1'b0 }; // 13
4'b1110: preatt_VI <= { step_VI, ~step_VI, 2'b0 }; // 14
4'b1111: preatt_VI <= 4'd8;// 15
default: preatt_VI <= { step_VI, 1'b0 };
endcase
att_VI <= ssg_en_VI ? { preatt_VI, 2'd0 } : { 2'd0, preatt_VI };
egatt_VI <= att_VI + eg_VI;
eg_stopped_VII <= eg_VI;
end
reg [8:0] ar_sum0;
reg [9:0] ar_result, ar_sum;
always @(*) begin : ar_calculation
casex( rate_VI[5:2] )
default: ar_sum0 <= eg_VI[9:4] + 1'd1;
4'b1100: ar_sum0 <= eg_VI[9:4] + 1'd1;
4'b1101: ar_sum0 <= eg_VI[9:3] + 1'd1;
4'b111x: ar_sum0 <= eg_VI[9:2] + 1'd1;
endcase
if( rate_VI[5:4] == 2'b11 )
ar_sum <= step_VI ? { ar_sum0, 1'b0 } : { 1'b0, ar_sum0 };
else
ar_sum <= step_VI ? { 1'b0, ar_sum0 } : 10'd0;
ar_result <= ar_sum<eg_VI ? eg_VI-ar_sum : 10'd0;
end
always @(posedge clk) begin
if( rst ) begin
eg_VII <= 10'h3ff;
state_VII <= RELEASE;
end
else begin
if( ar_off_VI ) begin
// eg_VII <= ssg_en_II ? 10'h200 : 10'd0;
eg_VII <= 10'd0;
end
else
if( state_VI == ATTACK ) begin
if( sum_up && eg_VI != 10'd0 )
if( rate_VI[5:1]==4'hf )
eg_VII <= 10'd0;
else
eg_VII <= ar_result;
else
eg_VII <= eg_VI;
end
else begin : DECAY_SUM
if( sum_up ) begin
if ( egatt_VI<= 10'd1023 )
eg_VII <= egatt_VI[9:0];
else eg_VII <= 10'h3FF;
end
else eg_VII <= eg_VI;
end
state_VII <= state_VI;
end
end
//////////////////////////////////////////////////////////////
// Register cycle VII
reg [9:0] eg_internal_VIII;
reg [8:0] am_final;
reg [11:0] sum_eg_tl;
always @(*) begin : sum_eg_and_tl
casex( {amsen_VII, ams_VII } )
3'b0xx,3'b100: am_final <= 9'd0;
3'b101: am_final <= { 2'b00, am };
3'b110: am_final <= { 1'b0, am, 1'b0};
3'b111: am_final <= { am, 2'b0 };
endcase
`ifdef TEST_SUPPORT
if( test_eg && tl_VII!=7'd0 )
sum_eg_tl <= 11'd0;
else
`endif
sum_eg_tl <= { tl_VII, 3'd0 }
+ eg_VII
+ { am_final, 1'b0 };
end
always @(posedge clk) begin
if( rst ) begin
eg_internal_VIII <= 10'h3ff;
state_VIII <= RELEASE;
end
else begin
eg_internal_VIII <= sum_eg_tl[11:10] > 2'b0 ? {10{1'b1}} : sum_eg_tl[9:0];
state_VIII <= state_VII;
end
end
//////////////////////////////////////////////////////////////
// Register cycle VIII
wire ssg_inv_VIII, ssg_en_VIII;
//reg [9:0] eg_IX;
always @(posedge clk) begin
if( rst )
eg_IX <= 10'h3ff;
else begin
if( ssg_en_VIII && (ssg_invertion_VIII ^^ ssg_inv_VIII) )
eg_IX <= eg_internal_VIII>=10'h200 ? 10'h0 : (10'h200 - eg_internal_VIII);
else
eg_IX <= eg_internal_VIII;
end
end
//////////////////////////////////////////////////////////////
// Register cycle IX-XII
/*
jt12_sh #(.width(10), .stages(12-8)) u_padding(
.clk ( clk ),
.din ( eg_IX ),
.drop ( eg_XII )
);
*/
//////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
// Shift registers
jt12_sh24 #( .width(1) ) u_ssgen(
.clk ( clk ),
.din ( ssg_en_in_II ),
.st4 ( ssg_en_VI ),
.st6 ( ssg_en_VIII ), // note that din is *_II
.st24 ( ssg_en_out )
);
jt12_sh #( .width(1), .stages(6) ) u_ssgattsh(
.clk ( clk ),
.din ( ssg_inv_II ),
.drop ( ssg_inv_VIII )
);
jt12_sh #( .width(1), .stages(3) ) u_aroffsh(
.clk ( clk ),
.din ( ar_off_III),
.drop ( ar_off_VI )
);
jt12_sh #( .width(1), .stages(5) ) u_ssg1sh(
.clk ( clk ),
.din ( ssg_invertion_III ),
.drop ( ssg_invertion_VIII )
);
jt12_sh #( .width(1), .stages(18) ) u_ssg2sh(
.clk ( clk ),
.din ( ssg_invertion_VIII ),
.drop ( ssg_invertion_II )
);
/* Had 27 stages in JT51, for 32 operators
Has 19 stages here, for 24 operators
plus 1 extra stage. 20 stages does not work well.
Maybe JT51 should be 26!! */
jt12_sh/*_rst*/ #( .width(10), .stages(19)/*, .rstval(1'b1)*/ ) u_egsh(
.clk ( clk ),
// .rst ( rst ),
.din ( eg_stop ? eg_stopped_VII : eg_VII ),
.drop ( eg_II )
);
/* Had 32 stages in JT51, for 32 operators
Has 24 stages here, for 24 operators */
jt12_sh/*_rst*/ #( .width(1), .stages(24) ) u_cntsh(
.clk ( clk ),
// .rst ( rst ),
.din ( cnt_V[0] ),
.drop ( cnt_out )
);
jt12_sh_rst #( .width(1), .stages(24) ) u_konsh(
.clk ( clk ),
// .rst ( rst ),
.din ( keyon_II ),
.drop ( keyon_last_II )
);
/* Had 31 stages in JT51, for 32 operators
Has 23 stages here, for 24 operators */
jt12_sh/*_rst*/ #( .width(3), .stages(18)/*, .rstval(1'b1)*/ ) u_statesh(
.clk ( clk ),
// .rst ( rst ),
.din ( state_VIII),
.drop ( state_II )
);
`ifdef SIMULATION
reg [4:0] sep24_cnt;
wire [2:0] state_ch0s1, state_ch1s1, state_ch2s1, state_ch3s1,
state_ch4s1, state_ch5s1, state_ch0s2, state_ch1s2,
state_ch2s2, state_ch3s2, state_ch4s2, state_ch5s2,
state_ch0s3, state_ch1s3, state_ch2s3, state_ch3s3,
state_ch4s3, state_ch5s3, state_ch0s4, state_ch1s4,
state_ch2s4, state_ch3s4, state_ch4s4, state_ch5s4;
always @(posedge clk)
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
sep24 #( .width(3), .pos0(0) ) stsep
(
.clk ( clk ),
.mixed ( state_II ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (state_ch0s1),
.ch1s1 (state_ch1s1),
.ch2s1 (state_ch2s1),
.ch3s1 (state_ch3s1),
.ch4s1 (state_ch4s1),
.ch5s1 (state_ch5s1),
.ch0s2 (state_ch0s2),
.ch1s2 (state_ch1s2),
.ch2s2 (state_ch2s2),
.ch3s2 (state_ch3s2),
.ch4s2 (state_ch4s2),
.ch5s2 (state_ch5s2),
.ch0s3 (state_ch0s3),
.ch1s3 (state_ch1s3),
.ch2s3 (state_ch2s3),
.ch3s3 (state_ch3s3),
.ch4s3 (state_ch4s3),
.ch5s3 (state_ch5s3),
.ch0s4 (state_ch0s4),
.ch1s4 (state_ch1s4),
.ch2s4 (state_ch2s4),
.ch3s4 (state_ch3s4),
.ch4s4 (state_ch4s4),
.ch5s4 (state_ch5s4)
);
`endif
endmodule

View File

@ -0,0 +1,76 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
// altera message_off 10030
module jt12_exprom
(
input [4:0] addr,
input clk,
output reg [44:0] exp
);
reg [44:0] explut_jt51[31:0];
initial
begin
explut_jt51[0] <= 45'b111110101011010110001011010000010010111011011;
explut_jt51[1] <= 45'b111101010011010101000011001100101110110101011;
explut_jt51[2] <= 45'b111011111011010011110111001000110010101110011;
explut_jt51[3] <= 45'b111010100101010010101111000100110010101000011;
explut_jt51[4] <= 45'b111001001101010001100111000000110010100001011;
explut_jt51[5] <= 45'b110111111011010000011110111101010010011011011;
explut_jt51[6] <= 45'b110110100011001111010110111001010010010100100;
explut_jt51[7] <= 45'b110101001011001110001110110101110010001110011;
explut_jt51[8] <= 45'b110011111011001101000110110001110010001000011;
explut_jt51[9] <= 45'b110010100011001011111110101110010010000010011;
explut_jt51[10] <= 45'b110001010011001010111010101010010001111011011;
explut_jt51[11] <= 45'b101111111011001001110010100110110001110101011;
explut_jt51[12] <= 45'b101110101011001000101010100011001101101111011;
explut_jt51[13] <= 45'b101101010101000111100110011111010001101001011;
explut_jt51[14] <= 45'b101100000011000110100010011011110001100011011;
explut_jt51[15] <= 45'b101010110011000101011110011000010001011101011;
explut_jt51[16] <= 45'b101001100011000100011010010100101101010111011;
explut_jt51[17] <= 45'b101000010011000011010010010001001101010001011;
explut_jt51[18] <= 45'b100111000011000010010010001101101101001011011;
explut_jt51[19] <= 45'b100101110011000001001110001010001101000101011;
explut_jt51[20] <= 45'b100100100011000000001010000110010000111111011;
explut_jt51[21] <= 45'b100011010010111111001010000011001100111001011;
explut_jt51[22] <= 45'b100010000010111110000101111111101100110011011;
explut_jt51[23] <= 45'b100000110010111101000001111100001100101101011;
explut_jt51[24] <= 45'b011111101010111100000001111000101100101000010;
explut_jt51[25] <= 45'b011110011010111011000001110101001100100010011;
explut_jt51[26] <= 45'b011101001010111010000001110001110000011100011;
explut_jt51[27] <= 45'b011100000010111001000001101110010000010110011;
explut_jt51[28] <= 45'b011010110010111000000001101011001100010001011;
explut_jt51[29] <= 45'b011001101010110111000001100111101100001011011;
explut_jt51[30] <= 45'b011000100000110110000001100100010000000110010;
explut_jt51[31] <= 45'b010111010010110101000001100001001100000000011;
end
always @ (posedge clk)
exp <= explut_jt51[addr];
endmodule

68
rtl/sound/jt12/jt12_kon.v Normal file
View File

@ -0,0 +1,68 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
module jt12_kon(
input rst,
input clk,
input [3:0] keyon_op,
input [2:0] keyon_ch,
input [1:0] cur_op,
input [2:0] cur_ch,
input up_keyon,
input csm,
input flag_A,
input overflow_A,
output reg keyon_II
);
//reg csm_copy;
reg din;
wire drop;
reg [3:0] cur_op_hot;
always @(posedge clk)
keyon_II <= (csm&&cur_ch==2'd2&&overflow_A) || drop;
always @(*) begin
case( cur_op )
2'd0: cur_op_hot <= 4'b0001; // S1
2'd1: cur_op_hot <= 4'b0100; // S3
2'd2: cur_op_hot <= 4'b0010; // S2
2'd3: cur_op_hot <= 4'b1000; // S4
endcase
din <= keyon_ch==cur_ch && up_keyon ? |(keyon_op&cur_op_hot) : drop;
end
jt12_sh_rst #(.width(1),.stages(24)) u_konch(
.clk ( clk ),
// .rst ( rst ),
.din ( din ),
.drop ( drop )
);
endmodule

68
rtl/sound/jt12/jt12_lfo.v Normal file
View File

@ -0,0 +1,68 @@
/* This file is part of jt12.
jt12 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.
jt12 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 jt12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 25-2-2017
*/
`timescale 1ns / 1ps
/*
tab size 4
*/
module jt12_lfo(
input rst,
input clk,
input zero,
input lfo_rst,
input lfo_en,
input [2:0] lfo_freq,
output reg [6:0] lfo_mod
);
reg [6:0] cnt, limit;
always @(*)
case( lfo_freq )
3'd0: limit <= 7'd108;
3'd1: limit <= 7'd78;
3'd2: limit <= 7'd71;
3'd3: limit <= 7'd67;
3'd4: limit <= 7'd62;
3'd5: limit <= 7'd44;
3'd6: limit <= 7'd8;
3'd7: limit <= 7'd5;
endcase
always @(posedge clk) begin
if( rst || !lfo_en )
{ lfo_mod, cnt } <= 14'd0;
else begin
if(zero) begin
if( cnt == limit ) begin
cnt <= 7'd0;
lfo_mod <= lfo_mod + 1'b1;
end
else
cnt <= cnt + 1'b1;
end
end
end
endmodule

View File

@ -0,0 +1,42 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: March, 10th 2017
*/
/* Limiting amplifier by 3dB * shift */
`timescale 1ns / 1ps
module jt12_limitamp #( parameter width=20, shift=5 ) (
input signed [width-1:0] left_in,
input signed [width-1:0] right_in,
output reg signed [width-1:0] left_out,
output reg signed [width-1:0] right_out
);
always @(*) begin
left_out <= ^left_in[width-1:width-1-shift] ?
{ left_in[width-1], {(width-1){~left_in[width-1]}}} :
left_in <<< shift;
right_out <= ^right_in[width-1:width-1-shift] ?
{ right_in[width-1], {(width-1){~right_in[width-1]}}} :
right_in <<< shift;
end
endmodule

370
rtl/sound/jt12/jt12_mmr.v Normal file
View File

@ -0,0 +1,370 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2017
*/
`timescale 1ns / 1ps
module jt12_mmr(
input rst,
input clk,
input [7:0] din,
input write,
input [1:0] addr,
output reg busy,
output ch6op,
// LFO
output reg [2:0] lfo_freq,
output reg lfo_en,
// Timers
output reg [9:0] value_A,
output reg [7:0] value_B,
output reg load_A,
output reg load_B,
output reg enable_irq_A,
output reg enable_irq_B,
output reg clr_flag_A,
output reg clr_flag_B,
output reg fast_timers,
input flag_A,
input overflow_A,
// PCM
output reg [8:0] pcm,
output reg pcm_en,
`ifdef TEST_SUPPORT
// Test
output reg test_eg,
output reg test_op0,
`endif
// Operator
output use_prevprev1,
output use_internal_x,
output use_internal_y,
output use_prev2,
output use_prev1,
// PG
output [10:0] fnum_I,
output [ 2:0] block_I,
output reg pg_stop,
// REG
output [ 1:0] rl,
output [ 2:0] fb_II,
output [ 2:0] alg,
output [ 2:0] pms,
output [ 1:0] ams_VII,
output amsen_VII,
output [ 2:0] dt1_II,
output [ 3:0] mul_V,
output [ 6:0] tl_VII,
output reg eg_stop,
output [ 4:0] ar_II,
output [ 4:0] d1r_II,
output [ 4:0] d2r_II,
output [ 3:0] rr_II,
output [ 3:0] d1l,
output [ 1:0] ks_III,
// SSG operation
output ssg_en_II,
output [2:0] ssg_eg_II,
output keyon_II,
// output [ 1:0] cur_op,
// Operator
output zero,
output s1_enters,
output s2_enters,
output s3_enters,
output s4_enters
);
reg [7:0] selected_register;
//reg sch; // 0 => CH1~CH3 only available. 1=>CH4~CH6
/*
reg irq_zero_en, irq_brdy_en, irq_eos_en,
irq_tb_en, irq_ta_en;
*/
reg up_clr;
reg up_alg;
reg up_block;
reg up_fnumlo;
reg up_pms;
reg up_dt1;
reg up_tl;
reg up_ks_ar;
reg up_amen_d1r;
reg up_d2r;
reg up_d1l;
reg up_ssgeg;
reg up_keyon;
wire busy_reg;
parameter REG_TEST = 8'h01,
REG_TEST2 = 8'h02,
REG_TESTYM = 8'h21,
REG_LFO = 8'h22,
REG_CLKA1 = 8'h24,
REG_CLKA2 = 8'h25,
REG_CLKB = 8'h26,
REG_TIMER = 8'h27,
REG_KON = 8'h28,
REG_IRQMASK = 8'h29,
REG_PCM = 8'h2A,
REG_PCM_EN = 8'h2B,
REG_DACTEST = 8'h2C,
REG_CLK_N6 = 8'h2D,
REG_CLK_N3 = 8'h2E,
REG_CLK_N2 = 8'h2F;
reg csm, effect;
reg [ 2:0] block_ch3op2, block_ch3op3, block_ch3op1;
reg [10:0] fnum_ch3op2, fnum_ch3op3, fnum_ch3op1;
reg [ 5:0] latch_ch3op2, latch_ch3op3, latch_ch3op1;
reg [2:0] up_ch;
reg [1:0] up_op;
`include "jt12_mmr_sim.vh"
always @(posedge clk) begin : memory_mapped_registers
reg old_write;
old_write <= write;
if( rst ) begin
selected_register <= 8'h0;
busy <= 1'b0;
up_ch <= 3'd0;
up_op <= 2'd0;
{ up_keyon, up_alg, up_block, up_fnumlo,
up_pms, up_dt1, up_tl, up_ks_ar,
up_amen_d1r,up_d2r, up_d1l, up_ssgeg } <= 12'd0;
`ifdef TEST_SUPPORT
{ test_eg, test_op0 } <= 2'd0;
`endif
// IRQ Mask
/*{ irq_zero_en, irq_brdy_en, irq_eos_en,
irq_tb_en, irq_ta_en } = 5'h1f; */
// timers
{ value_A, value_B } <= 18'd0;
{ clr_flag_B, clr_flag_A,
enable_irq_B, enable_irq_A, load_B, load_A } <= 6'd0;
up_clr <= 1'b0;
fast_timers <= 1'b0;
// LFO
lfo_freq <= 3'd0;
lfo_en <= 1'b0;
csm <= 1'b0;
effect <= 1'b0;
// PCM
pcm <= 9'h0;
pcm_en <= 1'b0;
// sch <= 1'b0;
// Original test features
eg_stop <= 1'b0;
pg_stop <= 1'b0;
`ifdef SIMULATION
mmr_dump <= 1'b0;
`endif
end else begin
// WRITE IN REGISTERS
if( old_write ^ write ) begin
busy <= 1'b1;
if( !addr[0] ) begin
selected_register <= din;
up_ch <= {addr[1], din[1:0]};
up_op <= din[3:2]; // 0=S1,1=S3,2=S2,3=S4
end else begin
// Global registers
if( selected_register < 8'h30 ) begin
case( selected_register)
// registros especiales
//REG_TEST: lfo_rst <= 1'b1; // regardless of din
`ifdef TEST_SUPPORT
REG_TEST2: { mmr_dump, test_op0, test_eg } <= din[2:0];
`endif
REG_TESTYM: begin
eg_stop <= din[5];
pg_stop <= din[3];
fast_timers <= din[2];
end
REG_KON: up_keyon <= 1'b1;
REG_CLKA1: value_A[9:2]<= din;
REG_CLKA2: value_A[1:0]<= din[1:0];
REG_CLKB: value_B <= din;
REG_TIMER: begin
effect <= |din[7:6];
csm <= din[7:6] == 2'b10;
{ clr_flag_B, clr_flag_A,
enable_irq_B, enable_irq_A,
load_B, load_A } <= din[5:0];
end
REG_LFO: { lfo_en, lfo_freq } <= din[3:0];
REG_DACTEST:pcm[0] <= din[3];
REG_PCM: pcm[8:1]<= din;
REG_PCM_EN: pcm_en <= din[7];
endcase
end
else if( selected_register[1:0]!=2'b11 ) begin
// channel registers
if( selected_register >= 8'hA0 ) begin
case( selected_register )
8'hA0, 8'hA1, 8'hA2: up_fnumlo <= 1'b1;
8'hA4, 8'hA5, 8'hA6: up_block <= 1'b1;
// CH3 special registers
8'hA9: { block_ch3op1, fnum_ch3op1 } <= { latch_ch3op1, din };
8'hA8: { block_ch3op3, fnum_ch3op3 } <= { latch_ch3op3, din };
8'hAA: { block_ch3op2, fnum_ch3op2 } <= { latch_ch3op2, din };
8'hAD: latch_ch3op1 <= din[5:0];
8'hAC: latch_ch3op3 <= din[5:0];
8'hAE: latch_ch3op2 <= din[5:0];
// FB + Algorithm
8'hB0, 8'hB1, 8'hB2: up_alg <= 1'b1;
8'hB4, 8'hB5, 8'hB6: up_pms <= 1'b1;
endcase
end
else
// operator registers
begin
case( selected_register[7:4] )
4'h3: up_dt1 <= 1'b1;
4'h4: up_tl <= 1'b1;
4'h5: up_ks_ar <= 1'b1;
4'h6: up_amen_d1r <= 1'b1;
4'h7: up_d2r <= 1'b1;
4'h8: up_d1l <= 1'b1;
4'h9: up_ssgeg <= 1'b1;
endcase
end
end
end
end
else begin /* clear once-only bits */
// csm <= 1'b0;
// lfo_rst <= 1'b0;
{ clr_flag_B, clr_flag_A, load_B, load_A } <= 4'd0;
`ifdef SIMULATION
mmr_dump <= 1'b0;
`endif
up_keyon <= 1'b0;
if( |{ up_keyon, up_alg, up_block, up_fnumlo,
up_pms, up_dt1, up_tl, up_ks_ar,
up_amen_d1r,up_d2r, up_d1l, up_ssgeg } == 1'b0 )
busy <= 0;
else
busy <= 1'b1;
if( busy_reg ) begin
up_clr <= 1'b1;
end
else begin
up_clr <= 1'b0;
if( up_clr )
{ up_alg, up_block, up_fnumlo,
up_pms, up_dt1, up_tl, up_ks_ar,
up_amen_d1r,up_d2r, up_d1l, up_ssgeg } <= 11'd0;
end
end
end
end
jt12_reg u_reg(
.rst ( rst ),
.clk ( clk ), // P1
.din ( din ),
.up_keyon ( up_keyon ),
.up_alg ( up_alg ),
.up_block ( up_block ),
.up_fnumlo ( up_fnumlo ),
.up_pms ( up_pms ),
.up_dt1 ( up_dt1 ),
.up_tl ( up_tl ),
.up_ks_ar ( up_ks_ar ),
.up_amen_d1r(up_amen_d1r),
.up_d2r ( up_d2r ),
.up_d1l ( up_d1l ),
.up_ssgeg ( up_ssgeg ),
.op ( up_op ), // operator to update
.ch ( up_ch ), // channel to update
.csm ( csm ),
.flag_A ( flag_A ),
.overflow_A ( overflow_A),
.busy ( busy_reg ),
.ch6op ( ch6op ),
// CH3 Effect-mode operation
.effect ( effect ), // allows independent freq. for CH 3
.fnum_ch3op2( fnum_ch3op2 ),
.fnum_ch3op3( fnum_ch3op3 ),
.fnum_ch3op1( fnum_ch3op1 ),
.block_ch3op2( block_ch3op2 ),
.block_ch3op3( block_ch3op3 ),
.block_ch3op1( block_ch3op1 ),
// Operator
.use_prevprev1(use_prevprev1),
.use_internal_x(use_internal_x),
.use_internal_y(use_internal_y),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 ),
// PG
.fnum_I ( fnum_I ),
.block_I ( block_I ),
.mul_V ( mul_V ),
.dt1_II ( dt1_II ),
// EG
.ar_II (ar_II ), // attack rate
.d1r_II (d1r_II ), // decay rate
.d2r_II (d2r_II ), // sustain rate
.rr_II (rr_II ), // release rate
.d1l (d1l ), // sustain level
.ks_III (ks_III ), // key scale
// SSG operation
.ssg_en_II ( ssg_en_II ),
.ssg_eg_II ( ssg_eg_II ),
// envelope number
.tl_VII (tl_VII ),
.pms (pms ),
.ams_VII (ams_VII ),
.amsen_VII (amsen_VII ),
// channel configuration
.rl ( rl ),
.fb_II ( fb_II ),
.alg ( alg ),
.keyon_II ( keyon_II ),
//.cur_op ( cur_op ),
.zero ( zero ),
.s1_enters ( s1_enters ),
.s2_enters ( s2_enters ),
.s3_enters ( s3_enters ),
.s4_enters ( s4_enters )
);
endmodule

View File

@ -0,0 +1,836 @@
`ifdef SIMULATION
reg [4:0] sep24_cnt;
reg mmr_dump;
always @(posedge clk )
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1,
fnum_ch4s1, fnum_ch5s1, fnum_ch0s2, fnum_ch1s2,
fnum_ch2s2, fnum_ch3s2, fnum_ch4s2, fnum_ch5s2,
fnum_ch0s3, fnum_ch1s3, fnum_ch2s3, fnum_ch3s3,
fnum_ch4s3, fnum_ch5s3, fnum_ch0s4, fnum_ch1s4,
fnum_ch2s4, fnum_ch3s4, fnum_ch4s4, fnum_ch5s4;
sep24 #( .width(11), .pos0(1) ) fnum_sep
(
.clk ( clk ),
.mixed ( fnum_I ),
.mask ( 11'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (fnum_ch0s1),
.ch1s1 (fnum_ch1s1),
.ch2s1 (fnum_ch2s1),
.ch3s1 (fnum_ch3s1),
.ch4s1 (fnum_ch4s1),
.ch5s1 (fnum_ch5s1),
.ch0s2 (fnum_ch0s2),
.ch1s2 (fnum_ch1s2),
.ch2s2 (fnum_ch2s2),
.ch3s2 (fnum_ch3s2),
.ch4s2 (fnum_ch4s2),
.ch5s2 (fnum_ch5s2),
.ch0s3 (fnum_ch0s3),
.ch1s3 (fnum_ch1s3),
.ch2s3 (fnum_ch2s3),
.ch3s3 (fnum_ch3s3),
.ch4s3 (fnum_ch4s3),
.ch5s3 (fnum_ch5s3),
.ch0s4 (fnum_ch0s4),
.ch1s4 (fnum_ch1s4),
.ch2s4 (fnum_ch2s4),
.ch3s4 (fnum_ch3s4),
.ch4s4 (fnum_ch4s4),
.ch5s4 (fnum_ch5s4)
);
wire [2:0] block_ch0s1, block_ch1s1, block_ch2s1, block_ch3s1,
block_ch4s1, block_ch5s1, block_ch0s2, block_ch1s2,
block_ch2s2, block_ch3s2, block_ch4s2, block_ch5s2,
block_ch0s3, block_ch1s3, block_ch2s3, block_ch3s3,
block_ch4s3, block_ch5s3, block_ch0s4, block_ch1s4,
block_ch2s4, block_ch3s4, block_ch4s4, block_ch5s4;
sep24 #( .width(3), .pos0(1) ) block_sep
(
.clk ( clk ),
.mixed ( block_I ),
.mask ( 3'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (block_ch0s1),
.ch1s1 (block_ch1s1),
.ch2s1 (block_ch2s1),
.ch3s1 (block_ch3s1),
.ch4s1 (block_ch4s1),
.ch5s1 (block_ch5s1),
.ch0s2 (block_ch0s2),
.ch1s2 (block_ch1s2),
.ch2s2 (block_ch2s2),
.ch3s2 (block_ch3s2),
.ch4s2 (block_ch4s2),
.ch5s2 (block_ch5s2),
.ch0s3 (block_ch0s3),
.ch1s3 (block_ch1s3),
.ch2s3 (block_ch2s3),
.ch3s3 (block_ch3s3),
.ch4s3 (block_ch4s3),
.ch5s3 (block_ch5s3),
.ch0s4 (block_ch0s4),
.ch1s4 (block_ch1s4),
.ch2s4 (block_ch2s4),
.ch3s4 (block_ch3s4),
.ch4s4 (block_ch4s4),
.ch5s4 (block_ch5s4)
);
wire [1:0] rl_ch0s1, rl_ch1s1, rl_ch2s1, rl_ch3s1,
rl_ch4s1, rl_ch5s1, rl_ch0s2, rl_ch1s2,
rl_ch2s2, rl_ch3s2, rl_ch4s2, rl_ch5s2,
rl_ch0s3, rl_ch1s3, rl_ch2s3, rl_ch3s3,
rl_ch4s3, rl_ch5s3, rl_ch0s4, rl_ch1s4,
rl_ch2s4, rl_ch3s4, rl_ch4s4, rl_ch5s4;
sep24 #( .width(2), .pos0(1) ) rl_sep
(
.clk ( clk ),
.mixed ( rl ),
.mask ( 2'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (rl_ch0s1),
.ch1s1 (rl_ch1s1),
.ch2s1 (rl_ch2s1),
.ch3s1 (rl_ch3s1),
.ch4s1 (rl_ch4s1),
.ch5s1 (rl_ch5s1),
.ch0s2 (rl_ch0s2),
.ch1s2 (rl_ch1s2),
.ch2s2 (rl_ch2s2),
.ch3s2 (rl_ch3s2),
.ch4s2 (rl_ch4s2),
.ch5s2 (rl_ch5s2),
.ch0s3 (rl_ch0s3),
.ch1s3 (rl_ch1s3),
.ch2s3 (rl_ch2s3),
.ch3s3 (rl_ch3s3),
.ch4s3 (rl_ch4s3),
.ch5s3 (rl_ch5s3),
.ch0s4 (rl_ch0s4),
.ch1s4 (rl_ch1s4),
.ch2s4 (rl_ch2s4),
.ch3s4 (rl_ch3s4),
.ch4s4 (rl_ch4s4),
.ch5s4 (rl_ch5s4)
);
wire [2:0] fb_ch0s1, fb_ch1s1, fb_ch2s1, fb_ch3s1,
fb_ch4s1, fb_ch5s1, fb_ch0s2, fb_ch1s2,
fb_ch2s2, fb_ch3s2, fb_ch4s2, fb_ch5s2,
fb_ch0s3, fb_ch1s3, fb_ch2s3, fb_ch3s3,
fb_ch4s3, fb_ch5s3, fb_ch0s4, fb_ch1s4,
fb_ch2s4, fb_ch3s4, fb_ch4s4, fb_ch5s4;
sep24 #( .width(3), .pos0(0) ) fb_sep
(
.clk ( clk ),
.mixed ( fb_II ),
.mask ( 3'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (fb_ch0s1),
.ch1s1 (fb_ch1s1),
.ch2s1 (fb_ch2s1),
.ch3s1 (fb_ch3s1),
.ch4s1 (fb_ch4s1),
.ch5s1 (fb_ch5s1),
.ch0s2 (fb_ch0s2),
.ch1s2 (fb_ch1s2),
.ch2s2 (fb_ch2s2),
.ch3s2 (fb_ch3s2),
.ch4s2 (fb_ch4s2),
.ch5s2 (fb_ch5s2),
.ch0s3 (fb_ch0s3),
.ch1s3 (fb_ch1s3),
.ch2s3 (fb_ch2s3),
.ch3s3 (fb_ch3s3),
.ch4s3 (fb_ch4s3),
.ch5s3 (fb_ch5s3),
.ch0s4 (fb_ch0s4),
.ch1s4 (fb_ch1s4),
.ch2s4 (fb_ch2s4),
.ch3s4 (fb_ch3s4),
.ch4s4 (fb_ch4s4),
.ch5s4 (fb_ch5s4)
);
wire [2:0] alg_ch0s1, alg_ch1s1, alg_ch2s1, alg_ch3s1,
alg_ch4s1, alg_ch5s1, alg_ch0s2, alg_ch1s2,
alg_ch2s2, alg_ch3s2, alg_ch4s2, alg_ch5s2,
alg_ch0s3, alg_ch1s3, alg_ch2s3, alg_ch3s3,
alg_ch4s3, alg_ch5s3, alg_ch0s4, alg_ch1s4,
alg_ch2s4, alg_ch3s4, alg_ch4s4, alg_ch5s4;
sep24 #( .width(3), .pos0(1) ) alg_sep
(
.clk ( clk ),
.mixed ( alg ),
.mask ( 3'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (alg_ch0s1),
.ch1s1 (alg_ch1s1),
.ch2s1 (alg_ch2s1),
.ch3s1 (alg_ch3s1),
.ch4s1 (alg_ch4s1),
.ch5s1 (alg_ch5s1),
.ch0s2 (alg_ch0s2),
.ch1s2 (alg_ch1s2),
.ch2s2 (alg_ch2s2),
.ch3s2 (alg_ch3s2),
.ch4s2 (alg_ch4s2),
.ch5s2 (alg_ch5s2),
.ch0s3 (alg_ch0s3),
.ch1s3 (alg_ch1s3),
.ch2s3 (alg_ch2s3),
.ch3s3 (alg_ch3s3),
.ch4s3 (alg_ch4s3),
.ch5s3 (alg_ch5s3),
.ch0s4 (alg_ch0s4),
.ch1s4 (alg_ch1s4),
.ch2s4 (alg_ch2s4),
.ch3s4 (alg_ch3s4),
.ch4s4 (alg_ch4s4),
.ch5s4 (alg_ch5s4)
);
wire [2:0] dt1_ch0s1, dt1_ch1s1, dt1_ch2s1, dt1_ch3s1,
dt1_ch4s1, dt1_ch5s1, dt1_ch0s2, dt1_ch1s2,
dt1_ch2s2, dt1_ch3s2, dt1_ch4s2, dt1_ch5s2,
dt1_ch0s3, dt1_ch1s3, dt1_ch2s3, dt1_ch3s3,
dt1_ch4s3, dt1_ch5s3, dt1_ch0s4, dt1_ch1s4,
dt1_ch2s4, dt1_ch3s4, dt1_ch4s4, dt1_ch5s4;
sep24 #( .width(3), .pos0(0) ) dt1_sep
(
.clk ( clk ),
.mixed ( dt1_II ),
.mask ( 3'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (dt1_ch0s1),
.ch1s1 (dt1_ch1s1),
.ch2s1 (dt1_ch2s1),
.ch3s1 (dt1_ch3s1),
.ch4s1 (dt1_ch4s1),
.ch5s1 (dt1_ch5s1),
.ch0s2 (dt1_ch0s2),
.ch1s2 (dt1_ch1s2),
.ch2s2 (dt1_ch2s2),
.ch3s2 (dt1_ch3s2),
.ch4s2 (dt1_ch4s2),
.ch5s2 (dt1_ch5s2),
.ch0s3 (dt1_ch0s3),
.ch1s3 (dt1_ch1s3),
.ch2s3 (dt1_ch2s3),
.ch3s3 (dt1_ch3s3),
.ch4s3 (dt1_ch4s3),
.ch5s3 (dt1_ch5s3),
.ch0s4 (dt1_ch0s4),
.ch1s4 (dt1_ch1s4),
.ch2s4 (dt1_ch2s4),
.ch3s4 (dt1_ch3s4),
.ch4s4 (dt1_ch4s4),
.ch5s4 (dt1_ch5s4)
);
wire [3:0] mul_ch0s1, mul_ch1s1, mul_ch2s1, mul_ch3s1,
mul_ch4s1, mul_ch5s1, mul_ch0s2, mul_ch1s2,
mul_ch2s2, mul_ch3s2, mul_ch4s2, mul_ch5s2,
mul_ch0s3, mul_ch1s3, mul_ch2s3, mul_ch3s3,
mul_ch4s3, mul_ch5s3, mul_ch0s4, mul_ch1s4,
mul_ch2s4, mul_ch3s4, mul_ch4s4, mul_ch5s4;
sep24 #( .width(4), .pos0(21) ) mul_sep
(
.clk ( clk ),
.mixed ( mul_V ),
.mask ( 4'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (mul_ch0s1),
.ch1s1 (mul_ch1s1),
.ch2s1 (mul_ch2s1),
.ch3s1 (mul_ch3s1),
.ch4s1 (mul_ch4s1),
.ch5s1 (mul_ch5s1),
.ch0s2 (mul_ch0s2),
.ch1s2 (mul_ch1s2),
.ch2s2 (mul_ch2s2),
.ch3s2 (mul_ch3s2),
.ch4s2 (mul_ch4s2),
.ch5s2 (mul_ch5s2),
.ch0s3 (mul_ch0s3),
.ch1s3 (mul_ch1s3),
.ch2s3 (mul_ch2s3),
.ch3s3 (mul_ch3s3),
.ch4s3 (mul_ch4s3),
.ch5s3 (mul_ch5s3),
.ch0s4 (mul_ch0s4),
.ch1s4 (mul_ch1s4),
.ch2s4 (mul_ch2s4),
.ch3s4 (mul_ch3s4),
.ch4s4 (mul_ch4s4),
.ch5s4 (mul_ch5s4)
);
wire [6:0] tl_ch0s1, tl_ch1s1, tl_ch2s1, tl_ch3s1,
tl_ch4s1, tl_ch5s1, tl_ch0s2, tl_ch1s2,
tl_ch2s2, tl_ch3s2, tl_ch4s2, tl_ch5s2,
tl_ch0s3, tl_ch1s3, tl_ch2s3, tl_ch3s3,
tl_ch4s3, tl_ch5s3, tl_ch0s4, tl_ch1s4,
tl_ch2s4, tl_ch3s4, tl_ch4s4, tl_ch5s4;
sep24 #( .width(7), .pos0(19) ) tl_step
(
.clk ( clk ),
.mixed ( tl_VII ),
.mask ( 7'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (tl_ch0s1),
.ch1s1 (tl_ch1s1),
.ch2s1 (tl_ch2s1),
.ch3s1 (tl_ch3s1),
.ch4s1 (tl_ch4s1),
.ch5s1 (tl_ch5s1),
.ch0s2 (tl_ch0s2),
.ch1s2 (tl_ch1s2),
.ch2s2 (tl_ch2s2),
.ch3s2 (tl_ch3s2),
.ch4s2 (tl_ch4s2),
.ch5s2 (tl_ch5s2),
.ch0s3 (tl_ch0s3),
.ch1s3 (tl_ch1s3),
.ch2s3 (tl_ch2s3),
.ch3s3 (tl_ch3s3),
.ch4s3 (tl_ch4s3),
.ch5s3 (tl_ch5s3),
.ch0s4 (tl_ch0s4),
.ch1s4 (tl_ch1s4),
.ch2s4 (tl_ch2s4),
.ch3s4 (tl_ch3s4),
.ch4s4 (tl_ch4s4),
.ch5s4 (tl_ch5s4)
);
wire [4:0] ar_ch0s1, ar_ch1s1, ar_ch2s1, ar_ch3s1,
ar_ch4s1, ar_ch5s1, ar_ch0s2, ar_ch1s2,
ar_ch2s2, ar_ch3s2, ar_ch4s2, ar_ch5s2,
ar_ch0s3, ar_ch1s3, ar_ch2s3, ar_ch3s3,
ar_ch4s3, ar_ch5s3, ar_ch0s4, ar_ch1s4,
ar_ch2s4, ar_ch3s4, ar_ch4s4, ar_ch5s4;
sep24 #( .width(5), .pos0(0) ) ar_step
(
.clk ( clk ),
.mixed ( ar_II ),
.mask ( 5'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (ar_ch0s1),
.ch1s1 (ar_ch1s1),
.ch2s1 (ar_ch2s1),
.ch3s1 (ar_ch3s1),
.ch4s1 (ar_ch4s1),
.ch5s1 (ar_ch5s1),
.ch0s2 (ar_ch0s2),
.ch1s2 (ar_ch1s2),
.ch2s2 (ar_ch2s2),
.ch3s2 (ar_ch3s2),
.ch4s2 (ar_ch4s2),
.ch5s2 (ar_ch5s2),
.ch0s3 (ar_ch0s3),
.ch1s3 (ar_ch1s3),
.ch2s3 (ar_ch2s3),
.ch3s3 (ar_ch3s3),
.ch4s3 (ar_ch4s3),
.ch5s3 (ar_ch5s3),
.ch0s4 (ar_ch0s4),
.ch1s4 (ar_ch1s4),
.ch2s4 (ar_ch2s4),
.ch3s4 (ar_ch3s4),
.ch4s4 (ar_ch4s4),
.ch5s4 (ar_ch5s4)
);
wire [4:0] d1r_ch0s1, d1r_ch1s1, d1r_ch2s1, d1r_ch3s1,
d1r_ch4s1, d1r_ch5s1, d1r_ch0s2, d1r_ch1s2,
d1r_ch2s2, d1r_ch3s2, d1r_ch4s2, d1r_ch5s2,
d1r_ch0s3, d1r_ch1s3, d1r_ch2s3, d1r_ch3s3,
d1r_ch4s3, d1r_ch5s3, d1r_ch0s4, d1r_ch1s4,
d1r_ch2s4, d1r_ch3s4, d1r_ch4s4, d1r_ch5s4;
sep24 #( .width(5), .pos0(0) ) d1r_step
(
.clk ( clk ),
.mixed ( d1r_II ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (d1r_ch0s1),
.ch1s1 (d1r_ch1s1),
.ch2s1 (d1r_ch2s1),
.ch3s1 (d1r_ch3s1),
.ch4s1 (d1r_ch4s1),
.ch5s1 (d1r_ch5s1),
.ch0s2 (d1r_ch0s2),
.ch1s2 (d1r_ch1s2),
.ch2s2 (d1r_ch2s2),
.ch3s2 (d1r_ch3s2),
.ch4s2 (d1r_ch4s2),
.ch5s2 (d1r_ch5s2),
.ch0s3 (d1r_ch0s3),
.ch1s3 (d1r_ch1s3),
.ch2s3 (d1r_ch2s3),
.ch3s3 (d1r_ch3s3),
.ch4s3 (d1r_ch4s3),
.ch5s3 (d1r_ch5s3),
.ch0s4 (d1r_ch0s4),
.ch1s4 (d1r_ch1s4),
.ch2s4 (d1r_ch2s4),
.ch3s4 (d1r_ch3s4),
.ch4s4 (d1r_ch4s4),
.ch5s4 (d1r_ch5s4)
);
wire [4:0] d2r_ch0s1, d2r_ch1s1, d2r_ch2s1, d2r_ch3s1,
d2r_ch4s1, d2r_ch5s1, d2r_ch0s2, d2r_ch1s2,
d2r_ch2s2, d2r_ch3s2, d2r_ch4s2, d2r_ch5s2,
d2r_ch0s3, d2r_ch1s3, d2r_ch2s3, d2r_ch3s3,
d2r_ch4s3, d2r_ch5s3, d2r_ch0s4, d2r_ch1s4,
d2r_ch2s4, d2r_ch3s4, d2r_ch4s4, d2r_ch5s4;
sep24 #( .width(5), .pos0(0) ) d2r_step
(
.clk ( clk ),
.mixed ( d2r_II ),
.mask ( 5'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (d2r_ch0s1),
.ch1s1 (d2r_ch1s1),
.ch2s1 (d2r_ch2s1),
.ch3s1 (d2r_ch3s1),
.ch4s1 (d2r_ch4s1),
.ch5s1 (d2r_ch5s1),
.ch0s2 (d2r_ch0s2),
.ch1s2 (d2r_ch1s2),
.ch2s2 (d2r_ch2s2),
.ch3s2 (d2r_ch3s2),
.ch4s2 (d2r_ch4s2),
.ch5s2 (d2r_ch5s2),
.ch0s3 (d2r_ch0s3),
.ch1s3 (d2r_ch1s3),
.ch2s3 (d2r_ch2s3),
.ch3s3 (d2r_ch3s3),
.ch4s3 (d2r_ch4s3),
.ch5s3 (d2r_ch5s3),
.ch0s4 (d2r_ch0s4),
.ch1s4 (d2r_ch1s4),
.ch2s4 (d2r_ch2s4),
.ch3s4 (d2r_ch3s4),
.ch4s4 (d2r_ch4s4),
.ch5s4 (d2r_ch5s4)
);
wire [3:0] rr_ch0s1, rr_ch1s1, rr_ch2s1, rr_ch3s1,
rr_ch4s1, rr_ch5s1, rr_ch0s2, rr_ch1s2,
rr_ch2s2, rr_ch3s2, rr_ch4s2, rr_ch5s2,
rr_ch0s3, rr_ch1s3, rr_ch2s3, rr_ch3s3,
rr_ch4s3, rr_ch5s3, rr_ch0s4, rr_ch1s4,
rr_ch2s4, rr_ch3s4, rr_ch4s4, rr_ch5s4;
sep24 #( .width(4), .pos0(0) ) rr_step
(
.clk ( clk ),
.mixed ( rr_II ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (rr_ch0s1),
.ch1s1 (rr_ch1s1),
.ch2s1 (rr_ch2s1),
.ch3s1 (rr_ch3s1),
.ch4s1 (rr_ch4s1),
.ch5s1 (rr_ch5s1),
.ch0s2 (rr_ch0s2),
.ch1s2 (rr_ch1s2),
.ch2s2 (rr_ch2s2),
.ch3s2 (rr_ch3s2),
.ch4s2 (rr_ch4s2),
.ch5s2 (rr_ch5s2),
.ch0s3 (rr_ch0s3),
.ch1s3 (rr_ch1s3),
.ch2s3 (rr_ch2s3),
.ch3s3 (rr_ch3s3),
.ch4s3 (rr_ch4s3),
.ch5s3 (rr_ch5s3),
.ch0s4 (rr_ch0s4),
.ch1s4 (rr_ch1s4),
.ch2s4 (rr_ch2s4),
.ch3s4 (rr_ch3s4),
.ch4s4 (rr_ch4s4),
.ch5s4 (rr_ch5s4)
);
wire [3:0] d1l_ch0s1, d1l_ch1s1, d1l_ch2s1, d1l_ch3s1,
d1l_ch4s1, d1l_ch5s1, d1l_ch0s2, d1l_ch1s2,
d1l_ch2s2, d1l_ch3s2, d1l_ch4s2, d1l_ch5s2,
d1l_ch0s3, d1l_ch1s3, d1l_ch2s3, d1l_ch3s3,
d1l_ch4s3, d1l_ch5s3, d1l_ch0s4, d1l_ch1s4,
d1l_ch2s4, d1l_ch3s4, d1l_ch4s4, d1l_ch5s4;
sep24 #( .width(4), .pos0(1) ) d1l_step
(
.clk ( clk ),
.mixed ( d1l ),
.mask ( 4'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (d1l_ch0s1),
.ch1s1 (d1l_ch1s1),
.ch2s1 (d1l_ch2s1),
.ch3s1 (d1l_ch3s1),
.ch4s1 (d1l_ch4s1),
.ch5s1 (d1l_ch5s1),
.ch0s2 (d1l_ch0s2),
.ch1s2 (d1l_ch1s2),
.ch2s2 (d1l_ch2s2),
.ch3s2 (d1l_ch3s2),
.ch4s2 (d1l_ch4s2),
.ch5s2 (d1l_ch5s2),
.ch0s3 (d1l_ch0s3),
.ch1s3 (d1l_ch1s3),
.ch2s3 (d1l_ch2s3),
.ch3s3 (d1l_ch3s3),
.ch4s3 (d1l_ch4s3),
.ch5s3 (d1l_ch5s3),
.ch0s4 (d1l_ch0s4),
.ch1s4 (d1l_ch1s4),
.ch2s4 (d1l_ch2s4),
.ch3s4 (d1l_ch3s4),
.ch4s4 (d1l_ch4s4),
.ch5s4 (d1l_ch5s4)
);
wire [1:0] ks_ch0s1, ks_ch1s1, ks_ch2s1, ks_ch3s1,
ks_ch4s1, ks_ch5s1, ks_ch0s2, ks_ch1s2,
ks_ch2s2, ks_ch3s2, ks_ch4s2, ks_ch5s2,
ks_ch0s3, ks_ch1s3, ks_ch2s3, ks_ch3s3,
ks_ch4s3, ks_ch5s3, ks_ch0s4, ks_ch1s4,
ks_ch2s4, ks_ch3s4, ks_ch4s4, ks_ch5s4;
sep24 #( .width(2), .pos0(23) ) ks_step
(
.clk ( clk ),
.mixed ( ks_III ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (ks_ch0s1),
.ch1s1 (ks_ch1s1),
.ch2s1 (ks_ch2s1),
.ch3s1 (ks_ch3s1),
.ch4s1 (ks_ch4s1),
.ch5s1 (ks_ch5s1),
.ch0s2 (ks_ch0s2),
.ch1s2 (ks_ch1s2),
.ch2s2 (ks_ch2s2),
.ch3s2 (ks_ch3s2),
.ch4s2 (ks_ch4s2),
.ch5s2 (ks_ch5s2),
.ch0s3 (ks_ch0s3),
.ch1s3 (ks_ch1s3),
.ch2s3 (ks_ch2s3),
.ch3s3 (ks_ch3s3),
.ch4s3 (ks_ch4s3),
.ch5s3 (ks_ch5s3),
.ch0s4 (ks_ch0s4),
.ch1s4 (ks_ch1s4),
.ch2s4 (ks_ch2s4),
.ch3s4 (ks_ch3s4),
.ch4s4 (ks_ch4s4),
.ch5s4 (ks_ch5s4)
);
wire [3:0] ssg_II = {ssg_en_II, ssg_eg_II};
wire [3:0] ssg_ch0s1, ssg_ch1s1, ssg_ch2s1, ssg_ch3s1,
ssg_ch4s1, ssg_ch5s1, ssg_ch0s2, ssg_ch1s2,
ssg_ch2s2, ssg_ch3s2, ssg_ch4s2, ssg_ch5s2,
ssg_ch0s3, ssg_ch1s3, ssg_ch2s3, ssg_ch3s3,
ssg_ch4s3, ssg_ch5s3, ssg_ch0s4, ssg_ch1s4,
ssg_ch2s4, ssg_ch3s4, ssg_ch4s4, ssg_ch5s4;
sep24 #( .width(4), .pos0(0) ) ssg_step
(
.clk ( clk ),
.mixed ( ssg_II ),
.mask ( 4'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (ssg_ch0s1),
.ch1s1 (ssg_ch1s1),
.ch2s1 (ssg_ch2s1),
.ch3s1 (ssg_ch3s1),
.ch4s1 (ssg_ch4s1),
.ch5s1 (ssg_ch5s1),
.ch0s2 (ssg_ch0s2),
.ch1s2 (ssg_ch1s2),
.ch2s2 (ssg_ch2s2),
.ch3s2 (ssg_ch3s2),
.ch4s2 (ssg_ch4s2),
.ch5s2 (ssg_ch5s2),
.ch0s3 (ssg_ch0s3),
.ch1s3 (ssg_ch1s3),
.ch2s3 (ssg_ch2s3),
.ch3s3 (ssg_ch3s3),
.ch4s3 (ssg_ch4s3),
.ch5s3 (ssg_ch5s3),
.ch0s4 (ssg_ch0s4),
.ch1s4 (ssg_ch1s4),
.ch2s4 (ssg_ch2s4),
.ch3s4 (ssg_ch3s4),
.ch4s4 (ssg_ch4s4),
.ch5s4 (ssg_ch5s4)
);
wire kon_ch0s1, kon_ch1s1, kon_ch2s1, kon_ch3s1,
kon_ch4s1, kon_ch5s1, kon_ch0s2, kon_ch1s2,
kon_ch2s2, kon_ch3s2, kon_ch4s2, kon_ch5s2,
kon_ch0s3, kon_ch1s3, kon_ch2s3, kon_ch3s3,
kon_ch4s3, kon_ch5s3, kon_ch0s4, kon_ch1s4,
kon_ch2s4, kon_ch3s4, kon_ch4s4, kon_ch5s4;
sep24 #( .width(1), .pos0(0) ) konstep
(
.clk ( clk ),
.mixed ( keyon_II ),
.mask ( 1'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (kon_ch0s1),
.ch1s1 (kon_ch1s1),
.ch2s1 (kon_ch2s1),
.ch3s1 (kon_ch3s1),
.ch4s1 (kon_ch4s1),
.ch5s1 (kon_ch5s1),
.ch0s2 (kon_ch0s2),
.ch1s2 (kon_ch1s2),
.ch2s2 (kon_ch2s2),
.ch3s2 (kon_ch3s2),
.ch4s2 (kon_ch4s2),
.ch5s2 (kon_ch5s2),
.ch0s3 (kon_ch0s3),
.ch1s3 (kon_ch1s3),
.ch2s3 (kon_ch2s3),
.ch3s3 (kon_ch3s3),
.ch4s3 (kon_ch4s3),
.ch5s3 (kon_ch5s3),
.ch0s4 (kon_ch0s4),
.ch1s4 (kon_ch1s4),
.ch2s4 (kon_ch2s4),
.ch3s4 (kon_ch3s4),
.ch4s4 (kon_ch4s4),
.ch5s4 (kon_ch5s4)
);
/* Dump all registers on request */
integer fmmr;
initial begin
fmmr=$fopen("mmr_dump.log");
end
always @(posedge clk )
if (mmr_dump ) begin
$fdisplay( fmmr, "-------------------------------");
// Channel 0
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s1, fnum_ch0s1, rl_ch0s1, fb_ch0s1, alg_ch0s1,
dt1_ch0s1, mul_ch0s1, tl_ch0s1, ar_ch0s1, d1r_ch0s1,
d2r_ch0s1, rr_ch0s1, d1l_ch0s1, ks_ch0s1, ssg_ch0s1,
kon_ch0s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s2, fnum_ch0s2, rl_ch0s2, fb_ch0s2, alg_ch0s2,
dt1_ch0s2, mul_ch0s2, tl_ch0s2, ar_ch0s2, d1r_ch0s2,
d2r_ch0s2, rr_ch0s2, d1l_ch0s2, ks_ch0s2, ssg_ch0s2,
kon_ch0s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s1, fnum_ch0s3, rl_ch0s3, fb_ch0s3, alg_ch0s3,
dt1_ch0s3, mul_ch0s3, tl_ch0s3, ar_ch0s3, d1r_ch0s3,
d2r_ch0s3, rr_ch0s3, d1l_ch0s3, ks_ch0s3, ssg_ch0s3,
kon_ch0s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch0s4, fnum_ch0s4, rl_ch0s4, fb_ch0s4, alg_ch0s4,
dt1_ch0s4, mul_ch0s4, tl_ch0s4, ar_ch0s4, d1r_ch0s4,
d2r_ch0s4, rr_ch0s4, d1l_ch0s4, ks_ch0s4, ssg_ch0s4,
kon_ch0s4 );
// Channel 1
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s1, fnum_ch1s1, rl_ch1s1, fb_ch1s1, alg_ch1s1,
dt1_ch1s1, mul_ch1s1, tl_ch1s1, ar_ch1s1, d1r_ch1s1,
d2r_ch1s1, rr_ch1s1, d1l_ch1s1, ks_ch1s1, ssg_ch1s1,
kon_ch1s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s2, fnum_ch1s2, rl_ch1s2, fb_ch1s2, alg_ch1s2,
dt1_ch1s2, mul_ch1s2, tl_ch1s2, ar_ch1s2, d1r_ch1s2,
d2r_ch1s2, rr_ch1s2, d1l_ch1s2, ks_ch1s2, ssg_ch1s2,
kon_ch1s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s3, fnum_ch1s3, rl_ch1s3, fb_ch1s3, alg_ch1s3,
dt1_ch1s3, mul_ch1s3, tl_ch1s3, ar_ch1s3, d1r_ch1s3,
d2r_ch1s3, rr_ch1s3, d1l_ch1s3, ks_ch1s3, ssg_ch1s3,
kon_ch1s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch1s4, fnum_ch1s4, rl_ch1s4, fb_ch1s4, alg_ch1s4,
dt1_ch1s4, mul_ch1s4, tl_ch1s4, ar_ch1s4, d1r_ch1s4,
d2r_ch1s4, rr_ch1s4, d1l_ch1s4, ks_ch1s4, ssg_ch1s4,
kon_ch1s4 );
// Channel 2
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s1, fnum_ch2s1, rl_ch2s1, fb_ch2s1, alg_ch2s1,
dt1_ch2s1, mul_ch2s1, tl_ch2s1, ar_ch2s1, d1r_ch2s1,
d2r_ch2s1, rr_ch2s1, d1l_ch2s1, ks_ch2s1, ssg_ch2s1,
kon_ch2s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s2, fnum_ch2s2, rl_ch2s2, fb_ch2s2, alg_ch2s2,
dt1_ch2s2, mul_ch2s2, tl_ch2s2, ar_ch2s2, d1r_ch2s2,
d2r_ch2s2, rr_ch2s2, d1l_ch2s2, ks_ch2s2, ssg_ch2s2,
kon_ch2s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s3, fnum_ch2s3, rl_ch2s3, fb_ch2s3, alg_ch2s3,
dt1_ch2s3, mul_ch2s3, tl_ch2s3, ar_ch2s3, d1r_ch2s3,
d2r_ch2s3, rr_ch2s3, d1l_ch2s3, ks_ch2s3, ssg_ch2s3,
kon_ch2s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch2s4, fnum_ch2s4, rl_ch2s4, fb_ch2s4, alg_ch2s4,
dt1_ch2s4, mul_ch2s4, tl_ch2s4, ar_ch2s4, d1r_ch2s4,
d2r_ch2s4, rr_ch2s4, d1l_ch2s4, ks_ch2s4, ssg_ch2s4,
kon_ch2s4 );
// Channel 3
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s1, fnum_ch3s1, rl_ch3s1, fb_ch3s1, alg_ch3s1,
dt1_ch3s1, mul_ch3s1, tl_ch3s1, ar_ch3s1, d1r_ch3s1,
d2r_ch3s1, rr_ch3s1, d1l_ch3s1, ks_ch3s1, ssg_ch3s1,
kon_ch3s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s2, fnum_ch3s2, rl_ch3s2, fb_ch3s2, alg_ch3s2,
dt1_ch3s2, mul_ch3s2, tl_ch3s2, ar_ch3s2, d1r_ch3s2,
d2r_ch3s2, rr_ch3s2, d1l_ch3s2, ks_ch3s2, ssg_ch3s2,
kon_ch3s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s3, fnum_ch3s3, rl_ch3s3, fb_ch3s3, alg_ch3s3,
dt1_ch3s3, mul_ch3s3, tl_ch3s3, ar_ch3s3, d1r_ch3s3,
d2r_ch3s3, rr_ch3s3, d1l_ch3s3, ks_ch3s3, ssg_ch3s3,
kon_ch3s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch3s4, fnum_ch3s4, rl_ch3s4, fb_ch3s4, alg_ch3s4,
dt1_ch3s4, mul_ch3s4, tl_ch3s4, ar_ch3s4, d1r_ch3s4,
d2r_ch3s4, rr_ch3s4, d1l_ch3s4, ks_ch3s4, ssg_ch3s4,
kon_ch3s4 );
// Channel 4
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s1, fnum_ch4s1, rl_ch4s1, fb_ch4s1, alg_ch4s1,
dt1_ch4s1, mul_ch4s1, tl_ch4s1, ar_ch4s1, d1r_ch4s1,
d2r_ch4s1, rr_ch4s1, d1l_ch4s1, ks_ch4s1, ssg_ch4s1,
kon_ch4s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s2, fnum_ch4s2, rl_ch4s2, fb_ch4s2, alg_ch4s2,
dt1_ch4s2, mul_ch4s2, tl_ch4s2, ar_ch4s2, d1r_ch4s2,
d2r_ch4s2, rr_ch4s2, d1l_ch4s2, ks_ch4s2, ssg_ch4s2,
kon_ch4s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s3, fnum_ch4s3, rl_ch4s3, fb_ch4s3, alg_ch4s3,
dt1_ch4s3, mul_ch4s3, tl_ch4s3, ar_ch4s3, d1r_ch4s3,
d2r_ch4s3, rr_ch4s3, d1l_ch4s3, ks_ch4s3, ssg_ch4s3,
kon_ch4s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch4s4, fnum_ch4s4, rl_ch4s4, fb_ch4s4, alg_ch4s4,
dt1_ch4s4, mul_ch4s4, tl_ch4s4, ar_ch4s4, d1r_ch4s4,
d2r_ch4s4, rr_ch4s4, d1l_ch4s4, ks_ch4s4, ssg_ch4s4,
kon_ch4s4 );
// Channel 5
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s1, fnum_ch5s1, rl_ch5s1, fb_ch5s1, alg_ch5s1,
dt1_ch5s1, mul_ch5s1, tl_ch5s1, ar_ch5s1, d1r_ch5s1,
d2r_ch5s1, rr_ch5s1, d1l_ch5s1, ks_ch5s1, ssg_ch5s1,
kon_ch5s1 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s2, fnum_ch5s2, rl_ch5s2, fb_ch5s2, alg_ch5s2,
dt1_ch5s2, mul_ch5s2, tl_ch5s2, ar_ch5s2, d1r_ch5s2,
d2r_ch5s2, rr_ch5s2, d1l_ch5s2, ks_ch5s2, ssg_ch5s2,
kon_ch5s2 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s3, fnum_ch5s3, rl_ch5s3, fb_ch5s3, alg_ch5s3,
dt1_ch5s3, mul_ch5s3, tl_ch5s3, ar_ch5s3, d1r_ch5s3,
d2r_ch5s3, rr_ch5s3, d1l_ch5s3, ks_ch5s3, ssg_ch5s3,
kon_ch5s3 );
$fdisplay( fmmr, "%x %x %x %x %x, %x %x %x %x %x %x, %x %x %x %x %x",
block_ch5s4, fnum_ch5s4, rl_ch5s4, fb_ch5s4, alg_ch5s4,
dt1_ch5s4, mul_ch5s4, tl_ch5s4, ar_ch5s4, d1r_ch5s4,
d2r_ch5s4, rr_ch5s4, d1l_ch5s4, ks_ch5s4, ssg_ch5s4,
kon_ch5s4 );
end
`endif

122
rtl/sound/jt12/jt12_mod.v Normal file
View File

@ -0,0 +1,122 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
module jt12_mod(
input s1_enters,
input s2_enters,
input s3_enters,
input s4_enters,
input [2:0] alg_I,
output reg use_prevprev1,
output reg use_internal_x,
output reg use_internal_y,
output reg use_prev2,
output reg use_prev1
);
reg [7:0] alg_hot;
always @(*) begin
case( alg_I )
3'd0: alg_hot <= 8'h1; // D0
3'd1: alg_hot <= 8'h2; // D1
3'd2: alg_hot <= 8'h4; // D2
3'd3: alg_hot <= 8'h8; // D3
3'd4: alg_hot <= 8'h10; // D4
3'd5: alg_hot <= 8'h20; // D5
3'd6: alg_hot <= 8'h40; // D6
3'd7: alg_hot <= 8'h80; // D7
endcase
end
always @(*) begin
use_prevprev1 <= s1_enters | (s3_enters&alg_hot[5]);
use_prev2 <= (s3_enters&(|alg_hot[2:0])) | (s4_enters&alg_hot[3]);
use_internal_x <= s4_enters & alg_hot[2];
use_internal_y <= s4_enters & (|{alg_hot[4:3],alg_hot[1:0]});
use_prev1 <= s1_enters | (s3_enters&alg_hot[1]) |
(s2_enters&(|{alg_hot[6:3],alg_hot[0]}) )|
(s4_enters&(|{alg_hot[5],alg_hot[2]}));
end
/*
always @(*) begin
use_prevprev1 <= s1_enters || (s3_enters&&(alg_I==3'd5));
use_prev2 <= (s3_enters&&(alg_I<=3'd2)) || (s4_enters&&(alg_I==3'd3));
use_internal_x <= s4_enters && (alg_I==3'd2);
use_internal_y <= s4_enters && (alg_I<=3'd4 && alg_I!=3'd2);
use_prev1 <= s1_enters || (s3_enters&&(alg_I==3'd1)) ||
(s2_enters&&(alg_I==3'd0 ||
alg_I==3'd3 || alg_I==3'd4 ||
alg_I==3'd5 || alg_I==3'd6)) ||
(s4_enters&&(alg_I==3'd2 || alg_I==3'd5));
end
always @(*) begin
case( {s1_enters, s3_enters, s2_enters, s4_enters} ) // synthesis parallel_case
4'b1000: begin // S1
use_prevprev1 <= 1'b1;
use_prev2 <= 1'b0;
use_internal_x<= 1'b0;
use_internal_y<= 1'b0;
use_prev1 <= 1'b1;
end
4'b0100: begin // S3
use_prevprev1 <= alg_I==3'd5;
use_prev2 <= (alg_I<=3'd2);
use_internal_x<= 1'b0;
use_internal_y<= 1'b0;
use_prev1 <= alg_I==3'd1;
end
4'b0010: begin // S2
use_prevprev1 <= 1'b0;
use_prev2 <= 1'b0;
use_internal_x<= 1'b0;
use_prev1 <= (alg_I==3'd0 ||
alg_I==3'd3 || alg_I==3'd4 ||
alg_I==3'd5 || alg_I==3'd6 );
use_internal_y<= 1'b0;
end
4'b0001: begin // S4
use_prevprev1 <= 1'b0;
use_prev2 <= ( alg_I==3'd3 );
use_internal_x <= alg_I==3'd2;
use_prev1 <= (alg_I==3'd2 || alg_I==3'd5);
use_internal_y <= ( alg_I<=3'd4 && alg_I!=3'd2);
end
default:begin
use_prevprev1 <= 1'bx;
use_prev2 <= 1'bx;
use_internal_x<= 1'bx;
use_prev1 <= 1'bx;
use_internal_y<= 1'bx;
end
endcase
end
*/
endmodule

536
rtl/sound/jt12/jt12_op.v Normal file
View File

@ -0,0 +1,536 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
module jt12_op(
input rst,
input clk,
input [9:0] pg_phase_VIII,
input [9:0] eg_atten_IX, // output from envelope generator
input [2:0] fb_II, // voice feedback
input use_prevprev1,
input use_internal_x,
input use_internal_y,
input use_prev2,
input use_prev1,
input test_214,
input s1_enters,
input s2_enters,
input s3_enters,
input s4_enters,
input zero,
output signed [8:0] op_result
);
/* enters exits
S1 S2
S3 S4
S2 S1
S4 S3
*/
reg [13:0] op_result_internal, op_XII;
reg [11:0] atten_internal_IX;
assign op_result = op_result_internal[13:5];
parameter NUM_VOICES = 6;
reg signbit_IX, signbit_X, signbit_XI;
reg [11:0] totalatten_X;
wire [13:0] prev1, prevprev1, prev2;
jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prev1_buffer(
// .rst ( rst ),
.clk ( clk ),
.din ( s2_enters ? op_result_internal : prev1 ),
.drop ( prev1 )
);
jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prevprev1_buffer(
// .rst ( rst ),
.clk ( clk ),
.din ( s2_enters ? prev1 : prevprev1 ),
.drop ( prevprev1 )
);
jt12_sh/*_rst*/ #( .width(14), .stages(NUM_VOICES)) prev2_buffer(
// .rst ( rst ),
.clk ( clk ),
.din ( s1_enters ? op_result_internal : prev2 ),
.drop ( prev2 )
);
reg [18:0] stb;
reg [10:0] stf, stg;
reg [11:0] logsin;
reg [10:0] subtresult;
reg [12:0] etb;
reg [ 9:0] etf, etg, mantissa_XI;
reg [ 3:0] exponent_XI;
reg [12:0] shifter, shifter_2, shifter_3;
// REGISTER/CYCLE 1
// Creation of phase modulation (FM) feedback signal, before shifting
reg [13:0] x, y;
reg [14:0] xs, ys, pm_preshift_II;
reg s1_II;
always @(*) begin
x <= ( {14{use_prevprev1}} & prevprev1 ) |
( {14{use_internal_x}} & op_result_internal ) |
( {14{use_prev2}} & prev2 );
y <= ( {14{use_prev1}} & prev1 ) |
( {14{use_internal_y}} & op_result_internal );
xs <= { x[13], x }; // sign-extend
ys <= { y[13], y }; // sign-extend
end
always @(posedge clk) begin
pm_preshift_II <= xs + ys; // carry is discarded
s1_II <= s1_enters;
end
/* REGISTER/CYCLE 2-7 (also YM2612 extra cycles 1-6)
Shifting of FM feedback signal, adding phase from PG to FM phase
In YM2203, phasemod_II is not registered at all, it is latched on the first edge
in add_pg_phase and the second edge is the output of add_pg_phase. In the YM2612, there
are 6 cycles worth of registers between the generated (non-registered) phasemod_II signal
and the input to add_pg_phase. */
reg [9:0] phasemod_II;
wire [9:0] phasemod_VIII;
always @(*) begin
// Shift FM feedback signal
if (!s1_II ) // Not S1
phasemod_II <= pm_preshift_II[10:1]; // Bit 0 of pm_preshift_II is never used
else // S1
case( fb_II )
3'd0: phasemod_II <= 10'd0;
3'd1: phasemod_II <= { {4{pm_preshift_II[14]}}, pm_preshift_II[14:9] };
3'd2: phasemod_II <= { {3{pm_preshift_II[14]}}, pm_preshift_II[14:8] };
3'd3: phasemod_II <= { {2{pm_preshift_II[14]}}, pm_preshift_II[14:7] };
3'd4: phasemod_II <= { pm_preshift_II[14], pm_preshift_II[14:6] };
3'd5: phasemod_II <= pm_preshift_II[14:5];
3'd6: phasemod_II <= pm_preshift_II[13:4];
3'd7: phasemod_II <= pm_preshift_II[12:3];
endcase
end
// REGISTER/CYCLE 2-7
jt12_sh #( .width(10), .stages(NUM_VOICES)) phasemod_sh(
.clk ( clk ),
.din ( phasemod_II ),
.drop ( phasemod_VIII )
);
// REGISTER/CYCLE 8
reg [ 9:0] phase;
// Sets the maximum number of fanouts for a register or combinational
// cell. The Quartus II software will replicate the cell and split
// the fanouts among the duplicates until the fanout of each cell
// is below the maximum.
reg [ 7:0] phaselo_IX, aux_VIII;
always @(*) begin
phase <= phasemod_VIII + pg_phase_VIII;
aux_VIII<= phase[7:0] ^ {8{~phase[8]}};
end
always @(posedge clk) begin
phaselo_IX <= aux_VIII;
signbit_IX <= phase[9];
end
wire [45:0] sta_IX;
jt12_phrom u_phrom(
.clk ( clk ),
.addr ( aux_VIII[5:1] ),
.ph ( sta_IX )
);
// REGISTER/CYCLE 9
// Sine table
// Main sine table body
always @(*) begin
//sta_IX <= sinetable[ phaselo_IX[5:1] ];
// 2-bit row chooser
case( phaselo_IX[7:6] )
2'b00: stb <= { 10'b0, sta_IX[29], sta_IX[25], 2'b0, sta_IX[18],
sta_IX[14], 1'b0, sta_IX[7] , sta_IX[3] };
2'b01: stb <= { 6'b0 , sta_IX[37], sta_IX[34], 2'b0, sta_IX[28],
sta_IX[24], 2'b0, sta_IX[17], sta_IX[13], sta_IX[10], sta_IX[6], sta_IX[2] };
2'b10: stb <= { 2'b0, sta_IX[43], sta_IX[41], 2'b0, sta_IX[36],
sta_IX[33], 2'b0, sta_IX[27], sta_IX[23], 1'b0, sta_IX[20],
sta_IX[16], sta_IX[12], sta_IX[9], sta_IX[5], sta_IX[1] };
default: stb <= {
sta_IX[45], sta_IX[44], sta_IX[42], sta_IX[40]
, sta_IX[39], sta_IX[38], sta_IX[35], sta_IX[32]
, sta_IX[31], sta_IX[30], sta_IX[26], sta_IX[22]
, sta_IX[21], sta_IX[19], sta_IX[15], sta_IX[11]
, sta_IX[8], sta_IX[4], sta_IX[0] };
endcase
// Fixed value to sum
stf <= { stb[18:15], stb[12:11], stb[8:7], stb[4:3], stb[0] };
// Gated value to sum; bit 14 is indeed used twice
if( phaselo_IX[0] )
stg <= { 2'b0, stb[14], stb[14:13], stb[10:9], stb[6:5], stb[2:1] };
else
stg <= 11'd0;
// Sum to produce final logsin value
logsin <= stf + stg; // Carry-out of 11-bit addition becomes 12th bit
// Invert-subtract logsin value from EG attenuation value, with inverted carry
// In the actual chip, the output of the above logsin sum is already inverted.
// The two LSBs go through inverters (so they're non-inverted); the eg_atten_IX signal goes through inverters.
// The adder is normal except the carry-in is 1. It's a 10-bit adder.
// The outputs are inverted outputs, including the carry bit.
//subtresult <= not (('0' & not eg_atten_IX) - ('1' & logsin([11:2])));
// After a little pencil-and-paper, turns out this is equivalent to a regular adder!
subtresult <= eg_atten_IX + logsin[11:2];
// Place all but carry bit into result; also two LSBs of logsin
// If addition overflowed, make it the largest value (saturate)
atten_internal_IX <= { subtresult[9:0], logsin[1:0] } | {12{subtresult[10]}};
end
wire [44:0] exp_X;
jt12_exprom u_exprom(
.clk ( clk ),
.addr ( atten_internal_IX[5:1] ),
.exp ( exp_X )
);
always @(posedge clk) begin
totalatten_X <= atten_internal_IX;
signbit_X <= signbit_IX;
end
//wire [1:0] et_sel = totalatten_X[7:6];
//wire [4:0] et_fine = totalatten_X[5:1];
// REGISTER/CYCLE 10
// Exponential table
// Main sine table body
always @(*) begin
//eta <= explut_jt51[ totalatten_X[5:1] ];
// 2-bit row chooser
case( totalatten_X[7:6] )
2'b00: begin
etf <= { 1'b1, exp_X[44:36] };
etg <= { 1'b1, exp_X[35:34] };
end
2'b01: begin
etf <= exp_X[33:24];
etg <= { 2'b10, exp_X[23] };
end
2'b10: begin
etf <= { 1'b0, exp_X[22:14] };
etg <= exp_X[13:11];
end
2'b11: begin
etf <= { 2'b00, exp_X[10:3] };
etg <= exp_X[2:0];
end
endcase
end
always @(posedge clk) begin
//RESULT
mantissa_XI <= etf + ( totalatten_X[0] ? 3'd0 : etg ); //carry-out discarded
exponent_XI <= totalatten_X[11:8];
signbit_XI <= signbit_X;
end
// REGISTER/CYCLE 11
// Introduce test bit as MSB, 2's complement & Carry-out discarded
always @(*) begin
// Floating-point to integer, and incorporating sign bit
// Two-stage shifting of mantissa_XI by exponent_XI
shifter <= { 3'b001, mantissa_XI };
case( ~exponent_XI[1:0] )
2'b00: shifter_2 <= { 1'b0, shifter[12:1] }; // LSB discarded
2'b01: shifter_2 <= shifter;
2'b10: shifter_2 <= { shifter[11:0], 1'b0 };
2'b11: shifter_2 <= { shifter[10:0], 2'b0 };
endcase
case( ~exponent_XI[3:2] )
2'b00: shifter_3 <= {12'b0, shifter_2[12] };
2'b01: shifter_3 <= { 8'b0, shifter_2[12:8] };
2'b10: shifter_3 <= { 4'b0, shifter_2[12:4] };
2'b11: shifter_3 <= shifter_2;
endcase
end
always @(posedge clk) begin
// REGISTER CYCLE 11
op_XII <= ({ test_214, shifter_3 } ^ {14{signbit_XI}}) + signbit_XI;
// REGISTER CYCLE 12
// Extra register, take output after here
op_result_internal <= op_XII;
end
`ifdef SIMULATION
reg [4:0] sep24_cnt;
wire signed [13:0] op_ch0s1, op_ch1s1, op_ch2s1, op_ch3s1,
op_ch4s1, op_ch5s1, op_ch0s2, op_ch1s2,
op_ch2s2, op_ch3s2, op_ch4s2, op_ch5s2,
op_ch0s3, op_ch1s3, op_ch2s3, op_ch3s3,
op_ch4s3, op_ch5s3, op_ch0s4, op_ch1s4,
op_ch2s4, op_ch3s4, op_ch4s4, op_ch5s4;
always @(posedge clk )
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
sep24 #( .width(14), .pos0(13)) opsep
(
.clk ( clk ),
.mixed ( op_result_internal ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (op_ch0s1),
.ch1s1 (op_ch1s1),
.ch2s1 (op_ch2s1),
.ch3s1 (op_ch3s1),
.ch4s1 (op_ch4s1),
.ch5s1 (op_ch5s1),
.ch0s2 (op_ch0s2),
.ch1s2 (op_ch1s2),
.ch2s2 (op_ch2s2),
.ch3s2 (op_ch3s2),
.ch4s2 (op_ch4s2),
.ch5s2 (op_ch5s2),
.ch0s3 (op_ch0s3),
.ch1s3 (op_ch1s3),
.ch2s3 (op_ch2s3),
.ch3s3 (op_ch3s3),
.ch4s3 (op_ch4s3),
.ch5s3 (op_ch5s3),
.ch0s4 (op_ch0s4),
.ch1s4 (op_ch1s4),
.ch2s4 (op_ch2s4),
.ch3s4 (op_ch3s4),
.ch4s4 (op_ch4s4),
.ch5s4 (op_ch5s4)
);
wire signed [8:0] acc_ch0s1, acc_ch1s1, acc_ch2s1, acc_ch3s1,
acc_ch4s1, acc_ch5s1, acc_ch0s2, acc_ch1s2,
acc_ch2s2, acc_ch3s2, acc_ch4s2, acc_ch5s2,
acc_ch0s3, acc_ch1s3, acc_ch2s3, acc_ch3s3,
acc_ch4s3, acc_ch5s3, acc_ch0s4, acc_ch1s4,
acc_ch2s4, acc_ch3s4, acc_ch4s4, acc_ch5s4;
sep24 #( .width(9), .pos0(13)) accsep
(
.clk ( clk ),
.mixed ( op_result_internal[13:5] ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (acc_ch0s1),
.ch1s1 (acc_ch1s1),
.ch2s1 (acc_ch2s1),
.ch3s1 (acc_ch3s1),
.ch4s1 (acc_ch4s1),
.ch5s1 (acc_ch5s1),
.ch0s2 (acc_ch0s2),
.ch1s2 (acc_ch1s2),
.ch2s2 (acc_ch2s2),
.ch3s2 (acc_ch3s2),
.ch4s2 (acc_ch4s2),
.ch5s2 (acc_ch5s2),
.ch0s3 (acc_ch0s3),
.ch1s3 (acc_ch1s3),
.ch2s3 (acc_ch2s3),
.ch3s3 (acc_ch3s3),
.ch4s3 (acc_ch4s3),
.ch5s3 (acc_ch5s3),
.ch0s4 (acc_ch0s4),
.ch1s4 (acc_ch1s4),
.ch2s4 (acc_ch2s4),
.ch3s4 (acc_ch3s4),
.ch4s4 (acc_ch4s4),
.ch5s4 (acc_ch5s4)
);
wire signed [9:0] pm_ch0s1, pm_ch1s1, pm_ch2s1, pm_ch3s1,
pm_ch4s1, pm_ch5s1, pm_ch0s2, pm_ch1s2,
pm_ch2s2, pm_ch3s2, pm_ch4s2, pm_ch5s2,
pm_ch0s3, pm_ch1s3, pm_ch2s3, pm_ch3s3,
pm_ch4s3, pm_ch5s3, pm_ch0s4, pm_ch1s4,
pm_ch2s4, pm_ch3s4, pm_ch4s4, pm_ch5s4;
sep24 #( .width(10), .pos0( 18 ) ) pmsep
(
.clk ( clk ),
.mixed ( phasemod_VIII ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (pm_ch0s1),
.ch1s1 (pm_ch1s1),
.ch2s1 (pm_ch2s1),
.ch3s1 (pm_ch3s1),
.ch4s1 (pm_ch4s1),
.ch5s1 (pm_ch5s1),
.ch0s2 (pm_ch0s2),
.ch1s2 (pm_ch1s2),
.ch2s2 (pm_ch2s2),
.ch3s2 (pm_ch3s2),
.ch4s2 (pm_ch4s2),
.ch5s2 (pm_ch5s2),
.ch0s3 (pm_ch0s3),
.ch1s3 (pm_ch1s3),
.ch2s3 (pm_ch2s3),
.ch3s3 (pm_ch3s3),
.ch4s3 (pm_ch4s3),
.ch5s3 (pm_ch5s3),
.ch0s4 (pm_ch0s4),
.ch1s4 (pm_ch1s4),
.ch2s4 (pm_ch2s4),
.ch3s4 (pm_ch3s4),
.ch4s4 (pm_ch4s4),
.ch5s4 (pm_ch5s4)
);
wire [9:0] phase_ch0s1, phase_ch1s1, phase_ch2s1, phase_ch3s1,
phase_ch4s1, phase_ch5s1, phase_ch0s2, phase_ch1s2,
phase_ch2s2, phase_ch3s2, phase_ch4s2, phase_ch5s2,
phase_ch0s3, phase_ch1s3, phase_ch2s3, phase_ch3s3,
phase_ch4s3, phase_ch5s3, phase_ch0s4, phase_ch1s4,
phase_ch2s4, phase_ch3s4, phase_ch4s4, phase_ch5s4;
sep24 #( .width(10), .pos0( 18 ) ) phsep
(
.clk ( clk ),
.mixed ( phase ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (phase_ch0s1),
.ch1s1 (phase_ch1s1),
.ch2s1 (phase_ch2s1),
.ch3s1 (phase_ch3s1),
.ch4s1 (phase_ch4s1),
.ch5s1 (phase_ch5s1),
.ch0s2 (phase_ch0s2),
.ch1s2 (phase_ch1s2),
.ch2s2 (phase_ch2s2),
.ch3s2 (phase_ch3s2),
.ch4s2 (phase_ch4s2),
.ch5s2 (phase_ch5s2),
.ch0s3 (phase_ch0s3),
.ch1s3 (phase_ch1s3),
.ch2s3 (phase_ch2s3),
.ch3s3 (phase_ch3s3),
.ch4s3 (phase_ch4s3),
.ch5s3 (phase_ch5s3),
.ch0s4 (phase_ch0s4),
.ch1s4 (phase_ch1s4),
.ch2s4 (phase_ch2s4),
.ch3s4 (phase_ch3s4),
.ch4s4 (phase_ch4s4),
.ch5s4 (phase_ch5s4)
);
wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1,
eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2,
eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3,
eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4;
sep24 #( .width(10), .pos0(17) ) egsep
(
.clk ( clk ),
.mixed ( eg_atten_IX ),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (eg_ch0s1),
.ch1s1 (eg_ch1s1),
.ch2s1 (eg_ch2s1),
.ch3s1 (eg_ch3s1),
.ch4s1 (eg_ch4s1),
.ch5s1 (eg_ch5s1),
.ch0s2 (eg_ch0s2),
.ch1s2 (eg_ch1s2),
.ch2s2 (eg_ch2s2),
.ch3s2 (eg_ch3s2),
.ch4s2 (eg_ch4s2),
.ch5s2 (eg_ch5s2),
.ch0s3 (eg_ch0s3),
.ch1s3 (eg_ch1s3),
.ch2s3 (eg_ch2s3),
.ch3s3 (eg_ch3s3),
.ch4s3 (eg_ch4s3),
.ch5s3 (eg_ch5s3),
.ch0s4 (eg_ch0s4),
.ch1s4 (eg_ch1s4),
.ch2s4 (eg_ch2s4),
.ch3s4 (eg_ch3s4),
.ch4s4 (eg_ch4s4),
.ch5s4 (eg_ch5s4)
);
`endif
endmodule

View File

@ -0,0 +1,79 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
module jt12_opram
(
input [4:0] wr_addr,
input [4:0] rd_addr,
input clk,
input [43:0] data,
output reg [43:0] q
);
reg [43:0] ram[31:0];
initial
begin
ram[0] = { ~7'd0, 37'd0 };
ram[1] = { ~7'd0, 37'd0 };
ram[2] = { ~7'd0, 37'd0 };
ram[3] = { ~7'd0, 37'd0 };
ram[4] = { ~7'd0, 37'd0 };
ram[5] = { ~7'd0, 37'd0 };
ram[6] = { ~7'd0, 37'd0 };
ram[7] = { ~7'd0, 37'd0 };
ram[8] = { ~7'd0, 37'd0 };
ram[9] = { ~7'd0, 37'd0 };
ram[10] = { ~7'd0, 37'd0 };
ram[11] = { ~7'd0, 37'd0 };
ram[12] = { ~7'd0, 37'd0 };
ram[13] = { ~7'd0, 37'd0 };
ram[14] = { ~7'd0, 37'd0 };
ram[15] = { ~7'd0, 37'd0 };
ram[16] = { ~7'd0, 37'd0 };
ram[17] = { ~7'd0, 37'd0 };
ram[18] = { ~7'd0, 37'd0 };
ram[19] = { ~7'd0, 37'd0 };
ram[20] = { ~7'd0, 37'd0 };
ram[21] = { ~7'd0, 37'd0 };
ram[22] = { ~7'd0, 37'd0 };
ram[23] = { ~7'd0, 37'd0 };
ram[24] = { ~7'd0, 37'd0 };
ram[25] = { ~7'd0, 37'd0 };
ram[26] = { ~7'd0, 37'd0 };
ram[27] = { ~7'd0, 37'd0 };
ram[28] = { ~7'd0, 37'd0 };
ram[29] = { ~7'd0, 37'd0 };
ram[30] = { ~7'd0, 37'd0 };
ram[31] = { ~7'd0, 37'd0 };
end
always @ (posedge clk) begin
q <= ram[rd_addr];
ram[wr_addr] <= data;
end
endmodule

412
rtl/sound/jt12/jt12_pg.v Normal file
View File

@ -0,0 +1,412 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2016
Based on information posted by Nemesis on:
http://gendev.spritesmind.net/forum/viewtopic.php?t=386&postdays=0&postorder=asc&start=167
Based on jt51_phasegen.v, from JT51
*/
`timescale 1ns / 1ps
/*
tab size 4
*/
module jt12_pg(
input clk,
input rst,
// Channel frequency
input [10:0] fnum_I,
input [ 2:0] block_I,
// Operator multiplying
input [ 3:0] mul_V,
// Operator detuning
input [ 2:0] dt1_II, // same as JT51's DT1
// phase modulation from LFO
//input [ 7:0] pm,
//input [ 2:0] pms,
// phase operation
input pg_rst_III,
input zero,
input pg_stop,
output reg [ 4:0] keycode_III,
output reg [ 9:0] phase_VIII
);
/*
reg signed [8:0] mod;
always @(*) begin
case( pms ) // comprobar en silicio
3'd0: mod <= 9'd0;
3'd1: mod <= { 7'd0, pm[6:5] };
3'd2: mod <= { 6'd0, pm[6:4] };
3'd3: mod <= { 5'd0, pm[6:3] };
3'd4: mod <= { 4'd0, pm[6:2] };
3'd5: mod <= { 3'd0, pm[6:1] };
3'd6: mod <= { 1'd0, pm[6:0], 1'b0 };
3'd7: mod <= { pm[6:0], 2'b0 };
endcase
end
jt12_pm u_pm(
// Channel frequency
.kc(kc),
.kf(kf),
.add(~pm[7]),
.mod(mod),
.kcex(keycode_I)
);
*/
wire pg_rst_VI;
//////////////////////////////////////////////////
// I
reg [4:0] keycode_II;
reg [16:0] phinc_II;
always @(posedge clk) begin : phase_calculation_I
case ( block_I )
3'd0: phinc_II <= { 7'd0, fnum_I[10:1] };
3'd1: phinc_II <= { 6'd0, fnum_I };
3'd2: phinc_II <= { 5'd0, fnum_I, 1'd0 };
3'd3: phinc_II <= { 4'd0, fnum_I, 2'd0 };
3'd4: phinc_II <= { 3'd0, fnum_I, 3'd0 };
3'd5: phinc_II <= { 2'd0, fnum_I, 4'd0 };
3'd6: phinc_II <= { 1'd0, fnum_I, 5'd0 };
3'd7: phinc_II <= { fnum_I, 6'd0 };
endcase
keycode_II <= { block_I, fnum_I[10], fnum_I[10] ? (|fnum_I[9:7]) : (&fnum_I[9:7])};
end
//////////////////////////////////////////////////
// II
reg [ 5:0] dt1_kf_III;
reg [16:0] phinc_III;
reg [ 2:0] dt1_III;
always @(posedge clk) begin : phase_calculation_II
case( dt1_II[1:0] )
2'd1: dt1_kf_III <= { 1'b0, keycode_II } - 6'd4;
2'd2: dt1_kf_III <= { 1'b0, keycode_II } + 6'd4;
2'd3: dt1_kf_III <= { 1'b0, keycode_II } + 6'd8;
default:dt1_kf_III <= { 1'b0, keycode_II };
endcase
dt1_III <= dt1_II;
phinc_III <= phinc_II;
keycode_III <= keycode_II;
end
//////////////////////////////////////////////////
// III
reg [16:0] phinc_IV;
reg [ 4:0] pow2;
reg [ 2:0] dt1_IV;
always @(*) begin : calcpow2
case( dt1_kf_III[2:0] )
3'd0: pow2 <= 5'd16;
3'd1: pow2 <= 5'd17;
3'd2: pow2 <= 5'd19;
3'd3: pow2 <= 5'd20;
3'd4: pow2 <= 5'd22;
3'd5: pow2 <= 5'd24;
3'd6: pow2 <= 5'd26;
3'd7: pow2 <= 5'd29;
endcase
end
reg [5:0] dt1_unlimited;
reg [4:0] dt1_limit, dt1_offset_IV;
always @(*) begin : dt1_limit_mux
case( dt1_III[1:0] )
default: dt1_limit <= 5'd8;
2'd1: dt1_limit <= 5'd8;
2'd2: dt1_limit <= 5'd16;
2'd3: dt1_limit <= 5'd22;
endcase
case( dt1_kf_III[5:3] )
3'd0: dt1_unlimited <= { 5'd0, pow2[4] }; // <2
3'd1: dt1_unlimited <= { 4'd0, pow2[4:3] }; // <4
3'd2: dt1_unlimited <= { 3'd0, pow2[4:2] }; // <8
3'd3: dt1_unlimited <= { 2'd0, pow2[4:1] };
3'd4: dt1_unlimited <= { 1'd0, pow2[4:0] };
3'd5: dt1_unlimited <= { pow2[4:0], 1'd0 };
default:dt1_unlimited <= 6'd0;
endcase
end
always @(posedge clk) begin : phase_calculation_III
dt1_offset_IV <= dt1_unlimited > dt1_limit ?
dt1_limit : dt1_unlimited[4:0];
dt1_IV <= dt1_III;
phinc_IV <= phinc_III;
end
//////////////////////////////////////////////////
// IV
reg [16:0] phinc_V;
always @(posedge clk) begin : phase_calculation_IV
if( dt1_IV[1:0]==2'd0 )
phinc_V <= phinc_IV;
else begin
if( !dt1_IV[2] )
phinc_V <= phinc_IV + dt1_offset_IV;
else
phinc_V <= phinc_IV - dt1_offset_IV;
end
end
//////////////////////////////////////////////////
// V APPLY_MUL
reg [16:0] phinc_VI;
always @(posedge clk) begin : phase_calculation_V
if( mul_V==4'd0 )
phinc_VI <= { 1'b0, phinc_V[16:1] };
else
phinc_VI <= phinc_V * mul_V;
end
//////////////////////////////////////////////////
// VI add phinc to the phase
wire keyon_VI;
wire [19:0] phase_drop;
reg [19:0] phase_in;
reg [ 9:0] phase_VII;
always @(*)
phase_in <= pg_rst_VI ? 20'd0 :
( pg_stop ? phase_drop : phase_drop + phinc_VI);
always @(posedge clk) begin : phase_calculation_VI
phase_VII <= phase_in[19:10];
end
//////////////////////////////////////////////////
// VIII padding
always @(posedge clk)
phase_VIII <= phase_VII;
jt12_sh #( .width(20), .stages(24) ) u_phsh(
.clk ( clk ),
// .rst ( rst ),
.din ( phase_in ),
.drop ( phase_drop)
);
jt12_sh #( .width(1), .stages(3) ) u_rstsh(
.clk ( clk ),
.din ( pg_rst_III),
.drop ( pg_rst_VI )
);
`ifdef SIMULATION
reg [4:0] sep24_cnt;
wire [9:0] pg_ch0s1, pg_ch1s1, pg_ch2s1, pg_ch3s1,
pg_ch4s1, pg_ch5s1, pg_ch0s2, pg_ch1s2,
pg_ch2s2, pg_ch3s2, pg_ch4s2, pg_ch5s2,
pg_ch0s3, pg_ch1s3, pg_ch2s3, pg_ch3s3,
pg_ch4s3, pg_ch5s3, pg_ch0s4, pg_ch1s4,
pg_ch2s4, pg_ch3s4, pg_ch4s4, pg_ch5s4;
always @(posedge clk)
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
sep24 #( .width(10), .pos0(18)) stsep
(
.clk ( clk ),
.mixed ( phase_VIII),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (pg_ch0s1),
.ch1s1 (pg_ch1s1),
.ch2s1 (pg_ch2s1),
.ch3s1 (pg_ch3s1),
.ch4s1 (pg_ch4s1),
.ch5s1 (pg_ch5s1),
.ch0s2 (pg_ch0s2),
.ch1s2 (pg_ch1s2),
.ch2s2 (pg_ch2s2),
.ch3s2 (pg_ch3s2),
.ch4s2 (pg_ch4s2),
.ch5s2 (pg_ch5s2),
.ch0s3 (pg_ch0s3),
.ch1s3 (pg_ch1s3),
.ch2s3 (pg_ch2s3),
.ch3s3 (pg_ch3s3),
.ch4s3 (pg_ch4s3),
.ch5s3 (pg_ch5s3),
.ch0s4 (pg_ch0s4),
.ch1s4 (pg_ch1s4),
.ch2s4 (pg_ch2s4),
.ch3s4 (pg_ch3s4),
.ch4s4 (pg_ch4s4),
.ch5s4 (pg_ch5s4)
);
wire [16:0] phinc_ch0s1, phinc_ch1s1, phinc_ch2s1, phinc_ch3s1,
phinc_ch4s1, phinc_ch5s1, phinc_ch0s2, phinc_ch1s2,
phinc_ch2s2, phinc_ch3s2, phinc_ch4s2, phinc_ch5s2,
phinc_ch0s3, phinc_ch1s3, phinc_ch2s3, phinc_ch3s3,
phinc_ch4s3, phinc_ch5s3, phinc_ch0s4, phinc_ch1s4,
phinc_ch2s4, phinc_ch3s4, phinc_ch4s4, phinc_ch5s4;
sep24 #( .width(17), .pos0(3+6)) pisep
(
.clk ( clk ),
.mixed ( phinc_VI),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (phinc_ch0s1),
.ch1s1 (phinc_ch1s1),
.ch2s1 (phinc_ch2s1),
.ch3s1 (phinc_ch3s1),
.ch4s1 (phinc_ch4s1),
.ch5s1 (phinc_ch5s1),
.ch0s2 (phinc_ch0s2),
.ch1s2 (phinc_ch1s2),
.ch2s2 (phinc_ch2s2),
.ch3s2 (phinc_ch3s2),
.ch4s2 (phinc_ch4s2),
.ch5s2 (phinc_ch5s2),
.ch0s3 (phinc_ch0s3),
.ch1s3 (phinc_ch1s3),
.ch2s3 (phinc_ch2s3),
.ch3s3 (phinc_ch3s3),
.ch4s3 (phinc_ch4s3),
.ch5s3 (phinc_ch5s3),
.ch0s4 (phinc_ch0s4),
.ch1s4 (phinc_ch1s4),
.ch2s4 (phinc_ch2s4),
.ch3s4 (phinc_ch3s4),
.ch4s4 (phinc_ch4s4),
.ch5s4 (phinc_ch5s4)
);
wire [10:0] fnum_ch0s1, fnum_ch1s1, fnum_ch2s1, fnum_ch3s1,
fnum_ch4s1, fnum_ch5s1, fnum_ch0s2, fnum_ch1s2,
fnum_ch2s2, fnum_ch3s2, fnum_ch4s2, fnum_ch5s2,
fnum_ch0s3, fnum_ch1s3, fnum_ch2s3, fnum_ch3s3,
fnum_ch4s3, fnum_ch5s3, fnum_ch0s4, fnum_ch1s4,
fnum_ch2s4, fnum_ch3s4, fnum_ch4s4, fnum_ch5s4;
sep24 #( .width(11), .pos0(3+1)) fnsep
(
.clk ( clk ),
.mixed ( fnum_I),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (fnum_ch0s1),
.ch1s1 (fnum_ch1s1),
.ch2s1 (fnum_ch2s1),
.ch3s1 (fnum_ch3s1),
.ch4s1 (fnum_ch4s1),
.ch5s1 (fnum_ch5s1),
.ch0s2 (fnum_ch0s2),
.ch1s2 (fnum_ch1s2),
.ch2s2 (fnum_ch2s2),
.ch3s2 (fnum_ch3s2),
.ch4s2 (fnum_ch4s2),
.ch5s2 (fnum_ch5s2),
.ch0s3 (fnum_ch0s3),
.ch1s3 (fnum_ch1s3),
.ch2s3 (fnum_ch2s3),
.ch3s3 (fnum_ch3s3),
.ch4s3 (fnum_ch4s3),
.ch5s3 (fnum_ch5s3),
.ch0s4 (fnum_ch0s4),
.ch1s4 (fnum_ch1s4),
.ch2s4 (fnum_ch2s4),
.ch3s4 (fnum_ch3s4),
.ch4s4 (fnum_ch4s4),
.ch5s4 (fnum_ch5s4)
);
wire pgrst_III_ch0s1, pgrst_III_ch1s1, pgrst_III_ch2s1, pgrst_III_ch3s1,
pgrst_III_ch4s1, pgrst_III_ch5s1, pgrst_III_ch0s2, pgrst_III_ch1s2,
pgrst_III_ch2s2, pgrst_III_ch3s2, pgrst_III_ch4s2, pgrst_III_ch5s2,
pgrst_III_ch0s3, pgrst_III_ch1s3, pgrst_III_ch2s3, pgrst_III_ch3s3,
pgrst_III_ch4s3, pgrst_III_ch5s3, pgrst_III_ch0s4, pgrst_III_ch1s4,
pgrst_III_ch2s4, pgrst_III_ch3s4, pgrst_III_ch4s4, pgrst_III_ch5s4;
sep24 #( .width(1), .pos0(23)) pgrstsep
(
.clk ( clk ),
.mixed ( pg_rst_III),
.mask ( 0 ),
.cnt ( sep24_cnt ),
.ch0s1 (pgrst_III_ch0s1),
.ch1s1 (pgrst_III_ch1s1),
.ch2s1 (pgrst_III_ch2s1),
.ch3s1 (pgrst_III_ch3s1),
.ch4s1 (pgrst_III_ch4s1),
.ch5s1 (pgrst_III_ch5s1),
.ch0s2 (pgrst_III_ch0s2),
.ch1s2 (pgrst_III_ch1s2),
.ch2s2 (pgrst_III_ch2s2),
.ch3s2 (pgrst_III_ch3s2),
.ch4s2 (pgrst_III_ch4s2),
.ch5s2 (pgrst_III_ch5s2),
.ch0s3 (pgrst_III_ch0s3),
.ch1s3 (pgrst_III_ch1s3),
.ch2s3 (pgrst_III_ch2s3),
.ch3s3 (pgrst_III_ch3s3),
.ch4s3 (pgrst_III_ch4s3),
.ch5s3 (pgrst_III_ch5s3),
.ch0s4 (pgrst_III_ch0s4),
.ch1s4 (pgrst_III_ch1s4),
.ch2s4 (pgrst_III_ch2s4),
.ch3s4 (pgrst_III_ch3s4),
.ch4s4 (pgrst_III_ch4s4),
.ch5s4 (pgrst_III_ch5s4)
);
`endif
endmodule

View File

@ -0,0 +1,77 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
// altera message_off 10030
module jt12_phrom
(
input [4:0] addr,
input clk,
output reg [45:0] ph
);
reg [45:0] sinetable[31:0];
initial
begin
sinetable[5'd0 ] <= 46'b0001100000100100010001000010101010101001010010;
sinetable[5'd1 ] <= 46'b0001100000110100000100000010010001001101000001;
sinetable[5'd2 ] <= 46'b0001100000110100000100110010001011001101100000;
sinetable[5'd3 ] <= 46'b0001110000010000000000110010110001001101110010;
sinetable[5'd4 ] <= 46'b0001110000010000001100000010111010001101101001;
sinetable[5'd5 ] <= 46'b0001110000010100001001100010000000101101111010;
sinetable[5'd6 ] <= 46'b0001110000010100001101100010010011001101011010;
sinetable[5'd7 ] <= 46'b0001110000011100000101010010111000101111111100;
sinetable[5'd8 ] <= 46'b0001110000111000000001110010101110001101110111;
sinetable[5'd9 ] <= 46'b0001110000111000010100111000011101011010100110;
sinetable[5'd10] <= 46'b0001110000111100011000011000111100001001111010;
sinetable[5'd11] <= 46'b0001110000111100011100111001101011001001110111;
sinetable[5'd12] <= 46'b0100100001010000010001011001001000111010110111;
sinetable[5'd13] <= 46'b0100100001010100010001001001110001111100101010;
sinetable[5'd14] <= 46'b0100100001010100010101101101111110100101000110;
sinetable[5'd15] <= 46'b0100100011100000001000011001010110101101111001;
sinetable[5'd16] <= 46'b0100100011100100001000101011100101001011101111;
sinetable[5'd17] <= 46'b0100100011101100000111011010000001011010110001;
sinetable[5'd18] <= 46'b0100110011001000000111101010000010111010111111;
sinetable[5'd19] <= 46'b0100110011001100001011011110101110110110000001;
sinetable[5'd20] <= 46'b0100110011101000011010111011001010001101110001;
sinetable[5'd21] <= 46'b0100110011101101011010110101111001010100001111;
sinetable[5'd22] <= 46'b0111000010000001010111000101010101010110010111;
sinetable[5'd23] <= 46'b0111000010000101010111110111110101010010111011;
sinetable[5'd24] <= 46'b0111000010110101101000101100001000010000011001;
sinetable[5'd25] <= 46'b0111010010011001100100011110100100010010010010;
sinetable[5'd26] <= 46'b0111010010111010100101100101000000110100100011;
sinetable[5'd27] <= 46'b1010000010011010101101011101100001110010011010;
sinetable[5'd28] <= 46'b1010000010111111111100100111010100010000111001;
sinetable[5'd29] <= 46'b1010010111110100110010001100111001010110100000;
sinetable[5'd30] <= 46'b1011010111010011111011011110000100110010100001;
sinetable[5'd31] <= 46'b1110011011110001111011100111100001110110100111;
end
always @ (posedge clk)
ph <= sinetable[addr];
endmodule

363
rtl/sound/jt12/jt12_reg.v Normal file
View File

@ -0,0 +1,363 @@
`timescale 1ns / 1ps
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2017
*/
module jt12_reg(
input rst,
input clk,
input [7:0] din,
input [2:0] ch,
input [1:0] op,
input csm,
input flag_A,
input overflow_A,
input up_keyon,
input up_alg,
input up_block,
input up_fnumlo,
input up_pms,
input up_dt1,
input up_tl,
input up_ks_ar,
input up_amen_d1r,
input up_d2r,
input up_d1l,
input up_ssgeg,
output busy,
output reg ch6op, // 1 when the operator belongs to CH6
// CH3 Effect-mode operation
input effect,
input [10:0] fnum_ch3op2,
input [10:0] fnum_ch3op3,
input [10:0] fnum_ch3op1,
input [ 2:0] block_ch3op2,
input [ 2:0] block_ch3op3,
input [ 2:0] block_ch3op1,
// Pipeline order
output reg zero,
output s1_enters,
output s2_enters,
output s3_enters,
output s4_enters,
// Operator
output use_prevprev1,
output use_internal_x,
output use_internal_y,
output use_prev2,
output use_prev1,
// PG
output [10:0] fnum_I,
output [ 2:0] block_I,
// channel configuration
output [1:0] rl,
output reg [2:0] fb_II,
output [2:0] alg,
// Operator multiplying
output [ 3:0] mul_V,
// Operator detuning
output [ 2:0] dt1_II,
// EG
output [4:0] ar_II, // attack rate
output [4:0] d1r_II, // decay rate
output [4:0] d2r_II, // sustain rate
output [3:0] rr_II, // release rate
output [3:0] d1l, // sustain level
output [1:0] ks_III, // key scale
output ssg_en_II,
output [2:0] ssg_eg_II,
output [6:0] tl_VII,
output [2:0] pms,
output [1:0] ams_VII,
output amsen_VII,
// envelope operation
output keyon_II
);
reg [4:0] cnt;
reg [1:0] next_op, cur_op;
reg [2:0] next_ch, cur_ch;
assign s1_enters = cur_op == 2'b00;
assign s3_enters = cur_op == 2'b01;
assign s2_enters = cur_op == 2'b10;
assign s4_enters = cur_op == 2'b11;
wire [4:0] next = { next_op, next_ch };
wire [4:0] cur = { cur_op, cur_ch };
wire [2:0] fb_I;
always @(posedge clk) begin
fb_II <= fb_I;
ch6op <= next_ch==3'd6;
end
// FNUM and BLOCK
wire [10:0] fnum_I_raw;
wire [ 2:0] block_I_raw;
wire effect_on = effect && (cur_ch==3'd2);
wire effect_on_s1 = effect_on && (cur_op == 2'd0 );
wire effect_on_s3 = effect_on && (cur_op == 2'd1 );
wire effect_on_s2 = effect_on && (cur_op == 2'd2 );
wire noeffect = ~|{effect_on_s1, effect_on_s3, effect_on_s2};
assign fnum_I = ( {11{effect_on_s1}} & fnum_ch3op1 ) |
( {11{effect_on_s2}} & fnum_ch3op2 ) |
( {11{effect_on_s3}} & fnum_ch3op3 ) |
( {11{noeffect}} & fnum_I_raw );
assign block_I =( {3{effect_on_s1}} & block_ch3op1 ) |
( {3{effect_on_s2}} & block_ch3op2 ) |
( {3{effect_on_s3}} & block_ch3op3 ) |
( {3{noeffect}} & block_I_raw );
wire [2:0] ch_II, ch_III, ch_IV, ch_V, ch_VI;
wire [4:0] req_opch_I = { op, ch };
wire [4:0] req_opch_II, req_opch_III,
req_opch_IV, req_opch_V, req_opch_VI;
jt12_sumch u_opch_II ( .chin(req_opch_I ), .chout(req_opch_II) );
jt12_sumch u_opch_III( .chin(req_opch_II ), .chout(req_opch_III) );
jt12_sumch u_opch_IV ( .chin(req_opch_III), .chout(req_opch_IV) );
jt12_sumch u_opch_V ( .chin(req_opch_IV ), .chout(req_opch_V) );
jt12_sumch u_opch_VI ( .chin(req_opch_V ), .chout(req_opch_VI) );
wire update_op_I = cur == req_opch_I;
wire update_op_II = cur == req_opch_II;
wire update_op_III= cur == req_opch_III;
// wire update_op_IV = cur == opch_IV;
wire update_op_V = cur == req_opch_V;
// wire update_op_VI = cur == opch_VI;
wire [2:0] op_plus1 = op+2'd1;
wire update_op_VII= cur == { op_plus1[1:0], ch };
// key on/off
wire [3:0] keyon_op = din[7:4];
wire [2:0] keyon_ch = din[2:0];
// channel data
wire [1:0] rl_in = din[7:6];
wire [2:0] fb_in = din[5:3];
wire [2:0] alg_in = din[2:0];
wire [2:0] pms_in = din[2:0];
wire [1:0] ams_in = din[5:4];
wire [2:0] block_in= din[5:3];
wire [2:0] fnhi_in = din[2:0];
wire [7:0] fnlo_in = din;
// operator data
wire [2:0] dt1_in = din[6:4];
wire [3:0] mul_in = din[3:0];
wire [6:0] tl_in = din[6:0];
wire [1:0] ks_in = din[7:6];
wire [4:0] ar_in = din[4:0];
wire amen_in = din[7];
wire [4:0] d1r_in = din[4:0];
wire [4:0] d2r_in = din[4:0];
wire [3:0] d1l_in = din[7:4];
wire [3:0] rr_in = din[3:0];
wire [3:0] ssg_in = din[3:0];
wire [3:0] ssg;
reg last;
wire update_ch_I = cur_ch == ch;
wire up_alg_ch = up_alg & update_ch_I;
wire up_block_ch= up_block & update_ch_I;
wire up_fnumlo_ch=up_fnumlo & update_ch_I;
wire up_pms_ch = up_pms & update_ch_I;
// DT1 & MUL
wire up_dt1_op = up_dt1 & update_op_II;
wire up_mul_op = up_dt1 & update_op_V;
// TL
wire up_tl_op = up_tl & update_op_VII;
// KS & AR
wire up_ks_op = up_ks_ar & update_op_III;
wire up_ar_op = up_ks_ar & update_op_II;
// AM ON, D1R
wire up_amen_op = up_amen_d1r & update_op_VII;
wire up_d1r_op = up_amen_d1r & update_op_II;
// Sustain Rate (D2R)
wire up_d2r_op = up_d2r & update_op_II;
// D1L & RR
wire up_d1l_op = up_d1l & update_op_I;
wire up_rr_op = up_d1l & update_op_II;
// SSG
//wire up_ssgen_op = up_ssgeg & update_op_I;
wire up_ssg_op = up_ssgeg & update_op_II;
wire up = up_alg | up_block | up_fnumlo | up_pms |
up_dt1 | up_tl | up_ks_ar | up_amen_d1r |
up_d2r | up_d1l | up_ssgeg | up_keyon;
always @(*) begin
// next <= cur==5'd23 ? 5'd0 : cur +1'b1;
next_op <= cur_ch==3'd6 ? cur_op+1'b1 : cur_op;
next_ch <= cur_ch[1:0]==2'b10 ? cur_ch+2'd2 : cur_ch+1'd1;
end
reg busy_op;
reg up_keyon_long;
assign busy = busy_op;
always @(posedge clk) begin : up_counter
if( rst ) begin
cnt <= 5'h0;
last <= 1'b0;
zero <= 1'b1;
busy_op <= 1'b0;
up_keyon_long <= 1'b0;
cur_op <= 2'd0;
cur_ch <= 3'd0;
end
else begin
{ cur_op, cur_ch } <= { next_op, next_ch };
zero <= next == 5'd0;
last <= up;
if( up && !last ) begin
cnt <= cur;
busy_op <= 1'b1;
up_keyon_long <= up_keyon;
end
else if( cnt == cur ) begin
busy_op <= 1'b0;
up_keyon_long <= 1'b0;
end
end
end
jt12_kon u_kon(
.rst ( rst ),
.clk ( clk ),
.keyon_op ( keyon_op ),
.keyon_ch ( keyon_ch ),
.cur_op ( cur_op ),
.cur_ch ( cur_ch ),
.up_keyon ( up_keyon_long ),
.csm ( csm ),
.flag_A ( flag_A ),
.overflow_A ( overflow_A),
.keyon_II ( keyon_II )
);
jt12_mod u_mod(
.alg_I ( alg ),
.s1_enters ( s1_enters ),
.s3_enters ( s3_enters ),
.s2_enters ( s2_enters ),
.s4_enters ( s4_enters ),
.use_prevprev1 ( use_prevprev1 ),
.use_internal_x( use_internal_x ),
.use_internal_y( use_internal_y ),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 )
);
// memory for OP registers
parameter regop_width=44;
wire [regop_width-1:0] regop_in, regop_out;
jt12_opram u_opram(
.clk ( clk ),
.wr_addr ( cur ),
.rd_addr ( next ),
.data ( regop_in ),
.q ( regop_out )
);
assign regop_in = {
up_tl_op ? tl_in : tl_VII, // 7
up_dt1_op ? dt1_in : dt1_II, // 3
up_mul_op ? mul_in : mul_V, // 4 - 7
up_ks_op ? ks_in : ks_III, // 2 - 16
up_ar_op ? ar_in : ar_II, // 5 - 21
up_amen_op ? amen_in: amsen_VII,// 1 - 22
up_d1r_op ? d1r_in : d1r_II, // 5 - 25
up_d2r_op ? d2r_in : d2r_II, // 5 - 30
up_d1l_op ? d1l_in : d1l, // 4 - 34
up_rr_op ? rr_in : rr_II, // 4 - 38
up_ssg_op ? ssg_in[3] : ssg_en_II, // 1 - 39
up_ssg_op ? ssg_in[2:0] : ssg_eg_II // 3 - 42
};
assign { tl_VII, dt1_II, mul_V, ks_III,
ar_II, amsen_VII, d1r_II, d2r_II, d1l, rr_II,
ssg_en_II, ssg_eg_II } = regop_out;
wire [2:0] block_latch, fnum_latch;
// memory for CH registers
// Block/fnum data is latched until fnum low byte is written to
// Trying to synthesize this memory as M-9K RAM in Altera devices
// turns out worse in terms of resource utilization. Probably because
// this memory is already very small. It is better to leave it as it is.
parameter regch_width=31;
wire [regch_width-1:0] regch_out;
wire [regch_width-1:0] regch_in = {
up_block_ch ? { block_in, fnhi_in } : { block_latch, fnum_latch }, // 3+3
up_fnumlo_ch? { block_latch, fnum_latch, fnlo_in } : { block_I_raw, fnum_I_raw }, // 14
up_alg_ch ? { fb_in, alg_in } : { fb_I, alg },//3+3
up_pms_ch ? { ams_in, pms_in } : { ams_VII, pms }//2+2+3
};
assign { block_latch, fnum_latch,
block_I_raw, fnum_I_raw,
fb_I, alg, ams_VII, pms } = regch_out;
jt12_sh #(.width(regch_width),.stages(6)) u_regch(
.clk ( clk ),
//.rst ( rst ),
.din ( regch_in ),
.drop ( regch_out )
);
// RL is on a different register to
// have the reset to 1
jt12_sh_rst #(.width(2),.stages(6),.rstval(1'b1)) u_regch_rl(
.clk ( clk ),
// .rst ( rst ),
.din ( up_pms_ch ? rl_in : rl ),
.drop ( rl )
);
endmodule

45
rtl/sound/jt12/jt12_sh.v Normal file
View File

@ -0,0 +1,45 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 1-31-2017
*/
`timescale 1ns / 1ps
module jt12_sh #(parameter width=5, stages=24 )
(
input clk,
input [width-1:0] din,
output [width-1:0] drop
);
reg [stages-1:0] bits[width-1:0];
genvar i;
generate
for (i=0; i < width; i=i+1) begin: bit_shifter
always @(posedge clk) begin
if( stages> 1 )
bits[i] <= {bits[i][stages-2:0], din[i]};
else
bits[i] <= din[i];
end
assign drop[i] = bits[i][stages-1];
end
endgenerate
endmodule

View File

@ -0,0 +1,80 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 1-31-2017
*/
`timescale 1ns / 1ps
module jt12_sh24 #(parameter width=5 )
(
input clk,
input [width-1:0] din,
output reg [width-1:0] st1,
output reg [width-1:0] st2,
output reg [width-1:0] st3,
output reg [width-1:0] st4,
output reg [width-1:0] st5,
output reg [width-1:0] st6,
output reg [width-1:0] st7,
output reg [width-1:0] st8,
output reg [width-1:0] st9,
output reg [width-1:0] st10,
output reg [width-1:0] st11,
output reg [width-1:0] st12,
output reg [width-1:0] st13,
output reg [width-1:0] st14,
output reg [width-1:0] st15,
output reg [width-1:0] st16,
output reg [width-1:0] st17,
output reg [width-1:0] st18,
output reg [width-1:0] st19,
output reg [width-1:0] st20,
output reg [width-1:0] st21,
output reg [width-1:0] st22,
output reg [width-1:0] st23,
output reg [width-1:0] st24
);
always @(posedge clk) begin
st24<= st23;
st23<= st22;
st22<= st21;
st21<= st20;
st20<= st19;
st19<= st18;
st18<= st17;
st17<= st16;
st16<= st15;
st15<= st14;
st14<= st13;
st13<= st12;
st12<= st11;
st11<= st10;
st10<= st9;
st9 <= st8;
st8 <= st7;
st7 <= st6;
st6 <= st5;
st5 <= st4;
st4 <= st3;
st3 <= st2;
st2 <= st1;
st1 <= din;
end
endmodule

View File

@ -0,0 +1,54 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 1-31-2017
*/
`timescale 1ns / 1ps
module jt12_sh_rst #(parameter width=5, stages=32, rstval=1'b0 )
(
// input rst,
input clk,
input [width-1:0] din,
output [width-1:0] drop
);
reg [stages-1:0] bits[width-1:0];
genvar i;
integer k;
generate
initial
for (k=0; k < width; k=k+1) begin
bits[k] <= { stages{rstval}};
end
endgenerate
generate
for (i=0; i < width; i=i+1) begin: bit_shifter
always @(posedge clk) begin
if( stages> 1 )
bits[i] <= {bits[i][stages-2:0], din[i]};
else
bits[i] <= din[i];
end
assign drop[i] = bits[i][stages-1];
end
endgenerate
endmodule

View File

@ -0,0 +1,37 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 1-31-2017
*/
`timescale 1ns / 1ps
module jt12_sumch
(
input [4:0] chin,
output reg [4:0] chout
);
reg [2:0] aux;
always @(*) begin
aux <= chin[2:0] + 3'd1;
chout[2:0] <= aux[1:0]==2'b11 ? aux+3'd1 : aux;
chout[4:3] <= chin[2:0]==3'd6 ? chin[4:3]+2'd1 : chin[4:3];
end
endmodule

338
rtl/sound/jt12/jt12_syn.v Normal file
View File

@ -0,0 +1,338 @@
module jt12_syn(
input rst,
input clk, // cpu_clk/6 ~ 1.3MHz
input [7:0] din,
input [1:0] addr,
input write,
input limiter_en,
output busy,
output flag_A,
output flag_B,
output irq_n,
// combined output
output signed [11:0] snd_right,
output signed [11:0] snd_left,
output snd_sample,
// multiplexed output
output signed [8:0] mux_right,
output signed [8:0] mux_left,
output mux_sample
);
// Timers
wire [9:0] value_A;
wire [7:0] value_B;
wire load_A, load_B;
wire enable_irq_A, enable_irq_B;
wire clr_flag_A, clr_flag_B;
wire overflow_A;
wire fast_timers;
wire zero; // Single-clock pulse at the begginig of s1_enters
// LFO
wire [2:0] lfo_freq;
wire lfo_en;
// Operators
wire amsen_VII;
wire [ 2:0] dt1_II;
wire [ 3:0] mul_V;
wire [ 6:0] tl_VII;
wire [4:0] keycode_III;
wire [ 4:0] ar_II;
wire [ 4:0] d1r_II;
wire [ 4:0] d2r_II;
wire [ 3:0] rr_II;
wire [ 3:0] d1l;
wire [ 1:0] ks_III;
// SSG operation
wire ssg_en_II;
wire [2:0] ssg_eg_II;
// envelope operation
wire keyon_II;
wire [9:0] eg_IX;
wire pg_rst_III;
// Channel
wire [10:0] fnum_I;
wire [ 2:0] block_I;
wire [ 1:0] rl;
wire [ 2:0] fb_II;
wire [ 2:0] alg;
wire [ 2:0] pms;
wire [ 1:0] ams_VII;
// PCM
wire pcm_en;
wire [ 8:0] pcm;
// Test
wire pg_stop, eg_stop;
wire ch6op;
// Operator
wire use_internal_x, use_internal_y;
wire use_prevprev1, use_prev2, use_prev1;
wire [ 9:0] phase_VIII;
wire s1_enters, s2_enters, s3_enters, s4_enters;
wire rst_int;
// LFO
wire [6:0] lfo_mod;
wire lfo_rst;
`ifdef TEST_SUPPORT
// Test bits
wire test_eg, test_op0;
`endif
jt12_mmr u_mmr(
.rst ( rst ),
.clk ( clk ),
.din ( din ),
.write ( write ),
.addr ( addr ),
.busy ( busy ),
.ch6op ( ch6op ),
// LFO
.lfo_freq ( lfo_freq ),
.lfo_en ( lfo_en ),
// Timers
.value_A ( value_A ),
.value_B ( value_B ),
.load_A ( load_A ),
.load_B ( load_B ),
.enable_irq_A ( enable_irq_A ),
.enable_irq_B ( enable_irq_B ),
.clr_flag_A ( clr_flag_A ),
.clr_flag_B ( clr_flag_B ),
.flag_A ( flag_A ),
.overflow_A ( overflow_A ),
.fast_timers( fast_timers ),
// PCM
.pcm ( pcm ),
.pcm_en ( pcm_en ),
`ifdef TEST_SUPPORT
// Test
.test_eg ( test_eg ),
.test_op0 ( test_op0 ),
`endif
// Operator
.use_prevprev1 ( use_prevprev1 ),
.use_internal_x ( use_internal_x ),
.use_internal_y ( use_internal_y ),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 ),
// PG
.fnum_I ( fnum_I ),
.block_I ( block_I ),
.pg_stop ( pg_stop ),
// EG
.rl ( rl ),
.fb_II ( fb_II ),
.alg ( alg ),
.pms ( pms ),
.ams_VII ( ams_VII ),
.amsen_VII ( amsen_VII ),
.dt1_II ( dt1_II ),
.mul_V ( mul_V ),
.tl_VII ( tl_VII ),
.ar_II ( ar_II ),
.d1r_II ( d1r_II ),
.d2r_II ( d2r_II ),
.rr_II ( rr_II ),
.d1l ( d1l ),
.ks_III ( ks_III ),
.eg_stop ( eg_stop ),
// SSG operation
.ssg_en_II ( ssg_en_II ),
.ssg_eg_II ( ssg_eg_II ),
.keyon_II ( keyon_II ),
// Operator
.zero ( zero ),
.s1_enters ( s1_enters ),
.s2_enters ( s2_enters ),
.s3_enters ( s3_enters ),
.s4_enters ( s4_enters )
);
jt12_timers u_timers(
.clk ( clk ),
.rst ( rst ),
.clk_en ( zero ),
.fast_timers( fast_timers ), // fix this to work well with clock enable signals
.value_A ( value_A ),
.value_B ( value_B ),
.load_A ( load_A ),
.load_B ( load_B ),
.enable_irq_A( enable_irq_B ),
.enable_irq_B( enable_irq_A ),
.clr_flag_A ( clr_flag_A ),
.clr_flag_B ( clr_flag_B ),
.flag_A ( flag_A ),
.flag_B ( flag_B ),
.overflow_A ( overflow_A ),
.irq_n ( irq_n )
);
jt12_lfo u_lfo(
.rst ( rst ),
.clk ( clk ),
.zero ( zero ),
.lfo_rst ( 1'b0 ),
.lfo_en ( lfo_en ),
.lfo_freq ( lfo_freq ),
.lfo_mod ( lfo_mod )
);
`ifndef TIMERONLY
jt12_pg u_pg(
.clk ( clk ),
.rst ( rst ),
// Channel frequency
.fnum_I ( fnum_I ),
.block_I ( block_I ),
// Operator multiplying
.mul_V ( mul_V ),
// Operator detuning
.dt1_II ( dt1_II ), // same as JT51's DT1
// phase operation
.pg_rst_III ( pg_rst_III ),
.zero ( zero ),
.pg_stop ( pg_stop ),
.keycode_III( keycode_III ),
.phase_VIII ( phase_VIII )
);
jt12_eg u_eg(
`ifdef TEST_SUPPORT
.test_eg ( test_eg ),
`endif
.rst ( rst ),
.clk ( clk ),
.zero ( zero ),
.eg_stop ( eg_stop ),
// envelope configuration
.keycode_III ( keycode_III ),
.arate_II ( ar_II ), // attack rate
.rate1_II ( d1r_II ), // decay rate
.rate2_II ( d2r_II ), // sustain rate
.rrate_II ( rr_II ), // release rate
.d1l ( d1l ), // sustain level
.ks_III ( ks_III ), // key scale
// SSG operation
.ssg_en_II ( ssg_en_II ),
.ssg_eg_II ( ssg_eg_II ),
// envelope operation
.keyon_II ( keyon_II ),
// envelope number
.am ( lfo_mod ),
.tl_VII ( tl_VII ),
.ams_VII ( ams_VII ),
.amsen_VII ( amsen_VII ),
.eg_IX ( eg_IX ),
.pg_rst_III ( pg_rst_III )
);
wire [8:0] op_result;
jt12_op u_op(
.rst ( rst ),
.clk ( clk ),
.pg_phase_VIII ( phase_VIII ),
.eg_atten_IX ( eg_IX ),
.fb_II ( fb_II ),
.test_214 ( 1'b0 ),
.s1_enters ( s1_enters ),
.s2_enters ( s2_enters ),
.s3_enters ( s3_enters ),
.s4_enters ( s4_enters ),
.use_prevprev1 ( use_prevprev1 ),
.use_internal_x ( use_internal_x),
.use_internal_y ( use_internal_y),
.use_prev2 ( use_prev2 ),
.use_prev1 ( use_prev1 ),
.zero ( zero ),
.op_result ( op_result )
);
jt12_acc u_acc(
.rst ( rst ),
.clk ( clk ),
.op_result ( op_result ),
.rl ( rl ),
.limiter_en ( limiter_en),
// note that the order changes to deal
// with the operator pipeline delay
.s1_enters ( s2_enters ),
.s2_enters ( s1_enters ),
.s3_enters ( s4_enters ),
.s4_enters ( s3_enters ),
.ch6op ( ch6op ),
.pcm_en ( pcm_en ), // only enabled for channel 6
.pcm ( pcm ),
.alg ( alg ),
// combined output
.left ( snd_left ),
.right ( snd_right ),
.sample ( snd_sample),
// muxed output
.mux_left ( mux_left ),
.mux_right ( mux_right ),
.mux_sample ( mux_sample)
);
`ifdef SIMULATION
reg [4:0] sep24_cnt;
wire [9:0] eg_ch0s1, eg_ch1s1, eg_ch2s1, eg_ch3s1, eg_ch4s1, eg_ch5s1,
eg_ch0s2, eg_ch1s2, eg_ch2s2, eg_ch3s2, eg_ch4s2, eg_ch5s2,
eg_ch0s3, eg_ch1s3, eg_ch2s3, eg_ch3s3, eg_ch4s3, eg_ch5s3,
eg_ch0s4, eg_ch1s4, eg_ch2s4, eg_ch3s4, eg_ch4s4, eg_ch5s4;
always @(posedge clk)
sep24_cnt <= !zero ? sep24_cnt+1'b1 : 5'd0;
sep24 #( .width(10), .pos0(5'd0)) egsep
(
.clk ( clk ),
.mixed ( eg_IX ),
.mask ( 10'd0 ),
.cnt ( sep24_cnt ),
.ch0s1 (eg_ch0s1),
.ch1s1 (eg_ch1s1),
.ch2s1 (eg_ch2s1),
.ch3s1 (eg_ch3s1),
.ch4s1 (eg_ch4s1),
.ch5s1 (eg_ch5s1),
.ch0s2 (eg_ch0s2),
.ch1s2 (eg_ch1s2),
.ch2s2 (eg_ch2s2),
.ch3s2 (eg_ch3s2),
.ch4s2 (eg_ch4s2),
.ch5s2 (eg_ch5s2),
.ch0s3 (eg_ch0s3),
.ch1s3 (eg_ch1s3),
.ch2s3 (eg_ch2s3),
.ch3s3 (eg_ch3s3),
.ch4s3 (eg_ch4s3),
.ch5s3 (eg_ch5s3),
.ch0s4 (eg_ch0s4),
.ch1s4 (eg_ch1s4),
.ch2s4 (eg_ch2s4),
.ch3s4 (eg_ch3s4),
.ch4s4 (eg_ch4s4),
.ch5s4 (eg_ch5s4)
);
`endif
`endif
endmodule

View File

@ -0,0 +1,112 @@
/* This file is part of JT12.
JT12 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.
JT12 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 JT12. If not, see <http://www.gnu.org/licenses/>.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 14-2-2017
YM3438_APL.pdf
Timer A = 144*(1024-NA)/Phi M
Timer B = 2304*(256-NB)/Phi M
*/
`timescale 1ns / 1ps
module jt12_timers(
input clk,
input rst,
input clk_en, // clock enable
input fast_timers,
input [9:0] value_A,
input [7:0] value_B,
input load_A,
input load_B,
input clr_flag_A,
input clr_flag_B,
input enable_irq_A,
input enable_irq_B,
output flag_A,
output flag_B,
output overflow_A,
output irq_n
);
assign irq_n = ~( (flag_A&enable_irq_A) | (flag_B&enable_irq_B) );
jt12_timer #(.mult_width(1), .mult_max(0), .counter_width(10))
timer_A(
.clk ( clk ),
.rst ( rst ),
.clk_en ( clk_en | fast_timers ),
.start_value( value_A ),
.load ( load_A ),
.clr_flag ( clr_flag_A),
.flag ( flag_A ),
.overflow ( overflow_A)
);
jt12_timer #(.mult_width(4), .mult_max(15), .counter_width(8))
timer_B(
.clk ( clk ),
.rst ( rst ),
.clk_en ( clk_en | fast_timers ),
.start_value( value_B ),
.load ( load_B ),
.clr_flag ( clr_flag_B),
.flag ( flag_B ),
.overflow ( )
);
endmodule
module jt12_timer #(parameter counter_width = 10, mult_width=5, mult_max=4 )
(
input clk,
input rst,
(* direct_enable *) input clk_en,
input [counter_width-1:0] start_value,
input load,
input clr_flag,
output reg flag,
output reg overflow
);
reg [ mult_width-1:0] mult;
reg [counter_width-1:0] cnt;
always@(posedge clk)
if( clr_flag || rst)
flag <= 1'b0;
else if(overflow) flag<=1'b1;
reg [mult_width+counter_width-1:0] next, init;
always @(*) begin
if( mult<mult_max )
{overflow, next } <= { {1'b0, cnt}, mult+1'b1 } ;
else
{overflow, next } <= { {1'b0, cnt}+1'b1, {mult_width{1'b0}} };
init <= { start_value, {mult_width{1'b0}} };
end
always @(posedge clk)
if( load || rst) begin
mult <= { (mult_width){1'b0} };
cnt <= start_value;
end
else if( clk_en )
{ cnt, mult } <= overflow ? init : next;
endmodule

92
rtl/sound/jt12/lut.vh Normal file
View File

@ -0,0 +1,92 @@
/* This file is part of JT12.
JT12 program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JT12 program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JT12. If not, see <http://www.gnu.org/licenses/>.
Based on Sauraen VHDL version of OPN/OPN2, which is based on die shots.
Author: Jose Tejada Gomez. Twitter: @topapate
Version: 1.0
Date: 27-1-2017
*/
initial begin
sinetable[5'd0 ] <= 46'b0001100000100100010001000010101010101001010010;
sinetable[5'd1 ] <= 46'b0001100000110100000100000010010001001101000001;
sinetable[5'd2 ] <= 46'b0001100000110100000100110010001011001101100000;
sinetable[5'd3 ] <= 46'b0001110000010000000000110010110001001101110010;
sinetable[5'd4 ] <= 46'b0001110000010000001100000010111010001101101001;
sinetable[5'd5 ] <= 46'b0001110000010100001001100010000000101101111010;
sinetable[5'd6 ] <= 46'b0001110000010100001101100010010011001101011010;
sinetable[5'd7 ] <= 46'b0001110000011100000101010010111000101111111100;
sinetable[5'd8 ] <= 46'b0001110000111000000001110010101110001101110111;
sinetable[5'd9 ] <= 46'b0001110000111000010100111000011101011010100110;
sinetable[5'd10] <= 46'b0001110000111100011000011000111100001001111010;
sinetable[5'd11] <= 46'b0001110000111100011100111001101011001001110111;
sinetable[5'd12] <= 46'b0100100001010000010001011001001000111010110111;
sinetable[5'd13] <= 46'b0100100001010100010001001001110001111100101010;
sinetable[5'd14] <= 46'b0100100001010100010101101101111110100101000110;
sinetable[5'd15] <= 46'b0100100011100000001000011001010110101101111001;
sinetable[5'd16] <= 46'b0100100011100100001000101011100101001011101111;
sinetable[5'd17] <= 46'b0100100011101100000111011010000001011010110001;
sinetable[5'd18] <= 46'b0100110011001000000111101010000010111010111111;
sinetable[5'd19] <= 46'b0100110011001100001011011110101110110110000001;
sinetable[5'd20] <= 46'b0100110011101000011010111011001010001101110001;
sinetable[5'd21] <= 46'b0100110011101101011010110101111001010100001111;
sinetable[5'd22] <= 46'b0111000010000001010111000101010101010110010111;
sinetable[5'd23] <= 46'b0111000010000101010111110111110101010010111011;
sinetable[5'd24] <= 46'b0111000010110101101000101100001000010000011001;
sinetable[5'd25] <= 46'b0111010010011001100100011110100100010010010010;
sinetable[5'd26] <= 46'b0111010010111010100101100101000000110100100011;
sinetable[5'd27] <= 46'b1010000010011010101101011101100001110010011010;
sinetable[5'd28] <= 46'b1010000010111111111100100111010100010000111001;
sinetable[5'd29] <= 46'b1010010111110100110010001100111001010110100000;
sinetable[5'd30] <= 46'b1011010111010011111011011110000100110010100001;
sinetable[5'd31] <= 46'b1110011011110001111011100111100001110110100111;
explut_jt51[0] <= 45'b111110101011010110001011010000010010111011011;
explut_jt51[1] <= 45'b111101010011010101000011001100101110110101011;
explut_jt51[2] <= 45'b111011111011010011110111001000110010101110011;
explut_jt51[3] <= 45'b111010100101010010101111000100110010101000011;
explut_jt51[4] <= 45'b111001001101010001100111000000110010100001011;
explut_jt51[5] <= 45'b110111111011010000011110111101010010011011011;
explut_jt51[6] <= 45'b110110100011001111010110111001010010010100100;
explut_jt51[7] <= 45'b110101001011001110001110110101110010001110011;
explut_jt51[8] <= 45'b110011111011001101000110110001110010001000011;
explut_jt51[9] <= 45'b110010100011001011111110101110010010000010011;
explut_jt51[10] <= 45'b110001010011001010111010101010010001111011011;
explut_jt51[11] <= 45'b101111111011001001110010100110110001110101011;
explut_jt51[12] <= 45'b101110101011001000101010100011001101101111011;
explut_jt51[13] <= 45'b101101010101000111100110011111010001101001011;
explut_jt51[14] <= 45'b101100000011000110100010011011110001100011011;
explut_jt51[15] <= 45'b101010110011000101011110011000010001011101011;
explut_jt51[16] <= 45'b101001100011000100011010010100101101010111011;
explut_jt51[17] <= 45'b101000010011000011010010010001001101010001011;
explut_jt51[18] <= 45'b100111000011000010010010001101101101001011011;
explut_jt51[19] <= 45'b100101110011000001001110001010001101000101011;
explut_jt51[20] <= 45'b100100100011000000001010000110010000111111011;
explut_jt51[21] <= 45'b100011010010111111001010000011001100111001011;
explut_jt51[22] <= 45'b100010000010111110000101111111101100110011011;
explut_jt51[23] <= 45'b100000110010111101000001111100001100101101011;
explut_jt51[24] <= 45'b011111101010111100000001111000101100101000010;
explut_jt51[25] <= 45'b011110011010111011000001110101001100100010011;
explut_jt51[26] <= 45'b011101001010111010000001110001110000011100011;
explut_jt51[27] <= 45'b011100000010111001000001101110010000010110011;
explut_jt51[28] <= 45'b011010110010111000000001101011001100010001011;
explut_jt51[29] <= 45'b011001101010110111000001100111101100001011011;
explut_jt51[30] <= 45'b011000100000110110000001100100010000000110010;
explut_jt51[31] <= 45'b010111010010110101000001100001001100000000011;
end

403
rtl/sound/saa1099.sv Normal file
View File

@ -0,0 +1,403 @@
//============================================================================
//
// SAA1099 sound generator
// Copyright (C) 2016 Sorgelig
//
// Based on SAA1099.v code from Miguel Angel Rodriguez Jodar
// Based on SAASound code from Dave Hooper
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
//============================================================================
`timescale 1ns / 1ps
`default_nettype none
module saa1099
(
input clk_sys,
input ce, // 8 MHz
input rst_n,
input cs_n,
input a0, // 0=data, 1=address
input wr_n,
input [7:0] din,
output [7:0] out_l,
output [7:0] out_r
);
reg [7:0] amplit0, amplit1, amplit2, amplit3, amplit4, amplit5;
reg [7:0] freq0, freq1, freq2, freq3, freq4, freq5;
reg [7:0] oct10, oct32, oct54;
reg [7:0] freqenable;
reg [7:0] noiseenable;
reg [7:0] noisegen;
reg [7:0] envelope0, envelope1;
reg [7:0] ctrl;
reg [4:0] addr;
wire rst = ~rst_n | ctrl[1];
reg wr;
always @(posedge clk_sys) begin
reg old_wr;
old_wr <= wr_n;
wr <= 0;
if(~rst_n) begin
addr <= 0;
{amplit0, amplit1, amplit2, amplit3, amplit4, amplit5} <= 0;
{freq0, freq1, freq2, freq3, freq4, freq5} <= 0;
{oct10, oct32, oct54} <= 0;
{freqenable, noiseenable, noisegen} <= 0;
{envelope0, envelope1} <= 0;
ctrl <= 0;
end
else begin
if(!cs_n & old_wr & !wr_n) begin
wr <= 1;
if(a0) addr <= din[4:0];
else begin
case (addr)
'h00: amplit0 <= din;
'h01: amplit1 <= din;
'h02: amplit2 <= din;
'h03: amplit3 <= din;
'h04: amplit4 <= din;
'h05: amplit5 <= din;
'h08: freq0 <= din;
'h09: freq1 <= din;
'h0A: freq2 <= din;
'h0B: freq3 <= din;
'h0C: freq4 <= din;
'h0D: freq5 <= din;
'h10: oct10 <= din;
'h11: oct32 <= din;
'h12: oct54 <= din;
'h14: freqenable <= din;
'h15: noiseenable<= din;
'h16: noisegen <= din;
'h18: envelope0 <= din;
'h19: envelope1 <= din;
'h1C: ctrl <= din;
endcase
end
end
end
end
wire [21:0] out0;
saa1099_triplet top
(
.*,
.vol('{amplit0, amplit1, amplit2}),
.env(envelope0),
.freq('{freq0, freq1, freq2}),
.octave('{oct10[2:0], oct10[6:4], oct32[2:0]}),
.freq_en(freqenable[2:0]),
.noise_en(noiseenable[2:0]),
.noise_freq(noisegen[1:0]),
.wr_addr(wr & a0 & (din[4:0] == 'h18)),
.wr_data(wr & !a0 & (addr == 'h18)),
.out(out0)
);
wire [21:0] out1;
saa1099_triplet bottom
(
.*,
.vol('{amplit3, amplit4, amplit5}),
.env(envelope1),
.freq('{freq3, freq4, freq5}),
.octave('{oct32[6:4], oct54[2:0], oct54[6:4]}),
.freq_en(freqenable[5:3]),
.noise_en(noiseenable[5:3]),
.noise_freq(noisegen[5:4]),
.wr_addr(wr & a0 & (din[4:0] == 'h19)),
.wr_data(wr & !a0 & (addr == 'h19)),
.out(out1)
);
saa1099_output_mixer outmix_l(.*, .en(ctrl[0]), .in0(out0[10:0]), .in1(out1[10:0]), .out(out_l));
saa1099_output_mixer outmix_r(.*, .en(ctrl[0]), .in0(out0[21:11]), .in1(out1[21:11]), .out(out_r));
endmodule
/////////////////////////////////////////////////////////////////////////////////
module saa1099_triplet
(
input rst,
input clk_sys,
input ce,
input [7:0] vol[3],
input [7:0] env,
input [7:0] freq[3],
input [2:0] octave[3],
input [2:0] freq_en,
input [2:0] noise_en,
input [1:0] noise_freq,
input wr_addr,
input wr_data,
output[21:0] out
);
wire tone0, tone1, tone2, noise;
wire pulse_noise, pulse_envelope;
wire[21:0] out0, out1, out2;
saa1099_tone freq_gen0(.*, .out(tone0), .octave(octave[0]), .freq(freq[0]), .pulse(pulse_noise));
saa1099_tone freq_gen1(.*, .out(tone1), .octave(octave[1]), .freq(freq[1]), .pulse(pulse_envelope));
saa1099_tone freq_gen2(.*, .out(tone2), .octave(octave[2]), .freq(freq[2]), .pulse());
saa1099_noise noise_gen(.*, .out(noise));
saa1099_amp amp0(.*, .mixmode({noise_en[0], freq_en[0]}), .tone(tone0), .envreg(0), .vol(vol[0]), .out(out0));
saa1099_amp amp1(.*, .mixmode({noise_en[1], freq_en[1]}), .tone(tone1), .envreg(0), .vol(vol[1]), .out(out1));
saa1099_amp amp2(.*, .mixmode({noise_en[2], freq_en[2]}), .tone(tone2), .envreg(env), .vol(vol[2]), .out(out2));
assign out[10:0] = out0[8:0] + out1[8:0] + out2[8:0];
assign out[21:11] = out0[17:9] + out1[17:9] + out2[17:9];
endmodule
/////////////////////////////////////////////////////////////////////////////////
module saa1099_tone
(
input rst,
input clk_sys,
input ce,
input [2:0] octave,
input [7:0] freq,
output reg out,
output reg pulse
);
wire [16:0] fcount = ((17'd511 - freq) << (4'd8 - octave)) - 1'd1;
always @(posedge clk_sys) begin
reg [16:0] count;
pulse <= 0;
if(rst) begin
count <= fcount;
out <= 0;
end else if(ce) begin
if(!count) begin
count <= fcount;
pulse <= 1;
out <= ~out;
end else begin
count <= count - 1'd1;
end
end
end
endmodule
/////////////////////////////////////////////////////////////////////////////////
module saa1099_noise
(
input rst,
input clk_sys,
input ce,
input pulse_noise,
input [1:0] noise_freq,
output out
);
reg [16:0] lfsr = 0;
wire [16:0] new_lfsr = {(lfsr[0] ^ lfsr[2] ^ !lfsr), lfsr[16:1]};
wire [10:0] fcount = (11'd256 << noise_freq) - 1'b1;
always @(posedge clk_sys) begin
reg [10:0] count;
if(rst) begin
count <= fcount;
end else
if(noise_freq != 3) begin
if(ce) begin
if(!count) begin
count <= fcount;
lfsr <= new_lfsr;
end else begin
count <= count - 1'd1;
end
end
end else if(pulse_noise) begin
lfsr <= new_lfsr;
end
end
assign out = lfsr[0];
endmodule
/////////////////////////////////////////////////////////////////////////////////
module saa1099_amp
(
input rst,
input clk_sys,
input [7:0] envreg,
input [1:0] mixmode,
input tone,
input noise,
input wr_addr,
input wr_data,
input pulse_envelope,
input [7:0] vol,
output reg [17:0] out
);
wire phases[8] = '{0,0,0,0,1,1,0,0};
wire [1:0] env[8][2] = '{'{0,0}, '{1,1}, '{2,0}, '{2,0}, '{3,2}, '{3,2}, '{3,0}, '{3,0}};
wire [3:0] levels[4][16] =
'{
'{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
'{15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15},
'{15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0},
'{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15}
};
reg [2:0] shape;
reg stereo;
wire resolution = envreg[4];
wire enable = envreg[7];
reg [3:0] counter;
reg phase;
wire[3:0] mask = {3'b000, resolution};
always @(posedge clk_sys) begin
reg clock;
reg new_data;
if(rst | ~enable) begin
new_data <= 0;
stereo <= envreg[0];
shape <= envreg[3:1];
clock <= envreg[5];
phase <= 0;
counter <= 0;
end
else begin
if(wr_data) new_data <= 1;
if(clock ? wr_addr : pulse_envelope) begin // pulse from internal or external clock?
counter <= counter + resolution + 1'd1;
if((counter | mask) == 15) begin
if(phase >= phases[shape]) begin
if(~shape[0]) counter <= 15;
if(new_data | shape[0]) begin // if we reached one of the designated points (3) or (4) and there is pending data, load it
new_data <= 0;
stereo <= envreg[0];
shape <= envreg[3:1];
clock <= envreg[5];
phase <= 0;
if(new_data) counter <= 0;
end
end else begin
phase <= 1;
end
end
end
end
end
wire [3:0] env_l = levels[env[shape][phase]][counter] & ~mask;
wire [3:0] env_r = stereo ? (4'd15 & ~mask) - env_l : env_l; // bit 0 of envreg inverts envelope shape
reg [1:0] outmix;
always_comb begin
case(mixmode)
0: outmix <= 0;
1: outmix <= {tone, 1'b0};
2: outmix <= {noise, 1'b0};
3: outmix <= {tone & ~noise, tone & noise};
endcase
end
wire [8:0] vol_mix_l = {vol[3:1], vol[0] & ~enable, 5'b00000} >> outmix[0];
wire [8:0] vol_mix_r = {vol[7:5], vol[4] & ~enable, 5'b00000} >> outmix[0];
wire [8:0] env_out_l;
wire [8:0] env_out_r;
saa1099_mul_env mod_l(.vol(vol_mix_l[8:4]), .env(env_l), .out(env_out_l));
saa1099_mul_env mod_r(.vol(vol_mix_r[8:4]), .env(env_r), .out(env_out_r));
always_comb begin
case({enable, outmix})
'b100, 'b101: out = {env_out_r, env_out_l};
'b001, 'b010: out = {vol_mix_r, vol_mix_l};
default: out = 0;
endcase
end
endmodule
/////////////////////////////////////////////////////////////////////////////////
module saa1099_mul_env
(
input [4:0] vol,
input [3:0] env,
output [8:0] out
);
assign out = (env[0] ? vol : 9'd0)+
(env[1] ? { vol,1'b0} : 9'd0)+
(env[2] ? { vol,2'b00} : 9'd0)+
(env[3] ? {vol,3'b000} : 9'd0);
endmodule
/////////////////////////////////////////////////////////////////////////////////
module saa1099_output_mixer
(
input clk_sys,
input ce,
input en,
input [10:0] in0,
input [10:0] in1,
output reg [7:0] out
);
wire [17:0] o = 18'd91 * ({1'b0,in0} + {1'b0,in1});
// Clean the audio.
always @(posedge clk_sys) begin
reg ced;
ced <= ce;
if(ced) out <= ~en ? 8'h00 : o[17:10];
end
endmodule

53
rtl/sound/soundrive.vhd Normal file
View File

@ -0,0 +1,53 @@
-------------------------------------------------------------------[27.10.2011]
-- Soundrive 1.05
-------------------------------------------------------------------------------
-- V0.1 05.10.2011 <09><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
-- SOUNDRIVE 1.05 PORTS mode 1
-- #0F = left channel A (stereo covox channel 1)
-- #1F = left channel B
-- #4F = right channel C (stereo covox channel 2)
-- #5F = right channel D
-- #FB = right channel D
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity soundrive is
Port (
RESET : in std_logic;
CLK : in std_logic;
CS : in std_logic;
A : in std_logic_vector(7 downto 0);
DI : in std_logic_vector(7 downto 0);
WR_n : in std_logic;
IORQ_n: in std_logic;
DOS : in std_logic;
OUTA : out std_logic_vector(7 downto 0);
OUTB : out std_logic_vector(7 downto 0);
OUTC : out std_logic_vector(7 downto 0);
OUTD : out std_logic_vector(7 downto 0));
end soundrive;
architecture soundrive_unit of soundrive is
begin
process (CLK, RESET, CS)
begin
if RESET = '1' or CS = '0' then
outa <= (others => '0');
outb <= (others => '0');
outc <= (others => '0');
outd <= (others => '0');
elsif rising_edge(CLK) then
if A = X"0F" and IORQ_n = '0' and WR_n = '0' and DOS = '0' then outa <= DI;
elsif A = X"1F" and IORQ_n = '0' and WR_n = '0' and DOS = '0' then outb <= DI;
elsif A = X"4F" and IORQ_n = '0' and WR_n = '0' and DOS = '0' then outc <= DI;
elsif A = X"5F" and IORQ_n = '0' and WR_n = '0' and DOS = '0' then outd <= DI;
elsif A = X"FB" and IORQ_n = '0' and WR_n = '0' and DOS = '0' then outd <= DI;
end if;
end if;
end process;
end soundrive_unit;

137
rtl/sound/turbosound.sv Normal file
View File

@ -0,0 +1,137 @@
//============================================================================
// Turbosound-FM
//
// Copyright (C) 2018 Ilia Sharin
// Copyright (C) 2018 Sorgelig
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//============================================================================
module turbosound
(
input RESET, // Chip RESET (set all Registers to '0', active high)
input CLK, // Global clock
input CE_CPU, // CPU Clock enable
input CE_YM, // YM2203 Master Clock enable x2 (due to YM2612 model!)
input BDIR, // Bus Direction (0 - read , 1 - write)
input BC, // Bus control
input [7:0] DI, // Data In
output [7:0] DO, // Data Out
output [11:0] CHANNEL_L, // Output channel L
output [11:0] CHANNEL_R, // Output channel R
output ACTIVE
);
// AY1 selected by default
reg ay_select = 1;
reg stat_sel = 1;
reg fm_ena = 0;
always_ff @(posedge CLK or posedge RESET) begin
if (RESET) begin
ay_select <= 1;
stat_sel <= 1;
fm_ena <= 0;
end
else if (BDIR & BC & &DI[7:3]) begin
ay_select <= DI[0];
stat_sel <= DI[1];
fm_ena <= ~DI[2];
end
end
wire [7:0] psg_ch_a_0;
wire [7:0] psg_ch_b_0;
wire [7:0] psg_ch_c_0;
wire [10:0] opn_0;
wire [7:0] DO_0;
wire WE_0 = ~ay_select & BDIR;
wire ay0_playing;
ym2203 ym2203_0
(
.RESET(RESET),
.CLK(CLK),
.CE_CPU(CE_CPU),
.CE_YM(CE_YM),
.A0(WE_0 ? ~BC : stat_sel),
.WE(WE_0),
.DI(DI),
.DO(DO_0),
.CHANNEL_A(psg_ch_a_0),
.CHANNEL_B(psg_ch_b_0),
.CHANNEL_C(psg_ch_c_0),
.CHANNEL_FM(opn_0),
.PSG_ACTIVE(ay0_playing),
.FM_ENA(fm_ena)
);
wire [7:0] psg_ch_a_1;
wire [7:0] psg_ch_b_1;
wire [7:0] psg_ch_c_1;
wire [10:0] opn_1;
wire [7:0] DO_1;
wire WE_1 = ay_select & BDIR;
wire ay1_playing;
ym2203 ym2203_1
(
.RESET(RESET),
.CLK(CLK),
.CE_CPU(CE_CPU),
.CE_YM(CE_YM),
.A0(WE_1 ? ~BC : stat_sel),
.WE(WE_1),
.DI(DI),
.DO(DO_1),
.CHANNEL_A(psg_ch_a_1),
.CHANNEL_B(psg_ch_b_1),
.CHANNEL_C(psg_ch_c_1),
.CHANNEL_FM(opn_1),
.PSG_ACTIVE(ay1_playing),
.FM_ENA(fm_ena)
);
assign DO = ay_select ? DO_1 : DO_0;
assign ACTIVE = ay0_playing | ay1_playing | fm_ena;
// Mix channel signals from both AY/YM chips (extending to 9 bits width to prevent clipping)
wire [8:0] sum_ch_a = { 1'b0, psg_ch_a_1 } + { 1'b0, psg_ch_a_0 };
wire [8:0] sum_ch_b = { 1'b0, psg_ch_b_1 } + { 1'b0, psg_ch_b_0 };
wire [8:0] sum_ch_c = { 1'b0, psg_ch_c_1 } + { 1'b0, psg_ch_c_0 };
// Control output channels (Only AY_1 plays if not in TurboSound mode)
wire [7:0] psg_a = ~ay0_playing ? psg_ch_a_1 : sum_ch_a[8:1];
wire [7:0] psg_b = ~ay0_playing ? psg_ch_b_1 : sum_ch_b[8:1];
wire [7:0] psg_c = ~ay0_playing ? psg_ch_c_1 : sum_ch_c[8:1];
wire signed [11:0] psg_l = {3'b000, psg_a, 1'd0} + {4'b0000, psg_b};
wire signed [11:0] psg_r = {3'b000, psg_c, 1'd0} + {4'b0000, psg_b};
wire signed [11:0] opn_s = {{2{opn_0[10]}}, opn_0[10:1]} + {{2{opn_1[10]}}, opn_1[10:1]};
assign CHANNEL_L = fm_ena ? opn_s + psg_l : psg_l;
assign CHANNEL_R = fm_ena ? opn_s + psg_r : psg_r;
endmodule

331
rtl/sound/ym2149.sv Normal file
View File

@ -0,0 +1,331 @@
//
// Copyright (c) MikeJ - Jan 2005
// Copyright (c) 2016-2018 Sorgelig
//
// All rights reserved
//
// Redistribution and use in source and synthezised forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// Redistributions in synthesized form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// Neither the name of the author nor the names of other contributors may
// be used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// BDIR BC MODE
// 0 0 inactive
// 0 1 read value
// 1 0 write value
// 1 1 set address
//
module ym2149
(
input CLK, // Global clock
input CE, // PSG Clock enable
input RESET, // Chip RESET (set all Registers to '0', active hi)
input BDIR, // Bus Direction (0 - read , 1 - write)
input BC, // Bus control
input [7:0] DI, // Data In
output [7:0] DO, // Data Out
output [7:0] CHANNEL_A, // PSG Output channel A
output [7:0] CHANNEL_B, // PSG Output channel B
output [7:0] CHANNEL_C, // PSG Output channel C
input SEL,
input MODE,
output [5:0] ACTIVE,
input [7:0] IOA_in,
output [7:0] IOA_out,
input [7:0] IOB_in,
output [7:0] IOB_out
);
assign ACTIVE = ~ymreg[7][5:0];
assign IOA_out = ymreg[14];
assign IOB_out = ymreg[15];
reg [7:0] addr;
reg [7:0] ymreg[16];
// Write to PSG
reg env_reset;
always @(posedge CLK) begin
if(RESET) begin
ymreg <= '{default:0};
ymreg[7] <= '1;
addr <= '0;
env_reset <= 0;
end else begin
env_reset <= 0;
if(BDIR) begin
if(BC) addr <= DI;
else if(!addr[7:4]) begin
ymreg[addr[3:0]] <= DI;
env_reset <= (addr == 13);
end
end
end
end
// Read from PSG
assign DO = dout;
reg [7:0] dout;
always_comb begin
dout = 8'hFF;
if(~BDIR & BC & !addr[7:4]) begin
case(addr[3:0])
0: dout = ymreg[0];
1: dout = ymreg[1][3:0];
2: dout = ymreg[2];
3: dout = ymreg[3][3:0];
4: dout = ymreg[4];
5: dout = ymreg[5][3:0];
6: dout = ymreg[6][4:0];
7: dout = ymreg[7];
8: dout = ymreg[8][4:0];
9: dout = ymreg[9][4:0];
10: dout = ymreg[10][4:0];
11: dout = ymreg[11];
12: dout = ymreg[12];
13: dout = ymreg[13][3:0];
14: dout = ymreg[7][6] ? ymreg[14] : IOA_in;
15: dout = ymreg[7][7] ? ymreg[15] : IOB_in;
endcase
end
end
reg ena_div;
reg ena_div_noise;
// p_divider
always @(posedge CLK) begin
reg [3:0] cnt_div;
reg noise_div;
if(CE) begin
ena_div <= 0;
ena_div_noise <= 0;
if(!cnt_div) begin
cnt_div <= {SEL, 3'b111};
ena_div <= 1;
noise_div <= (~noise_div);
if (noise_div) ena_div_noise <= 1;
end else begin
cnt_div <= cnt_div - 1'b1;
end
end
end
reg [2:0] noise_gen_op;
// p_noise_gen
always @(posedge CLK) begin
reg [16:0] poly17;
reg [4:0] noise_gen_cnt;
if(CE) begin
if (ena_div_noise) begin
if(ymreg[6][4:0]) begin
if (noise_gen_cnt >= ymreg[6][4:0] - 1'd1) begin
noise_gen_cnt <= 0;
poly17 <= {(poly17[0] ^ poly17[2] ^ !poly17), poly17[16:1]};
end else begin
noise_gen_cnt <= noise_gen_cnt + 1'd1;
end
noise_gen_op <= {3{poly17[0]}};
end else begin
noise_gen_op <= ymreg[7][5:3];
noise_gen_cnt <= 0;
end
end
end
end
wire [11:0] tone_gen_freq[1:3];
assign tone_gen_freq[1] = {ymreg[1][3:0], ymreg[0]};
assign tone_gen_freq[2] = {ymreg[3][3:0], ymreg[2]};
assign tone_gen_freq[3] = {ymreg[5][3:0], ymreg[4]};
reg [3:1] tone_gen_op;
//p_tone_gens
always @(posedge CLK) begin
integer i;
reg [11:0] tone_gen_cnt[1:3];
if(CE) begin
// looks like real chips count up - we need to get the Exact behaviour ..
for (i = 1; i <= 3; i = i + 1) begin
if(ena_div) begin
if (tone_gen_freq[i]) begin
if (tone_gen_cnt[i] >= (tone_gen_freq[i] - 1'd1)) begin
tone_gen_cnt[i] <= 0;
tone_gen_op[i] <= ~tone_gen_op[i];
end else begin
tone_gen_cnt[i] <= tone_gen_cnt[i] + 1'd1;
end
end else begin
tone_gen_op[i] <= ymreg[7][i];
tone_gen_cnt[i] <= 0;
end
end
end
end
end
reg env_ena;
wire [15:0] env_gen_comp = {ymreg[12], ymreg[11]} ? {ymreg[12], ymreg[11]} - 1'd1 : 16'd0;
//p_envelope_freq
always @(posedge CLK) begin
reg [15:0] env_gen_cnt;
if(CE) begin
env_ena <= 0;
if(ena_div) begin
if (env_gen_cnt >= env_gen_comp) begin
env_gen_cnt <= 0;
env_ena <= 1;
end else begin
env_gen_cnt <= (env_gen_cnt + 1'd1);
end
end
end
end
reg [4:0] env_vol;
wire is_bot = (env_vol == 5'b00000);
wire is_bot_p1 = (env_vol == 5'b00001);
wire is_top_m1 = (env_vol == 5'b11110);
wire is_top = (env_vol == 5'b11111);
always @(posedge CLK) begin
reg env_hold;
reg env_inc;
// envelope shapes
// C AtAlH
// 0 0 x x \___
//
// 0 1 x x /___
//
// 1 0 0 0 \\\\
//
// 1 0 0 1 \___
//
// 1 0 1 0 \/\/
// ___
// 1 0 1 1 \
//
// 1 1 0 0 ////
// ___
// 1 1 0 1 /
//
// 1 1 1 0 /\/\
//
// 1 1 1 1 /___
if(env_reset | RESET) begin
// load initial state
if(!ymreg[13][2]) begin // attack
env_vol <= 5'b11111;
env_inc <= 0; // -1
end else begin
env_vol <= 5'b00000;
env_inc <= 1; // +1
end
env_hold <= 0;
end
else if(CE) begin
if (env_ena) begin
if (!env_hold) begin
if (env_inc) env_vol <= (env_vol + 5'b00001);
else env_vol <= (env_vol + 5'b11111);
end
// envelope shape control.
if(!ymreg[13][3]) begin
if(!env_inc) begin // down
if(is_bot_p1) env_hold <= 1;
end else if (is_top) env_hold <= 1;
end else if(ymreg[13][0]) begin // hold = 1
if(!env_inc) begin // down
if(ymreg[13][1]) begin // alt
if(is_bot) env_hold <= 1;
end else if(is_bot_p1) env_hold <= 1;
end else if(ymreg[13][1]) begin // alt
if(is_top) env_hold <= 1;
end else if(is_top_m1) env_hold <= 1;
end else if(ymreg[13][1]) begin // alternate
if(env_inc == 1'b0) begin // down
if(is_bot_p1) env_hold <= 1;
if(is_bot) begin
env_hold <= 0;
env_inc <= 1;
end
end else begin
if(is_top_m1) env_hold <= 1;
if(is_top) begin
env_hold <= 0;
env_inc <= 0;
end
end
end
end
end
end
reg [5:0] A,B,C;
always @(posedge CLK) begin
A <= {MODE, ~((ymreg[7][0] | tone_gen_op[1]) & (ymreg[7][3] | noise_gen_op[0])) ? 5'd0 : ymreg[8][4] ? env_vol[4:0] : { ymreg[8][3:0], ymreg[8][3]}};
B <= {MODE, ~((ymreg[7][1] | tone_gen_op[2]) & (ymreg[7][4] | noise_gen_op[1])) ? 5'd0 : ymreg[9][4] ? env_vol[4:0] : { ymreg[9][3:0], ymreg[9][3]}};
C <= {MODE, ~((ymreg[7][2] | tone_gen_op[3]) & (ymreg[7][5] | noise_gen_op[2])) ? 5'd0 : ymreg[10][4] ? env_vol[4:0] : {ymreg[10][3:0], ymreg[10][3]}};
end
wire [7:0] volTable[64] = '{
//YM2149
8'h00, 8'h01, 8'h01, 8'h02, 8'h02, 8'h03, 8'h03, 8'h04,
8'h06, 8'h07, 8'h09, 8'h0a, 8'h0c, 8'h0e, 8'h11, 8'h13,
8'h17, 8'h1b, 8'h20, 8'h25, 8'h2c, 8'h35, 8'h3e, 8'h47,
8'h54, 8'h66, 8'h77, 8'h88, 8'ha1, 8'hc0, 8'he0, 8'hff,
//AY8910
8'h00, 8'h00, 8'h03, 8'h03, 8'h04, 8'h04, 8'h06, 8'h06,
8'h0a, 8'h0a, 8'h0f, 8'h0f, 8'h15, 8'h15, 8'h22, 8'h22,
8'h28, 8'h28, 8'h41, 8'h41, 8'h5b, 8'h5b, 8'h72, 8'h72,
8'h90, 8'h90, 8'hb5, 8'hb5, 8'hd7, 8'hd7, 8'hff, 8'hff
};
assign CHANNEL_A = volTable[A];
assign CHANNEL_B = volTable[B];
assign CHANNEL_C = volTable[C];
endmodule

130
rtl/sound/ym2203.sv Normal file
View File

@ -0,0 +1,130 @@
//============================================================================
// YM2203 wrapper
// Copyright (C) 2018 Sorgelig
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//============================================================================
module ym2203
(
input RESET,
input CLK, // Global clock
input CE_CPU, // CPU Clock enable
input CE_YM, // YM2203 Master Clock enable x2 (due to YM2612 model!)
input A0, // 0 - register number/read FM, 1 - data/read PSG
input WE, // 0 - read , 1 - write
input [7:0] DI, // Data In
output [7:0] DO, // Data Out
output [7:0] CHANNEL_A, // PSG Output channel A
output [7:0] CHANNEL_B, // PSG Output channel B
output [7:0] CHANNEL_C, // PSG Output channel C
output [10:0] CHANNEL_FM,// FM Output channel
output PSG_ACTIVE,
input FM_ENA
);
reg [7:0] ymreg;
reg [1:0] pres;
always @(posedge CLK) begin
if(RESET) pres <= 2;
else if(CE_CPU & WE) begin
if(FM_ENA) begin
if(~A0) ymreg <= DI;
else begin
case(ymreg)
'h2d: pres[1] <= 1;
'h2e: pres[0] <= 1;
'h2f: pres <= 0;
endcase
end
end
end
end
wire [2:0] opn_tbl[4] = '{1,1,5,2};
wire [2:0] opn_pres = opn_tbl[pres];
wire [2:0] psg_tbl[4] = '{0,0,3,1};
wire [2:0] psg_pres = psg_tbl[pres];
reg ce_psg_pre, ce_opn_pre;
always @(posedge CLK) begin
reg [2:0] div_psg, div_opn;
{ce_opn_pre, ce_psg_pre} <= 0;
if(RESET) {div_opn, div_psg} <= 0;
else if (CE_YM) begin
div_opn <= div_opn + 1'd1;
if(div_opn >= opn_pres) div_opn <= 0;
ce_opn_pre <= !div_opn;
div_psg <= div_psg + 1'd1;
if(div_psg >= psg_pres) div_psg <= 0;
ce_psg_pre <= !div_psg;
end
end
reg ce_opn, ce_psg;
always @(negedge CLK) {ce_opn, ce_psg} <= {ce_opn_pre, ce_psg_pre};
wire [5:0] psg_active;
wire [7:0] psg_dout;
ym2149 ym2149
(
.CLK(CLK),
.CE(ce_psg),
.RESET(RESET),
.BDIR(WE),
.BC(~A0 | ~WE),
.DI(DI),
.DO(psg_dout),
.CHANNEL_A(CHANNEL_A),
.CHANNEL_B(CHANNEL_B),
.CHANNEL_C(CHANNEL_C),
.ACTIVE(psg_active),
.SEL(1'b0),
.MODE(1'b0)
);
wire [7:0] opn_dout;
wire [11:0] opn_audio;
jt12 jt12
(
.rst(RESET),
.cpu_clk(CLK & CE_CPU),
.cpu_din(DI),
.cpu_dout(opn_dout),
.cpu_addr({1'b0,A0}),
.cpu_cs_n(~FM_ENA),
.cpu_wr_n(~WE),
.syn_clk(CLK & ce_opn),
.cpu_limiter_en(1'b1),
.syn_snd_right(opn_audio)
);
assign DO = A0 ? psg_dout : opn_dout;
assign PSG_ACTIVE = |psg_active;
assign CHANNEL_FM = opn_audio[10:0];
endmodule

88
rtl/spi.v Normal file
View File

@ -0,0 +1,88 @@
// part of NeoGS project (c) 2007-2008 NedoPC
//
// SPI mode 0 8-bit master module
//
// short diagram for speed=0 (Fclk/Fspi=2, no rdy shown)
//
// clk: ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ (positive edges)
// counter: 00|00|00|10|11|12|13|14|15|16|17|18|19|1A|1B|1C|1D|1E|1F|00|00|00 // internal!
// sck: ___________/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\_______
// sdo: --------< do7 | do6 | do5 | do4 | do3 | do2 | do1 | do0 >-------
// sdi: --------< di7 | di6 | di5 | di4 | di3 | di2 | di1 | di0 >-------
// bsync: ________/`````\_________________________________________________
// start: _____/``\_______________________________________________________
// din: -----<IN>-------------------------------------------------------
// dout: old old old old old old old old old old old old old | new new new
//
// data on sdo must be latched by slave on rising sck edge. data on sdo changes on falling edge of sck
//
// data from sdi is latched by master on positive edge of sck, while slave changes it on falling edge.
// WARNING: slave must emit valid di7 bit BEFORE first pulse on sck!
//
// start is synchronous pulse, which starts all transfer and also latches din data on the same clk edge
// as it is registered high. start can be given anytime (only when speed=0),
// so it is functioning then as synchronous reset. when speed!=0, there is global enable for majority of
// flipflops in the module, so start can't be accepted at any time
//
// dout updates with freshly received data at the clk edge in which sck goes high for the last time, thus
// latching last bit on sdi.
//
// sdo emits last bit shifted out after the transfer end
module spi
(
// SPI wires
input clk, // system clock
output sck, // SCK
output reg sdo, // MOSI
input sdi, // MISO
// DMA interface
input dma_req,
input [7:0] dma_din,
// Z80 interface
input cpu_req,
input [7:0] cpu_din,
// output
output start, // start strobe, 1 clock length
output reg [7:0] dout
);
assign sck = counter[0];
assign start = req && rdy;
wire [7:0] din = dma_req ? dma_din : cpu_din;
wire rdy = counter[4]; // 0 - transmission in progress
wire req = cpu_req || dma_req;
reg [4:0] counter;
always @(posedge clk) begin
reg [7:0] shift;
if (start) begin
counter <= 5'b0;
sdo <= din[7];
shift[7:1] <= din[6:0];
end
else if (!rdy) begin
counter <= counter + 5'd1;
// shift in (rising edge of SCK)
if (!sck) begin
shift[0] <= sdi;
if (&counter[3:1]) dout <= {shift[7:1], sdi};
end
// shift out (falling edge of sck)
if (sck) begin
sdo <= shift[7];
shift[7:1] <= shift[6:0]; // last bit remains after end of exchange
end
end
end
endmodule

2753
rtl/tsbios.mif Normal file

File diff suppressed because it is too large Load Diff

920
rtl/tsconf.v Normal file
View File

@ -0,0 +1,920 @@
/* ----------------------------------------------------------------[02.11.2014]
u16-TSConf Version 0.2.9
DEVBOARD ReVerSE-U16 By MVV
----------------------------------------------------------------------------
V0.1.0 27.07.2014 первая версия
V0.2.0 31.07.2014 добавлен транслятор PS/2, HDMI
V0.2.1 03.08.2014 добавлен Delta-Sigma DAC, I2C
V0.2.3 11.08.2014 добавлен enc424j600
V0.2.4 24.08.2014 добавлена поддержка IDE Video DAC (zports.v, video_out.v)
V0.2.5 07.09.2014 добавлен порт #0001=key_scan, изменения в keyboard.vhd
V0.2.6 09.09.2014 исправлен вывод палитры в (lut.vhd)
V0.2.7 13.09.2014 дрожание мультиколора на tv80s, заменил на t80s
V0.2.8 19.10.2014 инвентирован CLK в модулях video_tmbuf, video_sfile и добавлены регистры на выходе
V0.2.9 02.11.2014 замена t80s, исправления в zint.v, zports.v, delta-sigma (приводит к намагничиванию динамиков)
WXEDA 10.03.2015 порт на девборду WXEDA
http://tslabs.info/forum/viewtopic.php?f=31&t=401
http://zx-pk.ru/showthread.php?t=23528
Copyright (c) 2014 MVV, TS-Labs, dsp, waybester, palsw
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 agreement from the author.
* License is granted for non-commercial use only. A fee may not be charged
for redistributions as source code or in synthesized/hardware form without
specific prior written agreement from the author.
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.
*/
module tsconf
(
// Clocks
input clk,
input ce,
// SDRAM (32MB 16x16bit)
inout [15:0] SDRAM_DQ,
output [12:0] SDRAM_A,
output [1:0] SDRAM_BA,
output SDRAM_DQML,
output SDRAM_DQMH,
output SDRAM_nCS,
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nWE,
output SDRAM_CKE,
output SDRAM_CLK,
// VGA
output [7:0] VGA_R,
output [7:0] VGA_G,
output [7:0] VGA_B,
output VGA_HS,
output VGA_VS,
output VGA_HBLANK,
output VGA_VBLANK,
output VGA_CEPIX,
// SD/MMC Memory Card
input SD_SO,
output SD_SI,
output SD_CLK,
output SD_CS_N,
// General Sound
output [20:0] GS_ADDR,
output [7:0] GS_DI,
input [7:0] GS_DO,
output GS_RD,
output GS_WR,
input GS_WAIT,
// Audio
output [15:0] SOUND_L,
output [15:0] SOUND_R,
// Misc. I/O
input COLD_RESET,
input WARM_RESET,
output RESET_OUT,
input [64:0] RTC,
input [31:0] CMOSCfg,
input OUT0,
// PS/2 Keyboard
input [10:0] PS2_KEY,
input [24:0] PS2_MOUSE,
input [5:0] joystick,
input [15:0] loader_addr,
input [7:0] loader_data,
input loader_wr
);
// CPU0
wire [15:0] cpu_a_bus;
wire [7:0] cpu_do_bus;
wire [7:0] cpu_di_bus;
wire cpu_mreq_n;
wire cpu_iorq_n;
wire cpu_wr_n;
wire cpu_rd_n;
wire cpu_int_n_TS;
wire cpu_m1_n;
wire cpu_rfsh_n;
wire [1:0] turbo;
wire [7:0] im2vect;
// zsignal
wire cpu_stall; // zmem -> zclock
wire cpu_req; // zmem -> arbiter
wire cpu_wrbsel; // zmem -> arbiter
wire cpu_next; // arbiter -> zmem
wire cpu_current; // arbiter -> zmem
wire cpu_strobe; // arbiter -> zmem
wire cpu_latch; // arbiter -> zmem
wire [23:0] cpu_addr;
wire [20:0] cpu_addr_20;
wire csrom;
wire curr_cpu;
// SDRAM
wire [7:0] sdr_do_bus;
wire [15:0] sdr_do_bus_16;
wire [15:0] sdr_do_bus_16cpu;
wire sdr_wr;
wire sdr_rd;
wire req;
wire rnw;
wire [23:0] dram_addr;
wire [1:0] dram_bsel;
wire [15:0] dram_wrdata;
wire dram_req;
wire dram_rnw;
wire dos;
wire vdos;
wire pre_vdos;
wire vdos_off;
wire vdos_on;
wire dos_on;
wire m1;
wire rd;
wire wr;
wire iorq;
wire mreq;
wire rdwr;
wire iord;
wire iowr;
wire iorw;
wire memrd;
wire memwr;
wire opfetch;
wire intack;
wire iorq_s;
wire iord_s;
wire iowr_s;
wire iorw_s;
wire memwr_s;
wire opfetch_s;
wire regs_we;
// zports OUT
wire [7:0] dout_ports;
wire ena_ports;
wire [31:0] xt_page;
wire [4:0] fmaddr;
wire [7:0] sysconf;
wire [7:0] memconf;
wire [7:0] intmask;
wire [8:0] dmaport_wr;
wire go_arbiter;
wire [3:0] cacheconf;
// z80
wire [15:0] zmd;
wire [7:0] zma;
wire cram_we;
wire sfile_we;
wire zborder_wr;
wire border_wr;
wire zvpage_wr;
wire vpage_wr;
wire vconf_wr;
wire gx_offsl_wr;
wire gx_offsh_wr;
wire gy_offsl_wr;
wire gy_offsh_wr;
wire t0x_offsl_wr;
wire t0x_offsh_wr;
wire t0y_offsl_wr;
wire t0y_offsh_wr;
wire t1x_offsl_wr;
wire t1x_offsh_wr;
wire t1y_offsl_wr;
wire t1y_offsh_wr;
wire tsconf_wr;
wire palsel_wr;
wire tmpage_wr;
wire t0gpage_wr;
wire t1gpage_wr;
wire sgpage_wr;
wire hint_beg_wr;
wire vint_begl_wr;
wire vint_begh_wr;
// ZX controls
wire res;
wire int_start_frm;
wire int_start_lin;
// DRAM interface
wire [20:0] video_addr;
wire [4:0] video_bw;
wire video_go;
wire video_next;
wire video_pre_next;
wire next_video;
wire video_strobe;
// TS
wire [20:0] ts_addr;
wire ts_req;
// IN
wire ts_pre_next;
wire ts_next;
// TM
wire [20:0] tm_addr;
wire tm_req;
wire tm_next;
// DMA
wire dma_rnw;
wire dma_req;
wire [15:0] dma_wrdata;
wire [20:0] dma_addr;
wire dma_next;
wire dma_act;
wire dma_cram_we;
wire dma_sfile_we;
// zmap
wire [15:0] dma_data;
wire [7:0] dma_wraddr;
wire int_start_dma;
// SPI
wire spi_start;
wire dma_spi_req;
wire [7:0] dma_spi_din;
wire cpu_spi_req;
wire [7:0] cpu_spi_din;
wire [7:0] spi_dout;
wire [7:0] mouse_do;
// clock
wire clk_28mhz = clk & ce;
wire f0,f1;
wire h0,h1;
wire c0,c1,c2,c3;
clock TS01
(
.clk(clk_28mhz),
.f0(f0),
.f1(f1),
.h0(h0),
.h1(h1),
.c0(c0),
.c1(c1),
.c2(c2),
.c3(c3)
);
wire zclk;
wire zpos, zneg;
zclock TS02
(
.clk(clk_28mhz),
.c0(c0),
.c2(c2),
.f0(f0),
.f1(f1),
.zclk_out(zclk),
.zpos(zpos),
.zneg(zneg),
.iorq_s(iorq_s),
.dos_on(dos_on),
.vdos_off(vdos_off),
.cpu_stall(cpu_stall),
.ide_stall(0),
.external_port(0),
.turbo(turbo)
);
reg zclk_r;
always @(posedge clk) zclk_r <= zclk;
T80s CPU
(
.RESET_n(~reset),
.CLK(clk),
.CEN(~zclk_r & zclk),
.INT_n(cpu_int_n_TS),
.M1_n(cpu_m1_n),
.MREQ_n(cpu_mreq_n),
.IORQ_n(cpu_iorq_n),
.RD_n(cpu_rd_n),
.WR_n(cpu_wr_n),
.RFSH_n(cpu_rfsh_n),
.OUT0(OUT0),
.A(cpu_a_bus),
.DI(cpu_di_bus),
.DO(cpu_do_bus)
);
zsignals TS04
(
.clk(clk_28mhz),
.iorq_n(cpu_iorq_n),
.mreq_n(cpu_mreq_n),
.m1_n(cpu_m1_n),
.rfsh_n(cpu_rfsh_n),
.rd_n(cpu_rd_n),
.wr_n(cpu_wr_n),
.rd(rd),
.wr(wr),
.iorq(iorq),
.mreq(mreq),
.rdwr(rdwr),
.iord(iord),
.iowr(iowr),
.iorw(iorw),
.memrd(memrd),
.memwr(memwr),
.opfetch(opfetch),
.intack(intack),
.iorq_s(iorq_s),
.iord_s(iord_s),
.iowr_s(iowr_s),
.iorw_s(iorw_s),
.memwr_s(memwr_s),
.opfetch_s(opfetch_s)
);
zports TS05
(
.clk(clk_28mhz),
.din(cpu_do_bus),
.dout(dout_ports),
.dataout(ena_ports),
.a(cpu_a_bus),
.rst(reset),
.opfetch(opfetch), // from zsignals
.rd(rd),
.wr(wr),
.rdwr(rdwr),
.iorq(iorq),
.iorq_s(iorq_s),
.iord(iord),
.iord_s(iord_s),
.iowr(iowr),
.iowr_s(iowr_s),
.iordwr(iorw),
.iordwr_s(iorw_s),
.zborder_wr(zborder_wr),
.border_wr(border_wr),
.zvpage_wr(zvpage_wr),
.vpage_wr(vpage_wr),
.vconf_wr(vconf_wr),
.gx_offsl_wr(gx_offsl_wr),
.gx_offsh_wr(gx_offsh_wr),
.gy_offsl_wr(gy_offsl_wr),
.gy_offsh_wr(gy_offsh_wr),
.t0x_offsl_wr(t0x_offsl_wr),
.t0x_offsh_wr(t0x_offsh_wr),
.t0y_offsl_wr(t0y_offsl_wr),
.t0y_offsh_wr(t0y_offsh_wr),
.t1x_offsl_wr(t1x_offsl_wr),
.t1x_offsh_wr(t1x_offsh_wr),
.t1y_offsl_wr(t1y_offsl_wr),
.t1y_offsh_wr(t1y_offsh_wr),
.tsconf_wr(tsconf_wr),
.palsel_wr(palsel_wr),
.tmpage_wr(tmpage_wr),
.t0gpage_wr(t0gpage_wr),
.t1gpage_wr(t1gpage_wr),
.sgpage_wr(sgpage_wr),
.hint_beg_wr(hint_beg_wr),
.vint_begl_wr(vint_begl_wr),
.vint_begh_wr(vint_begh_wr),
.xt_page(xt_page),
.fmaddr(fmaddr),
.regs_we(regs_we),
.sysconf(sysconf),
.memconf(memconf),
.cacheconf(cacheconf),
.intmask(intmask),
.dmaport_wr(dmaport_wr), // dmaport_wr
.dma_act(dma_act), // from DMA (status of DMA)
.dos(dos),
.vdos(vdos),
.vdos_on(vdos_on),
.vdos_off(vdos_off),
.tape_read(1),
.keys_in(kb_do_bus), // keys (port FE)
.mus_in(mouse_do), // mouse (xxDF)
.kj_in(joystick),
.vg_intrq(0),
.vg_drq(0), // from vg93 module - drq + irq read
.sdcs_n(SD_CS_N), // to SD card
.sd_start(cpu_spi_req), // to SPI
.sd_datain(cpu_spi_din), // to SPI(7 downto 0);
.sd_dataout(spi_dout), // from SPI(7 downto 0);
.wait_addr(wait_addr),
.wait_start_gluclock(wait_start_gluclock),
.wait_read(mc146818a_do_bus)
);
zmem TS06
(
.clk(clk_28mhz),
.c0(c0),
.c1(c1),
.c2(c2),
.c3(c3),
.zpos(zpos),
.zneg(zneg),
.rst(reset), // PLL locked
.za(cpu_a_bus), // from CPU
.zd_out(sdr_do_bus), // output to Z80 bus 8bit ==>
.zd_ena(), // output to Z80 bus enable
.opfetch(opfetch), // from zsignals
.opfetch_s(opfetch_s), // from zsignals
.mreq(mreq), // from zsignals
.memrd(memrd), // from zsignals
.memwr(memwr), // from zsignals
.memwr_s(memwr_s), // from zsignals
.turbo(turbo),
.cache_en(cacheconf), // from zport
.memconf(memconf[3:0]),
.xt_page(xt_page),
.csrom(csrom),
.dos(dos),
.dos_on(dos_on),
.vdos(vdos),
.pre_vdos(pre_vdos),
.vdos_on(vdos_on),
.vdos_off(vdos_off),
.cpu_req(cpu_req),
.cpu_addr(cpu_addr_20),
.cpu_wrbsel(cpu_wrbsel), // for 16bit data
.cpu_rddata(sdr_do_bus_16cpu),
.cpu_next(cpu_next),
.cpu_strobe(cpu_strobe), // from ARBITER ACTIVE=HI
.cpu_latch(cpu_latch),
.cpu_stall(cpu_stall) // for Zclock if HI-> STALL (ZCLK)
);
arbiter TS07
(
.clk(clk_28mhz),
.c0(c0),
.c1(c1),
.c2(c2),
.c3(c3),
.dram_addr(dram_addr),
.dram_req(dram_req),
.dram_rnw(dram_rnw),
.dram_bsel(dram_bsel),
.dram_wrdata(dram_wrdata), // data to be written
.video_addr(video_addr), // during access block, only when video_strobe==1
.go(go_arbiter), // start video access blocks
.video_bw(video_bw), // ZX="11001", [4:3] -total cycles: 11 = 8 / 01 = 4 / 00 = 2
.video_pre_next(video_pre_next),
.video_next(video_next), // (c2) at this signal video_addr may be changed; it is one clock leading the video_strobe
.video_strobe(video_strobe), // (c3) one-cycle strobe meaning that video_data is available
.next_vid(next_video), // used for TM prefetch
.cpu_addr(cpu_addr_20),
.cpu_wrdata(cpu_do_bus),
.cpu_req(cpu_req),
.cpu_rnw(rd | csrom),
.cpu_wrbsel(cpu_wrbsel),
.cpu_next(cpu_next), // next cycle is allowed to be used by CPU
.cpu_strobe(cpu_strobe), // c2 strobe
.cpu_latch(cpu_latch), // c2-c3 strobe
.curr_cpu_o(curr_cpu),
.dma_addr(dma_addr),
.dma_wrdata(dma_wrdata),
.dma_req(dma_req),
.dma_rnw(dma_rnw),
.dma_next(dma_next),
.ts_addr(ts_addr),
.ts_req(ts_req),
.ts_pre_next(ts_pre_next),
.ts_next(ts_next),
.tm_addr(tm_addr),
.tm_req(tm_req),
.tm_next(tm_next)
);
video_top TS08
(
.clk(clk_28mhz),
.f0(f0),
.f1(f1),
.h0(h0),
.h1(h1),
.c0(c0),
.c1(c1),
.c2(c2),
.c3(c3),
.vred(VGA_R),
.vgrn(VGA_G),
.vblu(VGA_B),
.hsync(VGA_HS),
.vsync(VGA_VS),
.hblank(VGA_HBLANK),
.vblank(VGA_VBLANK),
.pix_stb(VGA_CEPIX),
.d(cpu_do_bus),
.zmd(zmd),
.zma(zma),
.cram_we(cram_we),
.sfile_we(sfile_we),
.zborder_wr(zborder_wr),
.border_wr(border_wr),
.zvpage_wr(zvpage_wr),
.vpage_wr(vpage_wr),
.vconf_wr(vconf_wr),
.gx_offsl_wr(gx_offsl_wr),
.gx_offsh_wr(gx_offsh_wr),
.gy_offsl_wr(gy_offsl_wr),
.gy_offsh_wr(gy_offsh_wr),
.t0x_offsl_wr(t0x_offsl_wr),
.t0x_offsh_wr(t0x_offsh_wr),
.t0y_offsl_wr(t0y_offsl_wr),
.t0y_offsh_wr(t0y_offsh_wr),
.t1x_offsl_wr(t1x_offsl_wr),
.t1x_offsh_wr(t1x_offsh_wr),
.t1y_offsl_wr(t1y_offsl_wr),
.t1y_offsh_wr(t1y_offsh_wr),
.tsconf_wr(tsconf_wr),
.palsel_wr(palsel_wr),
.tmpage_wr(tmpage_wr),
.t0gpage_wr(t0gpage_wr),
.t1gpage_wr(t1gpage_wr),
.sgpage_wr(sgpage_wr),
.hint_beg_wr(hint_beg_wr),
.vint_begl_wr(vint_begl_wr),
.vint_begh_wr(vint_begh_wr),
.res(reset),
.int_start(int_start_frm),
.line_start_s(int_start_lin),
.video_addr(video_addr),
.video_bw(video_bw),
.video_go(go_arbiter),
.dram_rdata(sdr_do_bus_16), // raw, should be latched by c2 (video_next)
.video_next(video_next),
.video_pre_next(video_pre_next),
.next_video(next_video),
.video_strobe(video_strobe),
.ts_addr(ts_addr),
.ts_req(ts_req),
.ts_pre_next(ts_pre_next),
.ts_next(ts_next),
.tm_addr(tm_addr),
.tm_req(tm_req),
.tm_next(tm_next)
);
dma TS09
(
.clk(clk_28mhz),
.c2(c2),
.reset(reset),
.dmaport_wr(dmaport_wr),
.dma_act(dma_act),
.data(dma_data),
.wraddr(dma_wraddr),
.int_start(int_start_dma),
.zdata(cpu_do_bus),
.dram_addr(dma_addr),
.dram_rddata(sdr_do_bus_16),
.dram_wrdata(dma_wrdata),
.dram_req(dma_req),
.dram_rnw(dma_rnw),
.dram_next(dma_next),
.spi_rddata(spi_dout),
.spi_wrdata(dma_spi_din),
.spi_req(dma_spi_req),
.spi_stb(spi_start),
.ide_in(0),
.ide_stb(0),
.cram_we(dma_cram_we),
.sfile_we(dma_sfile_we)
);
zmaps TS10
(
.clk(clk_28mhz),
.memwr_s(memwr_s),
.a(cpu_a_bus),
.d(cpu_do_bus),
.fmaddr(fmaddr),
.zmd(zmd),
.zma(zma),
.dma_data(dma_data),
.dma_wraddr(dma_wraddr),
.dma_cram_we(dma_cram_we),
.dma_sfile_we(dma_sfile_we),
.cram_we(cram_we),
.sfile_we(sfile_we),
.regs_we(regs_we)
);
spi TS11
(
.clk(clk_28mhz),
.sck(SD_CLK),
.sdo(SD_SI),
.sdi(SD_SO),
.dma_req(dma_spi_req),
.dma_din(dma_spi_din),
.cpu_req(cpu_spi_req),
.cpu_din(cpu_spi_din),
.start(spi_start),
.dout(spi_dout)
);
zint TS13
(
.clk(clk_28mhz),
.zpos(zpos),
.res(reset),
.int_start_frm(int_start_frm), //< N1 VIDEO
.int_start_lin(int_start_lin), //< N2 VIDEO
.int_start_dma(int_start_dma), //< N3 DMA
.vdos(pre_vdos), // vdos,--pre_vdos
.intack(intack), //< zsignals === (intack ? im2vect : 8'hFF)));
.intmask(intmask), //< ZPORT (7 downto 0);
.im2vect(im2vect), //> CPU Din (2 downto 0);
.int_n(cpu_int_n_TS)
);
// BIOS
wire [7:0] bios_do_bus;
dpram #(.ADDRWIDTH(16), .MEM_INIT_FILE("rtl/tsbios.mif")) BIOS
(
.clock(clk),
.address_a({cpu_addr_20[14:0],cpu_wrbsel}),
.q_a(bios_do_bus),
.address_b(loader_addr),
.data_b(loader_data),
.wren_b(loader_wr)
);
// SDRAM Controller
sdram SE4
(
.clk(clk),
.cyc(ce&c3),
.curr_cpu(curr_cpu),
.bsel(dram_bsel),
.A(dram_addr),
.DI(dram_wrdata),
.DO(sdr_do_bus_16),
.DO_cpu(sdr_do_bus_16cpu),
.REQ(dram_req),
.RNW(dram_rnw),
.SDRAM_DQ(SDRAM_DQ),
.SDRAM_A(SDRAM_A),
.SDRAM_BA(SDRAM_BA),
.SDRAM_DQML(SDRAM_DQML),
.SDRAM_DQMH(SDRAM_DQMH),
.SDRAM_nCS(SDRAM_nCS),
.SDRAM_nCAS(SDRAM_nCAS),
.SDRAM_nRAS(SDRAM_nRAS),
.SDRAM_nWE(SDRAM_nWE),
.SDRAM_CKE(SDRAM_CKE),
.SDRAM_CLK(SDRAM_CLK)
);
// PS/2 Keyboard
wire [4:0] kb_do_bus;
wire key_reset;
wire [7:0] key_scancode;
keyboard SE5
(
.clk(clk_28mhz),
.reset(COLD_RESET | WARM_RESET),
.a(cpu_a_bus[15:8]),
.keyb(kb_do_bus),
.KEY_RESET(key_reset),
.scancode(key_scancode),
.ps2_key(PS2_KEY)
);
kempston_mouse KM
(
.clk_sys(clk_28mhz),
.reset(reset),
.ps2_mouse(PS2_MOUSE),
.addr(cpu_a_bus[10:8]),
.dout(mouse_do)
);
// MC146818A,RTC
wire [7:0] wait_addr;
wire wait_start_gluclock;
wire [7:0] mc146818a_do_bus;
reg ena_0_4375mhz;
always @(negedge clk_28mhz) begin
reg [5:0] div;
div <= div + 1'd1;
ena_0_4375mhz <= !div; //28MHz/64
end
mc146818a SE9
(
.RESET(reset),
.CLK(clk_28mhz),
.ENA(ena_0_4375mhz),
.CS(1),
.KEYSCANCODE(key_scancode),
.RTC(RTC),
.CMOSCfg(CMOSCfg),
.WR(wait_start_gluclock & ~cpu_wr_n),
.A(wait_addr),
.DI(cpu_do_bus),
.DO(mc146818a_do_bus)
);
// Soundrive
wire [7:0] covox_a;
wire [7:0] covox_b;
wire [7:0] covox_c;
wire [7:0] covox_d;
soundrive SE10
(
.reset(reset),
.clk(clk_28mhz),
.cs(1),
.wr_n(cpu_wr_n),
.a(cpu_a_bus[7:0]),
.di(cpu_do_bus),
.iorq_n(cpu_iorq_n),
.dos(dos),
.outa(covox_a),
.outb(covox_b),
.outc(covox_c),
.outd(covox_d)
);
// Turbosound FM
reg ce_ym;
always @(posedge clk_28mhz) begin
reg [1:0] div;
div <= div + 1'd1;
ce_ym <= !div;
end
wire ts_enable = ~cpu_iorq_n & cpu_a_bus[0] & cpu_a_bus[15] & ~cpu_a_bus[1];
wire ts_we = ts_enable & ~cpu_wr_n;
wire [11:0] ts_l, ts_r;
wire [7:0] ts_do;
turbosound SE12
(
.RESET(reset),
.CLK(clk_28mhz),
.CE_CPU(zpos),
.CE_YM(ce_ym),
.BDIR(ts_we),
.BC(cpu_a_bus[14]),
.DI(cpu_do_bus),
.DO(ts_do),
.CHANNEL_L(ts_l),
.CHANNEL_R(ts_r)
);
// General Sound
wire [14:0] gs_l;
wire [14:0] gs_r;
wire [7:0] gs_do_bus;
wire gs_sel = ~cpu_iorq_n & cpu_m1_n & (cpu_a_bus[7:4] == 'hB && cpu_a_bus[2:0] == 'h3);
gs #("rtl/sound/gs105b.mif") U15
(
.RESET(reset),
.CLK(clk),
.CE(ce),
.A(cpu_a_bus[3]),
.DI(cpu_do_bus),
.DO(gs_do_bus),
.CS_n(cpu_iorq_n | ~gs_sel),
.WR_n(cpu_wr_n),
.RD_n(cpu_rd_n),
.MEM_ADDR(GS_ADDR),
.MEM_DI(GS_DI),
.MEM_DO(GS_DO),
.MEM_RD(GS_RD),
.MEM_WR(GS_WR),
.MEM_WAIT(GS_WAIT),
.OUTL(gs_l),
.OUTR(gs_r)
);
// SAA1099
wire [7:0] saa_out_l;
wire [7:0] saa_out_r;
wire saa_wr_n = ~cpu_iorq_n && ~cpu_wr_n && cpu_a_bus[7:0] == 8'hFF && ~dos;
reg ce_saa;
always @(posedge clk_28mhz) begin
reg [2:0] div;
div <= div + 1'd1;
if(div == 6) div <= 0;
ce_saa <= (div == 0 || div == 3);
end
saa1099 U16
(
.clk_sys(clk_28mhz),
.ce(ce_saa),
.rst_n(~reset),
.cs_n(0),
.a0(cpu_a_bus[8]), // 0=data, 1=address
.wr_n(saa_wr_n),
.din(cpu_do_bus),
.out_l(saa_out_l),
.out_r(saa_out_r)
);
wire [11:0] audio_l = ts_l + {gs_l[14], gs_l[14:4]} + {2'b00, covox_a, 2'b00} + {2'b00, covox_b, 2'b00} + {1'b0, saa_out_l, 3'b000} + {3'b000, port_xxfe_reg[4], 8'b00000000};
wire [11:0] audio_r = ts_r + {gs_r[14], gs_r[14:4]} + {2'b00, covox_c, 2'b00} + {2'b00, covox_d, 2'b00} + {1'b0, saa_out_r, 3'b000} + {3'b000, port_xxfe_reg[4], 8'b00000000};
compressor compressor
(
clk_28mhz,
audio_l, audio_r,
SOUND_L, SOUND_R
);
//-----------------------------------------------------------------------------
// Global
//-----------------------------------------------------------------------------
wire reset = COLD_RESET | WARM_RESET | key_reset;
assign RESET_OUT = reset;
// CPU interface
assign cpu_di_bus =
(csrom && ~cpu_mreq_n && ~cpu_rd_n) ? bios_do_bus : // BIOS
(~cpu_mreq_n && ~cpu_rd_n) ? sdr_do_bus : // SDRAM
(intack) ? im2vect :
(gs_sel && ~cpu_rd_n) ? gs_do_bus : // General Sound
(ts_enable && ~cpu_rd_n) ? ts_do : // TurboSound
(cpu_a_bus == 16'h0001 && ~cpu_iorq_n && ~cpu_rd_n) ? key_scancode :
(ena_ports) ? dout_ports :
8'b11111111;
// TURBO
assign turbo = sysconf[1:0];
reg [7:0] port_xxfe_reg;
always @(posedge clk_28mhz) begin
if (reset) port_xxfe_reg <= 0;
else if (~cpu_iorq_n && ~cpu_wr_n && cpu_a_bus[7:0] == 8'hFE) port_xxfe_reg <= cpu_do_bus;
end
endmodule

280
rtl/video/video_cram.mif Normal file
View File

@ -0,0 +1,280 @@
-- 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.
-- Quartus II generated Memory Initialization File (.mif)
WIDTH=16;
DEPTH=256;
ADDRESS_RADIX=HEX;
DATA_RADIX=HEX;
CONTENT BEGIN
000 : 0000;
001 : 0008;
002 : 0010;
003 : 0018;
004 : 2000;
005 : 2008;
006 : 2010;
007 : 2018;
008 : 4000;
009 : 4008;
00A : 4010;
00B : 4018;
00C : 6000;
00D : 6008;
00E : 6010;
00F : 6018;
010 : 0100;
011 : 0108;
012 : 0110;
013 : 0118;
014 : 2100;
015 : 2108;
016 : 2110;
017 : 2118;
018 : 4100;
019 : 4108;
01A : 4110;
01B : 4118;
01C : 6100;
01D : 6108;
01E : 6110;
01F : 6118;
020 : 0200;
021 : 0208;
022 : 0210;
023 : 0218;
024 : 2200;
025 : 2208;
026 : 2210;
027 : 2218;
028 : 4200;
029 : 4208;
02A : 4210;
02B : 4218;
02C : 6200;
02D : 6208;
02E : 6210;
02F : 6218;
030 : 0300;
031 : 0308;
032 : 0310;
033 : 0318;
034 : 2300;
035 : 2308;
036 : 2310;
037 : 2318;
038 : 4300;
039 : 4308;
03A : 4310;
03B : 4318;
03C : 6300;
03D : 6308;
03E : 6310;
03F : 6318;
040 : 0000;
041 : 0010;
042 : 4000;
043 : 4010;
044 : 0200;
045 : 0210;
046 : 4200;
047 : 4210;
048 : 2108;
049 : 0018;
04A : 6000;
04B : 6018;
04C : 0300;
04D : 0318;
04E : 6300;
04F : 6318;
050 : 0000;
051 : 0010;
052 : 4000;
053 : 4010;
054 : 0200;
055 : 0210;
056 : 4200;
057 : 4210;
058 : 0000;
059 : 0018;
05A : 6000;
05B : 6018;
05C : 0300;
05D : 0318;
05E : 6300;
05F : 6318;
060 : 0000;
061 : 0010;
062 : 4000;
063 : 4010;
064 : 0200;
065 : 0210;
066 : 4200;
067 : 4210;
068 : 2108;
069 : 0018;
06A : 6000;
06B : 6018;
06C : 0300;
06D : 0318;
06E : 6300;
06F : 6318;
070 : 0000;
071 : 0010;
072 : 4000;
073 : 4010;
074 : 0200;
075 : 0210;
076 : 4200;
077 : 4210;
078 : 0000;
079 : 0018;
07A : 6000;
07B : 6018;
07C : 0300;
07D : 0318;
07E : 6300;
07F : 6318;
080 : 0000;
081 : 0010;
082 : 4000;
083 : 4010;
084 : 0200;
085 : 0210;
086 : 4200;
087 : 4210;
088 : 2108;
089 : 0018;
08A : 6000;
08B : 6018;
08C : 0300;
08D : 0318;
08E : 6300;
08F : 6318;
090 : 0000;
091 : 0010;
092 : 4000;
093 : 4010;
094 : 0200;
095 : 0210;
096 : 4200;
097 : 4210;
098 : 0000;
099 : 0018;
09A : 6000;
09B : 6018;
09C : 0300;
09D : 0318;
09E : 6300;
09F : 6318;
0A0 : 0000;
0A1 : 0010;
0A2 : 4000;
0A3 : 4010;
0A4 : 0200;
0A5 : 0210;
0A6 : 4200;
0A7 : 4210;
0A8 : 2108;
0A9 : 0018;
0AA : 6000;
0AB : 6018;
0AC : 0300;
0AD : 0318;
0AE : 6300;
0AF : 6318;
0B0 : 0000;
0B1 : 0010;
0B2 : 4000;
0B3 : 4010;
0B4 : 0200;
0B5 : 0210;
0B6 : 4200;
0B7 : 4210;
0B8 : 0000;
0B9 : 0018;
0BA : 6000;
0BB : 6018;
0BC : 0300;
0BD : 0318;
0BE : 6300;
0BF : 6318;
0C0 : 0000;
0C1 : 0010;
0C2 : 4000;
0C3 : 4010;
0C4 : 0200;
0C5 : 0210;
0C6 : 4200;
0C7 : 4210;
0C8 : 2108;
0C9 : 0018;
0CA : 6000;
0CB : 6018;
0CC : 0300;
0CD : 0318;
0CE : 6300;
0CF : 6318;
0D0 : 0000;
0D1 : 0010;
0D2 : 4000;
0D3 : 4010;
0D4 : 0200;
0D5 : 0210;
0D6 : 4200;
0D7 : 4210;
0D8 : 0000;
0D9 : 0018;
0DA : 6000;
0DB : 6018;
0DC : 0300;
0DD : 0318;
0DE : 6300;
0DF : 6318;
0E0 : 0000;
0E1 : 0010;
0E2 : 4000;
0E3 : 4010;
0E4 : 0200;
0E5 : 0210;
0E6 : 4200;
0E7 : 4210;
0E8 : 2108;
0E9 : 0018;
0EA : 6000;
0EB : 6018;
0EC : 0300;
0ED : 0318;
0EE : 6300;
0EF : 6318;
0F0 : 0000;
0F1 : 0010;
0F2 : 4000;
0F3 : 4010;
0F4 : 0200;
0F5 : 0210;
0F6 : 4200;
0F7 : 4210;
0F8 : 0000;
0F9 : 0018;
0FA : 6000;
0FB : 6018;
0FC : 0300;
0FD : 0318;
0FE : 6300;
0FF : 6318;
END;

33
rtl/video/video_fetch.v Normal file
View File

@ -0,0 +1,33 @@
// This module fetches video data from DRAM
module video_fetch
(
// clocks
input wire clk,
// control
input wire [3:0] f_sel,
input wire [1:0] b_sel,
input wire fetch_stb,
// video data
output reg [31:0] fetch_data,
output reg [31:0] fetch_temp,
// DRAM interface
input wire video_strobe,
input wire [15:0] video_data
);
// fetching data
always @(posedge clk) if (video_strobe)
begin
if (f_sel[0]) fetch_temp[ 7: 0] <= b_sel[0] ? video_data[15:8] : video_data[ 7:0];
if (f_sel[1]) fetch_temp[15: 8] <= b_sel[1] ? video_data[15:8] : video_data[ 7:0];
if (f_sel[2]) fetch_temp[23:16] <= video_data[ 7:0];
if (f_sel[3]) fetch_temp[31:24] <= video_data[15:8];
end
always @(posedge clk) if (fetch_stb) fetch_data <= fetch_temp;
endmodule

235
rtl/video/video_mode.v Normal file
View File

@ -0,0 +1,235 @@
// This module decodes video modes
module video_mode
(
// clocks
input wire clk, f1, c3,
// video config
input wire [7:0] vpage,
input wire [7:0] vconf,
input wire ts_rres_ext,
// video parameters & mode controls
input wire [8:0] gx_offs,
output wire [9:0] x_offs_mode,
output wire [8:0] hpix_beg,
output wire [8:0] hpix_end,
output wire [8:0] vpix_beg,
output wire [8:0] vpix_end,
output wire [8:0] hpix_beg_ts,
output wire [8:0] hpix_end_ts,
output wire [8:0] vpix_beg_ts,
output wire [8:0] vpix_end_ts,
output wire [5:0] x_tiles,
output wire [4:0] go_offs,
output wire [3:0] fetch_sel,
output wire [1:0] fetch_bsl,
input wire [3:0] fetch_cnt,
input wire pix_start,
input wire line_start_s,
output wire tv_hires,
output wire [1:0] render_mode,
output wire pix_stb,
output wire fetch_stb,
// video data
input wire [15:0] txt_char,
// video counters
input wire [7:0] cnt_col,
input wire [8:0] cnt_row,
input wire cptr,
// DRAM interface
output wire [20:0] video_addr,
output wire [ 4:0] video_bw
);
wire [1:0] vmod = vconf[1:0];
wire [1:0] rres = vconf[7:6];
// clocking strobe for pixels (TV)
assign pix_stb = tv_hires ? f1 : c3;
// Modes
localparam M_ZX = 2'h0; // ZX
localparam M_HC = 2'h1; // 16c
localparam M_XC = 2'h2; // 256c
localparam M_TX = 2'h3; // Text
// Render modes (affects 'video_render.v')
localparam R_ZX = 2'h0;
localparam R_HC = 2'h1;
localparam R_XC = 2'h2;
localparam R_TX = 2'h3;
// fetch strobes
wire ftch[0:3];
assign fetch_stb = (pix_start | ftch[render_mode]) && c3;
assign ftch[R_ZX] = &fetch_cnt[3:0];
assign ftch[R_HC] = &fetch_cnt[1:0];
assign ftch[R_XC] = fetch_cnt[0];
assign ftch[R_TX] = &fetch_cnt[3:0];
// fetch window
wire [4:0] g_offs[0:3];
// these values are from a thin air!!! recheck them occasionally!
assign g_offs[M_ZX] = 5'd18;
assign g_offs[M_HC] = 5'd6;
assign g_offs[M_XC] = 5'd4;
assign g_offs[M_TX] = 5'd10;
assign go_offs = g_offs[vmod];
// fetch selectors
// Attention: counter is already incremented at the time of video data fetching!
// wire m_c = (vmod == M_HC) | (vmod == M_XC);
// assign fetch_sel = vmod == M_TX ? f_txt_sel[cnt_col[1:0]] : {~cptr, ~cptr, cptr | m_c, cptr | m_c};
// wire [3:0] f_sel[0:7];
wire [3:0] f_sel[0:3];
assign f_sel[M_ZX] = {~cptr, ~cptr, cptr, cptr};
assign f_sel[M_HC] = {~cptr, ~cptr, 2'b11};
assign f_sel[M_XC] = {~cptr, ~cptr, 2'b11};
assign f_sel[M_TX] = f_txt_sel[cnt_col[1:0]];
assign fetch_sel = f_sel[vmod];
assign fetch_bsl = (vmod == M_TX) ? f_txt_bsl[cnt_col[1:0]] : 2'b10;
// wire [1:0] f_bsl[0:7];
// assign f_bsl[M_ZX] = 2'b10;
// assign f_bsl[M_HC] = 2'b10;
// assign f_bsl[M_XC] = 2'b10;
// assign f_bsl[M_TX] = f_txt_bsl[cnt_col[1:0]];
// assign fetch_bsl = f_bsl[vmod];
wire [3:0] f_txt_sel[0:3];
assign f_txt_sel[1] = 4'b0011; // char
assign f_txt_sel[2] = 4'b1100; // attr
assign f_txt_sel[3] = 4'b0001; // gfx0
assign f_txt_sel[0] = 4'b0010; // gfx1
wire [1:0] f_txt_bsl[0:3];
assign f_txt_bsl[1] = 2'b10; // char
assign f_txt_bsl[2] = 2'b10; // attr
assign f_txt_bsl[3] = {2{cnt_row[0]}}; // gfx0
assign f_txt_bsl[0] = {2{cnt_row[0]}}; // gfx1
// X offset
assign x_offs_mode = {vmod == M_XC ? {gx_offs[8:1], 1'b0} : {1'b0, gx_offs[8:1]}, gx_offs[0]};
// DRAM bandwidth usage
localparam BW2 = 2'b00;
localparam BW4 = 2'b01;
localparam BW8 = 2'b11;
localparam BU1 = 3'b001;
localparam BU2 = 3'b010;
localparam BU4 = 3'b100;
// [4:3] - total cycles: 11 = 8 / 01 = 4 / 00 = 2
// [2:0] - need cycles
wire [4:0] bw[0:3];
assign bw[M_ZX] = {BW8, BU1}; // '1 of 8' (ZX)
assign bw[M_HC] = {BW4, BU1}; // '1 of 4' (16c)
assign bw[M_XC] = {BW2, BU1}; // '1 of 2' (256c)
assign bw[M_TX] = {BW8, BU4}; // '4 of 8' (text)
assign video_bw = bw[vmod];
// pixelrate
wire [3:0] pixrate = 4'b1000; // change these if you change the modes indexes!
assign tv_hires = pixrate[vmod];
// render mode
// wire [1:0] r_mode[0:7];
wire [1:0] r_mode[0:3];
assign r_mode[M_ZX] = R_ZX;
assign r_mode[M_HC] = R_HC;
assign r_mode[M_XC] = R_XC;
assign r_mode[M_TX] = R_TX;
assign render_mode = r_mode[vmod];
// raster resolution
wire [8:0] hp_beg[0:3];
wire [8:0] hp_end[0:3];
wire [8:0] vp_beg[0:3];
wire [8:0] vp_end[0:3];
wire [5:0] x_tile[0:3];
assign hp_beg[0] = 9'd136; // 256 (88-52-256-52)
assign hp_beg[1] = 9'd108; // 320 (88-20-320-20)
assign hp_beg[2] = 9'd108; // 320 (88-20-320-20)
assign hp_beg[3] = 9'd88; // 360 (88-0-360-0)
assign hp_end[0] = 9'd392; // 256
assign hp_end[1] = 9'd428; // 320
assign hp_end[2] = 9'd428; // 320
assign hp_end[3] = 9'd448; // 360
assign vp_beg[0] = 9'd080; // 192 (22-24-192-24)/(32-48-192-48) (blank-border-pixels-border)
assign vp_beg[1] = 9'd076; // 200 (22-20-200-20)/(32-44-200-44)
assign vp_beg[2] = 9'd056; // 240 (22-0-240-0)/(32-24-240-24)
assign vp_beg[3] = 9'd032; // 288 (22-0-240-0)/(32-0-288-0)
assign vp_end[0] = 9'd272; // 192
assign vp_end[1] = 9'd276; // 200
assign vp_end[2] = 9'd296; // 240
assign vp_end[3] = 9'd320; // 240/288
assign x_tile[0] = 6'd34; // 256
assign x_tile[1] = 6'd42; // 320
assign x_tile[2] = 6'd42; // 320
assign x_tile[3] = 6'd47; // 360
assign hpix_beg = hp_beg[rres];
assign hpix_end = hp_end[rres];
assign vpix_beg = vp_beg[rres];
assign vpix_end = vp_end[rres];
assign hpix_beg_ts = ts_rres_ext ? hp_beg[3] : hp_beg[rres];
assign hpix_end_ts = ts_rres_ext ? hp_end[3] : hp_end[rres];
assign vpix_beg_ts = ts_rres_ext ? vp_beg[3] : vp_beg[rres];
assign vpix_end_ts = ts_rres_ext ? vp_end[3] : vp_end[rres];
assign x_tiles = ts_rres_ext ? x_tile[3] : x_tile[rres];
// videomode addresses
wire [20:0] v_addr[0:3];
assign v_addr[M_ZX] = addr_zx;
assign v_addr[M_HC] = addr_16c;
assign v_addr[M_XC] = addr_256c;
assign v_addr[M_TX] = addr_text;
assign video_addr = v_addr[vmod];
// ZX
wire [20:0] addr_zx = {vpage, 1'b0, ~cnt_col[0] ? addr_zx_gfx : addr_zx_atr};
wire [11:0] addr_zx_gfx = {cnt_row[7:6], cnt_row[2:0], cnt_row[5:3], cnt_col[4:1]};
wire [11:0] addr_zx_atr = {3'b110, cnt_row[7:3], cnt_col[4:1]};
// 16c
wire [20:0] addr_16c = {vpage[7:3], cnt_row, cnt_col[6:0]};
// 256c
wire [20:0] addr_256c = {vpage[7:4], cnt_row, cnt_col[7:0]};
// Textmode
wire [20:0] addr_text = {vpage[7:1], addr_tx[cnt_col[1:0]]};
wire [13:0] addr_tx[0:3];
assign addr_tx[0] = {vpage[0], cnt_row[8:3], 1'b0, cnt_col[7:2]}; // char codes, data[15:0]
assign addr_tx[1] = {vpage[0], cnt_row[8:3], 1'b1, cnt_col[7:2]}; // char attributes, data[31:16]
assign addr_tx[2] = {~vpage[0], 3'b000, (txt_char[7:0]), cnt_row[2:1]}; // char0 graphics, data[7:0]
assign addr_tx[3] = {~vpage[0], 3'b000, (txt_char[15:8]), cnt_row[2:1]}; // char1 graphics, data[15:8]
endmodule

60
rtl/video/video_out.v Normal file
View File

@ -0,0 +1,60 @@
// This module generates video for DAC
// (c)2015 TSL
module video_out
(
// clocks
input wire clk, c3,
// video controls
input wire tv_blank,
input wire [1:0] plex_sel_in,
// mode controls
input wire tv_hires,
input wire [3:0] palsel,
// Z80 pins
input wire [15:0] cram_data_in,
input wire [7:0] cram_addr_in,
input wire cram_we,
// video data
input wire [7:0] vplex_in,
output wire [7:0] vred,
output wire [7:0] vgrn,
output wire [7:0] vblu,
output wire vdac_mode
);
reg [7:0] vplex;
always @(posedge clk) if (c3) vplex <= vplex_in;
wire [7:0] vdata = tv_hires ? {palsel, plex_sel_in[1] ? vplex[3:0] : vplex[7:4]} : vplex;
// CRAM
wire [15:0] vpixel;
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8), .MEM_INIT_FILE("rtl/video/video_cram.mif")) video_cram
(
.clock (clk),
.address_a(cram_addr_in),
.data_a (cram_data_in),
.wren_a (cram_we),
.address_b(vdata),
.q_b (vpixel)
);
reg blank;
always @(posedge clk) blank <= tv_blank;
wire [14:0] vpix = blank ? 15'b0 : vpixel[14:0];
assign vred = {vpix[14:10], vpix[14:12]};
assign vgrn = {vpix[ 9: 5], vpix[ 9: 7]};
assign vblu = {vpix[ 4: 0], vpix[ 4: 2]};
assign vdac_mode = vpixel[15];
endmodule

149
rtl/video/video_ports.v Normal file
View File

@ -0,0 +1,149 @@
// This module latches all port parameters for video from Z80
module video_ports
(
// clocks
input wire clk,
input wire [ 7:0] d,
input wire res,
input wire int_start,
input wire line_start_s,
// port write strobes
input wire zborder_wr,
input wire border_wr,
input wire zvpage_wr,
input wire vpage_wr,
input wire vconf_wr,
input wire gx_offsl_wr,
input wire gx_offsh_wr,
input wire gy_offsl_wr,
input wire gy_offsh_wr,
input wire t0x_offsl_wr,
input wire t0x_offsh_wr,
input wire t0y_offsl_wr,
input wire t0y_offsh_wr,
input wire t1x_offsl_wr,
input wire t1x_offsh_wr,
input wire t1y_offsl_wr,
input wire t1y_offsh_wr,
input wire tsconf_wr,
input wire palsel_wr,
input wire tmpage_wr,
input wire t0gpage_wr,
input wire t1gpage_wr,
input wire sgpage_wr,
input wire hint_beg_wr ,
input wire vint_begl_wr,
input wire vint_begh_wr,
// video parameters
output reg [7:0] border,
output reg [7:0] vpage,
output reg [7:0] vconf,
output reg [8:0] gx_offs,
output reg [8:0] gy_offs,
output reg [8:0] t0x_offs,
output reg [8:0] t0y_offs,
output reg [8:0] t1x_offs,
output reg [8:0] t1y_offs,
output reg [7:0] palsel,
output reg [7:0] hint_beg,
output reg [8:0] vint_beg,
output reg [7:0] tsconf,
output reg [7:0] tmpage,
output reg [7:0] t0gpage,
output reg [7:0] t1gpage,
output reg [7:0] sgpage
);
reg [7:0] vpage_r;
reg [7:0] vconf_r;
reg [7:0] t0gpage_r;
reg [7:0] t1gpage_r;
reg [8:0] gx_offs_r;
reg [8:0] t0x_offs_r;
reg [8:0] t1x_offs_r;
reg [7:0] palsel_r;
wire [8:0] vint_beg_inc = vint_beg + vint_inc;
wire [8:0] vint_beg_next = {(vint_beg_inc[8:6] == 3'b101) ? 3'b0 : vint_beg_inc[8:6], vint_beg_inc[5:0]}; // if over 319 lines, decrement 320
reg [3:0] vint_inc;
always @(posedge clk) begin
if (res) begin
vint_beg <= 9'd0;
vint_inc <= 4'b0;
end
else if (vint_begl_wr) vint_beg[7:0] <= d;
else if (vint_begh_wr) begin
vint_beg[8] <= d[0];
vint_inc <= d[7:4];
end
else if (int_start) vint_beg <= vint_beg_next;
end
always @(posedge clk) begin
if (res) begin
vpage_r <= 8'h05;
vconf_r <= 8'h00;
gx_offs_r <= 9'b0;
palsel_r <= 8'h0F;
gy_offs <= 9'b0;
tsconf <= 8'b0;
hint_beg <= 8'd1;
end
else begin
if (zborder_wr ) border <= {palsel[3:0], 1'b0, d[2:0]};
if (border_wr ) border <= d;
if (gy_offsl_wr ) gy_offs[7:0] <= d;
if (gy_offsh_wr ) gy_offs[8] <= d[0];
if (t0y_offsl_wr) t0y_offs[7:0] <= d;
if (t0y_offsh_wr) t0y_offs[8] <= d[0];
if (t1y_offsl_wr) t1y_offs[7:0] <= d;
if (t1y_offsh_wr) t1y_offs[8] <= d[0];
if (tsconf_wr ) tsconf <= d;
if (tmpage_wr ) tmpage <= d;
if (sgpage_wr ) sgpage <= d;
if (hint_beg_wr ) hint_beg <= d;
if (zvpage_wr ) vpage_r <= {6'b000001, d[3], 1'b1};
if (vpage_wr ) vpage_r <= d;
if (vconf_wr ) vconf_r <= d;
if (gx_offsl_wr ) gx_offs_r[7:0] <= d;
if (gx_offsh_wr ) gx_offs_r[8] <= d[0];
if (palsel_wr ) palsel_r <= d;
if (t0x_offsl_wr) t0x_offs_r[7:0] <= d;
if (t0x_offsh_wr) t0x_offs_r[8] <= d[0];
if (t1x_offsl_wr) t1x_offs_r[7:0] <= d;
if (t1x_offsh_wr) t1x_offs_r[8] <= d[0];
if (t0gpage_wr ) t0gpage_r <= d;
if (t1gpage_wr ) t1gpage_r <= d;
end
end
// latching regs at line start, delaying hires for 1 line
always @(posedge clk) begin
if (res)
begin
vpage <= 8'h05;
vconf <= 8'h00;
gx_offs <= 9'b0;
palsel <= 8'h0F;
end
else if (zvpage_wr) vpage <= {6'b000001, d[3], 1'b1};
else if (line_start_s) begin
vpage <= vpage_r;
vconf <= vconf_r;
gx_offs <= gx_offs_r;
palsel <= palsel_r;
t0x_offs <= t0x_offs_r;
t1x_offs <= t1x_offs_r;
t0gpage <= t0gpage_r;
t1gpage <= t1gpage_r;
end
end
endmodule

84
rtl/video/video_render.v Normal file
View File

@ -0,0 +1,84 @@
// This module renders video data for output
module video_render
(
// clocks
input wire clk, c1,
// video controls
input wire hvpix,
input wire hvtspix,
input wire nogfx,
input wire notsu,
input wire gfxovr,
input wire flash,
input wire hires,
input wire [3:0] psel,
input wire [3:0] palsel,
// mode controls
input wire [1:0] render_mode,
// video data
input wire [31:0] data,
input wire [ 7:0] border_in,
input wire [ 7:0] tsdata_in,
output wire [ 7:0] vplex_out
);
localparam R_ZX = 2'h0;
localparam R_HC = 2'h1;
localparam R_XC = 2'h2;
localparam R_TX = 2'h3;
// ZX graphics
wire [15:0] zx_gfx = data[15: 0];
wire [15:0] zx_atr = data[31:16];
wire zx_dot = zx_gfx[{psel[3], ~psel[2:0]}];
wire [7:0] zx_attr = ~psel[3] ? zx_atr[7:0] : zx_atr[15:8];
wire [7:0] zx_pix = {palsel, zx_attr[6], zx_dot ^ (flash & zx_attr[7]) ? zx_attr[2:0] : zx_attr[5:3]};
// text graphics
// (it uses common renderer with ZX, but different attributes)
wire [7:0] tx_pix = {palsel, zx_dot ? zx_attr[3:0] : zx_attr[7:4]};
// 16c graphics
wire [3:0] hc_dot[0:3];
assign hc_dot[0] = data[ 7: 4];
assign hc_dot[1] = data[ 3: 0];
assign hc_dot[2] = data[15:12];
assign hc_dot[3] = data[11: 8];
wire [7:0] hc_pix = {palsel, hc_dot[psel[1:0]]};
// 256c graphics
wire [7:0] xc_dot[0:1];
assign xc_dot[0] = data[ 7: 0];
assign xc_dot[1] = data[15: 8];
wire [7:0] xc_pix = xc_dot[psel[0]];
// mode selects
wire [7:0] pix[0:3];
assign pix[R_ZX] = zx_pix; // ZX
assign pix[R_HC] = hc_pix; // 16c
assign pix[R_XC] = xc_pix; // 256c
assign pix[R_TX] = tx_pix; // text
wire pixv[0:3];
assign pixv[R_ZX] = zx_dot ^ (flash & zx_attr[7]);
assign pixv[R_HC] = |hc_dot[psel[1:0]];
assign pixv[R_XC] = |xc_dot[psel[0]];
assign pixv[R_TX] = zx_dot;
// video plex muxer
wire tsu_visible = (|tsdata_in[3:0] && !notsu);
wire gfx_visible = (pixv[render_mode] && !nogfx);
wire [7:0] video1 = tsu_visible ? tsdata_in : (nogfx ? border_in : pix[render_mode]);
wire [7:0] video2 = gfx_visible ? pix[render_mode] : (tsu_visible ? tsdata_in : border_in);
wire [7:0] video = hvpix ? (gfxovr ? video2 : video1) : ((hvtspix && tsu_visible) ? tsdata_in : border_in);
assign vplex_out = hires ? {temp, video[3:0]} : video; // in hi-res plex contains two pixels 4 bits each
reg [3:0] temp;
always @(posedge clk) if (c1) temp <= video[3:0];
endmodule

169
rtl/video/video_sync.v Normal file
View File

@ -0,0 +1,169 @@
// This module generates all video raster signals
module video_sync
(
// clocks
input wire clk, f1, c0, c1, c3, pix_stb,
// video parameters
input wire [8:0] hpix_beg,
input wire [8:0] hpix_end,
input wire [8:0] vpix_beg,
input wire [8:0] vpix_end,
input wire [8:0] hpix_beg_ts,
input wire [8:0] hpix_end_ts,
input wire [8:0] vpix_beg_ts,
input wire [8:0] vpix_end_ts,
input wire [4:0] go_offs,
input wire [1:0] x_offs,
input wire [7:0] hint_beg,
input wire [8:0] vint_beg,
input wire [7:0] cstart,
input wire [8:0] rstart,
// video syncs
output reg hsync,
output reg vsync,
// video controls
input wire nogfx,
output wire v_pf,
output wire hpix,
output wire vpix,
output wire v_ts,
output wire hvpix,
output wire hvtspix,
output wire tv_hblank,
output wire tv_vblank,
output wire frame_start,
output wire line_start_s,
output wire pix_start,
output wire ts_start,
output wire frame,
output wire flash,
// video counters
output wire [8:0] ts_raddr,
output reg [8:0] lcount,
output reg [7:0] cnt_col,
output reg [8:0] cnt_row,
output reg cptr,
output reg [3:0] scnt,
// DRAM
input wire video_pre_next,
output reg video_go,
// ZX controls
input wire y_offs_wr,
output wire int_start
);
localparam HSYNC_BEG = 9'd11;
localparam HSYNC_END = 9'd43;
localparam HBLNK_BEG = 9'd00;
localparam HBLNK_END = 9'd88;
localparam HSYNCV_BEG = 9'd5;
localparam HSYNCV_END = 9'd31;
localparam HBLNKV_END = 9'd42;
localparam HPERIOD = 9'd448;
localparam VSYNC_BEG = 9'd08;
localparam VSYNC_END = 9'd11;
localparam VBLNK_BEG = 9'd00;
localparam VBLNK_END = 9'd32;
localparam VPERIOD = 9'd320;
// counters
reg [8:0] hcount = 0;
reg [8:0] vcount = 0;
// horizontal TV (7 MHz)
always @(posedge clk) if (c3) hcount <= line_start ? 9'b0 : hcount + 9'b1;
// vertical TV (15.625 kHz)
always @(posedge clk) if (line_start_s) vcount <= (vcount == (VPERIOD - 1)) ? 9'b0 : vcount + 9'b1;
// column address for DRAM
always @(posedge clk) begin
if (line_start2) begin
cnt_col <= cstart;
cptr <= 1'b0;
end
else if (video_pre_next) begin
cnt_col <= cnt_col + 8'b1;
cptr <= ~cptr;
end
end
// row address for DRAM
always @(posedge clk) begin if (c3)
if (vis_start || (line_start && y_offs_wr_r)) cnt_row <= rstart;
else if (line_start && vpix) cnt_row <= cnt_row + 9'b1;
end
// pixel counter
always @(posedge clk) if (pix_stb) scnt <= pix_start ? 4'b0 : scnt + 4'b1; // f1 or c3
// TS-line counter
assign ts_raddr = hcount - hpix_beg_ts;
always @(posedge clk) if (ts_start_coarse) lcount <= vcount - vpix_beg_ts + 9'b1;
// Y offset re-latch trigger
reg y_offs_wr_r;
always @(posedge clk) begin
if (y_offs_wr) y_offs_wr_r <= 1'b1;
else if (line_start_s) y_offs_wr_r <= 1'b0;
end
// FLASH generator
reg [4:0] flash_ctr;
assign frame = flash_ctr[0];
assign flash = flash_ctr[4];
always @(posedge clk) begin
if (frame_start && c3) begin
flash_ctr <= flash_ctr + 5'b1;
end
end
// sync strobes
wire hs = (hcount >= HSYNC_BEG) && (hcount < HSYNC_END);
wire vs = (vcount >= VSYNC_BEG) && (vcount < VSYNC_END);
assign tv_hblank = (hcount > HBLNK_BEG) && (hcount <= HBLNK_END);
assign tv_vblank = (vcount >= VBLNK_BEG) && (vcount < VBLNK_END);
assign hvpix = hpix && vpix;
assign hpix = (hcount >= hpix_beg) && (hcount < hpix_end);
assign vpix = (vcount >= vpix_beg) && (vcount < vpix_end);
assign hvtspix = htspix && vtspix;
wire htspix = (hcount >= hpix_beg_ts) && (hcount < hpix_end_ts);
wire vtspix = (vcount >= vpix_beg_ts) && (vcount < vpix_end_ts);
assign v_ts = (vcount >= (vpix_beg_ts - 1)) && (vcount < (vpix_end_ts - 1)); // vertical TS window
assign v_pf = (vcount >= (vpix_beg_ts - 17)) && (vcount < (vpix_end_ts - 9)); // vertical tilemap prefetch window
always @(posedge clk) video_go <= (hcount >= (hpix_beg - go_offs - x_offs)) && (hcount < (hpix_end - go_offs - x_offs + 4)) && vpix && !nogfx;
wire line_start = hcount == (HPERIOD - 1);
assign line_start_s = line_start && c3;
wire line_start2 = hcount == (HSYNC_END - 1);
assign frame_start = line_start && (vcount == (VPERIOD - 1));
wire vis_start = line_start && (vcount == (VBLNK_END - 1));
assign pix_start = hcount == (hpix_beg - x_offs - 1);
wire ts_start_coarse = hcount == (hpix_beg_ts - 1);
assign ts_start = c3 && ts_start_coarse;
assign int_start = (hcount == {hint_beg, 1'b0}) && (vcount == vint_beg) && c0;
always @(posedge clk) begin
hsync <= hs;
vsync <= vs;
end
endmodule

467
rtl/video/video_top.v Normal file
View File

@ -0,0 +1,467 @@
// This module is a video top-level
module video_top
(
// clocks
input wire clk,
input wire f0, f1,
input wire h0, h1,
input wire c0, c1, c2, c3,
// input wire t0, // debug!!!
// video DAC
output wire [7:0] vred,
output wire [7:0] vgrn,
output wire [7:0] vblu,
output wire vdac_mode,
// video syncs
output wire hsync,
output wire vsync,
output wire hblank,
output wire vblank,
output wire pix_stb,
// Z80 controls
input wire [ 7:0] d,
input wire [15:0] zmd,
input wire [ 7:0] zma,
input wire cram_we,
input wire sfile_we,
// port write strobes
input wire zborder_wr,
input wire border_wr,
input wire zvpage_wr,
input wire vpage_wr,
input wire vconf_wr,
input wire gx_offsl_wr,
input wire gx_offsh_wr,
input wire gy_offsl_wr,
input wire gy_offsh_wr,
input wire t0x_offsl_wr,
input wire t0x_offsh_wr,
input wire t0y_offsl_wr,
input wire t0y_offsh_wr,
input wire t1x_offsl_wr,
input wire t1x_offsh_wr,
input wire t1y_offsl_wr,
input wire t1y_offsh_wr,
input wire tsconf_wr,
input wire palsel_wr,
input wire tmpage_wr,
input wire t0gpage_wr,
input wire t1gpage_wr,
input wire sgpage_wr,
input wire hint_beg_wr ,
input wire vint_begl_wr,
input wire vint_begh_wr,
// ZX controls
input wire res,
output wire int_start,
output wire line_start_s,
// DRAM interface
output wire [20:0] video_addr,
output wire [ 4:0] video_bw,
output wire video_go,
input wire [15:0] dram_rdata, // raw, should be latched by c2 (video_next)
input wire video_next,
input wire video_pre_next,
input wire next_video,
input wire video_strobe,
output wire [20:0] ts_addr,
output wire ts_req,
input wire ts_pre_next,
input wire ts_next,
output wire [20:0] tm_addr,
output wire tm_req,
input wire tm_next
);
// video config
wire [7:0] vpage; // re-latched at line_start
wire [7:0] vconf; //
wire [8:0] gx_offs; //
wire [8:0] gy_offs; //
wire [7:0] palsel; //
wire [8:0] t0x_offs; //
wire [8:0] t1x_offs; //
wire [7:0] t0gpage; //
wire [7:0] t1gpage; //
wire [7:0] sgpage; // * not yet !!!
wire [8:0] t0y_offs;
wire [8:0] t1y_offs;
wire [7:0] tsconf;
wire [7:0] tmpage;
wire [7:0] hint_beg;
wire [8:0] vint_beg;
wire [8:0] hpix_beg;
wire [8:0] hpix_end;
wire [8:0] vpix_beg;
wire [8:0] vpix_end;
wire [8:0] hpix_beg_ts;
wire [8:0] hpix_end_ts;
wire [8:0] vpix_beg_ts;
wire [8:0] vpix_end_ts;
wire [5:0] x_tiles;
wire [9:0] x_offs_mode;
wire [4:0] go_offs;
wire [1:0] render_mode;
wire tv_hires;
wire nogfx = vconf[5];
wire notsu = vconf[4];
wire gfxovr = vconf[3];
wire tv_hblank;
wire tv_vblank;
// counters
wire [7:0] cnt_col;
wire [8:0] cnt_row;
wire cptr;
wire [3:0] scnt;
wire [8:0] lcount;
// synchro
wire frame_start;
wire pix_start;
wire tv_pix_start;
wire ts_start;
wire v_ts;
wire v_pf;
wire hpix;
wire vpix;
wire hvpix;
wire hvtspix;
wire flash;
// fetcher
wire [31:0] fetch_data;
wire [31:0] fetch_temp;
wire [3:0] fetch_sel;
wire [1:0] fetch_bsl;
wire fetch_stb;
// video data
wire [7:0] border;
wire [7:0] vplex;
// TS
wire tsr_go;
wire [5:0] tsr_addr;
wire [8:0] tsr_line;
wire [7:0] tsr_page;
wire [8:0] tsr_x;
wire [2:0] tsr_xs;
wire tsr_xf;
wire [3:0] tsr_pal;
wire tsr_rdy;
// TS-line
wire [8:0] ts_waddr;
wire [7:0] ts_wdata;
wire ts_we;
wire [8:0] ts_raddr;
video_ports video_ports
(
.clk (clk),
.d (d),
.res (res),
.line_start_s (line_start_s),
.border_wr (border_wr),
.zborder_wr (zborder_wr),
.zvpage_wr (zvpage_wr),
.vpage_wr (vpage_wr),
.vconf_wr (vconf_wr),
.gx_offsl_wr (gx_offsl_wr),
.gx_offsh_wr (gx_offsh_wr),
.gy_offsl_wr (gy_offsl_wr),
.gy_offsh_wr (gy_offsh_wr),
.t0x_offsl_wr (t0x_offsl_wr),
.t0x_offsh_wr (t0x_offsh_wr),
.t0y_offsl_wr (t0y_offsl_wr),
.t0y_offsh_wr (t0y_offsh_wr),
.t1x_offsl_wr (t1x_offsl_wr),
.t1x_offsh_wr (t1x_offsh_wr),
.t1y_offsl_wr (t1y_offsl_wr),
.t1y_offsh_wr (t1y_offsh_wr),
.palsel_wr (palsel_wr),
.hint_beg_wr (hint_beg_wr),
.vint_begl_wr (vint_begl_wr),
.vint_begh_wr (vint_begh_wr),
.tsconf_wr (tsconf_wr),
.tmpage_wr (tmpage_wr),
.t0gpage_wr (t0gpage_wr),
.t1gpage_wr (t1gpage_wr),
.sgpage_wr (sgpage_wr),
.border (border),
.vpage (vpage),
.vconf (vconf),
.gx_offs (gx_offs),
.gy_offs (gy_offs),
.t0x_offs (t0x_offs),
.t1x_offs (t1x_offs),
.t0y_offs (t0y_offs),
.t1y_offs (t1y_offs),
.palsel (palsel),
.hint_beg (hint_beg),
.vint_beg (vint_beg),
.int_start (0),
.tsconf (tsconf),
.tmpage (tmpage),
.t0gpage (t0gpage),
.t1gpage (t1gpage),
.sgpage (sgpage)
);
video_mode video_mode
(
.clk (clk),
.f1 (f1),
.c3 (c3),
.vpage (vpage),
.vconf (vconf),
.fetch_sel (fetch_sel),
.fetch_bsl (fetch_bsl),
.fetch_cnt (scnt),
.fetch_stb (fetch_stb),
.txt_char (fetch_temp[15:0]),
.gx_offs (gx_offs),
.x_offs_mode (x_offs_mode),
.ts_rres_ext (tsconf[0]),
.hpix_beg (hpix_beg),
.hpix_end (hpix_end),
.vpix_beg (vpix_beg),
.vpix_end (vpix_end),
.hpix_beg_ts (hpix_beg_ts),
.hpix_end_ts (hpix_end_ts),
.vpix_beg_ts (vpix_beg_ts),
.vpix_end_ts (vpix_end_ts),
.x_tiles (x_tiles),
.go_offs (go_offs),
.cnt_col (cnt_col),
.cnt_row (cnt_row),
.cptr (cptr),
.line_start_s (line_start_s),
.pix_start (pix_start),
.tv_hires (tv_hires),
.pix_stb (pix_stb),
.render_mode (render_mode),
.video_addr (video_addr),
.video_bw (video_bw)
);
video_sync video_sync
(
.clk (clk),
.f1 (f1),
.c0 (c0),
.c1 (c1),
.c3 (c3),
.hpix_beg (hpix_beg),
.hpix_end (hpix_end),
.vpix_beg (vpix_beg),
.vpix_end (vpix_end),
.hpix_beg_ts (hpix_beg_ts),
.hpix_end_ts (hpix_end_ts),
.vpix_beg_ts (vpix_beg_ts),
.vpix_end_ts (vpix_end_ts),
.go_offs (go_offs),
.x_offs (x_offs_mode[1:0]),
.y_offs_wr (gy_offsl_wr || gy_offsh_wr),
.line_start_s (line_start_s),
.hint_beg (hint_beg),
.vint_beg (vint_beg),
.hsync (hsync),
.vsync (vsync),
.tv_hblank (tv_hblank),
.tv_vblank (tv_vblank),
.ts_raddr (ts_raddr),
.lcount (lcount),
.cnt_col (cnt_col),
.cnt_row (cnt_row),
.cptr (cptr),
.scnt (scnt),
.flash (flash),
.pix_stb (pix_stb),
.pix_start (pix_start),
.ts_start (ts_start),
.cstart (x_offs_mode[9:2]),
.rstart (gy_offs),
.frame_start (frame_start),
.int_start (int_start),
.v_pf (v_pf),
.hpix (hpix),
.v_ts (v_ts),
.vpix (vpix),
.hvpix (hvpix),
.hvtspix (hvtspix),
.nogfx (nogfx),
.video_go (video_go),
.video_pre_next(video_pre_next)
);
video_fetch video_fetch
(
.clk (clk),
.f_sel (fetch_sel),
.b_sel (fetch_bsl),
.fetch_stb (fetch_stb),
.fetch_data (fetch_data),
.fetch_temp (fetch_temp),
.video_strobe (video_strobe),
.video_data (dram_rdata)
);
video_ts video_ts
(
.clk (clk),
.start (ts_start),
.line (lcount),
.v_ts (v_ts),
.tsconf (tsconf),
.t0gpage (t0gpage),
.t1gpage (t1gpage),
.sgpage (sgpage),
.tmpage (tmpage),
.num_tiles (x_tiles),
.v_pf (v_pf),
.t0x_offs (t0x_offs),
.t1x_offs (t1x_offs),
.t0y_offs (t0y_offs),
.t1y_offs (t1y_offs),
.t0_palsel (palsel[5:4]),
.t1_palsel (palsel[7:6]),
.dram_addr (tm_addr),
.dram_req (tm_req),
.dram_next (tm_next),
.dram_rdata (dram_rdata),
.tsr_go (tsr_go),
.tsr_addr (tsr_addr),
.tsr_line (tsr_line),
.tsr_page (tsr_page),
.tsr_pal (tsr_pal),
.tsr_x (tsr_x),
.tsr_xs (tsr_xs),
.tsr_xf (tsr_xf),
.tsr_rdy (tsr_rdy),
.sfile_addr_in (zma),
.sfile_data_in (zmd),
.sfile_we (sfile_we)
);
video_ts_render video_ts_render
(
.clk (clk),
.reset (ts_start),
.tsr_go (tsr_go),
.addr (tsr_addr),
.line (tsr_line),
.page (tsr_page),
.pal (tsr_pal),
.x_coord (tsr_x),
.x_size (tsr_xs),
.flip (tsr_xf),
.mem_rdy (tsr_rdy),
.ts_waddr (ts_waddr),
.ts_wdata (ts_wdata),
.ts_we (ts_we),
.dram_addr (ts_addr),
.dram_req (ts_req),
.dram_pre_next (ts_pre_next),
.dram_next (ts_next),
.dram_rdata (dram_rdata)
);
video_render video_render
(
.clk (clk),
.c1 (c1),
.hvpix (hvpix),
.hvtspix (hvtspix),
.nogfx (nogfx),
.notsu (notsu),
.gfxovr (gfxovr),
.flash (flash),
.hires (tv_hires),
.psel (scnt),
.palsel (palsel[3:0]),
.render_mode (render_mode),
.data (fetch_data),
.border_in (border),
.tsdata_in (ts_rdata),
.vplex_out (vplex)
);
video_out video_out
(
.clk (clk),
.c3 (c3),
.tv_blank (tv_hblank|tv_vblank),
.palsel (palsel[3:0]),
.plex_sel_in ({h1, f1}),
.tv_hires (tv_hires),
.cram_addr_in (zma),
.cram_data_in (zmd[15:0]),
.cram_we (cram_we),
.vplex_in (vplex),
.vred (vred),
.vgrn (vgrn),
.vblu (vblu),
.vdac_mode (vdac_mode)
);
assign hblank = tv_hblank;
assign vblank = tv_vblank;
// 2 buffers: 512 pixels * 8 bits (9x8) - used as bitmap buffer for TS overlay over graphics
// (2 altdprams)
wire tl_act0 = lcount[0];
wire tl_act1 = ~lcount[0];
wire [8:0] ts_waddr0 = tl_act0 ? ts_raddr : ts_waddr;
wire [7:0] ts_wdata0 = tl_act0 ? 8'd0 : ts_wdata;
wire ts_we0 = tl_act0 ? c3 : ts_we;
wire [8:0] ts_waddr1 = tl_act1 ? ts_raddr : ts_waddr;
wire [7:0] ts_wdata1 = tl_act1 ? 8'd0 : ts_wdata;
wire ts_we1 = tl_act1 ? c3 : ts_we;
wire [7:0] ts_rdata = tl_act0 ? ts_rdata0 : ts_rdata1;
wire [7:0] ts_rdata0, ts_rdata1;
dpram #(.ADDRWIDTH(9)) video_tsline0
(
.clock (clk),
.address_a (ts_waddr0),
.data_a (ts_wdata0),
.wren_a (ts_we0),
.address_b (ts_raddr),
.q_b (ts_rdata0)
);
dpram #(.ADDRWIDTH(9)) video_tsline1
(
.clock (clk),
.address_a (ts_waddr1),
.data_a (ts_wdata1),
.wren_a (ts_we1),
.address_b (ts_raddr),
.q_b (ts_rdata1)
);
endmodule

379
rtl/video/video_ts.v Normal file
View File

@ -0,0 +1,379 @@
// This is the Tile Sprite Processing Unit
// Tiles map address:
// bits desc
// 20:13 tmpage
// 12:
// Graphics address:
// bits desc
// 20:13 Xgpage
// 15:7 line (bits 15:13 are added) - 512 lines
// 6:0 word within line - 128 words = 512 pixels
module video_ts
(
// clocks
input wire clk,
// video controls
input wire start,
input wire [8:0] line, // = vcount - vpix_beg + 9'b1;
input wire v_ts,
input wire v_pf, // vertical tilemap prefetch window
// video config
input wire [7:0] tsconf,
input wire [7:0] t0gpage,
input wire [7:0] t1gpage,
input wire [7:0] sgpage,
input wire [7:0] tmpage,
input wire [5:0] num_tiles,
input wire [8:0] t0x_offs,
input wire [8:0] t1x_offs,
input wire [8:0] t0y_offs,
input wire [8:0] t1y_offs,
input wire [1:0] t0_palsel,
input wire [1:0] t1_palsel,
// SFYS interface
input wire [7:0] sfile_addr_in,
input wire [15:0] sfile_data_in,
input wire sfile_we,
// renderer interface
output wire tsr_go,
output wire [5:0] tsr_addr, // graphics address within the line
output wire [8:0] tsr_line, // bitmap line
output wire [7:0] tsr_page, // bitmap 1st page
output wire [8:0] tsr_x, // addr in buffer (0-359 visibles)
output wire [2:0] tsr_xs, // size (8-64 pix)
output wire tsr_xf, // X flip
output wire [3:0] tsr_pal, // palette
input wire tsr_rdy, // renderer is done and ready to receive a new task
// DRAM interface
output wire [20:0] dram_addr,
output wire dram_req,
input wire dram_next,
input wire [15:0] dram_rdata
);
// config
wire s_en = tsconf[7];
wire t1_en = tsconf[6];
wire t0_en = tsconf[5];
wire t1z_en = tsconf[3];
wire t0z_en = tsconf[2];
// TS renderer interface
assign tsr_go = sprite_go || tile_go;
assign tsr_x = sprites ? sprites_x : tile_x;
assign tsr_xs = sprites ? sprites_xs : 3'd0;
assign tsr_xf = sprites ? sprites_xf : t_xflp;
assign tsr_page = sprites ? sgpage : tile_page;
assign tsr_line = sprites ? sprites_line : tile_line;
assign tsr_addr = sprites ? sprites_addr : tile_addr;
assign tsr_pal = sprites ? s_pal : tile_pal;
// Layer selectors control
localparam LAYERS = 6; // Total number of layers to process
localparam TM = 0; // Individual layers
localparam S0 = 1;
localparam T0 = 2;
localparam S1 = 3;
localparam T1 = 4;
localparam S2 = 5;
wire tmap = layer_active[TM];
wire sprites = layer_active[S0] || layer_active[S1] || layer_active[S2];
wire tiles = layer_active[T0] || layer_active[T1];
reg [LAYERS-1:0] layer;
always @(posedge clk)
if (start)
layer <= 1;
else if (|(layer & layer_skip))
layer <= {layer[LAYERS-2:0], 1'b0};
reg [LAYERS-1:0] layer_active;
always @(posedge clk)
if (start)
layer_active <= 0;
else
layer_active <= layer & ~layer_skip;
wire [LAYERS-1:0] layer_enabled = {s_en, t1_en, s_en, t0_en, s_en, t1_en || t0_en};
wire [LAYERS-1:0] layer_allowed = {{5{v_ts}}, v_pf};
wire [LAYERS-1:0] layer_end = {spr_end[2], tile_end[1], spr_end[1], tile_end[0], spr_end[0], tm_end};
reg [LAYERS-1:0] layer_skip;
always @(posedge clk)
if (start)
layer_skip <= ~(layer_enabled & layer_allowed);
else
layer_skip <= layer_skip | layer_end;
// --- Tile map prefetch ---
// DRAM controls
assign dram_addr = {tmpage, tm_b_row, tm_layer, tm_b_line, tm_num}; // 20:13 - page, 12:7 - row, 6 - layer, 5:0 - column (burst number : number in burst)
assign dram_req = tmap;
// TMB control
wire [8:0] tmb_waddr = {tm_line[4:3], tm_b_line, tm_num, tm_layer}; // 8:7 - buffer #, 6:4 - burst number (of 8 bursts), 3:1 - number in burst (8 tiles per burst), 0 - layer
wire [8:0] tm_line = line + 9'd16;
wire [2:0] tm_b_line = tm_line[2:0];
wire [5:0] tm_b_row = tm_line[8:3] + (tm_layer ? t1y_offs[8:3] : t0y_offs[8:3]);
wire [2:0] tm_num = tm_x[2:0];
wire tm_layer = tm_x[3];
// internal layers control
wire tm_end = tm_x == (t1_en ? 5'd16 : 5'd8);
wire tm_next = dram_next && tmap;
reg [1:0] m_layer;
always @(posedge clk)
if (start)
m_layer <= 2'b1;
else if (tm_end)
m_layer <= {m_layer[0], 1'b0};
// tilemap X coordinate
reg [4:0] tm_x;
always @(posedge clk)
if (start)
tm_x <= t0_en ? 5'd0 : 5'd8;
else if (tm_next)
tm_x <= tm_x + 5'd1;
// --- Tiles ---
// tile descriptor fields
wire [11:0] t_tnum = tmb_rdata[11:0];
wire [1:0] t_pal = tmb_rdata[13:12];
wire t_xflp = tmb_rdata[14];
wire t_yflp = tmb_rdata[15];
// TSR control
wire [7:0] tile_page = t_sel ? t0gpage : t1gpage;
wire [8:0] tile_line = {t_tnum[11:6], (t_line[2:0] ^ {3{t_yflp}})};
wire [5:0] tile_addr = t_tnum[5:0];
wire [8:0] tile_x = {(tx - 6'd1), 3'd0} - tx_offs[2:0];
wire [3:0] tile_pal = {t_sel ? t0_palsel : t1_palsel, t_pal};
// TMB control
wire [8:0] tmb_raddr = {t_line[4:3], tx + tx_offs[8:3], ~t_sel};
// layer parameter selectors
wire [8:0] tx_offs = t_sel ? t0x_offs : t1x_offs;
wire [3:0] ty_offs = t_sel ? t0y_offs[2:0] : t1y_offs[2:0];
wire t_sel = t_layer[0];
// internal layers control
wire [1:0] tile_end = {2{t_layer_end}} & t_layer[1:0];
wire t_layer_end = tx == num_tiles;
wire t_layer_start = start || t_layer_end;
reg [1:0] t_layer;
always @(posedge clk)
if (start)
t_layer <= t0_en ? 2'b01 : 2'b10;
else if (t_layer_end)
t_layer <= {t_layer[0], 1'b0};
// TMBUF control
// condition write to tx write to tm_valid
// t_layer_start 0 TM_PRE_VALID
// tm_pre_valid tx+1 TM_VALID
// tile_skip tx+1 -
// tile_go tx+1 TM_VALID
// tile_wait tx-1 TM_PRE_VALID
localparam TM_PRE_VALID = 2'b01;
localparam TM_VALID = 2'b10;
wire tile_go = tile_good && tsr_allowed;
wire tile_wait = tile_good && !tsr_allowed;
wire tile_good = tm_valid && tile_valid;
wire tile_skip = tm_valid && !tile_valid;
wire tsr_allowed = tiles && tsr_rdy;
wire tile_valid = |t_tnum || (t_sel ? t0z_en : t1z_en);
wire tm_pre_valid = tm_valid_r[0];
wire tm_valid = tm_valid_r[1];
reg [1:0] tm_valid_r;
always @(posedge clk)
if (t_layer_start || tile_wait)
tm_valid_r <= TM_PRE_VALID;
else if (tm_pre_valid || tile_go)
tm_valid_r <= TM_VALID;
reg [5:0] tx;
always @(posedge clk)
if (t_layer_start)
tx <= 6'd0;
else if (tm_pre_valid || tile_skip || tile_go)
tx <= tx + 6'd1;
else if (tile_wait)
tx <= tx - 6'd1;
// tile Y geometry
wire [4:0] t_line = line[4:0] + ty_offs;
// --- Sprites ---
// sprite descriptor fields
// R0
wire [8:0] s_ycrd = sfile_rdata[8:0];
wire [2:0] s_ysz = sfile_rdata[11:9];
wire s_act = sfile_rdata[13];
wire s_leap = sfile_rdata[14];
wire s_yflp = sfile_rdata[15];
// R1
wire [8:0] s_xcrd = sfile_rdata[8:0];
wire [2:0] s_xsz = sfile_rdata[11:9];
wire s_xflp = sfile_rdata[15];
// R2
wire [11:0] s_tnum = sfile_rdata[11:0];
wire [3:0] s_pal = sfile_rdata[15:12];
// TSR control
reg [8:0] sprites_x;
reg [2:0] sprites_xs;
reg sprites_xf;
wire [5:0] sprites_addr = s_tnum[5:0];
// internal layers control
wire [2:0] spr_end = ({3{s_layer_end}} & s_layer[2:0]) | {3{sprites_last}};
wire s_layer_end = (sr0_valid && !spr_valid && s_leap) || (sprite_go && s_leap_r);
wire sprites_last = sreg == 8'd255;
reg [2:0] s_layer;
always @(posedge clk)
if (start)
s_layer <= 3'b1;
else if (s_layer_end)
s_layer <= {s_layer[1:0], 1'b0};
// SFile registers control
// condition write to sreg write to sr_valid action
// start 0 SR0_PRE_VALID Start
// sr0_pre_valid sreg+3 SR0_VALID SR0 pre-read
// sr0_valid && !spr_valid sreg+3 - Skip sprite
// sr0_valid && spr_valid sreg-2 SR1_PRE_VALID SR1 pre-read
// sr1_pre_valid sreg+1 SR1_VALID SR1 read
// sr1_valid sreg+1 SR2_VALID SR2 pre-read
// sr2_valid && !tsr_rdy - - Wait for TSR ready
// sr2_valid && tsr_rdy sreg+1 SR0_PRE_VALID Next sprite
// sprites_last - NONE_VALID End
localparam NONE_VALID = 5'b00000;
localparam SR0_PRE_VALID = 5'b00001;
localparam SR0_VALID = 5'b00010;
localparam SR1_PRE_VALID = 5'b00100;
localparam SR1_VALID = 5'b01000;
localparam SR2_VALID = 5'b10000;
wire sprite_go = sr2_valid && sprites && tsr_rdy; // kick to renderer
wire spr_valid = s_visible && s_act;
wire sr0_pre_valid = sr_valid[0];
wire sr0_valid = sr_valid[1];
wire sr1_pre_valid = sr_valid[2];
wire sr1_valid = sr_valid[3];
wire sr2_valid = sr_valid[4];
reg [4:0] sr_valid;
always @(posedge clk)
if (start)
sr_valid <= SR0_PRE_VALID;
else if (sprites_last)
sr_valid <= NONE_VALID;
else if (sr0_pre_valid)
sr_valid <= SR0_VALID;
else if (sr0_valid && spr_valid)
sr_valid <= SR1_PRE_VALID;
else if (sr1_pre_valid)
sr_valid <= SR1_VALID;
else if (sr1_valid)
sr_valid <= SR2_VALID;
else if (sprite_go)
sr_valid <= SR0_PRE_VALID;
reg [7:0] sreg;
always @(posedge clk)
if (start)
sreg <= 8'd0;
else if (sr0_pre_valid)
sreg <= sreg + 8'd3;
else if (sr0_valid)
sreg <= spr_valid ? (sreg - 8'd2) : (sreg + 8'd3);
else if (sr1_pre_valid || sprite_go)
sreg <= sreg + 8'd1;
// SFile control
reg [5:0] s_bmline_offset_r;
reg s_leap_r;
always @(posedge clk) begin
if (sr0_valid)
begin
s_leap_r <= s_leap;
s_bmline_offset_r <= s_bmline_offset;
end
if (sr1_valid)
begin
sprites_x <= s_xcrd;
sprites_xs <= s_xsz;
sprites_xf <= s_xflp;
end
end
// sprite Y geometry
wire [8:0] s_line = line - s_ycrd; // visible line of sprite in current video line
wire s_visible = (s_line <= s_ymax); // check if sprite line is within Y size
wire [5:0] s_ymax = {s_ysz, 3'b111};
wire [8:0] sprites_line = {s_tnum[11:6], 3'b0} + s_bmline_offset_r;
wire [5:0] s_bmline_offset = s_yflp ? (s_ymax - s_line[5:0]) : s_line[5:0];
// SFile
wire [15:0] sfile_rdata;
dpram #(.DATAWIDTH(16), .ADDRWIDTH(8)) video_sfile
(
.clock (clk),
.address_a (sfile_addr_in),
.data_a (sfile_data_in),
.wren_a (sfile_we),
.address_b (sreg),
.q_b (sfile_rdata)
);
// 4 buffers * 2 tile-planes * 64 tiles * 16 bits (9x16) - used to prefetch tiles
// (2 altdprams)
wire [15:0] tmb_rdata;
dpram #(.DATAWIDTH(16), .ADDRWIDTH(9)) video_tmbuf
(
.clock (clk),
.address_a (tmb_waddr),
.data_a (dram_rdata),
.wren_a (tm_next),
.address_b (tmb_raddr),
.q_b (tmb_rdata)
);
endmodule

150
rtl/video/video_ts_render.v Normal file
View File

@ -0,0 +1,150 @@
// This module renders pixels into TS-line for tiles/sprites
// Task execution is initiated by 'tsr_go' (one 'clk' period strobe).
// Inputs (only valid by 'tsr_go'):
// - DRAM address of graphics data (including page, line, word)
// - number of cycles to render (one cycle is 2 words = 8 pixels; 8 cycles = 64 pixels max)
// - X coordinate
// - X flip bit
// - palette selector
// Address in TS-line is calculated from X coordinate respecting the X flip.
// Inc/dec direction is set automatically.
// At the 'c2' of last DRAM cycle 'mem_rdy' is asserted.
// It should be used in comb to generate next cycle 'tsr_go' strobe for continuous renderer operation.
// First 'tsr_go' may be issued at any DRAM cycle, but the operation starts only
// after TS request recognized and processed by DRAM controller.
// It is recommended to assert 'tsr_go' at 'c2'.
module video_ts_render
(
// clocks
input wire clk,
// controls
input wire reset, // line start strobe, inits the machine
input wire [ 8:0] x_coord, // address in TS-line where render to, auto-flipped to match 'flip' times 'x_size'
input wire [ 2:0] x_size, // number of rendering cycles (each cycle is 8 pixels, 0 = 1 cycle)
input wire flip, // indicates that sprite is X-flipped
input wire tsr_go, // 1 clk 28MHz strobe for render start. Should be issued along with 'mem_rdy' for continuous process
input wire [ 5:0] addr, // address of dword within the line (dword = 8 pix)
input wire [ 8:0] line, // line of bitmap
input wire [ 7:0] page, // 1st page of bitmap (TxGpage or SGpage)
input wire [ 3:0] pal, // palette selector, bits[7:4] of CRAM address
output wire mem_rdy, // ready to receive new task
// TS-Line interface
output reg [ 8:0] ts_waddr,
output wire [ 7:0] ts_wdata,
output wire ts_we,
// DRAM interface
output wire [20:0] dram_addr,
output wire dram_req,
input wire [15:0] dram_rdata,
input wire dram_pre_next,
input wire dram_next
);
// DRAM request
assign dram_req = tsr_go || !mem_rdy;
// DRAM addressing
assign dram_addr = tsr_go ? addr_in : addr_next;
wire [20:0] addr_in = {addr_offset, addr, 1'b0};
wire [13:0] addr_offset = {page[7:3], line};
wire [20:0] addr_next = {addr_reg[20:7], addr_reg[6:0] + dram_next};
// as renderer can't move outside the single bitmap line, only 7 bits are processed
reg [20:0] addr_reg;
always @(posedge clk) addr_reg <= dram_addr;
// DRAM cycles counter
assign mem_rdy = cyc[4];
reg [4:0] cyc;
always @(posedge clk)
if (reset)
cyc <= 5'b10000;
else if (tsr_go)
cyc <= {1'b0, x_size, 1'b1};
else if (dram_pre_next)
cyc <= cyc - 5'd1;
// DRAM data fetching
reg [15:0] data;
always @(posedge clk) if (dram_next) data <= dram_rdata;
// pixel render counter
assign ts_we = render_on && |pix; // write signal for TS-line
wire render_on = !cnt[2];
reg [2:0] cnt;
always @(posedge clk)
if (reset)
cnt <= 3'b100;
else if (dram_next)
cnt <= 3'b000;
else if (render_on)
cnt <= cnt + 3'd1;
// renderer reload
reg tsr_rld;
always @(posedge clk)
if (reset)
tsr_rld <= 1'b0;
else if (tsr_go)
tsr_rld <= 1'b1;
else if (dram_next)
tsr_rld <= 1'b0;
// delayed values
reg [8:0] x_coord_d;
reg [3:0] pal_d;
reg flip_d;
always @(posedge clk)
if (tsr_go)
begin
x_coord_d <= x_coord + (flip ? {x_size, 3'b111} : 6'd0);
pal_d <= pal;
flip_d <= flip;
end
// TS-line address
wire [8:0] ts_waddr_mx = tsr_rld_stb ? x_coord_d : (render_on ? x_next : ts_waddr);
wire [8:0] x_next = ts_waddr + {{8{flip_r}}, 1'b1};
wire tsr_rld_stb = tsr_rld && dram_next;
always @(posedge clk) ts_waddr <= ts_waddr_mx;
reg [3:0] pal_r;
reg flip_r;
always @(posedge clk)
if (tsr_rld_stb)
begin
pal_r <= pal_d;
flip_r <= flip_d;
end
// renderer mux
assign ts_wdata = {pal_r, pix};
wire [3:0] pix = pix_m[cnt[1:0]];
wire [3:0] pix_m[0:3];
assign pix_m[0] = data[7:4];
assign pix_m[1] = data[3:0];
assign pix_m[2] = data[15:12];
assign pix_m[3] = data[11:8];
endmodule