Updates due to WD1793 development
This commit is contained in:
0
CPLD/SW700/v1.3/MZ700/build/emuMZ_ClockII.qip
Normal file
0
CPLD/SW700/v1.3/MZ700/build/emuMZ_ClockII.qip
Normal file
0
CPLD/SW700/v1.3/MZ80A/build/emuMZ_Clock.qip
Normal file
0
CPLD/SW700/v1.3/MZ80A/build/emuMZ_Clock.qip
Normal file
@@ -638,8 +638,6 @@ architecture rtl of VideoController is
|
||||
signal FB_PALETTE_B : std_logic_vector(4 downto 0); -- Current palette map value for given video state input.
|
||||
signal CONFIG_LAST : std_logic_vector(CONFIG_WIDTH); -- Configuration string change detection, used by the Sharp MZ Series Emulator to configure video settings rather than register writes.
|
||||
|
||||
|
||||
|
||||
signal VIDEO_ADDRi : std_logic_vector(23 downto 0); -- CPU Address bus. Upper byte is for direct addressing (ie /= 0) and used by external systems or a soft CPU.
|
||||
signal VIDEO_DATA_INi : std_logic_vector(31 downto 0); -- Data bus into video module.
|
||||
signal VIDEO_DATA_OUTi : std_logic_vector(31 downto 0); -- Data bus out from video module to CPU.
|
||||
@@ -3646,8 +3644,8 @@ begin
|
||||
-- 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter
|
||||
--
|
||||
-- IO Range for Graphics enhancements is set by the Video Mode registers at 0xB0->.
|
||||
-- 0xB8=<val> sets the mode of the Video Module. Bits [3:0] define the Video Module machine compatibility. 0000 = MZ80K, 0001 = MZ80C, 0010 = MZ1200, 0011 = MZ80A, 0100 = MZ-700, 0101 = MZ-1500, 0110 = MZ-800, 0111 = MZ-80B, 1000 = MZ-2000, 1001 = MZ-2200, 1010 = MZ-2500. [4] = 0 - 40 col, 1 - 80 col, [5] = 0 - mono, 1 - colour.
|
||||
-- [4] defines the colour mode, 0 = mono, 1 = colour - ignored on certain modes. [5] defines wether PCGRAM is enabled, 0 = disabled, 1 = enabled. [7:6] define the VGA mode.
|
||||
-- 0xB8=<val> sets the mode of the Video Module. Bits [3:0] define the Video Module machine compatibility. 0000 = MZ80K, 0001 = MZ80C, 0010 = MZ1200, 0011 = MZ80A, 0100 = MZ-700, 0101 = MZ-1500, 0110 = MZ-800, 0111 = MZ-80B, 1000 = MZ-2000, 1001 = MZ-2200, 1010 = MZ-2500.
|
||||
-- [4] = 0 - 40 col, 1 - 80 col, [5] = 0 - mono, 1 - colour. [5] defines the colour mode, 0 = mono, 1 = colour - ignored on certain modes. [6] defines wether PCGRAM is enabled, 0 = disabled, 1 = enabled.
|
||||
-- 0xB9=<val> sets the graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used).
|
||||
-- 0xBA=<val> sets the Red bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
-- 0xBB=<val> sets the Green bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
@@ -3715,16 +3713,17 @@ begin
|
||||
CGRAM_WEn <= '1';
|
||||
GPU_PARAMS <= (others => '0');
|
||||
GPU_COMMAND <= (others => '0');
|
||||
CONFIG_LAST <= CONFIG;
|
||||
CONFIG_LAST <= CONFIG; --(others => '0');
|
||||
|
||||
else
|
||||
|
||||
-- Change detection, whenever the config value changes, use its values to update the register settings.
|
||||
-- Only used in the Sharp MZ Series Emulator.
|
||||
CONFIG_LAST <= CONFIG;
|
||||
-- if CONFIG /= CONFIG_LAST
|
||||
-- CONFIG_LAST <= CONFIG;
|
||||
|
||||
-- Clear the data available flag on each cycle. If in an active read state the signal will mirror the RD/CS combination.
|
||||
VIDEO_DATA_AVAILn <= '1';
|
||||
VIDEO_DATA_AVAILn <= '1';
|
||||
|
||||
-- If the GPU goes busy, clear the command register ready for next command.
|
||||
--
|
||||
@@ -4294,81 +4293,91 @@ begin
|
||||
-- Sharp MZ Series Emulation configuration. When using the emulation an external I/O processor changes the settings via a configuration string and not via
|
||||
-- register writes. This block detects changes and updates internal settings.
|
||||
--
|
||||
-- When not using the emulation this vector wont change and therefore no updates will be made.
|
||||
if CONFIG(VGAMODE) /= CONFIG_LAST(VGAMODE) then
|
||||
VGA_MODE_REG(CONFIG(VGAMODE)'length-1 downto 0) <= CONFIG(VGAMODE);
|
||||
end if;
|
||||
-- Machine mode change?
|
||||
if CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
--
|
||||
-- Setup the machine type based on the CONFIG string.
|
||||
--
|
||||
if CONFIG(MZ80K) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0000";
|
||||
elsif CONFIG(MZ80C) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0001";
|
||||
elsif CONFIG(MZ1200) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0010";
|
||||
elsif CONFIG(MZ80A) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0011";
|
||||
elsif CONFIG(MZ700) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0100";
|
||||
elsif CONFIG(MZ800) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0101";
|
||||
elsif CONFIG(MZ1500) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0110";
|
||||
elsif CONFIG(MZ80B) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0111";
|
||||
elsif CONFIG(MZ2000) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "1000";
|
||||
elsif CONFIG(MZ2200) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "1001";
|
||||
elsif CONFIG(MZ2500) = '1' then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "1010";
|
||||
else
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0100";
|
||||
-- if CONFIG(CHANGED) = '1' then
|
||||
--NEED TO TAKE INTO ACCOUNT THE RENDERING, ONLY CHANGE DURING VERTICAL BLANKING
|
||||
-- When not using the emulation this vector wont change and therefore no updates will be made.
|
||||
-- if CONFIG(VGAMODE) /= CONFIG_LAST(VGAMODE) then
|
||||
-- VGA_MODE_REG(CONFIG(VGAMODE)'length-1 downto 0) <= CONFIG(VGAMODE);
|
||||
-- end if;
|
||||
-- Machine mode change?
|
||||
if CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
--
|
||||
-- Setup the machine type based on the CONFIG string.
|
||||
--
|
||||
if CONFIG(MZ80K) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0000" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0000";
|
||||
elsif CONFIG(MZ80C) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0001" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0001";
|
||||
elsif CONFIG(MZ1200) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0010" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0010";
|
||||
elsif CONFIG(MZ80A) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0011" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0011";
|
||||
elsif CONFIG(MZ700) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0100" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0100";
|
||||
elsif CONFIG(MZ800) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0101" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0101";
|
||||
elsif CONFIG(MZ1500) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0110" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0110";
|
||||
elsif CONFIG(MZ80B) = '1' and VIDEO_MODE_REG(3 downto 0) /= "0111" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "0111";
|
||||
elsif CONFIG(MZ2000) = '1' and VIDEO_MODE_REG(3 downto 0) /= "1000" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "1000";
|
||||
elsif CONFIG(MZ2200) = '1' and VIDEO_MODE_REG(3 downto 0) /= "1001" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "1001";
|
||||
elsif CONFIG(MZ2500) = '1' and VIDEO_MODE_REG(3 downto 0)<= "1010" then
|
||||
VIDEO_MODE_REG(3 downto 0)<= "1010";
|
||||
end if;
|
||||
CONFIG_LAST(CURRENTMACHINE) <= CONFIG(CURRENTMACHINE);
|
||||
end if;
|
||||
end if;
|
||||
-- Display mode change?
|
||||
if CONFIG(CURRENTDISPLAY) /= CONFIG_LAST(CURRENTDISPLAY) then
|
||||
if CONFIG(NORMAL80) = '1' or CONFIG(COLOUR80)= '1' then
|
||||
VIDEO_MODE_REG(4) <= '1';
|
||||
else
|
||||
VIDEO_MODE_REG(4) <= '0';
|
||||
-- Display mode change?
|
||||
if CONFIG(CURRENTDISPLAY) /= CONFIG_LAST(CURRENTDISPLAY) then
|
||||
if (CONFIG(NORMAL80) = '1' or CONFIG(COLOUR80)= '1') and VIDEO_MODE_REG(4) /= '1' then
|
||||
VIDEO_MODE_REG(4) <= '1';
|
||||
else
|
||||
VIDEO_MODE_REG(4) <= '0';
|
||||
end if;
|
||||
if (CONFIG(COLOUR) = '1' or CONFIG(COLOUR80)= '1') and VIDEO_MODE_REG(5) /= '1' then
|
||||
VIDEO_MODE_REG(5) <= '1';
|
||||
else
|
||||
VIDEO_MODE_REG(5) <= '0';
|
||||
end if;
|
||||
CONFIG_LAST(CURRENTDISPLAY) <= CONFIG(CURRENTDISPLAY);
|
||||
end if;
|
||||
if CONFIG(COLOUR) = '1' or CONFIG(COLOUR80)= '1' then
|
||||
VIDEO_MODE_REG(5) <= '1';
|
||||
else
|
||||
VIDEO_MODE_REG(5) <= '0';
|
||||
-- Option changes?
|
||||
if CONFIG(VRAMDISABLE) /= CONFIG_LAST(VRAMDISABLE) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(4) <= CONFIG(VRAMDISABLE);
|
||||
CONFIG_LAST(VRAMDISABLE) <= CONFIG(VRAMDISABLE);
|
||||
end if;
|
||||
end if;
|
||||
-- Option changes?
|
||||
if CONFIG(VRAMDISABLE) /= CONFIG_LAST(VRAMDISABLE) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(4) <= CONFIG(VRAMDISABLE);
|
||||
end if;
|
||||
if CONFIG(GRAMDISABLE) /= CONFIG_LAST(VRAMDISABLE) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(5) <= CONFIG(GRAMDISABLE);
|
||||
end if;
|
||||
if CONFIG(VRAMWAIT) /= CONFIG_LAST(VRAMWAIT) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(6) <= CONFIG(VRAMWAIT);
|
||||
end if;
|
||||
if CONFIG(PCGRAM) /= CONFIG_LAST(PCGRAM) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(7) <= CONFIG(PCGRAM);
|
||||
end if;
|
||||
-- GRAM installed change?
|
||||
if CONFIG(GRAPHICSOPTION) /= CONFIG_LAST(GRAPHICSOPTION) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
OPTION_REG(0) <= CONFIG(GRAPHICSOPTION)(OPT_GRAMI);
|
||||
OPTION_REG(1) <= CONFIG(GRAPHICSOPTION)(OPT_GRAMII);
|
||||
OPTION_REG(2) <= CONFIG(GRAPHICSOPTION)(OPT_GRAMIII);
|
||||
OPTION_REG(3) <= CONFIG(GRAPHICSOPTION)(OPT_PCG);
|
||||
end if;
|
||||
-- OSD Menu/Status change?
|
||||
if CONFIG(MENUENABLE) /= CONFIG_LAST(MENUENABLE) then
|
||||
VGA_ATTR_REG(6) <= CONFIG(MENUENABLE);
|
||||
end if;
|
||||
if CONFIG(STATUSENABLE) /= CONFIG_LAST(STATUSENABLE) then
|
||||
VGA_ATTR_REG(7) <= CONFIG(STATUSENABLE);
|
||||
end if;
|
||||
if CONFIG(GRAMDISABLE) /= CONFIG_LAST(VRAMDISABLE) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(5) <= CONFIG(GRAMDISABLE);
|
||||
CONFIG_LAST(GRAMDISABLE) <= CONFIG(GRAMDISABLE);
|
||||
end if;
|
||||
if CONFIG(VRAMWAIT) /= CONFIG_LAST(VRAMWAIT) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(6) <= CONFIG(VRAMWAIT);
|
||||
CONFIG_LAST(VRAMWAIT) <= CONFIG(VRAMWAIT);
|
||||
end if;
|
||||
if CONFIG(PCGRAM) /= CONFIG_LAST(PCGRAM) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
GRAM_MODE_REG(7) <= CONFIG(PCGRAM);
|
||||
CONFIG_LAST(PCGRAM) <= CONFIG(PCGRAM);
|
||||
end if;
|
||||
-- GRAM installed change?
|
||||
if CONFIG(GRAPHICSOPTION) /= CONFIG_LAST(GRAPHICSOPTION) or CONFIG(CURRENTMACHINE) /= CONFIG_LAST(CURRENTMACHINE) then
|
||||
OPTION_REG(0) <= CONFIG(GRAPHICSOPTION)(OPT_GRAMI);
|
||||
OPTION_REG(1) <= CONFIG(GRAPHICSOPTION)(OPT_GRAMII);
|
||||
OPTION_REG(2) <= CONFIG(GRAPHICSOPTION)(OPT_GRAMIII);
|
||||
OPTION_REG(3) <= CONFIG(GRAPHICSOPTION)(OPT_PCG);
|
||||
CONFIG_LAST(GRAPHICSOPTION) <= CONFIG(GRAPHICSOPTION);
|
||||
end if;
|
||||
-- OSD Menu/Status change?
|
||||
if CONFIG(MENUENABLE) /= CONFIG_LAST(MENUENABLE) then
|
||||
VGA_ATTR_REG(6) <= CONFIG(MENUENABLE);
|
||||
CONFIG_LAST(MENUENABLE) <= CONFIG(MENUENABLE);
|
||||
end if;
|
||||
if CONFIG(STATUSENABLE) /= CONFIG_LAST(STATUSENABLE) then
|
||||
VGA_ATTR_REG(7) <= CONFIG(STATUSENABLE);
|
||||
CONFIG_LAST(STATUSENABLE) <= CONFIG(STATUSENABLE);
|
||||
end if;
|
||||
-- end if;
|
||||
|
||||
-- Update the video mode according to the stored register value.
|
||||
--
|
||||
|
||||
@@ -111,6 +111,7 @@ architecture rtl of coreMZ is
|
||||
signal CPUCLK_75MHZ : std_logic;
|
||||
signal PLL_LOCKED : std_logic;
|
||||
signal RESETn : std_logic := '0';
|
||||
signal VRESETn : std_logic := '0';
|
||||
signal EMURESETn : std_logic := '0';
|
||||
signal RESET_COUNTER : unsigned(3 downto 0) := (others => '1');
|
||||
signal CTRLREG_RESET : std_logic := '1'; -- Flag to indicate when a hard reset occurs so that registers can be preloaded based on conditions.
|
||||
@@ -129,6 +130,8 @@ architecture rtl of coreMZ is
|
||||
signal CS_CPLD_CFGn : std_logic; -- Chip Select to write to the CPLD configuration register at 0x6E.
|
||||
signal VZ80_BUSACKni : std_logic; -- Internal combination of BUSACK signals.
|
||||
signal COLOUR_CARRIER_FREQ : std_logic; -- Modulator colour carrier frequency output by video module.
|
||||
signal COMPOSITE_SYNCn : std_logic; -- Composite sync (negative) for use with the composite video out.
|
||||
signal COMPOSITE_SYNC : std_logic; -- Composite sync (positive) for use with the composite video out.
|
||||
signal HBLANK_OUTi : std_logic; -- Horizontal video blanking.
|
||||
signal VBLANK_OUTi : std_logic; -- Vertical video blanking.
|
||||
|
||||
@@ -206,6 +209,7 @@ architecture rtl of coreMZ is
|
||||
signal MZ_KEYB_ADDR : std_logic_vector(15 downto 0);
|
||||
signal MZ_KEYB_DOUT : std_logic_vector(7 downto 0);
|
||||
signal MZ_KEYB_DIN : std_logic_vector(7 downto 0);
|
||||
signal MZ_KEYB_INITn : std_logic;
|
||||
--
|
||||
-- Master Control signals and configuration.
|
||||
--
|
||||
@@ -238,12 +242,14 @@ architecture rtl of coreMZ is
|
||||
signal MZ_INTR_ADDR : std_logic_vector(15 downto 0);
|
||||
signal MZ_INTR_DOUT : std_logic_vector(7 downto 0);
|
||||
signal MZ_INTR_DIN : std_logic_vector(7 downto 0);
|
||||
signal MZ_INTR_INITn : std_logic;
|
||||
|
||||
-- I/O Processor signals.
|
||||
signal IOP_MCTRL_CSn : std_logic;
|
||||
signal IOP_MZ80K_CSn : std_logic;
|
||||
signal IOP_MZ80B_CSn : std_logic;
|
||||
signal IOP_KEYB_CSn : std_logic;
|
||||
signal IOP_FDD_CSn : std_logic;
|
||||
signal IOP_CMT0_CSn : std_logic;
|
||||
signal IOP_CMT1_CSn : std_logic;
|
||||
signal IOP_INTR_CSn : std_logic;
|
||||
@@ -252,11 +258,19 @@ architecture rtl of coreMZ is
|
||||
signal IOP_MZ80K_DOUT : std_logic_vector(7 downto 0);
|
||||
signal IOP_MZ80B_DOUT : std_logic_vector(7 downto 0);
|
||||
signal IOP_KEYB_DOUT : std_logic_vector(7 downto 0);
|
||||
signal IOP_FDD_DOUT : std_logic_vector(7 downto 0);
|
||||
signal IOP_CMT0_DOUT : std_logic_vector(7 downto 0);
|
||||
signal IOP_CMT1_DOUT : std_logic_vector(7 downto 0);
|
||||
signal IOP_INTR_DOUT : std_logic_vector(7 downto 0);
|
||||
signal IOP_SND_DOUT : std_logic_vector(7 downto 0);
|
||||
--
|
||||
-- FDD
|
||||
--
|
||||
signal T80_FDD_INTn : std_logic;
|
||||
signal MZ_FDD_INTRn : std_logic;
|
||||
signal MZ_FDD_CSn : std_logic;
|
||||
signal MZ_FDD_DI : std_logic_vector(7 downto 0);
|
||||
--
|
||||
-- CMT
|
||||
--
|
||||
signal CMT_BUS_OUT : std_logic_vector(CMT_BUS_OUT_WIDTH);
|
||||
@@ -270,6 +284,7 @@ architecture rtl of coreMZ is
|
||||
signal MZ_CMT_ADDR : std_logic_vector(15 downto 0);
|
||||
signal MZ_CMT_DOUT : std_logic_vector(7 downto 0);
|
||||
signal MZ_CMT_DIN : std_logic_vector(7 downto 0);
|
||||
signal MZ_CMT_INITn : std_logic;
|
||||
signal MZ_CMT_INTRn : std_logic;
|
||||
--
|
||||
-- Sound
|
||||
@@ -281,6 +296,7 @@ architecture rtl of coreMZ is
|
||||
signal MZ_SND_M1n : std_logic;
|
||||
signal MZ_SND_ADDR : std_logic_vector(15 downto 0);
|
||||
signal MZ_SND_DOUT : std_logic_vector(7 downto 0);
|
||||
signal MZ_SND_INITn : std_logic;
|
||||
signal MZ_SOUND_LEFT : std_logic;
|
||||
signal MZ_SOUND_RIGHT : std_logic;
|
||||
|
||||
@@ -310,6 +326,7 @@ architecture rtl of coreMZ is
|
||||
signal MZ80K_CS_ROMn : std_logic;
|
||||
signal MZ80K_CS_RAMn : std_logic;
|
||||
signal MZ80K_CS_VRAMn : std_logic;
|
||||
signal MZ80K_CS_FDDn : std_logic;
|
||||
signal MZ80K_CS_MEM_Gn : std_logic;
|
||||
signal MZ80K_CS_IO_Gn : std_logic;
|
||||
signal MZ80K_CS_GRAMn : std_logic;
|
||||
@@ -339,6 +356,7 @@ architecture rtl of coreMZ is
|
||||
signal MZ80B_CS_ROMn : std_logic;
|
||||
signal MZ80B_CS_RAMn : std_logic;
|
||||
signal MZ80B_CS_VRAMn : std_logic;
|
||||
signal MZ80B_CS_FDDn : std_logic;
|
||||
signal MZ80B_CS_IO_CTRLn : std_logic;
|
||||
-- signal MZ80B_CS_IO_GFBn : std_logic;
|
||||
signal MZ80B_CS_IO_Gn : std_logic;
|
||||
@@ -454,24 +472,37 @@ begin
|
||||
-- and a counter to set minimum width.
|
||||
--
|
||||
FPGARESET: process(CLOCK_50, PLL_LOCKED, MCTRL_RESETn)
|
||||
variable HOST_RESET_LAST : std_logic_vector(1 downto 0);
|
||||
begin
|
||||
if PLL_LOCKED = '0' then
|
||||
RESET_COUNTER <= (others => '1');
|
||||
RESETn <= '0';
|
||||
VRESETn <= '0';
|
||||
EMURESETn <= '0';
|
||||
|
||||
elsif PLL_LOCKED = '1' then
|
||||
if rising_edge(CLOCK_50) then
|
||||
if RESET_COUNTER /= 0 then
|
||||
RESET_COUNTER <= RESET_COUNTER - 1;
|
||||
--elsif HOST_RESET_LAST = "00" and (VIDEO_WRn = '1' or VIDEO_RDn = '1') then
|
||||
elsif VIDEO_WRn = '0' and VIDEO_RDn = '0' then
|
||||
RESETn <= '0';
|
||||
VRESETn <= '0';
|
||||
EMURESETn <= '0';
|
||||
-- RESET_COUNTER <= (others => '1');
|
||||
elsif MCTRL_RESETn = '0' then
|
||||
EMURESETn <= '0';
|
||||
-- VRESETn <= '0';
|
||||
-- RESETn <= '0';
|
||||
-- RESET_COUNTER <= (others => '1');
|
||||
elsif (VIDEO_WRn = '1' or VIDEO_RDn = '1') and MCTRL_RESETn = '1' and RESET_COUNTER = 0 then
|
||||
-- elsif MCTRL_RESETn = '1' and RESET_COUNTER = 0 then
|
||||
RESETn <= '1';
|
||||
VRESETn <= '1';
|
||||
EMURESETn <= '1';
|
||||
end if;
|
||||
|
||||
HOST_RESET_LAST := VIDEO_WRn & VIDEO_RDn;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
@@ -541,7 +572,9 @@ begin
|
||||
else
|
||||
MZ80K_WAITn when CONFIG(MZ_K) = '1'
|
||||
else MZ80B_WAITn;
|
||||
T80_INTn <= MZ80K_INTn when CONFIG(MZ_K) = '1'
|
||||
T80_INTn <= '0' when T80_FDD_INTn = '0' and CONFIG(FDDINTEN) = '1'
|
||||
else
|
||||
MZ80K_INTn when CONFIG(MZ_K) = '1'
|
||||
else
|
||||
MZ80B_INTn;
|
||||
T80_NMIn <= MZ80K_NMIn when CONFIG(MZ_K) = '1'
|
||||
@@ -552,15 +585,17 @@ begin
|
||||
else
|
||||
CPU_INFO_DATA when CS_CPU_INFOn = '0' -- Read CPU version & hw build information.
|
||||
else
|
||||
SYSRAM_DO when SYSRAM_SELECT ='1' -- Read from System RAM
|
||||
SYSRAM_DO when SYSRAM_SELECT = '1' -- Read from System RAM
|
||||
else
|
||||
SYSROM_DO when SYSROM_SELECT ='1' -- Read from System ROM
|
||||
SYSROM_DO when SYSROM_SELECT = '1' -- Read from System ROM
|
||||
else
|
||||
CORE_DATA_OUT(7 downto 0) when CORE_DATA_AVAILn = '0' --CORE_VIDEO_RDn = '0'
|
||||
else
|
||||
MZ80B_DI when CONFIG(MZ_B) = '1' and MZ80B_DATA_AVAILn = '0'
|
||||
MZ_FDD_DI when MZ_FDD_CSn = '0'
|
||||
else
|
||||
MZ80K_DI when CONFIG(MZ_K) = '1' and MZ80K_DATA_AVAILn = '0'
|
||||
MZ80B_DI when (T80_M1n = '0' and T80_IORQn = '0') or (CONFIG(MZ_B) = '1' and MZ80B_DATA_AVAILn = '0')
|
||||
else
|
||||
MZ80K_DI when (T80_M1n = '0' and T80_IORQn = '0') or (CONFIG(MZ_K) = '1' and MZ80K_DATA_AVAILn = '0')
|
||||
else (others => '1');
|
||||
|
||||
-- Busack is granted during RESET, through the BUSRQ mechanism or during the period the clock has been disabled. This is necessary
|
||||
@@ -595,7 +630,7 @@ begin
|
||||
else
|
||||
'1' when CORE_ADDR(23 downto 17) = "0001001" and VZ80_BUSACKni = '0'
|
||||
else '0';
|
||||
SYSRAM_WEN <= '1' when SYSRAM_SELECT = '1' and CORE_WRn = '0'
|
||||
SYSRAM_WEN <= '1' when SYSRAM_SELECT = '1' and CORE_WRn = '0'
|
||||
else '0';
|
||||
|
||||
RAMBANK <= (not CORE_ADDR(15))&CORE_ADDR(14 downto 12) when CONFIG(MZ_B) = '1' and MZ80B_CS_SWP_MEMn = '0' and VZ80_BUSACKni = '1'
|
||||
@@ -653,7 +688,7 @@ begin
|
||||
CLOCK_50 => CLOCK_50, -- 50MHz main FPGA clock.
|
||||
|
||||
-- Reset.
|
||||
VRESETn => RESETn, -- Internal reset.
|
||||
VRESETn => VRESETn, -- Internal reset.
|
||||
|
||||
-- V[name] = Voltage translated signals which mirror the mainboard signals but at a lower voltage.
|
||||
-- Address Bus
|
||||
@@ -684,8 +719,8 @@ begin
|
||||
HBLANK_OUT => HBLANK_OUTi, -- Horizontal blanking.
|
||||
VBLANK_OUT => VBLANK_OUTi, -- Vertical blanking.
|
||||
COLR_OUT => COLOUR_CARRIER_FREQ, -- Composite colour and RF base frequency.
|
||||
CSYNC_OUTn => CSYNC_OUTn, -- Composite sync (negative).
|
||||
CSYNC_OUT => CSYNC_OUT, -- Composite sync (positive).
|
||||
CSYNC_OUTn => COMPOSITE_SYNCn, -- Composite sync (negative).
|
||||
CSYNC_OUT => COMPOSITE_SYNC, -- Composite sync (positive).
|
||||
|
||||
-- RGB & Composite input signals.
|
||||
VWAITn_V_CSYNC => VWAITn_A21_V_CSYNC, -- Wait signal to the CPU when accessing FPGA video RAM / Composite sync from mainboard.
|
||||
@@ -751,6 +786,18 @@ begin
|
||||
------------------------------------------------------------------------------------
|
||||
-- MZ-80K Group Machine Dependent Hardware
|
||||
-- IOP Address: 0x310000:0x31FFFF
|
||||
-- 0x310000:0x310003 - 8255
|
||||
-- 0x310004:0x310007 - 8254
|
||||
-- 0x310008:0x31000B - LS367
|
||||
-- 0x31000C:0x31000F - JOYSTK
|
||||
-- 0x310010:0x310013 - PIO
|
||||
-- 0x310014:0x310017 - PSG0
|
||||
-- 0x310018:0x31001B - PSG1
|
||||
-- 0x31001C:0x31001F - GCRTC
|
||||
-- 0x310020:0x310023 - GDMD
|
||||
-- 0x310024:0x310027 - GRF
|
||||
-- 0x310028:0x31002B - GWF
|
||||
-- 0x31002C:0x31002F - GPALLET
|
||||
------------------------------------------------------------------------------------
|
||||
MZ80KHW : entity work.mz80k_hw
|
||||
port map (
|
||||
@@ -780,6 +827,7 @@ begin
|
||||
CS_RAMn => MZ80K_CS_RAMn,
|
||||
CS_VRAMn => MZ80K_CS_VRAMn, -- VRAM Select
|
||||
CS_MEM_Gn => MZ80K_CS_MEM_Gn, -- Memory mapped Peripherals Select
|
||||
CS_FDDn => MZ80K_CS_FDDn, -- Floppy Disk Controller select.
|
||||
CS_IO_Gn => MZ80K_CS_IO_Gn, -- Graphics Options IO Select range
|
||||
CS_GRAMn => MZ80K_CS_GRAMn, -- Colour GRAM Select
|
||||
-- CS_IO_GFBn => MZ80K_CS_IO_GFBn, -- Graphics FB IO Select range
|
||||
@@ -810,7 +858,7 @@ begin
|
||||
IOP_CSn => IOP_MZ80K_CSn, -- Chip select from the I/O Processor decoding.
|
||||
IOP_WRn => VZ80_WRni, -- Write Enable.
|
||||
IOP_RDn => VZ80_RDni, -- Read Enable.
|
||||
IOP_ADDR => VZ80_ADDRi(3 downto 0), -- Address bus.
|
||||
IOP_ADDR => VZ80_ADDRi(5 downto 0), -- Address bus.
|
||||
IOP_DOUT => VZ80_DATAi, -- Data into the MZ80K unit.
|
||||
IOP_DIN => IOP_MZ80K_DOUT -- Data out from the MZ80K unit.
|
||||
);
|
||||
@@ -851,6 +899,7 @@ begin
|
||||
CS_RAMn => MZ80B_CS_RAMn,
|
||||
CS_VRAMn => MZ80B_CS_VRAMn, -- VRAM Select
|
||||
CS_GRAMn => MZ80B_CS_GRAMn, -- MZ80B GRAM Select
|
||||
CS_FDDn => MZ80B_CS_FDDn, -- Floppy Disk Controller select.
|
||||
-- CS_IO_GFBn => MZ80B_CS_IO_GFBn, -- Graphics FB IO Select range
|
||||
CS_IO_Gn => MZ80B_CS_IO_Gn, -- Graphics Options IO Select range
|
||||
CS_IO_CTRLn => MZ80B_CS_IO_CTRLn, -- PPI/PIO video control registers.
|
||||
@@ -892,6 +941,65 @@ begin
|
||||
else '1';
|
||||
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
-- FDD Controller
|
||||
-- IOP Address: 0x330000:0x33FFFF
|
||||
-- 0x330000 : 0x800 = WD1793 Sector Cache.
|
||||
-- 0x330800 : 0x1 = WD1793 COMMAND/STATUS Register
|
||||
-- 0x330801 : 0x1 = WD1793 TRACK Register
|
||||
-- 0x330802 : 0x1 = WD1793 SECTOR Register
|
||||
-- 0x330803 : 0x1 = WD1793 DATA Register
|
||||
-- 0x330804 : 0x1 = WD1793 Sector Cache current byte.
|
||||
-- 0x330808 : 0x6 = WD1793 Read Address status stack
|
||||
-- 0x331000 : 0x1 = Control/Status Register
|
||||
-- 0x331001 : 0x1 = WD1793 active sector.
|
||||
-- 0x331002 : 0x1 = WD1793 active track.
|
||||
-- 0x331003 : 0x1 = FDC Signal state and status.
|
||||
------------------------------------------------------------------------------------
|
||||
FDD : entity work.fdd
|
||||
port map (
|
||||
RSTn => EMURESETn,
|
||||
|
||||
-- Clock signals needed by this module.
|
||||
CLKBUS => CLKBUS,
|
||||
|
||||
-- Different operations modes.
|
||||
CONFIG => CONFIG,
|
||||
|
||||
-- Z80 CPU Interface.
|
||||
Z80_DI => MZ_FDD_DI,
|
||||
Z80_DO => T80_DATA_OUT,
|
||||
Z80_ADDR => T80_ADDR,
|
||||
Z80_RDn => T80_RDn,
|
||||
Z80_WRn => T80_WRn,
|
||||
Z80_INTn => T80_FDD_INTn,
|
||||
|
||||
-- Module activation signal (allows for different memory address mapping in the controlling module).
|
||||
-- The signal should include IORQn/MREQn.
|
||||
FDD_CSn => MZ_FDD_CSn,
|
||||
|
||||
-- IOP interrupt. This is raised whenever the WD1793 requires servicing, ie. the IOP_SECTOR_REQ line goes active.
|
||||
IOP_INTn => MZ_FDD_INTRn,
|
||||
|
||||
-- I/O Processor Interface
|
||||
IOP_CSn => IOP_FDD_CSn, -- Chip select from the I/O Processor decoding.
|
||||
IOP_WRn => VZ80_WRn, -- Write Enable.
|
||||
IOP_RDn => VZ80_RDn, -- Read Enable.
|
||||
IOP_ADDR => VZ80_ADDR(12 downto 0), -- Address bus.
|
||||
IOP_DOUT => VZ80_DATAi, -- Data into the mctrl unit.
|
||||
IOP_DIN => IOP_FDD_DOUT -- Data out from the mctrl unit.
|
||||
);
|
||||
|
||||
-- Select address for external access to the Hardware FDD logic.
|
||||
IOP_FDD_CSn <= '0' when (CORE_ADDR >= std_logic_vector(to_unsigned(16#330000#, CORE_ADDR'LENGTH)) and CORE_ADDR < std_logic_vector(to_unsigned(16#340000#, CORE_ADDR'LENGTH))) and CORE_MREQn = '0' and VZ80_BUSACKni = '0'
|
||||
else '1';
|
||||
|
||||
-- Floppy disk drive access by the T80/active host.
|
||||
MZ_FDD_CSn <= '0' when CONFIG(MZ_K) = '1' and CONFIG(FDDENABLE) = '1' and MZ80K_CS_FDDn = '0' and VZ80_BUSACKni = '1' -- MZ-80K Group Machines, 80K,80C,1200,80A,700
|
||||
else
|
||||
'0' when CONFIG(MZ_B) = '1' and CONFIG(FDDENABLE) = '1' and MZ80B_CS_FDDn = '0' and VZ80_BUSACKni = '1' -- MZ-80B Group Machines, 80B,2000,2200,2500
|
||||
else '1';
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
-- CMT Controller
|
||||
-- IOP Address: 0x340000:0x36FFFF
|
||||
@@ -966,6 +1074,7 @@ begin
|
||||
CMT_DOUT => MZ_CMT_DOUT,
|
||||
CMT_DIN => MZ_CMT_DIN,
|
||||
CMT_INIT_HW => '0', -- FSM to initialise underlying hardware?
|
||||
CMT_INIT_DONEn => MZ_CMT_INITn, -- Underlying hardware initialised.
|
||||
|
||||
-- Arbiter control signals
|
||||
CMT_GRANTn => MZ_CMT_GRANTn,
|
||||
@@ -1019,6 +1128,7 @@ begin
|
||||
KEYB_DOUT => MZ_KEYB_DOUT,
|
||||
KEYB_DIN => MZ_KEYB_DIN,
|
||||
KEYB_INIT_HW => '1', -- FSM to initialise underlying hardware?
|
||||
KEYB_INIT_DONEn => MZ_KEYB_INITn, -- Underlying hardware initialised.
|
||||
KEYB_INTRn => MZ_KEYB_INTRn, -- Keyboard generating an external I/O processor interrupt.
|
||||
|
||||
-- Arbiter control signals
|
||||
@@ -1047,7 +1157,12 @@ begin
|
||||
else (others => '1');
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
-- Sound generator (8253/bit toggle).
|
||||
-- Sound module.
|
||||
-- In host mode creates sound by accessing the underlying hardware (ie 8253/bit
|
||||
-- toggle) and generates sound from the host speaker.
|
||||
-- In FPGA mode, provide a full stereo DAC with sound mixing and volume control
|
||||
-- outputting the stereo audio from the FPGA.
|
||||
--
|
||||
-- IOP Address: 0x300200:0x3002FF
|
||||
------------------------------------------------------------------------------------
|
||||
SND : entity work.snd
|
||||
@@ -1066,7 +1181,7 @@ begin
|
||||
Z80_WRn => T80_WRn,
|
||||
CS_SNDn => MZ80K_CS_8253n,
|
||||
|
||||
-- Physical bus connection to underlying MZ-700 hardware.
|
||||
-- Physical bus connection to underlying host hardware.
|
||||
SND_RDn => MZ_SND_RDn,
|
||||
SND_WRn => MZ_SND_WRn,
|
||||
SND_MREQn => MZ_SND_MREQn,
|
||||
@@ -1075,6 +1190,8 @@ begin
|
||||
SND_ADDR => MZ_SND_ADDR,
|
||||
SND_DOUT => MZ_SND_DOUT,
|
||||
SND_DIN => (others => '0'),
|
||||
SND_INIT_HW => '0', -- FSM to initialise underlying hardware?
|
||||
SND_INIT_DONEn => MZ_SND_INITn, -- Underlying hardware initialised.
|
||||
|
||||
-- Arbiter control signals
|
||||
SND_GRANTn => MZ_SND_GRANTn,
|
||||
@@ -1136,18 +1253,22 @@ begin
|
||||
-- First FPGA side device requiring BUS access.
|
||||
BUSGRANT0n => MZ_KEYB_GRANTn,
|
||||
BUSBUSY0n => MZ_KEYB_BUSYn,
|
||||
BUSINIT0n => MZ_KEYB_INITn,
|
||||
|
||||
-- Second FPGA side device requiring BUS access.
|
||||
BUSGRANT1n => MZ_CMT_GRANTn,
|
||||
BUSBUSY1n => MZ_CMT_BUSYn,
|
||||
BUSINIT1n => MZ_CMT_INITn,
|
||||
|
||||
-- Third FPGA side device requiring BUS access.
|
||||
BUSGRANT2n => MZ_SND_GRANTn,
|
||||
BUSBUSY2n => MZ_SND_BUSYn,
|
||||
BUSINIT2n => MZ_SND_INITn,
|
||||
|
||||
-- Fourth FPGA side device requiring BUS access.
|
||||
BUSGRANT3n => MZ_INTR_GRANTn,
|
||||
BUSBUSY3n => MZ_INTR_BUSYn
|
||||
BUSBUSY3n => MZ_INTR_BUSYn,
|
||||
BUSINIT3n => MZ_INTR_INITn
|
||||
);
|
||||
|
||||
------------------------------------------------------------------------------------
|
||||
@@ -1167,7 +1288,7 @@ begin
|
||||
-- Interrupt sources.
|
||||
INTR0n => MZ_KEYB_INTRn,
|
||||
INTR1n => MZ_CMT_INTRn,
|
||||
INTR2n => '1',
|
||||
INTR2n => MZ_FDD_INTRn,
|
||||
INTR3n => '1',
|
||||
INTR4n => '1',
|
||||
INTR5n => '1',
|
||||
@@ -1184,6 +1305,7 @@ begin
|
||||
INTR_DOUT => MZ_INTR_DOUT,
|
||||
INTR_DIN => MZ_INTR_DIN,
|
||||
INTR_INIT_HW => '0',
|
||||
INTR_INIT_DONEn => MZ_INTR_INITn, -- Underlying hardware initialised.
|
||||
|
||||
-- Arbiter control signals
|
||||
INTR_GRANTn => MZ_INTR_GRANTn,
|
||||
@@ -1528,6 +1650,8 @@ begin
|
||||
else
|
||||
IOP_KEYB_DOUT when IOP_KEYB_CSn = '0' and VZ80_RDni = '0' and VZ80_BUSACKni = '0'
|
||||
else
|
||||
IOP_FDD_DOUT when IOP_FDD_CSn = '0' and VZ80_RDni = '0' and VZ80_BUSACKni = '0'
|
||||
else
|
||||
IOP_MZ80K_DOUT when IOP_MZ80K_CSn = '0' and VZ80_RDni = '0' and VZ80_BUSACKni = '0'
|
||||
else
|
||||
IOP_MZ80B_DOUT when IOP_MZ80B_CSn = '0' and VZ80_RDni = '0' and VZ80_BUSACKni = '0'
|
||||
@@ -1565,8 +1689,15 @@ begin
|
||||
MZ80B_KEYB_STALL when CONFIG(MZ_B) = '1'
|
||||
else '0';
|
||||
|
||||
COLR_OUT <= MZ_SOUND_LEFT or MZ_SOUND_RIGHT when MODE_EMU = '1'
|
||||
else
|
||||
COLOUR_CARRIER_FREQ;
|
||||
-- As the tranZPUter design progresses, a short coming is the requirement to output audio from the emulation hardware. We thus, temporarily, use
|
||||
-- the composite outputs which are rarely used.
|
||||
COLR_OUT <= COLOUR_CARRIER_FREQ;
|
||||
|
||||
CSYNC_OUTn <= MZ_SOUND_LEFT when MODE_EMU = '1'
|
||||
else
|
||||
'1'; --COMPOSITE_SYNCn;
|
||||
|
||||
CSYNC_OUT <= MZ_SOUND_RIGHT when MODE_EMU = '1'
|
||||
else
|
||||
'1'; --COMPOSITE_SYNC;
|
||||
end architecture;
|
||||
|
||||
181
FPGA/SW700/v1.3/coreMZ_emuMZ_constraints.sdc
Normal file
181
FPGA/SW700/v1.3/coreMZ_emuMZ_constraints.sdc
Normal file
@@ -0,0 +1,181 @@
|
||||
## Generated SDC file "VideoController700_constraints.sdc"
|
||||
|
||||
## Copyright (C) 1991-2013 Altera Corporation
|
||||
## Your use of Altera Corporation's design tools, logic functions
|
||||
## and other software and tools, and its AMPP partner logic
|
||||
## functions, and any output files from any of the foregoing
|
||||
## (including device programming or simulation files), and any
|
||||
## associated documentation or information are expressly subject
|
||||
## to the terms and conditions of the Altera Program License
|
||||
## Subscription Agreement, Altera MegaCore Function License
|
||||
## Agreement, or other applicable license agreement, including,
|
||||
## without limitation, that your use is for the sole purpose of
|
||||
## programming logic devices manufactured by Altera and sold by
|
||||
## Altera or its authorized distributors. Please refer to the
|
||||
## applicable agreement for further details.
|
||||
|
||||
|
||||
## VENDOR "Altera"
|
||||
## PROGRAM "Quartus II"
|
||||
## VERSION "Version 13.1.0 Build 162 10/23/2013 SJ Full Version"
|
||||
|
||||
## DATE "Fri Jul 3 00:11:58 2020"
|
||||
|
||||
##
|
||||
## DEVICE "EP3C25E144C8"
|
||||
##
|
||||
|
||||
|
||||
#**************************************************************
|
||||
# Time Information
|
||||
#**************************************************************
|
||||
|
||||
set_time_format -unit ns -decimal_places 3
|
||||
|
||||
|
||||
#**************************************************************
|
||||
# Create Clock
|
||||
#**************************************************************
|
||||
|
||||
create_clock -name {altera_reserved_tck} -period 100.000 -waveform { 0.000 50.000 } [get_ports {altera_reserved_tck}]
|
||||
create_clock -name {CLOCK_50} -period 20.000 -waveform { 0.000 10.000 } [get_ports {CLOCK_50}]
|
||||
create_clock -name {VZ80_CLK} -period 50.000 -waveform { 0.000 14.1242938 } [get_ports {VZ80_CLK}]
|
||||
#create_clock -name {softT80:\CPU0:T80CPU|T80_CLK} -period 50
|
||||
|
||||
#**************************************************************
|
||||
# Create Generated Clock
|
||||
#**************************************************************
|
||||
#derive_pll_clocks
|
||||
#create_generated_clock -name {CPUCLK_75MHZ} -source [get_pins {COREMZPLL1|altpll_component|auto_generated|pll1|inclk[0]}] -duty_cycle 50/1 -multiply_by 3 -divide_by 2 -phase 0.00 -master_clock {CLOCK_50} [get_pins {COREMZPLL1|altpll_component|auto_generated|pll1|clk[0]}]
|
||||
|
||||
|
||||
#**************************************************************
|
||||
# Set Clock Latency
|
||||
#**************************************************************
|
||||
|
||||
#**************************************************************
|
||||
# Set Clock Uncertainty
|
||||
#**************************************************************
|
||||
derive_clock_uncertainty
|
||||
|
||||
#**************************************************************
|
||||
# Set Input Delay
|
||||
#**************************************************************
|
||||
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {CLOCK_50}]
|
||||
set_input_delay -add_delay -clock [get_clocks {VZ80_CLK}] 1.000 [get_ports {VZ80_CLK}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VIDEO_WRn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VIDEO_RDn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_WRn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_RDn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_IORQn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_MREQn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_M1n}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_ADDR[*]}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_DATA[*]}]
|
||||
# set_input_delay -add_delay -clock [get_clocks {SYS_CLK}] 1.000 [get_ports {VGA_B_COMPOSITE}]
|
||||
# set_input_delay -add_delay -clock [get_clocks {SYS_CLK}] 1.000 [get_ports {VGA_G_COMPOSITE}]
|
||||
# set_input_delay -add_delay -clock [get_clocks {SYS_CLK}] 1.000 [get_ports {VGA_R_COMPOSITE}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VWAITn_A21_V_CSYNC}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_A20_RFSHn_V_HSYNCn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_A19_HALTn_V_VSYNCn}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_BUSRQn_V_G}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_A16_WAITn_V_B}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_A18_INTn_V_R}]
|
||||
set_input_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_A17_NMIn_V_COLR}]
|
||||
# # Required for the Serial Flash Loader.
|
||||
set_input_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {altera_reserved_tck}]
|
||||
set_input_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {SFL_IV:\SERIALFLASHLOADER:SFL|altserial_flash_loader:altserial_flash_loader_component|\GEN_ASMI_TYPE_1:asmi_inst~ALTERA_DATA0}]
|
||||
set_input_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {altera_reserved_tdi}]
|
||||
set_input_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {altera_reserved_tms}]
|
||||
|
||||
|
||||
#**************************************************************
|
||||
# Set Output Delay
|
||||
#**************************************************************
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_DATA[*]}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_WRn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_RDn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_IORQn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_MREQn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_M1n}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_BUSACKn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VWAITn_A21_V_CSYNC}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_A20_RFSHn_V_HSYNCn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 5.000 [get_ports {VZ80_A19_HALTn_V_VSYNCn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VGA_B[*]}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VGA_B_COMPOSITE}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VGA_G[*]}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VGA_G_COMPOSITE}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VGA_R[*]}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VGA_R_COMPOSITE}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {HSYNC_OUTn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {VSYNC_OUTn}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {COLR_OUT}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {CSYNC_OUT}]
|
||||
set_output_delay -add_delay -clock [get_clocks {CLOCK_50}] 1.000 [get_ports {CSYNC_OUTn}]
|
||||
# # Required for the Serial Flash Loader.
|
||||
set_output_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {SFL_IV:\SERIALFLASHLOADER:SFL|altserial_flash_loader:altserial_flash_loader_component|\GEN_ASMI_TYPE_1:asmi_inst~ALTERA_DCLK}]
|
||||
set_output_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {SFL_IV:\SERIALFLASHLOADER:SFL|altserial_flash_loader:altserial_flash_loader_component|\GEN_ASMI_TYPE_1:asmi_inst~ALTERA_SCE}]
|
||||
set_output_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {SFL_IV:\SERIALFLASHLOADER:SFL|altserial_flash_loader:altserial_flash_loader_component|\GEN_ASMI_TYPE_1:asmi_inst~ALTERA_SDO}]
|
||||
set_output_delay -add_delay -clock { altera_reserved_tck } 1.000 [get_ports {altera_reserved_tdo}]
|
||||
|
||||
|
||||
#**************************************************************
|
||||
# Set Clock Groups
|
||||
#**************************************************************
|
||||
set_clock_groups -asynchronous -group [get_clocks {altera_reserved_tck}]
|
||||
|
||||
#**************************************************************
|
||||
# Set False Path
|
||||
#**************************************************************
|
||||
|
||||
#**************************************************************
|
||||
# Set Multicycle Path
|
||||
#**************************************************************
|
||||
#set_multicycle_path -from [get_clocks {CLOCK_50}] -to [get_clocks {CPUCLK_75MHZ}] -setup -end 3
|
||||
#set_multicycle_path -from [get_clocks {CLOCK_50}] -to [get_clocks {CPUCLK_75MHZ}] -hold -end 2
|
||||
|
||||
#**************************************************************
|
||||
# Set Maximum Delay
|
||||
#**************************************************************
|
||||
set_max_delay -from {VZ80_BUSRQn_V_G} -to [get_ports {VZ80_ADDR[*]}] 100.00
|
||||
set_max_delay -from {CPLD_CFG_DATA[*]} -to [get_ports {VZ80_ADDR[*]}] 100.00
|
||||
set_max_delay -from {CPU_CFG_DATA[*]} -to [get_ports {VZ80_ADDR[*]}] 100.00
|
||||
set_max_delay -from {CPLD_CFG_DATA[*]} -to [get_ports {VZ80_DATA[*]}] 100.00
|
||||
set_max_delay -from {CPU_CFG_DATA[*]} -to [get_ports {VZ80_DATA[*]}] 100.00
|
||||
set_max_delay -from {VZ80_BUSRQn_V_G} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_RDn} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_IORQn} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VIDEO_RDn} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_ADDR[*]} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VWAITn_A21_V_CSYNC} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_A20_RFSHn_V_HSYNCn} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_A19_HALTn_V_VSYNCn} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_A18_INTn_V_R} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_A17_NMIn_V_COLR} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
set_max_delay -from {VZ80_A16_WAITn_V_B} -to [get_ports {VZ80_DATA[*]}] 50.00
|
||||
|
||||
#**************************************************************
|
||||
# Set Minimum Delay
|
||||
#**************************************************************
|
||||
set_min_delay -from {VZ80_BUSRQn_V_G} -to [get_ports {VZ80_ADDR[*]}] 1.00
|
||||
set_min_delay -from {CPLD_CFG_DATA[*]} -to [get_ports {VZ80_ADDR[*]}] 1.00
|
||||
set_min_delay -from {CPU_CFG_DATA[*]} -to [get_ports {VZ80_ADDR[*]}] 1.00
|
||||
set_min_delay -from {CPLD_CFG_DATA[*]} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {CPU_CFG_DATA[*]} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_BUSRQn_V_G} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_RDn} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_IORQn} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VIDEO_RDn} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_ADDR[*]} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VWAITn_A21_V_CSYNC} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_A20_RFSHn_V_HSYNCn} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_A19_HALTn_V_VSYNCn} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_A18_INTn_V_R} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_A17_NMIn_V_COLR} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
set_min_delay -from {VZ80_A16_WAITn_V_B} -to [get_ports {VZ80_DATA[*]}] 1.00
|
||||
|
||||
#**************************************************************
|
||||
# Set Input Transition
|
||||
#**************************************************************
|
||||
@@ -60,18 +60,22 @@ entity arbiter is
|
||||
-- First FPGA side device requiring BUS access.
|
||||
BUSGRANT0n : out std_logic;
|
||||
BUSBUSY0n : in std_logic;
|
||||
BUSINIT0n : in std_logic;
|
||||
|
||||
-- Second FPGA side device requiring BUS access.
|
||||
BUSGRANT1n : out std_logic;
|
||||
BUSBUSY1n : in std_logic;
|
||||
BUSINIT1n : in std_logic;
|
||||
|
||||
-- Third FPGA side device requiring BUS access.
|
||||
BUSGRANT2n : out std_logic;
|
||||
BUSBUSY2n : in std_logic;
|
||||
BUSINIT2n : in std_logic;
|
||||
|
||||
-- Fourth FPGA side device requiring BUS access.
|
||||
BUSGRANT3n : out std_logic;
|
||||
BUSBUSY3n : in std_logic
|
||||
BUSBUSY3n : in std_logic;
|
||||
BUSINIT3n : in std_logic
|
||||
);
|
||||
end arbiter;
|
||||
|
||||
@@ -164,7 +168,7 @@ begin
|
||||
|
||||
-- If device 1 has the bus, wait until it releases it.
|
||||
when State_Dev0Busy =>
|
||||
if BUSBUSY0n = '0' then
|
||||
if BUSBUSY0n = '0' or BUSINIT0n = '1' then
|
||||
MB_STATE <= State_Dev0Busy;
|
||||
else
|
||||
MB_STATE <= State_OfferDev1;
|
||||
@@ -172,7 +176,7 @@ begin
|
||||
|
||||
-- If device 2 has the bus, wait until it releases it.
|
||||
when State_Dev1Busy =>
|
||||
if BUSBUSY1n = '0' then
|
||||
if BUSBUSY1n = '0' or BUSINIT1n = '1' then
|
||||
MB_STATE <= State_Dev1Busy;
|
||||
else
|
||||
MB_STATE <= State_OfferDev2;
|
||||
@@ -180,7 +184,7 @@ begin
|
||||
|
||||
-- If device 3 has the bus, wait until it releases it.
|
||||
when State_Dev2Busy =>
|
||||
if BUSBUSY2n = '0' then
|
||||
if BUSBUSY2n = '0' or BUSINIT2n = '1' then
|
||||
MB_STATE <= State_Dev2Busy;
|
||||
else
|
||||
MB_STATE <= State_OfferDev3;
|
||||
@@ -188,7 +192,7 @@ begin
|
||||
|
||||
-- If device 4 has the bus, wait until it releases it.
|
||||
when State_Dev3Busy =>
|
||||
if BUSBUSY3n = '0' then
|
||||
if BUSBUSY3n = '0' or BUSINIT3n = '1' then
|
||||
MB_STATE <= State_Dev3Busy;
|
||||
else
|
||||
MB_STATE <= State_OfferDev0;
|
||||
|
||||
@@ -54,7 +54,7 @@ package clkgen_pkg is
|
||||
|
||||
-- Clock bus, various clocks on a single bus construct.
|
||||
--
|
||||
subtype CLKBUS_WIDTH is integer range 5 downto 0;
|
||||
subtype CLKBUS_WIDTH is integer range 6 downto 0;
|
||||
|
||||
-- Indexes to the various clocks on the bus.
|
||||
--
|
||||
@@ -64,6 +64,7 @@ package clkgen_pkg is
|
||||
constant CKRTC : integer := 3; -- RTC clock.
|
||||
constant CKENCPU : integer := 4; -- CPU clock enable.
|
||||
constant CKENPERIPH : integer := 5; -- Peripheral clock enable.
|
||||
constant CKENFDC : integer := 6; -- Floppy Disk Controller clock.
|
||||
end clkgen_pkg;
|
||||
|
||||
library ieee;
|
||||
@@ -113,12 +114,14 @@ signal CK14M1875i : std_logic; -- 14MH
|
||||
signal CK8M8672i : std_logic; -- 8.8MHz
|
||||
signal CK8Mi : std_logic; -- 8MHz
|
||||
signal CK7M709i : std_logic; -- 7MHz
|
||||
signal CK7M709_LAST : std_logic; -- 7MHz edge detection.
|
||||
signal CK4Mi : std_logic; -- 4MHz
|
||||
signal CK3M546875i : std_logic; -- 3.5MHz
|
||||
signal CK2Mi : std_logic; -- 2MHz
|
||||
signal CK2M_LAST : std_logic; -- 2MHz edge detection.
|
||||
signal CK1Mi : std_logic; -- 1MHz
|
||||
signal CK895Ki : std_logic; -- 895KHz Sound frequency.
|
||||
signal CK1M1i : std_logic; -- 1.1MHz Sound frequency MZ-800
|
||||
signal CK895Ki : std_logic; -- 895KHz Sound frequency MZ-700.
|
||||
signal CK31500i : std_logic; -- Clock base frequency,
|
||||
signal CK31250i : std_logic; -- Clock base frequency.
|
||||
signal CK15611i : std_logic; -- Clock base frequency.
|
||||
@@ -129,11 +132,13 @@ signal CKRTCi : std_logic; -- RTC
|
||||
--
|
||||
signal CKENCPUi : std_logic;
|
||||
signal CKENPERi : std_logic;
|
||||
signal CKENFDCi : std_logic;
|
||||
--
|
||||
-- Clock edge detection for creating clock enables.
|
||||
--
|
||||
signal CPUEDGE : std_logic_vector(1 downto 0);
|
||||
signal PEREDGE : std_logic_vector(1 downto 0);
|
||||
signal FDCEDGE : std_logic_vector(1 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
@@ -321,11 +326,12 @@ begin
|
||||
--
|
||||
-- Clock Generator - Basic divide circuit for lower end frequencies.
|
||||
--
|
||||
process (PLLLOCKED1, CK128Mi, CK2Mi)
|
||||
process (PLLLOCKED1, CK128Mi, CK7M709i, CK2Mi)
|
||||
--
|
||||
-- Divide by counters to create the various Clock enable signals.
|
||||
--
|
||||
variable counter1Mi : unsigned(0 downto 0); -- Binary divider to create 1Mi clock.
|
||||
variable counter1M1i : unsigned(2 downto 0); -- Binary divider to create 1Mi clock.
|
||||
variable counter895Ki : unsigned(0 downto 0); -- Binary divider to create 895Ki clock.
|
||||
variable counter31500i : unsigned(5 downto 0); -- Binary divider to create 31500i clock.
|
||||
variable counter31250i : unsigned(5 downto 0); -- Binary divider to create 31250i clock.
|
||||
@@ -334,11 +340,13 @@ begin
|
||||
begin
|
||||
if PLLLOCKED1 = '0' then
|
||||
counter1Mi := (others => '0');
|
||||
counter1M1i := (others => '0');
|
||||
counter895Ki := (others => '0');
|
||||
counter31500i := (others => '0');
|
||||
counter31250i := (others => '0');
|
||||
counter15611i := (others => '0');
|
||||
CK1Mi <= '0';
|
||||
CK1M1i <= '0';
|
||||
CK895Ki <= '0';
|
||||
CK31500i <= '0';
|
||||
CK31250i <= '0';
|
||||
@@ -350,9 +358,23 @@ begin
|
||||
--elsif rising_edge(CK2Mi) then
|
||||
elsif rising_edge(CK128Mi) then
|
||||
CK2M_LAST <= CK2Mi;
|
||||
CK7M709_LAST <= CK7M709i;
|
||||
|
||||
if CK7M709i = '1' and CK7M709_LAST = '0' then
|
||||
-- 1100000Hz
|
||||
if counter1M1i = 3 or counter1M1i = 6 then
|
||||
CK1M1i <= not CK1M1i;
|
||||
if counter1M1i = 1 then
|
||||
counter1M1i:= (others => '0');
|
||||
else
|
||||
counter1M1i:= counter1M1i + 1;
|
||||
end if;
|
||||
else
|
||||
counter1M1i := counter1M1i + 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if CK2Mi = '1' and CK2M_LAST = '0' then
|
||||
|
||||
-- 1000000Hz
|
||||
if counter1Mi = 0 or counter1Mi = 1 then
|
||||
CK1Mi <= not CK1Mi;
|
||||
@@ -435,8 +457,10 @@ begin
|
||||
if PLLLOCKED2 = '0' then
|
||||
CKENCPUi <= '0';
|
||||
CKENPERi <= '0';
|
||||
CKENFDCi <= '0';
|
||||
CPUEDGE <= "00";
|
||||
PEREDGE <= "00";
|
||||
FDCEDGE <= "00";
|
||||
|
||||
elsif rising_edge(CKSYS) then
|
||||
|
||||
@@ -454,7 +478,10 @@ begin
|
||||
when "01" =>
|
||||
CKSOUNDi <= CK895Ki;
|
||||
|
||||
when "00" | "10" | "11" =>
|
||||
when "10" =>
|
||||
CKSOUNDi <= CK1M1i;
|
||||
|
||||
when "00" | "11" =>
|
||||
CKSOUNDi <= CK2Mi;
|
||||
end case;
|
||||
|
||||
@@ -465,6 +492,14 @@ begin
|
||||
if PEREDGE = "10" then
|
||||
CKENPERi <= '1';
|
||||
end if;
|
||||
|
||||
-- Floppy Disk Controller runs at 8MHz so we generate an enable signal based on this clock rate.
|
||||
FDCEDGE(0) <= FDCEDGE(1);
|
||||
FDCEDGE(1) <= CK8Mi;
|
||||
CKENFDCi <= '0';
|
||||
if FDCEDGE = "10" then
|
||||
CKENFDCi <= '1';
|
||||
end if;
|
||||
|
||||
-- The CPU speed is configured by the CMT register and CMT state or the CPU register. Select the right
|
||||
-- frequency and form the clock by flipping on the right flip flag.
|
||||
@@ -502,22 +537,25 @@ begin
|
||||
when "00" => -- 2MHz
|
||||
PEREDGE(1) <= CK2Mi;
|
||||
|
||||
when "01" | "10" | "11" => -- 2MHz
|
||||
when "01" => -- 4MHz
|
||||
PEREDGE(1) <= CK4Mi;
|
||||
|
||||
when "10" | "11" => -- 2MHz
|
||||
PEREDGE(1) <= CK2Mi;
|
||||
end case;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Assign necessary clocks and enables.
|
||||
--
|
||||
CKSYS <= CK100Mi; --CK113M5i;
|
||||
CKSYS <= CK128Mi; --CK100Mi; --CK113M5i;
|
||||
CLKBUS(CKMASTER) <= CKSYS; -- System wide synchronous logic clock.
|
||||
CLKBUS(CKHOST) <= CLKHOST; -- Host hardware clock (ie. MZ-700/MZ-2000 host).
|
||||
CLKBUS(CKSOUND) <= CKSOUNDi; -- Sound base clock, 50/50 duty cycle.
|
||||
CLKBUS(CKRTC) <= CKRTCi; -- RTC base clock, 50/50 duty cycle.
|
||||
CLKBUS(CKENCPU) <= CKENCPUi; -- Enable signal for CPU base clock.
|
||||
CLKBUS(CKENPERIPH) <= CKENPERi; -- Enable signal for Peripheral base clock.
|
||||
CLKBUS(CKENFDC) <= CKENFDCi; -- Floppy Disk Controller clock enable signal. Required to match correct timing.
|
||||
PLLLOCKED <= PLLLOCKED1; -- Indicate when the PLL has synchronised and locked.
|
||||
|
||||
end RTL;
|
||||
|
||||
@@ -93,6 +93,7 @@ architecture RTL of cmt is
|
||||
signal CMT_STATUS_INTR : std_logic_vector(15 downto 0);
|
||||
signal CMT_STATUS_LAST : std_logic_vector(15 downto 0);
|
||||
signal CMT_INTRni : std_logic;
|
||||
signal CMT_SIGNAL_LAST : std_logic_vector(8 downto 0);
|
||||
signal CMT_BUS_OUTi : std_logic_vector(CMT_BUS_OUT_WIDTH); -- CMT bus output.
|
||||
signal BUTTONS_LAST : std_logic_vector(1 downto 0); -- Virtual buttons last sample, used to detect changes.
|
||||
signal PLAY_READY_SET_CNT : integer range 0 to 32000000 := 0; -- 1 second timer from last cache upload to PLAY_READY being set.
|
||||
@@ -108,7 +109,7 @@ architecture RTL of cmt is
|
||||
signal RECORDING : std_logic; -- Signal indicating a Record is underway, Active = 1.
|
||||
signal RECSEQ : std_logic_vector(2 downto 0); -- Signal, 3 cycles, indicating
|
||||
signal MOTOR_TOGGLE : std_logic_vector(1 downto 0); -- Signal indicating if the MZ wants to start or toggle the motor.
|
||||
signal APSS_TIMER_CNT : unsigned(20 downto 0); -- 1 second virtual APSS SEEK time.
|
||||
signal REEL_TIMER_CNT : unsigned(23 downto 0); -- 4 second virtual REEL Rewind/Forward and APSS SEEK time.
|
||||
signal WRITEBIT : std_logic; -- Tape data signal sent to the MZ (for playback).
|
||||
signal READBIT : std_logic; -- Tape data signal eminating from the MZ (for recording).
|
||||
signal TAPE_MOTOR_ONn : std_logic; -- Virtual motor signal, tape motor running = 0.
|
||||
@@ -266,13 +267,13 @@ begin
|
||||
CMT_STATUS_LAST <= (others => '0');
|
||||
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
if CMT_WAITn = '1' and CLKBUS(CKENCPU) = '1' then
|
||||
CMT_INTRni <= '1';
|
||||
|
||||
-- Store current signal state and compare with previous, any change then raise an interrupt.
|
||||
CMT_STATUS <= '0' &
|
||||
CMT_BUS_OUTi(AUTOPLAY) &
|
||||
CMT_BUS_OUTi(AUTOREW) &
|
||||
CMT_BUS_OUTi(APSS_AUTOPLAY) &
|
||||
CMT_BUS_OUTi(APSS_AUTOREW) &
|
||||
CMT_BUS_OUTi(APSS_STOP) &
|
||||
CMT_BUS_OUTi(APSS_PLAY) &
|
||||
CMT_BUS_OUTi(APSS_EJECT) &
|
||||
@@ -465,16 +466,31 @@ begin
|
||||
PLAYING <= "000";
|
||||
RECORDING <= '0';
|
||||
MOTOR_TOGGLE(0) <= '0';
|
||||
APSS_TIMER_CNT <= (others => '0');
|
||||
REEL_TIMER_CNT <= (others => '0');
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
CMT_BUS_OUTi(APSS_DIR) <= '0';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '1';
|
||||
CMT_BUS_OUTi(APSS_AUTOREW) <= '0';
|
||||
CMT_BUS_OUTi(APSS_AUTOPLAY) <= '0';
|
||||
CMT_SIGNAL_LAST <= (others => '0');
|
||||
|
||||
elsif CLKBUS(CKMASTER)'event and CLKBUS(CKMASTER)='1' then
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
--if CLKBUS(CKENCPU) = '1' then
|
||||
if CMT_WAITn = '1' and CLKBUS(CKENCPU) = '1' then
|
||||
|
||||
-- Edge detection of activation signals.
|
||||
CMT_SIGNAL_LAST <= CMT_BUS_IN(pkgs.mctrl_pkg.REEL_MOTOR) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.AUTOREW) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.AUTOPLAY) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.EJECT) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.PLAY) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.STOP) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.CMTREW) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.CMTFF) &
|
||||
CMT_BUS_IN(pkgs.mctrl_pkg.SEEK);
|
||||
|
||||
-- Store last state so we detect change.
|
||||
BUTTONS_LAST <= CONFIG(BUTTONS);
|
||||
@@ -482,6 +498,9 @@ begin
|
||||
|
||||
-- Store last state so we can detect a switch to recording or play mode.
|
||||
PLAYING(1 downto 0) <= PLAYING(2 downto 1);
|
||||
|
||||
-- Eject signal only 1 clock wide.
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
|
||||
-- The MZ80K series use a manual cassette deck with motor automation, so we
|
||||
-- need to simulate buttons and the states therein.
|
||||
@@ -498,20 +517,27 @@ begin
|
||||
TAPE_MOTOR_ONn <= '1';
|
||||
CMT_BUS_OUTi(TAPEREADY) <= '1'; -- Indicates tape ejected.
|
||||
CMT_BUS_OUTi(WRITEREADY)<= '1'; -- Indicates write mechanism disabled.
|
||||
when "01" => -- Play
|
||||
-- Playback mode.
|
||||
PLAY_BUTTON <= '1';
|
||||
RECORD_BUTTON <= '0';
|
||||
TAPE_MOTOR_ONn <= '0';
|
||||
CMT_BUS_OUTi(TAPEREADY) <= '0'; -- Indicates tape loaded, active Low.
|
||||
CMT_BUS_OUTi(WRITEREADY)<= '1'; -- Indicates write mechanism disabled.
|
||||
when "10" => -- Record
|
||||
PLAY_BUTTON <= '0';
|
||||
RECORD_BUTTON <= '1';
|
||||
TAPE_MOTOR_ONn <= '0';
|
||||
CMT_BUS_OUTi(TAPEREADY) <= '0'; -- Indicates tape loaded, active Low.
|
||||
CMT_BUS_OUTi(WRITEREADY)<= '1'; -- Indicates write mechanism enabled.
|
||||
when "01"|"11" => -- Play/Auto
|
||||
CMT_BUS_OUTi(WRITEREADY)<= '0'; -- Indicates write mechanism enabled.
|
||||
when "11" => -- Auto
|
||||
-- Assume playback mode for Auto unless activity is detected from the MZ,
|
||||
-- in which case switch to Recording.
|
||||
PLAY_BUTTON <= '1';
|
||||
RECORD_BUTTON <= '0';
|
||||
TAPE_MOTOR_ONn <= '0';
|
||||
CMT_BUS_OUTi(TAPEREADY) <= '0'; -- Indicates tape loaded, active Low.
|
||||
CMT_BUS_OUTi(WRITEREADY)<= '0'; -- Indicates write mechanism disabled.
|
||||
CMT_BUS_OUTi(WRITEREADY)<= '0'; -- Indicates write mechanism enabled.
|
||||
end case;
|
||||
end if;
|
||||
|
||||
@@ -528,7 +554,6 @@ begin
|
||||
if RCV_SEQ = "11" or RECORDING = '1' then
|
||||
PLAY_BUTTON <= '0';
|
||||
RECORD_BUTTON <= '1';
|
||||
CMT_BUS_OUTi(WRITEREADY) <= '1'; -- Indicates write mechanism disabled.
|
||||
else
|
||||
PLAY_BUTTON <= '1';
|
||||
RECORD_BUTTON <= '0';
|
||||
@@ -561,17 +586,22 @@ begin
|
||||
-- Tape is always ready and able to write.
|
||||
--
|
||||
CMT_BUS_OUTi(TAPEREADY) <= '0'; -- Indicates tape loaded, active low.
|
||||
CMT_BUS_OUTi(WRITEREADY) <= '1'; -- Indicates write mechanism disabled.
|
||||
CMT_BUS_OUTi(WRITEREADY) <= '0'; -- Indicates write mechanism enabled.
|
||||
|
||||
-- If seek pulses high, store the direction.
|
||||
--
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.SEEK) = '1' then
|
||||
CMT_BUS_OUTi(APSS_DIR) <= CMT_BUS_IN(pkgs.mctrl_pkg.DIRECTION);
|
||||
end if;
|
||||
|
||||
if (CMT_BUS_IN(pkgs.mctrl_pkg.REEL_MOTOR) = '0' and CMT_SIGNAL_LAST(2) = '1') or (CMT_BUS_IN(pkgs.mctrl_pkg.SEEK) = '1' and CMT_SIGNAL_LAST(0) = '0') then
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
end if;
|
||||
|
||||
-- If Eject goes active, latch and invert it for reading.
|
||||
--
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.EJECT) = '0' then
|
||||
-- if CMT_BUS_IN(pkgs.mctrl_pkg.EJECT) = '0' then
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.EJECT) = '0' and CMT_SIGNAL_LAST(5) = '1' then
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '1';
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
@@ -580,37 +610,38 @@ begin
|
||||
|
||||
-- The play motor is started/stopped by the PLAY/STOP signals.
|
||||
--
|
||||
if MOTOR_TOGGLE = "11" and CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '0' then
|
||||
--if MOTOR_TOGGLE = "11" and CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '0' then
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.PLAY) = '0' and CMT_SIGNAL_LAST(4) = '1' then
|
||||
TAPE_MOTOR_ONn <= '0';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '1';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '0';
|
||||
end if;
|
||||
|
||||
elsif MOTOR_TOGGLE /= "11" and CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '1' then
|
||||
--elsif MOTOR_TOGGLE /= "11" and CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '1' then
|
||||
if (CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '0' and CMT_SIGNAL_LAST(3) = '1') or REEL_TIMER_CNT = X"FFFFFF" then
|
||||
TAPE_MOTOR_ONn <= '1';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '1';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
end if;
|
||||
|
||||
-- If REEL_MOTOR pulses high, then engage APSS seek.
|
||||
--
|
||||
elsif CMT_BUS_IN(REEL_MOTOR) = '1' then
|
||||
if CMT_BUS_IN(REEL_MOTOR) = '1' and CMT_SIGNAL_LAST(8) = '0' then
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '1';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '0';
|
||||
APSS_TIMER_CNT <= to_unsigned(1, 21);
|
||||
REEL_TIMER_CNT <= to_unsigned(1, 24);
|
||||
end if;
|
||||
|
||||
-- If the APSS SEEK action has been started, reset it after 1 second to simulate the real action.
|
||||
-- If the APSS SEEK action has been started, reset it after 4 seconds to simulate the real action.
|
||||
--
|
||||
if APSS_TIMER_CNT > 0 then
|
||||
APSS_TIMER_CNT <= APSS_TIMER_CNT + 1;
|
||||
end if;
|
||||
if APSS_TIMER_CNT = X"FFFFF" then
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
if REEL_TIMER_CNT > 0 then
|
||||
REEL_TIMER_CNT <= REEL_TIMER_CNT + 1;
|
||||
end if;
|
||||
|
||||
-- Update the status as to wether we are playing, recording or idle.
|
||||
@@ -637,62 +668,84 @@ begin
|
||||
-- W READY PB4 - WRITEREADY - Write/record ready
|
||||
-- TAPE END PB3 - ENDOFTAPE - End of tape detected.
|
||||
--
|
||||
elsif CONFIG(MZ2000) = '1' then
|
||||
elsif CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1' then
|
||||
-- Tape is always ready and able to write.
|
||||
--
|
||||
CMT_BUS_OUTi(TAPEREADY) <= '0'; -- L Indicates tape loaded, active low.
|
||||
CMT_BUS_OUTi(WRITEREADY) <= '1'; -- L Indicates write mechanism disabled.
|
||||
|
||||
-- If seek pulses high, store the direction.
|
||||
--
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.SEEK) = '1' then
|
||||
CMT_BUS_OUTi(APSS_DIR) <= CMT_BUS_IN(pkgs.mctrl_pkg.DIRECTION);
|
||||
CMT_BUS_OUTi(WRITEREADY) <= '0'; -- L Indicates write mechanism enabled.
|
||||
|
||||
if (CMT_BUS_IN(pkgs.mctrl_pkg.CMTREW) = '1' and CMT_SIGNAL_LAST(2) = '0') or (CMT_BUS_IN(pkgs.mctrl_pkg.CMTFF) = '1' and CMT_SIGNAL_LAST(1) = '0') or (CMT_BUS_IN(pkgs.mctrl_pkg.SEEK) = '1' and CMT_SIGNAL_LAST(0) = '0') then
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
end if;
|
||||
|
||||
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.AUTOREW) = '0' and CMT_SIGNAL_LAST(7) = '1' then
|
||||
CMT_BUS_OUTi(APSS_AUTOREW) <= '1';
|
||||
elsif CMT_BUS_IN(pkgs.mctrl_pkg.AUTOREW) = '1' and CMT_SIGNAL_LAST(7) = '0' then
|
||||
CMT_BUS_OUTi(APSS_AUTOREW) <= '0';
|
||||
end if;
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.AUTOPLAY) = '0' and CMT_SIGNAL_LAST(6) = '1' then
|
||||
CMT_BUS_OUTi(APSS_AUTOPLAY) <= '1';
|
||||
elsif CMT_BUS_IN(pkgs.mctrl_pkg.AUTOPLAY) = '1' and CMT_SIGNAL_LAST(6) = '0' then
|
||||
CMT_BUS_OUTi(APSS_AUTOPLAY) <= '0';
|
||||
end if;
|
||||
|
||||
-- If the APSS SEEK action or Rewind/FFwd has been started, count up until the period expires and then issue a STOP action to simulate real action.
|
||||
--
|
||||
if REEL_TIMER_CNT > 0 then
|
||||
REEL_TIMER_CNT <= REEL_TIMER_CNT + 1;
|
||||
end if;
|
||||
|
||||
-- If Eject goes active, latch and invert it for reading.
|
||||
--
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.EJECT) = '0' then
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.EJECT) = '0' and CMT_SIGNAL_LAST(5) = '1' then
|
||||
TAPE_MOTOR_ONn <= '1';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '1';
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '0';
|
||||
CMT_BUS_OUTi(APSS_AUTOREW) <= '0';
|
||||
CMT_BUS_OUTi(APSS_AUTOPLAY) <= '0';
|
||||
REEL_TIMER_CNT <= (others => '0');
|
||||
end if;
|
||||
|
||||
-- The play motor is started/stopped by the PLAY/STOP signals.
|
||||
--
|
||||
if MOTOR_TOGGLE = "11" and CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '1' then
|
||||
TAPE_MOTOR_ONn <= '0';
|
||||
if CMT_BUS_IN(pkgs.mctrl_pkg.PLAY) = '0' and CMT_SIGNAL_LAST(4) = '1' then
|
||||
TAPE_MOTOR_ONn <= '0';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '1';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '0';
|
||||
|
||||
elsif MOTOR_TOGGLE /= "11" and CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '0' then
|
||||
TAPE_MOTOR_ONn <= '1';
|
||||
REEL_TIMER_CNT <= (others => '0');
|
||||
end if;
|
||||
--
|
||||
if (CMT_BUS_IN(pkgs.mctrl_pkg.STOP) = '0' and CMT_SIGNAL_LAST(3) = '1') or REEL_TIMER_CNT = X"FFFFFF" then
|
||||
TAPE_MOTOR_ONn <= '1';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '1';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
|
||||
-- If REEL_MOTOR pulses high, then engage APSS seek.
|
||||
CMT_BUS_OUTi(APSS_AUTOREW) <= '0';
|
||||
CMT_BUS_OUTi(APSS_AUTOPLAY) <= '0';
|
||||
REEL_TIMER_CNT <= (others => '0');
|
||||
end if;
|
||||
|
||||
-- Rewind and Fast Forward start a timer and when it expires, a STOP action occurs. If a STOP or other action occurs before the timer has expired
|
||||
-- it is cancelled. This simulates the tape being rewound or fast forwarded and a secondary action triggered, such as pressing play.
|
||||
--
|
||||
elsif CMT_BUS_IN(REEL_MOTOR) = '1' then
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '1';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
-- APSS Seek is an extension of Rew/FF and in keeping with other models, sets the direction flag and starts a simulated seek forward or backward. This is accomplished by a timer which upon expiry clears the
|
||||
-- state.
|
||||
if (CMT_BUS_IN(pkgs.mctrl_pkg.CMTREW) = '0' and CMT_SIGNAL_LAST(2) = '1') or (CMT_BUS_IN(pkgs.mctrl_pkg.CMTFF) = '0' and CMT_SIGNAL_LAST(1) = '1') or (CMT_BUS_IN(pkgs.mctrl_pkg.SEEK) = '0' and CMT_SIGNAL_LAST(0) = '1') then
|
||||
CMT_BUS_OUTi(APSS_DIR) <= CMT_BUS_IN(pkgs.mctrl_pkg.CMTREW);
|
||||
|
||||
TAPE_MOTOR_ONn <= '0';
|
||||
CMT_BUS_OUTi(APSS_STOP) <= '0';
|
||||
APSS_TIMER_CNT <= to_unsigned(1, 21);
|
||||
CMT_BUS_OUTi(APSS_PLAY) <= '0';
|
||||
CMT_BUS_OUTi(APSS_EJECT) <= '0';
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '1';
|
||||
REEL_TIMER_CNT <= to_unsigned(1, 24);
|
||||
end if;
|
||||
|
||||
-- If the APSS SEEK action has been started, reset it after 1 second to simulate the real action.
|
||||
--
|
||||
if APSS_TIMER_CNT > 0 then
|
||||
APSS_TIMER_CNT <= APSS_TIMER_CNT + 1;
|
||||
end if;
|
||||
if APSS_TIMER_CNT = X"FFFFF" then
|
||||
CMT_BUS_OUTi(APSS_SEEK) <= '0';
|
||||
end if;
|
||||
|
||||
|
||||
-- Update the status as to wether we are playing, recording or idle.
|
||||
--
|
||||
PLAYING(2) <= PLAY_READY and CMT_BUS_OUTi(APSS_PLAY);
|
||||
|
||||
@@ -63,6 +63,7 @@ entity cmt_hw is
|
||||
CMT_DOUT : out std_logic_vector(7 downto 0);
|
||||
CMT_DIN : in std_logic_vector(7 downto 0);
|
||||
CMT_INIT_HW : in std_logic;
|
||||
CMT_INIT_DONEn : out std_logic;
|
||||
|
||||
-- Arbiter control signals
|
||||
CMT_GRANTn : in std_logic;
|
||||
@@ -351,5 +352,6 @@ begin
|
||||
CMT_IORQn <= CMT_IORQni;
|
||||
CMT_M1n <= CMT_M1ni;
|
||||
CMT_BUSYn <= CMT_BUSYni;
|
||||
CMT_INIT_DONEn <= CMT_INITi;
|
||||
|
||||
end RTL;
|
||||
|
||||
@@ -9,6 +9,7 @@ set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) cmt_hw.
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) arbiter.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) iointr.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) snd.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) fdd.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) mz80k_hw.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) mz80b_hw.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) i8254/i8254_counter.vhd]
|
||||
@@ -16,6 +17,9 @@ set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) i8254/i
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) i8255/i8255.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) z8420/z8420.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) z8420/Interrupt.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) z8420/z8420_v2.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) z8420/Interrupt_v2.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) wd1793/wd1793.vhd]
|
||||
set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) sn76489_audio.vhd]
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v]
|
||||
set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) emuMZ_constraints.sdc]
|
||||
|
||||
356
FPGA/SW700/v1.3/emuMZ/fdd.vhd
Normal file
356
FPGA/SW700/v1.3/emuMZ/fdd.vhd
Normal file
@@ -0,0 +1,356 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
--
|
||||
-- Name: fdd.vhd
|
||||
-- Created: Jan 2022
|
||||
-- Author(s): Philip Smart
|
||||
-- Description: Sharp MZ series Floppy Disk Interface.
|
||||
-- This module fully emulates the Floppy Disk Controller as used in all the Sharp MZ
|
||||
-- series computers. The design is based on the Western Digital controller model
|
||||
-- which is used by the MB8866 and WD1773 controllers found in most interface cards.
|
||||
-- As the FPGA has limited BRAM resources, cacheing a floppy image is not practical
|
||||
-- so the I/O processor is used (as it would be anyway to load an entire cached image)
|
||||
-- and the disk controller only caches 1 sector, with the I/O processor fetching/
|
||||
-- saving as directed. The advantage being the I/O processor can offer extended
|
||||
-- services such as EDSK or D88 mapping from SD card to disk controller sector.
|
||||
--
|
||||
-- Credits:
|
||||
-- Copyright: (c) 2018-22 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: Jan 2022 - Initial module.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- 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->.
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
library pkgs;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.std_logic_unsigned.all;
|
||||
use ieee.numeric_std.all;
|
||||
use work.clkgen_pkg.all;
|
||||
use work.mctrl_pkg.all;
|
||||
|
||||
entity fdd is
|
||||
port (
|
||||
RSTn : in std_logic;
|
||||
|
||||
-- Clock signals needed by this module.
|
||||
CLKBUS : in std_logic_vector(CLKBUS_WIDTH);
|
||||
|
||||
-- Different operations modes.
|
||||
CONFIG : in std_logic_vector(CONFIG_WIDTH);
|
||||
|
||||
-- Z80 CPU Interface.
|
||||
Z80_DI : out std_logic_vector(7 downto 0);
|
||||
Z80_DO : in std_logic_vector(7 downto 0);
|
||||
Z80_ADDR : in std_logic_vector(15 downto 0);
|
||||
Z80_RDn : in std_logic;
|
||||
Z80_WRn : in std_logic;
|
||||
Z80_INTn : out std_logic;
|
||||
|
||||
-- Module activation signal (allows for different memory address mapping in the controlling module).
|
||||
-- The signal should include IORQn/MREQn, span 7 bytes.
|
||||
FDD_CSn : in std_logic;
|
||||
|
||||
-- IOP interrupt. This is raised whenever the WD1793 requires servicing, ie. the IOP_SECTOR_REQ line goes active.
|
||||
IOP_INTn : out std_logic;
|
||||
|
||||
-- I/O Processor Interface
|
||||
IOP_CSn : in std_logic; -- Chip select from the I/O Processor decoding.
|
||||
IOP_WRn : in std_logic; -- Write Enable.
|
||||
IOP_RDn : in std_logic; -- Read Enable.
|
||||
IOP_ADDR : in std_logic_vector(12 downto 0); -- Address bus.
|
||||
IOP_DOUT : in std_logic_vector(7 downto 0); -- Data into the mctrl unit.
|
||||
IOP_DIN : out std_logic_vector(7 downto 0) -- Data out from the mctrl unit.
|
||||
);
|
||||
end fdd;
|
||||
|
||||
architecture RTL of fdd is
|
||||
|
||||
type POLARITY_TYPE is array(integer range 0 to 3) of std_logic;
|
||||
type READONLY_TYPE is array(integer range 0 to 3) of std_logic;
|
||||
type DISKREADY_TYPE is array(integer range 0 to 3) of std_logic;
|
||||
type DISK_TYPE is array(integer range 0 to 3) of std_logic_vector(3 downto 0);
|
||||
|
||||
-- IO Processor Control signals.
|
||||
signal IOP_WD1793_CSn : std_logic;
|
||||
signal IOP_CTRL_CSn : std_logic;
|
||||
signal IOP_SECTOR_CSn : std_logic;
|
||||
signal IOP_TRACK_CSn : std_logic;
|
||||
signal IOP_FDC_CSn : std_logic;
|
||||
signal IOP_WD1793_DIN : std_logic_vector(7 downto 0);
|
||||
signal IOP_SECTOR : std_logic_vector(7 downto 0);
|
||||
signal IOP_TRACK : std_logic_vector(7 downto 0);
|
||||
signal IOP_WRPROTECT : READONLY_TYPE;
|
||||
signal IOP_POLARITY : POLARITY_TYPE;
|
||||
signal IOP_DISKREADY : DISKREADY_TYPE;
|
||||
signal IOP_TYPE : DISK_TYPE;
|
||||
signal IOP_DIN_DISKNO : integer range 0 to 3;
|
||||
signal IOP_READY : std_logic;
|
||||
signal IOP_SECTOR_REQ : std_logic;
|
||||
signal IOP_SECTOR_DIR : std_logic;
|
||||
signal IOP_SERVICE_REQ : std_logic;
|
||||
signal IOP_SIDE : std_logic;
|
||||
signal IOP_INTR_CNT : unsigned(7 downto 0);
|
||||
|
||||
-- Host side floppy control signals.
|
||||
signal WD1793_CSn : std_logic;
|
||||
signal DRIVESEL_CSn : std_logic;
|
||||
signal SIDESEL_CSn : std_logic;
|
||||
signal DDENSEL_CSn : std_logic;
|
||||
signal DISK_DRQ : std_logic;
|
||||
signal DISK_MOTORON : std_logic;
|
||||
signal DISK_SELECT : std_logic_vector(2 downto 0);
|
||||
signal DISK_BUSY : std_logic;
|
||||
signal DISK_SIDE : std_logic;
|
||||
signal DISK_DDEN : std_logic;
|
||||
signal DISK_NO : integer range 0 to 3;
|
||||
signal WD1793_INT : std_logic;
|
||||
signal Z80_NOT_DO : std_logic_vector(7 downto 0);
|
||||
signal Z80_NOT_DI : std_logic_vector(7 downto 0);
|
||||
signal WD1793_DI : std_logic_vector(7 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
WD1793: entity work.wd1793
|
||||
generic map (
|
||||
MAX_SECTOR_SIZE => 2048 -- Maximum sector size, used for sizing cache and signals.
|
||||
)
|
||||
port map (
|
||||
-- WD177X-00 CPU Interface
|
||||
CLK => CLKBUS(CKMASTER), -- System or FPGA clock.
|
||||
CLKEN => CLKBUS(CKENFDC), -- Clock enable running at original 8MHz FDC timing frequency.
|
||||
MRn => RSTn, -- Async reset
|
||||
CSn => WD1793_CSn, -- Device enable.
|
||||
RDn => Z80_RDn, -- I/O read
|
||||
WRn => Z80_WRn, -- I/O write
|
||||
ADDR => Z80_ADDR(1 downto 0), -- I/O port addr
|
||||
DIN => Z80_NOT_DO, -- I/O data in - note: inverted
|
||||
DOUT => WD1793_DI, -- I/O data out - note: inverted
|
||||
DRQ => DISK_DRQ, -- DMA request
|
||||
INTRQ => WD1793_INT, -- Interrupt request for data transfer or service.
|
||||
BUSY => DISK_BUSY, -- Controller busy with previous command.
|
||||
RDY => IOP_DISKREADY(DISK_NO), -- Disk loaded and ready.
|
||||
WPRT => IOP_WRPROTECT(DISK_NO), -- Write protect
|
||||
POLARITY => IOP_POLARITY(DISK_NO), -- Data in/out polarity, normal = 0, inverse = 1
|
||||
DDEN => DISK_DDEN, -- Double density enable flag.
|
||||
SIDE => DISK_SIDE, -- Disk side.
|
||||
|
||||
-- Disk parameters, valid and latched prior to a disk command.
|
||||
DISK_TYPE => IOP_TYPE(DISK_NO), -- Type of disk structure.
|
||||
|
||||
-- I/O Processor disk service interface.
|
||||
IOP_READY => IOP_READY, -- IO Processor ready to service floppy requests.
|
||||
IOP_SECTOR_REQ => IOP_SECTOR_REQ, -- Request for I/O processor for a sector.
|
||||
IOP_SECTOR_DIR => IOP_SECTOR_DIR, -- Direction of sector, 0 = sector is written into cache (IOP->WD1793), 1 = sector is read from cache (WD1793->IOP).
|
||||
IOP_SECTOR_NO => IOP_SECTOR, -- Sector number required.
|
||||
IOP_TRACK_NO => IOP_TRACK, -- Track number of required sector.
|
||||
IOP_SIDE => IOP_SIDE, -- Disk side of required sector.
|
||||
|
||||
-- I/O Processor interface.
|
||||
IOP_CSn => IOP_WD1793_CSn, -- Chip select from the I/O Processor decoding.
|
||||
IOP_WRn => IOP_WRn, -- Write Enable.
|
||||
IOP_RDn => IOP_RDn, -- Read Enable.
|
||||
IOP_ADDR => IOP_ADDR(11 downto 0), -- Address bus, width of sector cache + internal register access addresses.
|
||||
IOP_DOUT => IOP_DOUT, -- Data into the WD1793 unit.
|
||||
IOP_DIN => IOP_WD1793_DIN -- Data out from the WD1793 unit.
|
||||
);
|
||||
|
||||
|
||||
-- Sharp used the MB8866 IC which had negated data input/output. The WD177X uses standard data in/out. Thus we need to invert prior to application.
|
||||
Z80_NOT_DI <= not(WD1793_DI);
|
||||
Z80_NOT_DO <= not(Z80_DO);
|
||||
Z80_DI <= Z80_NOT_DI;
|
||||
|
||||
IOP_DIN <= IOP_WD1793_DIN when IOP_WD1793_CSn = '0'
|
||||
else
|
||||
-- IOP Control register, used to service an interrupt request.
|
||||
DISK_SELECT & IOP_INTn & IOP_READY & IOP_SIDE & IOP_SERVICE_REQ & IOP_SECTOR_DIR when IOP_CTRL_CSn = '0'
|
||||
else
|
||||
-- Sector number register, indicates the current sector being serviced by the WD1793 controller.
|
||||
IOP_SECTOR when IOP_SECTOR_CSn = '0'
|
||||
else
|
||||
-- Track number register, indicates the current track being serviced by the WD1793 controller.
|
||||
IOP_TRACK when IOP_TRACK_CSn = '0'
|
||||
else
|
||||
-- Floppy disk controller (this module) state signals.
|
||||
'0' & DISK_BUSY & DISK_DRQ & DISK_MOTORON & DISK_DDEN & DISK_SELECT when IOP_FDC_CSn = '0'
|
||||
else
|
||||
IOP_TYPE(IOP_DIN_DISKNO) & "00" & IOP_POLARITY(IOP_DIN_DISKNO) & IOP_WRPROTECT(IOP_DIN_DISKNO) when IOP_CSn = '0' and IOP_ADDR(12) = '1' and IOP_ADDR(3) = '0'
|
||||
else
|
||||
std_logic_vector(IOP_INTR_CNT) when IOP_CSn = '0' and IOP_ADDR(12) = '1' and IOP_ADDR(3 downto 0) = "1000"
|
||||
else (others => '0');
|
||||
IOP_DIN_DISKNO <= to_integer(unsigned(IOP_ADDR(1 downto 0)));
|
||||
|
||||
-- Sub divide the chip select to finer granularity. The lower 2K accesses the WD1793 sector cache.
|
||||
IOP_WD1793_CSn <= '0' when IOP_CSn = '0' and IOP_ADDR(12) = '0'
|
||||
else '1';
|
||||
IOP_CTRL_CSn <= '0' when IOP_CSn = '0' and IOP_ADDR(12) = '1' and IOP_ADDR(2 downto 0) = "000"
|
||||
else '1';
|
||||
IOP_TRACK_CSn <= '0' when IOP_CSn = '0' and IOP_ADDR(12) = '1' and IOP_ADDR(2 downto 0) = "001"
|
||||
else '1';
|
||||
IOP_SECTOR_CSn <= '0' when IOP_CSn = '0' and IOP_ADDR(12) = '1' and IOP_ADDR(2 downto 0) = "010"
|
||||
else '1';
|
||||
IOP_FDC_CSn <= '0' when IOP_CSn = '0' and IOP_ADDR(12) = '1' and IOP_ADDR(2 downto 0) = "011"
|
||||
else '1';
|
||||
|
||||
-- WD1773 Chip Select.
|
||||
WD1793_CSn <= '0' when FDD_CSn = '0' and Z80_ADDR(2) = '0'
|
||||
else '1';
|
||||
-- 0xDC Drive Select.
|
||||
DRIVESEL_CSn <= '0' when FDD_CSn = '0' and Z80_ADDR(2 downto 0) = "100"
|
||||
else '1';
|
||||
-- 0xDD Head Select (Side).
|
||||
SIDESEL_CSn <= '0' when FDD_CSn = '0' and Z80_ADDR(2 downto 0) = "101"
|
||||
else '1';
|
||||
-- 0xDE Double Density Select.
|
||||
DDENSEL_CSn <= '0' when FDD_CSn = '0' and Z80_ADDR(2 downto 0) = "110"
|
||||
else '1';
|
||||
|
||||
Z80_INTn <= not WD1793_INT;
|
||||
|
||||
-- Process to latch I/O processor data for presentation to the WD1793.
|
||||
process(CLKBUS, RSTn, CONFIG)
|
||||
variable IOP_WR_LASTn : std_logic_vector(1 downto 0);
|
||||
begin
|
||||
if RSTn = '0' then
|
||||
IOP_WRPROTECT <= (others => '0');
|
||||
IOP_POLARITY <= (others => '0');
|
||||
IOP_TYPE <= (others => (others => '0'));
|
||||
IOP_READY <= '0';
|
||||
IOP_WR_LASTn := "11";
|
||||
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
|
||||
-- Write on edge detection.
|
||||
if IOP_CTRL_CSn = '0' and IOP_WR_LASTn = "00" and IOP_WRn = '0' then
|
||||
IOP_READY <= IOP_DOUT(0);
|
||||
ADD ERROR FLAGS HERE FOR TRACK AND SECTOR OUT OF BOUNDS
|
||||
end if;
|
||||
|
||||
-- Disk parameters and control signals.
|
||||
-- Disk type.
|
||||
IOP_TYPE(0) <= CONFIG(FDDTYPE_0);
|
||||
IOP_TYPE(1) <= CONFIG(FDDTYPE_1);
|
||||
IOP_TYPE(2) <= CONFIG(FDDTYPE_2);
|
||||
IOP_TYPE(3) <= CONFIG(FDDTYPE_3);
|
||||
|
||||
-- Disk loaded and ready (0 = No Disk, 1 = Disk loaded).
|
||||
IOP_DISKREADY(0) <= CONFIG(FDDDISKREADY_0);
|
||||
IOP_DISKREADY(1) <= CONFIG(FDDDISKREADY_1);
|
||||
IOP_DISKREADY(2) <= CONFIG(FDDDISKREADY_2);
|
||||
IOP_DISKREADY(3) <= CONFIG(FDDDISKREADY_3);
|
||||
|
||||
-- Polarity (0 = Normal, 1 = Inverted)
|
||||
IOP_POLARITY(0) <= CONFIG(FDDPOLARITY_0);
|
||||
IOP_POLARITY(1) <= CONFIG(FDDPOLARITY_1);
|
||||
IOP_POLARITY(2) <= CONFIG(FDDPOLARITY_2);
|
||||
IOP_POLARITY(3) <= CONFIG(FDDPOLARITY_3);
|
||||
|
||||
-- Monitor the write protect flags.
|
||||
-- Write protect (1 = write protected, 0 = read/write).
|
||||
IOP_WRPROTECT(0) <= CONFIG(FDDWRPROTECT_0);
|
||||
IOP_WRPROTECT(1) <= CONFIG(FDDWRPROTECT_1);
|
||||
IOP_WRPROTECT(2) <= CONFIG(FDDWRPROTECT_2);
|
||||
IOP_WRPROTECT(3) <= CONFIG(FDDWRPROTECT_3);
|
||||
|
||||
-- Edge record.
|
||||
IOP_WR_LASTn := IOP_WR_LASTn(0) & IOP_WRn;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Process to detect a WD1793 service request and raise an interrupt on the I/O processor.
|
||||
process(CLKBUS, RSTn, CONFIG)
|
||||
variable IOP_SR_LAST : std_logic;
|
||||
variable IOP_RD_LAST : std_logic_vector(1 downto 0);
|
||||
begin
|
||||
if RSTn = '0' then
|
||||
IOP_INTn <= '1';
|
||||
IOP_SERVICE_REQ <= '0';
|
||||
IOP_SR_LAST := '1';
|
||||
IOP_RD_LAST := "11";
|
||||
IOP_INTR_CNT <= (others => '0');
|
||||
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
-- Interrupt is only 1 clock cycle wide.
|
||||
IOP_INTn <= '1';
|
||||
|
||||
-- If the service request goes active, raise an interrupt.
|
||||
if IOP_SR_LAST = '0' and IOP_SECTOR_REQ = '1' then
|
||||
IOP_INTn <= '0';
|
||||
IOP_INTR_CNT <= IOP_INTR_CNT + 1;
|
||||
IOP_SERVICE_REQ <= '1';
|
||||
end if;
|
||||
|
||||
-- Service request flag is cleared once the register is read.
|
||||
if IOP_RD_LAST = "00" and IOP_RDn = '1' then
|
||||
IOP_SERVICE_REQ <= '0';
|
||||
end if;
|
||||
|
||||
-- Edge detection.
|
||||
IOP_SR_LAST := IOP_SECTOR_REQ;
|
||||
IOP_RD_LAST := IOP_RD_LAST(0) & (IOP_RDn or IOP_CTRL_CSn);
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Process to latch the disk control signals from the host.
|
||||
process(CLKBUS, RSTn, CONFIG)
|
||||
variable Z80_WR_LASTn : std_logic_vector(1 downto 0);
|
||||
begin
|
||||
if RSTn = '0' then
|
||||
DISK_SELECT <= "100";
|
||||
DISK_NO <= 0;
|
||||
DISK_MOTORON <= '0';
|
||||
DISK_SIDE <= '0';
|
||||
DISK_DDEN <= '1';
|
||||
Z80_WR_LASTn := "00";
|
||||
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
|
||||
-- Write edge detect.
|
||||
if Z80_WR_LASTn = "11" and Z80_WRn = '0' then
|
||||
|
||||
-- Drive Select. 2:0 - DS0 = 100, DS1 = 101, DS2 = 110, DS3 = 111
|
||||
-- Motor Select. 7 - Active low at physical interface, active high in this module.
|
||||
if DRIVESEL_CSn = '0' then
|
||||
DISK_SELECT <= Z80_DO(2 downto 0);
|
||||
DISK_MOTORON <= Z80_DO(7);
|
||||
end if;
|
||||
-- Side Select. 0 : 0 = Side 1, 1 = Side 0.
|
||||
if SIDESEL_CSn = '0' then
|
||||
DISK_SIDE <= Z80_DO(0);
|
||||
end if;
|
||||
-- Double Density Enable. 0 = Double Density Enabled, 1 = Single Density.
|
||||
if DDENSEL_CSn = '0' then
|
||||
DISK_DDEN <= Z80_NOT_DO(0);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Edge record.
|
||||
Z80_WR_LASTn := Z80_WR_LASTn(0) & Z80_WRn;
|
||||
|
||||
-- Ease of use disk number.
|
||||
DISK_NO <= to_integer(unsigned(DISK_SELECT(1 downto 0)));
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end RTL;
|
||||
@@ -69,6 +69,7 @@ entity iointr is
|
||||
INTR_DOUT : out std_logic_vector(7 downto 0);
|
||||
INTR_DIN : in std_logic_vector(7 downto 0);
|
||||
INTR_INIT_HW : in std_logic;
|
||||
INTR_INIT_DONEn : out std_logic;
|
||||
|
||||
-- Arbiter control signals
|
||||
INTR_GRANTn : in std_logic;
|
||||
@@ -104,16 +105,19 @@ architecture RTL of iointr is
|
||||
-- Interrupt control signals.
|
||||
signal IR_STATE : IntrStateType;
|
||||
signal ISR_FIFO : isrArray;
|
||||
signal ISR : std_logic_vector(7 downto 0);
|
||||
signal ISR_LAST : std_logic_vector(7 downto 0);
|
||||
signal ISR_RD_DATA : std_logic_vector(7 downto 0);
|
||||
signal ISR_DATA : std_logic_vector(7 downto 0);
|
||||
signal ISR : std_logic_vector( 7 downto 0);
|
||||
signal ISR_LAST : std_logic_vector( 7 downto 0);
|
||||
signal ISR_RD_DATA : std_logic_vector( 7 downto 0);
|
||||
signal ISR_DATA : std_logic_vector( 7 downto 0);
|
||||
signal ISR_FIFO_WEN : std_logic;
|
||||
signal ISR_FIFO_RD : natural range 0 to CACHE_SIZE;
|
||||
signal ISR_FIFO_RD_ADDR : natural range 0 to CACHE_SIZE;
|
||||
signal ISR_FIFO_WR : natural range 0 to CACHE_SIZE;
|
||||
signal IOP_RD_LASTn : std_logic_vector(1 downto 0);
|
||||
signal ISR_FIFO_TIMER : unsigned(15 downto 0);
|
||||
signal ISR_CNT : unsigned(18 downto 0);
|
||||
signal ISR_INTR_XMIT_CNT : unsigned( 7 downto 0);
|
||||
signal ISR_INTR_RCV_CNT : unsigned( 7 downto 0);
|
||||
|
||||
-- Mainboard writeback multiplexing signals.
|
||||
signal INTR_RDni : std_logic;
|
||||
@@ -122,6 +126,7 @@ architecture RTL of iointr is
|
||||
signal INTR_IORQni : std_logic;
|
||||
signal INTR_M1ni : std_logic;
|
||||
signal INTR_BUSYni : std_logic;
|
||||
signal INTR_INITi : std_logic;
|
||||
begin
|
||||
|
||||
-- Assign registers to the output data bus to be read by the I/O processor.
|
||||
@@ -131,6 +136,10 @@ begin
|
||||
else
|
||||
std_logic_vector(to_unsigned(ISR_FIFO_RD, 8)) when IOP_ADDR = "0010"
|
||||
else
|
||||
std_logic_vector(ISR_INTR_XMIT_CNT) when IOP_ADDR = "0011"
|
||||
else
|
||||
std_logic_vector(ISR_INTR_RCV_CNT) when IOP_ADDR = "0100"
|
||||
else
|
||||
ISR_DATA when IOP_ADDR(3) = '1'
|
||||
else (others => '1');
|
||||
|
||||
@@ -142,17 +151,15 @@ begin
|
||||
ISR_FIFO_WEN <= '0';
|
||||
ISR <= (others => '0');
|
||||
ISR_LAST <= (others => '0');
|
||||
ISR_FIFO_TIMER <= (others => '0');
|
||||
ISR_INTR_RCV_CNT <= (others => '0');
|
||||
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
|
||||
-- Detect interrupt edge as trigger.
|
||||
ISR_LAST <= INTR7n & INTR6n & INTR5n & INTR4n &INTR3n & INTR2n & INTR1n & INTR0n;
|
||||
ISR <= (others => '0');
|
||||
ISR_LAST <= INTR7n & INTR6n & INTR5n & INTR4n & INTR3n & INTR2n & INTR1n & INTR0n;
|
||||
IOP_RD_LASTn <= IOP_RD_LASTn(IOP_RD_LASTn'length-2 downto 0) & IOP_RDn;
|
||||
|
||||
-- Write signal to block RAM is only 1 clock wide.
|
||||
ISR_FIFO_WEN <= '0';
|
||||
|
||||
-- Detect the interrupt edge and trigger an interrupt.
|
||||
if INTR0n = '0' and ISR_LAST(0) = '1' then
|
||||
ISR(0) <= '1';
|
||||
@@ -162,7 +169,7 @@ begin
|
||||
ISR(1) <= '1';
|
||||
ISR_FIFO_WEN <= '1';
|
||||
end if;
|
||||
if INTR2n = '0' and ISR_LAST(2) = '1' then
|
||||
if INTR2n = '0' and ISR_LAST(2) = '0' then
|
||||
ISR(2) <= '1';
|
||||
ISR_FIFO_WEN <= '1';
|
||||
end if;
|
||||
@@ -187,11 +194,10 @@ begin
|
||||
ISR_FIFO_WEN <= '1';
|
||||
end if;
|
||||
|
||||
-- Save any detected interrupts in the FIFO cache. Cache is used as the speed from interrupt to I/O processor being interrupted can be many cycles
|
||||
-- so potential exists for missing an interrupt.
|
||||
if ISR_FIFO_WEN = '1' then
|
||||
ISR_FIFO(ISR_FIFO_WR) <= ISR;
|
||||
ISR_FIFO_WR <= ISR_FIFO_WR + 1;
|
||||
-- A timer used to merge interrupt requests. When not zero, any incoming interrupts will be merged if the
|
||||
-- queue > 0.
|
||||
if ISR_FIFO_TIMER /= 0 then
|
||||
ISR_FIFO_TIMER <= ISR_FIFO_TIMER - 1;
|
||||
end if;
|
||||
|
||||
-- Setup the FIFO read address, needs to be stable 1 clock prior to data read.
|
||||
@@ -206,9 +212,26 @@ begin
|
||||
if ISR_FIFO_RD /= ISR_FIFO_WR then
|
||||
ISR_DATA <= ISR_FIFO(ISR_FIFO_RD_ADDR);
|
||||
ISR_FIFO_RD <= ISR_FIFO_RD+1;
|
||||
ISR_FIFO_TIMER <= (others => '0');
|
||||
else
|
||||
ISR_DATA <= (others => '0');
|
||||
end if;
|
||||
|
||||
-- Save any detected interrupts in the FIFO cache. Cache is used as the speed from interrupt to I/O processor being interrupted can be many cycles
|
||||
-- so potential exists for missing an interrupt.
|
||||
elsif ISR_FIFO_WEN = '1' then
|
||||
-- Merge interrupts where possible as the I/O processor will process them in one interrupt request.
|
||||
if ISR_FIFO_WR /= ISR_FIFO_RD and ISR_FIFO_TIMER /= 0 then
|
||||
ISR_FIFO(ISR_FIFO_WR-1) <= ISR_FIFO(ISR_FIFO_WR-1) or ISR;
|
||||
else
|
||||
ISR_FIFO(ISR_FIFO_WR) <= ISR;
|
||||
ISR_FIFO_WR <= ISR_FIFO_WR + 1;
|
||||
ISR_FIFO_TIMER <= (others => '1');
|
||||
end if;
|
||||
ISR_FIFO_WEN <= '0';
|
||||
ISR <= (others => '0');
|
||||
ISR_INTR_RCV_CNT <= ISR_INTR_RCV_CNT + 1;
|
||||
|
||||
-- I/O processor debug read, view the past cache contents.
|
||||
elsif IOP_CSn = '0' and IOP_RDn = '0' and IOP_RD_LASTn = "10" and IOP_ADDR(3) = '1' then
|
||||
ISR_DATA <= ISR_FIFO(ISR_FIFO_RD_ADDR);
|
||||
@@ -233,6 +256,8 @@ begin
|
||||
INTR_RDni <= '1';
|
||||
INTR_M1ni <= '1';
|
||||
INTR_BUSYni <= '1';
|
||||
INTR_INITi <= INTR_INIT_HW;
|
||||
ISR_INTR_XMIT_CNT <= (others => '0');
|
||||
ISR_CNT <= (others => '0');
|
||||
|
||||
elsif rising_edge(CLKBUS(CKHOST)) then
|
||||
@@ -280,6 +305,7 @@ begin
|
||||
IR_STATE <= State_Stage2;
|
||||
|
||||
when State_Stage2 =>
|
||||
ISR_INTR_XMIT_CNT <= ISR_INTR_XMIT_CNT + 1;
|
||||
INTR_BUSYni <= '1';
|
||||
IR_STATE <= State_Idle;
|
||||
|
||||
@@ -296,5 +322,6 @@ begin
|
||||
INTR_IORQn <= INTR_IORQni;
|
||||
INTR_M1n <= INTR_M1ni;
|
||||
INTR_BUSYn <= INTR_BUSYni;
|
||||
INTR_INIT_DONEn <= INTR_INITi;
|
||||
|
||||
end RTL;
|
||||
|
||||
@@ -70,6 +70,7 @@ entity keymatrix_mz700 is
|
||||
KEYB_DOUT : out std_logic_vector(7 downto 0);
|
||||
KEYB_DIN : in std_logic_vector(7 downto 0);
|
||||
KEYB_INIT_HW : in std_logic;
|
||||
KEYB_INIT_DONEn : out std_logic;
|
||||
KEYB_INTRn : out std_logic;
|
||||
|
||||
-- Arbiter control signals
|
||||
@@ -495,6 +496,23 @@ begin
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Configurable delay, a tick by tick timer and a millisecond timer, halts all actions whilst the timer > 0.
|
||||
if MB_DELAY_TICKS /= 0 or MB_DELAY_MS /= 0 or MB_DELAY_SEC /= 0 then
|
||||
|
||||
if MB_DELAY_TICKS = 0 and MB_DELAY_MS = 0 and MB_DELAY_SEC /= 0 then
|
||||
MB_DELAY_TICKS <= X"DFC"; -- 1ms with a 3.58MHz clock (the base clock of the underlying hardware).
|
||||
MB_DELAY_MS <= X"3E7"; -- 999ms.
|
||||
MB_DELAY_SEC <= MB_DELAY_SEC - 1; -- Decrement second counter.
|
||||
|
||||
elsif MB_DELAY_TICKS = 0 and MB_DELAY_MS /= 0 then
|
||||
MB_DELAY_TICKS <= X"DFC"; -- 1ms with a 3.58MHz clock (the base clock of the underlying hardware).
|
||||
MB_DELAY_MS <= MB_DELAY_MS - 1;
|
||||
|
||||
else
|
||||
MB_DELAY_TICKS <= MB_DELAY_TICKS - 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Normal run mode we periodically scan the key matrix or on host activity, scan on demand.
|
||||
-- If a reset has occurred, the underlying hardware needs to be programmed before it can be used.
|
||||
--
|
||||
@@ -651,23 +669,6 @@ begin
|
||||
-- array (matrix) lookup table. The lookup table is then used to map the physical key pressed to the emulation keyboard
|
||||
-- matrix where the emulation would expect it.
|
||||
|
||||
-- Configurable delay, a tick by tick timer and a millisecond timer, halts all actions whilst the timer > 0.
|
||||
if MB_DELAY_TICKS /= 0 or MB_DELAY_MS /= 0 or MB_DELAY_SEC /= 0 then
|
||||
|
||||
if MB_DELAY_TICKS = 0 and MB_DELAY_MS = 0 and MB_DELAY_SEC /= 0 then
|
||||
MB_DELAY_TICKS <= X"DFC"; -- 1ms with a 3.58MHz clock (the base clock of the underlying hardware).
|
||||
MB_DELAY_MS <= X"3E7"; -- 999ms.
|
||||
MB_DELAY_SEC <= MB_DELAY_SEC - 1; -- Decrement second counter.
|
||||
|
||||
elsif MB_DELAY_TICKS = 0 and MB_DELAY_MS /= 0 then
|
||||
MB_DELAY_TICKS <= X"DFC"; -- 1ms with a 3.58MHz clock (the base clock of the underlying hardware).
|
||||
MB_DELAY_MS <= MB_DELAY_MS - 1;
|
||||
|
||||
else
|
||||
MB_DELAY_TICKS <= MB_DELAY_TICKS - 1;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- If the CMT (hardware unit) is active, only scan the break key row.
|
||||
--
|
||||
if CONFIG(CMT_HWMODE) = '1' and CMT_ACTIVE = '1' and MB_STATE = 0 then
|
||||
@@ -807,7 +808,7 @@ begin
|
||||
elsif KEYB_INITi = '1' then
|
||||
|
||||
-- Ensure we have access to the bus before commencing the FSM.
|
||||
if KEYB_GRANTn = '0' or MB_STATE /= 0 then
|
||||
if MB_DELAY_TICKS = 0 and MB_DELAY_MS = 0 and MB_DELAY_SEC = 0 and (KEYB_GRANTn = '0' or MB_STATE /= 0) then
|
||||
|
||||
-- Move along the state machine, next state can be overriden if required.
|
||||
--
|
||||
@@ -815,14 +816,18 @@ begin
|
||||
|
||||
-- FSM.
|
||||
case MB_STATE is
|
||||
-- Start up delay allowing reset to settle and host mainboard to initialise.
|
||||
when 0 =>
|
||||
MB_DELAY_MS <= X"0FA";
|
||||
|
||||
when 1 =>
|
||||
KEYB_MREQni <= '0'; -- Special signal combination to set CPLD into TZPU Mainboard Access Mode.
|
||||
KEYB_IORQni <= '0';
|
||||
KEYB_M1ni <= '1';
|
||||
KEYB_DOUT <= X"80";
|
||||
KEYB_BUSYni <= '0';
|
||||
|
||||
when 1 =>
|
||||
when 2 =>
|
||||
KEYB_MREQni <= '1';
|
||||
KEYB_IORQni <= '1';
|
||||
KEYB_M1ni <= '1';
|
||||
@@ -844,16 +849,16 @@ begin
|
||||
KEYB_MREQni <= '0';
|
||||
|
||||
-- Allow at least 1 cycle for the write pulse.
|
||||
when 2 =>
|
||||
when 3 =>
|
||||
KEYB_WRni <= '0';
|
||||
|
||||
-- Terminate write pulse.
|
||||
when 3 =>
|
||||
when 4 =>
|
||||
KEYB_MREQni <= '1';
|
||||
KEYB_WRni <= '1';
|
||||
|
||||
-- After writing a config byte, check if more needed, otherwise exit clearing INIT flag.
|
||||
when 4 =>
|
||||
when 5 =>
|
||||
if KEYB_CFG_BYTE = 4 then
|
||||
KEYB_INITi <= '0';
|
||||
KEYB_BUSYni <= '1';
|
||||
@@ -984,5 +989,6 @@ begin
|
||||
KEYB_M1n <= KEYB_M1ni;
|
||||
KEYB_BUSYn <= KEYB_BUSYni;
|
||||
KEYB_INTRn <= KEYB_INTRni;
|
||||
KEYB_INIT_DONEn <= KEYB_INITi;
|
||||
|
||||
end Behavioral;
|
||||
|
||||
@@ -48,7 +48,7 @@ package mctrl_pkg is
|
||||
|
||||
-- Config Bus
|
||||
--
|
||||
subtype CONFIG_WIDTH is integer range 90 downto 0;
|
||||
subtype CONFIG_WIDTH is integer range 106 downto 0;
|
||||
|
||||
|
||||
-- Mode signals indicating type of machine we are emulating.
|
||||
@@ -82,61 +82,85 @@ package mctrl_pkg is
|
||||
|
||||
-- Option Roms Enable (some machines by design dont have them, but this emulation allows them to be enabled if needed).
|
||||
--
|
||||
subtype USERROM is integer range 31 downto 24; -- User ROM E800 - EFFF enable per machine.
|
||||
subtype FDCROM is integer range 39 downto 32; -- FDC ROM F000 - FFFF enable per machine.
|
||||
constant USERROM : integer := 24; -- User ROM E800 - EFFF enable.
|
||||
constant FDCROM : integer := 25; -- FDC ROM F000 - FFFF enable.
|
||||
|
||||
-- Floppy drive/interface options.
|
||||
constant FDDENABLE : integer := 26; -- Enable the Floppy Disk Controller.
|
||||
constant FDDINTEN : integer := 27; -- Enable the interrupt request from the FDC controller (non standard).
|
||||
subtype FDDDISKREADY is integer range 31 downto 28; -- Drive data polarity.
|
||||
subtype FDDPOLARITY is integer range 35 downto 32; -- Drive data polarity.
|
||||
subtype FDDWRPROTECT is integer range 39 downto 36; -- Drive write protect/readonly.
|
||||
constant FDDDISKREADY_0 : integer := 28; -- Drive 0 disk loaded and drive ready.
|
||||
constant FDDDISKREADY_1 : integer := 29; -- Drive 1 disk loaded and drive ready.
|
||||
constant FDDDISKREADY_2 : integer := 30; -- Drive 2 disk loaded and drive ready.
|
||||
constant FDDDISKREADY_3 : integer := 31; -- Drive 3 disk loaded and drive ready.
|
||||
constant FDDPOLARITY_0 : integer := 32; -- Drive 0 data polarity.
|
||||
constant FDDPOLARITY_1 : integer := 33; -- Drive 1 data polarity.
|
||||
constant FDDPOLARITY_2 : integer := 34; -- Drive 2 data polarity.
|
||||
constant FDDPOLARITY_3 : integer := 35; -- Drive 3 data polarity.
|
||||
constant FDDWRPROTECT_0 : integer := 36; -- Drive 0 write protect/readonly.
|
||||
constant FDDWRPROTECT_1 : integer := 37; -- Drive 1 write protect/readonly.
|
||||
constant FDDWRPROTECT_2 : integer := 38; -- Drive 2 write protect/readonly.
|
||||
constant FDDWRPROTECT_3 : integer := 39; -- Drive 3 write protect/readonly.
|
||||
subtype FDDTYPE is integer range 55 downto 40; -- Disk type selection.
|
||||
subtype FDDTYPE_0 is integer range 43 downto 40; -- Drive 0 disk type setting.
|
||||
subtype FDDTYPE_1 is integer range 47 downto 44; -- Drive 1 disk type setting.
|
||||
subtype FDDTYPE_2 is integer range 51 downto 48; -- Drive 2 disk type setting.
|
||||
subtype FDDTYPE_3 is integer range 55 downto 52; -- Drive 3 disk type setting.
|
||||
|
||||
-- RAM options installed.
|
||||
subtype RAMINSTALLED is integer range 42 downto 40; -- RAM installed in machine.
|
||||
subtype GRAPHICSOPTION is integer range 50 downto 43; -- GRAM installed in machine.
|
||||
subtype RAMINSTALLED is integer range 58 downto 56; -- RAM installed in machine.
|
||||
subtype GRAPHICSOPTION is integer range 66 downto 59; -- GRAM installed in machine.
|
||||
|
||||
-- RAM options.
|
||||
constant OPT_MINRAM : std_logic_vector(2 downto 0) := "000"; -- Minimum RAM installed on machine.
|
||||
constant OPT_STDRAM : std_logic_vector(2 downto 0) := "001"; -- Standard (considered Normal, but upgraded for early machines) RAM installed on machine.
|
||||
|
||||
-- GRAM options.
|
||||
constant OPT_GRAMI : integer := 43; -- MZ80B GRAMI / MZ2000 GRAM BLUE installed.
|
||||
constant OPT_GRAMII : integer := 44; -- MZ80B GRAMII / MZ2000 GRAM RED installed.
|
||||
constant OPT_GRAMIII : integer := 45; -- MZ2000 GRAM GREEN installed.
|
||||
constant OPT_PCG : integer := 46; -- PCG installed.
|
||||
constant OPT_MZ1R25 : integer := 47; -- 16K Video RAM installed
|
||||
constant OPT_GRAMI : integer := 59; -- MZ80B GRAMI / MZ2000 GRAM BLUE installed.
|
||||
constant OPT_GRAMII : integer := 60; -- MZ80B GRAMII / MZ2000 GRAM RED installed.
|
||||
constant OPT_GRAMIII : integer := 61; -- MZ2000 GRAM GREEN installed.
|
||||
constant OPT_PCG : integer := 62; -- PCG installed.
|
||||
constant OPT_MZ1R25 : integer := 63; -- 16K Video RAM installed
|
||||
|
||||
-- Various configurable settings.
|
||||
--
|
||||
constant AUDIOSRC : integer := 51; -- Audio source, 0 = sound generator, 1 = tape audio.
|
||||
subtype AUDIOVOL is integer range 55 downto 52; -- Audio volume, 3:0 = 16 level volume.
|
||||
subtype AUDIOMIX is integer range 57 downto 56; -- Audio mixer, blend left and right channels.
|
||||
constant AUDIOHW : integer := 58; -- Audio hardware to use, host or fpga.
|
||||
subtype TURBO is integer range 61 downto 59; -- 2MHz/4MHz/8MHz/16MHz/32MHz switch (various).
|
||||
subtype FASTTAPE is integer range 64 downto 62; -- Speed of tape read/write.
|
||||
subtype BUTTONS is integer range 66 downto 65; -- Various external buttons, such as CMT play/record.
|
||||
constant PCGRAM : integer := 67; -- PCG ROM(0) or RAM(1) based.
|
||||
constant VRAMWAIT : integer := 68; -- Insert video wait states on CPU access as per original design.
|
||||
constant VRAMDISABLE : integer := 69; -- Disable the Video RAM from display output.
|
||||
constant GRAMDISABLE : integer := 70; -- Disable the graphics RAM from display output.
|
||||
constant MENUENABLE : integer := 71; -- Enable the OSD menu on display output.
|
||||
constant STATUSENABLE : integer := 72; -- Enable the OSD menu on display output.
|
||||
constant BOOT_RESET : integer := 73; -- MZ80B/2000 Boot IPL Reset Enable.
|
||||
constant CMTASCII_IN : integer := 74; -- Enable CMT conversion of Sharp Ascii <-> Ascii on receipt of data from Sharp.
|
||||
constant CMTASCII_OUT : integer := 75; -- Enable CMT conversion of Sharp Ascii <-> Ascii on sending data to Sharp.
|
||||
constant CMT_HWMODE : integer := 76; -- Select the hardware CMT drive (1) or the emulation (0).
|
||||
subtype MZ800_SWITCH is integer range 80 downto 77; -- MZ800 Hardware selection switch bank.
|
||||
constant AUDIOSRC : integer := 67; -- Audio source, 0 = sound generator, 1 = tape audio.
|
||||
subtype AUDIOVOL is integer range 71 downto 68; -- Audio volume, 3:0 = 16 level volume.
|
||||
subtype AUDIOMIX is integer range 73 downto 72; -- Audio mixer, blend left and right channels.
|
||||
constant AUDIOHW : integer := 74; -- Audio hardware to use, host or fpga.
|
||||
subtype TURBO is integer range 77 downto 75; -- 2MHz/4MHz/8MHz/16MHz/32MHz switch (various).
|
||||
subtype FASTTAPE is integer range 80 downto 81; -- Speed of tape read/write.
|
||||
subtype BUTTONS is integer range 82 downto 81; -- Various external buttons, such as CMT play/record.
|
||||
constant PCGRAM : integer := 83; -- PCG ROM(0) or RAM(1) based.
|
||||
constant VRAMWAIT : integer := 84; -- Insert video wait states on CPU access as per original design.
|
||||
constant VRAMDISABLE : integer := 85; -- Disable the Video RAM from display output.
|
||||
constant GRAMDISABLE : integer := 86; -- Disable the graphics RAM from display output.
|
||||
constant MENUENABLE : integer := 87; -- Enable the OSD menu on display output.
|
||||
constant STATUSENABLE : integer := 88; -- Enable the OSD menu on display output.
|
||||
constant BOOT_RESET : integer := 89; -- MZ80B/2000 Boot IPL Reset Enable.
|
||||
constant CMTASCII_IN : integer := 90; -- Enable CMT conversion of Sharp Ascii <-> Ascii on receipt of data from Sharp.
|
||||
constant CMTASCII_OUT : integer := 91; -- Enable CMT conversion of Sharp Ascii <-> Ascii on sending data to Sharp.
|
||||
constant CMT_HWMODE : integer := 92; -- Select the hardware CMT drive (1) or the emulation (0).
|
||||
subtype MZ800_SWITCH is integer range 96 downto 93; -- MZ800 Hardware selection switch bank.
|
||||
|
||||
-- MZ-800 Switches.
|
||||
constant SWITCH_MZ800 : integer := 77; -- Machine set to MZ800 mode.
|
||||
constant SWITCH_PRINTER1 : integer := 78; -- MZ/Centronics Printer.
|
||||
constant SWITCH_PRINTER2 : integer := 79; -- MZ/Centronics Printer.
|
||||
constant SWITCH_TAPEIN : integer := 80; -- Enable external data recorder input.
|
||||
constant SWITCH_MZ800 : integer := 93; -- Machine set to MZ800 mode.
|
||||
constant SWITCH_PRINTER1 : integer := 94; -- MZ/Centronics Printer.
|
||||
constant SWITCH_PRINTER2 : integer := 95; -- MZ/Centronics Printer.
|
||||
constant SWITCH_TAPEIN : integer := 96; -- Enable external data recorder input.
|
||||
|
||||
-- Derivative settings to program the clock generator.
|
||||
--
|
||||
subtype CPUSPEED is integer range 84 downto 81; -- Active CPU Speed.
|
||||
subtype PERSPEED is integer range 86 downto 85; -- Active Peripheral Speed.
|
||||
subtype RTCSPEED is integer range 88 downto 87; -- Active RTC Speed.
|
||||
subtype SNDSPEED is integer range 90 downto 89; -- Active Sound Speed.
|
||||
subtype CPUSPEED is integer range 100 downto 97; -- Active CPU Speed.
|
||||
subtype PERSPEED is integer range 102 downto 101; -- Active Peripheral Speed.
|
||||
subtype RTCSPEED is integer range 104 downto 103; -- Active RTC Speed.
|
||||
subtype SNDSPEED is integer range 106 downto 105; -- Active Sound Speed.
|
||||
|
||||
-- CMT Bus
|
||||
--
|
||||
subtype CMT_BUS_OUT_WIDTH is integer range 14 downto 0;
|
||||
subtype CMT_BUS_OUT_WIDTH is integer range 16 downto 0;
|
||||
subtype CMT_BUS_IN_WIDTH is integer range 12 downto 0;
|
||||
|
||||
-- CMT exported Signals.
|
||||
@@ -155,7 +179,9 @@ package mctrl_pkg is
|
||||
constant APSS_EJECT : integer := 11; -- Eject cassette.
|
||||
constant APSS_PLAY : integer := 12; -- Play cassette.
|
||||
constant APSS_STOP : integer := 13; -- Stop playing/rwd/ff of cassette.
|
||||
constant ENDOFTAPE : integer := 14; -- End of tape detected.
|
||||
constant APSS_AUTOREW : integer := 14; -- Deck set to auto rewind at tape end.
|
||||
constant APSS_AUTOPLAY : integer := 15; -- Deck set to auto play after APSS action.
|
||||
constant ENDOFTAPE : integer := 16; -- End of tape detected.
|
||||
|
||||
-- CMT imported Signals.
|
||||
--
|
||||
@@ -220,28 +246,29 @@ signal REGISTER_AUDIO : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_CMT : std_logic_vector(7 downto 0) := "00011000";
|
||||
signal REGISTER_CMT2 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_CMT3 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_USERROM : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_FDCROM : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_FDD : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_FDD2 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_FDD3 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_FDD4 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_ROMS : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_SWITCHES : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_12 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_13 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_14 : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal REGISTER_CTRL : std_logic_vector(7 downto 0) := "00000000";
|
||||
signal delay : integer range 0 to 63;
|
||||
signal READ_STATUS : std_logic_vector(15 downto 0);
|
||||
signal RESET_MACHINEni : std_logic;
|
||||
signal RESET_MACHINE_TIMER : unsigned(2 downto 0);
|
||||
signal CMT_BUS_OUT_LAST : std_logic_vector(CMT_BUS_OUT_WIDTH);
|
||||
signal CONFIG_LAST : std_logic_vector(CONFIG_WIDTH);
|
||||
|
||||
begin
|
||||
-- Synchronise the register update with the configuration signals according to the CPU clock.
|
||||
--
|
||||
process (RESETn, CLKBUS(CKMASTER), RESET_MACHINEni)
|
||||
process (RESETn, CLKBUS, RESET_MACHINEni, IOP_CSn, IOP_WRn)
|
||||
begin
|
||||
if RESETn = '0' then
|
||||
CONFIG(CONFIG_WIDTH) <= "0000000000000000000000000000000000000000000000000001100000000000000000000011001000000001000";
|
||||
CONFIG(CONFIG_WIDTH) <= "00000000000000000000000000000000000000000000000000000000000000000001100000000000000000000011001000000001000";
|
||||
|
||||
elsif CLKBUS(CKMASTER)'event and CLKBUS(CKMASTER)='1' then
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
|
||||
@@ -453,14 +480,22 @@ begin
|
||||
-- Setup RTC clock frequency dependent upon model, same with sound and peripheral speed..
|
||||
-- Setup the peripheral speed.
|
||||
case REGISTER_MODEL(3 downto 0) is
|
||||
-- MZ80K MZ80C MZ1200 MZ80A
|
||||
when "0000" | "0001" | "0010" | "0011" =>
|
||||
CONFIG(RTCSPEED) <= "00";
|
||||
CONFIG(SNDSPEED) <= "00";
|
||||
CONFIG(PERSPEED) <= "00";
|
||||
when "0100" | "0101" | "0110" =>
|
||||
-- MZ700 MZ1500
|
||||
when "0100" | "0110" =>
|
||||
CONFIG(RTCSPEED) <= "10";
|
||||
CONFIG(SNDSPEED) <= "00";
|
||||
CONFIG(SNDSPEED) <= "01";
|
||||
CONFIG(PERSPEED) <= "00";
|
||||
-- MZ800
|
||||
when "0101" =>
|
||||
CONFIG(RTCSPEED) <= "10";
|
||||
CONFIG(SNDSPEED) <= "10";
|
||||
CONFIG(PERSPEED) <= "01";
|
||||
-- MZ80B MZ2000 MZ2200 MZ2500
|
||||
when "0111" | "1000" | "1001" | "1010" =>
|
||||
CONFIG(RTCSPEED) <= "01";
|
||||
CONFIG(SNDSPEED) <= "01";
|
||||
@@ -495,8 +530,14 @@ begin
|
||||
CONFIG(AUDIOVOL) <= REGISTER_AUDIO(4 downto 1);
|
||||
CONFIG(AUDIOMIX) <= REGISTER_AUDIO(6 downto 5);
|
||||
CONFIG(AUDIOHW) <= REGISTER_AUDIO(7);
|
||||
CONFIG(USERROM) <= REGISTER_USERROM;
|
||||
CONFIG(FDCROM) <= REGISTER_FDCROM;
|
||||
CONFIG(USERROM) <= REGISTER_ROMS(0);
|
||||
CONFIG(FDCROM) <= REGISTER_ROMS(1);
|
||||
CONFIG(FDDENABLE) <= REGISTER_FDD(0);
|
||||
CONFIG(FDDINTEN) <= REGISTER_FDD(1);
|
||||
CONFIG(FDDDISKREADY) <= REGISTER_FDD(7 downto 4);
|
||||
CONFIG(FDDPOLARITY) <= REGISTER_FDD4(6) & REGISTER_FDD4(4) & REGISTER_FDD4(2) & REGISTER_FDD4(0);
|
||||
CONFIG(FDDWRPROTECT) <= REGISTER_FDD4(7) & REGISTER_FDD4(5) & REGISTER_FDD4(3) & REGISTER_FDD4(1);
|
||||
CONFIG(FDDTYPE) <= REGISTER_FDD3(7 downto 0) & REGISTER_FDD2(7 downto 0);
|
||||
CONFIG(MZ800_SWITCH) <= REGISTER_SWITCHES(3 downto 0);
|
||||
CONFIG(BOOT_RESET) <= REGISTER_CPU(7);
|
||||
end if;
|
||||
@@ -521,11 +562,12 @@ begin
|
||||
REGISTER_CMT <= "00000000";
|
||||
REGISTER_CMT2 <= "00000000";
|
||||
REGISTER_CMT3 <= "00000000";
|
||||
REGISTER_USERROM <= "00000000";
|
||||
REGISTER_FDCROM <= "00000000";
|
||||
REGISTER_FDD <= "00000000";
|
||||
REGISTER_FDD2 <= "00000000";
|
||||
REGISTER_FDD3 <= "00000000";
|
||||
REGISTER_FDD4 <= "00000000";
|
||||
REGISTER_ROMS <= "00000000";
|
||||
REGISTER_SWITCHES <= "00000000";
|
||||
REGISTER_12 <= "00000000";
|
||||
REGISTER_14 <= "00000000";
|
||||
REGISTER_CTRL <= "00000000";
|
||||
READ_STATUS <= (others => '0');
|
||||
RESET_MACHINEni <= '1';
|
||||
@@ -535,113 +577,116 @@ begin
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
-- Reset apss register if it has been read, ready for next status change.
|
||||
--
|
||||
if READ_STATUS(7) = '1' then
|
||||
REGISTER_CMT2 <= (others => '0');
|
||||
|
||||
-- Reset apss register if it has been read, ready for next status change.
|
||||
--
|
||||
if READ_STATUS(7) = '1' then
|
||||
REGISTER_CMT2 <= (others => '0');
|
||||
end if;
|
||||
|
||||
-- CMT Register 2, for bits 0,2,3 & 4, they set an active bit, then upon read it is reset.
|
||||
--
|
||||
REGISTER_CMT2(6) <= CMT_BUS_OUT(APSS_AUTOPLAY);
|
||||
REGISTER_CMT2(5) <= CMT_BUS_OUT(APSS_AUTOREW);
|
||||
if CMT_BUS_OUT(APSS_STOP) /= CMT_BUS_OUT_LAST(APSS_STOP) and CMT_BUS_OUT(APSS_STOP) = '1' then
|
||||
REGISTER_CMT2(4) <= CMT_BUS_OUT(APSS_STOP);
|
||||
end if;
|
||||
--if CMT_BUS_OUT(APSS_PLAY) /= CMT_BUS_OUT_LAST(APSS_PLAY) and CMT_BUS_OUT(APSS_PLAY) = '1' then
|
||||
REGISTER_CMT2(3) <= CMT_BUS_OUT(APSS_PLAY);
|
||||
--end if;
|
||||
if CMT_BUS_OUT(APSS_EJECT) /= CMT_BUS_OUT_LAST(APSS_EJECT) and CMT_BUS_OUT(APSS_EJECT) = '1' then
|
||||
REGISTER_CMT2(2) <= '1';
|
||||
end if;
|
||||
REGISTER_CMT2(1) <= CMT_BUS_OUT(APSS_DIR);
|
||||
if CMT_BUS_OUT(APSS_SEEK) /= CMT_BUS_OUT_LAST(APSS_SEEK) and CMT_BUS_OUT(APSS_SEEK) = '1' then
|
||||
REGISTER_CMT2(0) <= '1';
|
||||
end if;
|
||||
CMT_BUS_OUT_LAST <= CMT_BUS_OUT;
|
||||
READ_STATUS <= (others => '0');
|
||||
|
||||
-- For reading of registers, if no specific signal is required, just read back the output latch.
|
||||
--
|
||||
-- if IOP_CSn = '0' and IOP_CS_LASTn = "110" and IOP_RDn = '0' then
|
||||
if IOP_CSn = '0' and IOP_RDn = '0' then
|
||||
|
||||
case IOP_ADDR(3 downto 0) is
|
||||
when "0000" => IOP_DIN <= REGISTER_MODEL; READ_STATUS(0) <= '1';
|
||||
when "0001" => IOP_DIN <= REGISTER_DISPLAY; READ_STATUS(1) <= '1';
|
||||
when "0010" => IOP_DIN <= REGISTER_DISPLAY2; READ_STATUS(2) <= '1';
|
||||
when "0011" => IOP_DIN <= REGISTER_DISPLAY3; READ_STATUS(3) <= '1';
|
||||
when "0100" => IOP_DIN <= REGISTER_CPU; READ_STATUS(4) <= '1';
|
||||
when "0101" => IOP_DIN <= REGISTER_AUDIO; READ_STATUS(5) <= '1';
|
||||
when "0110" => IOP_DIN <= REGISTER_CMT; READ_STATUS(6) <= '1'; -- CMT = Config register, readback configuration value.
|
||||
when "0111" => IOP_DIN <= REGISTER_CMT2; READ_STATUS(7) <= '1'; -- CMT 2 = APSS status register, read only.
|
||||
when "1000" => IOP_DIN <= CMT_BUS_OUT(7 downto 0); READ_STATUS(8) <= '1'; -- CMT 3 = CMT status register, read only.
|
||||
when "1001" => IOP_DIN <= REGISTER_FDD ; READ_STATUS(9) <= '1';
|
||||
when "1010" => IOP_DIN <= REGISTER_FDD2 ; READ_STATUS(10) <= '1';
|
||||
when "1011" => IOP_DIN <= REGISTER_FDD3; READ_STATUS(11) <= '1';
|
||||
when "1100" => IOP_DIN <= REGISTER_FDD4; READ_STATUS(12) <= '1';
|
||||
when "1101" => IOP_DIN <= REGISTER_ROMS; READ_STATUS(13) <= '1';
|
||||
when "1110" => IOP_DIN <= REGISTER_SWITCHES; READ_STATUS(14) <= '1';
|
||||
when "1111" => IOP_DIN <= REGISTER_CTRL; READ_STATUS(15) <= '1'; -- Read = STATUS
|
||||
end case;
|
||||
end if;
|
||||
-- For writing of registers, just assign the input bus to the register.
|
||||
-- if IOP_CSn = '0' and IOP_CS_LASTn = "100" and IOP_WRn = '0' then
|
||||
if IOP_CSn = '0' and IOP_WRn = '0' then
|
||||
|
||||
case IOP_ADDR(3 downto 0) is
|
||||
when "0000" =>
|
||||
-- Assign the model data to the register and preset the default display hardware.
|
||||
REGISTER_MODEL <= IOP_DOUT(7 downto 0);
|
||||
case IOP_DOUT(3 downto 0) is
|
||||
when "0100" | "0101" | "0110" =>
|
||||
REGISTER_DISPLAY <= REGISTER_DISPLAY(7 downto 3) & "010";
|
||||
when others =>
|
||||
REGISTER_DISPLAY <= REGISTER_DISPLAY(7 downto 3) & "000";
|
||||
end case;
|
||||
when "0001" =>
|
||||
REGISTER_DISPLAY <= IOP_DOUT(7 downto 0);
|
||||
|
||||
when "0010" =>
|
||||
-- Check the sanity, certain address ranges are blocked by the underlying machine.
|
||||
--
|
||||
if IOP_DOUT(7 downto 4) /= "1111" and IOP_DOUT(7 downto 4) /= "1110" and IOP_DOUT(7 downto 4) /= "1101" then
|
||||
REGISTER_DISPLAY2 <= IOP_DOUT(7 downto 0);
|
||||
end if;
|
||||
|
||||
when "0011" => REGISTER_DISPLAY3<= IOP_DOUT(7 downto 0);
|
||||
|
||||
when "0100" => REGISTER_CPU <= IOP_DOUT(7 downto 0);
|
||||
when "0101" => REGISTER_AUDIO <= IOP_DOUT(7 downto 0);
|
||||
when "0110" => REGISTER_CMT <= IOP_DOUT(7 downto 0);
|
||||
when "0111" => REGISTER_CMT2 <= IOP_DOUT(7 downto 0);
|
||||
when "1000" => REGISTER_CMT3 <= IOP_DOUT(7 downto 0);
|
||||
when "1001" => REGISTER_FDD <= IOP_DOUT(7 downto 0);
|
||||
when "1010" => REGISTER_FDD2 <= IOP_DOUT(7 downto 0);
|
||||
when "1011" => REGISTER_FDD3 <= IOP_DOUT(7 downto 0);
|
||||
when "1100" => REGISTER_FDD4 <= IOP_DOUT(7 downto 0);
|
||||
when "1101" => REGISTER_ROMS <= IOP_DOUT(7 downto 0);
|
||||
when "1110" => REGISTER_SWITCHES<= IOP_DOUT(7 downto 0);
|
||||
when "1111" =>
|
||||
REGISTER_CTRL <= IOP_DOUT(7 downto 1) & '0';
|
||||
if IOP_DOUT(0) = '1' then
|
||||
RESET_MACHINEni <= '0';
|
||||
RESET_MACHINE_TIMER <= (others => '1');
|
||||
end if;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
|
||||
-- Trigger an external reset, hold for several clock cycles to synchronise the reset with the primary reset controller.
|
||||
--
|
||||
if RESET_MACHINE_TIMER /= 0 then
|
||||
RESET_MACHINE_TIMER <= RESET_MACHINE_TIMER - 1;
|
||||
end if;
|
||||
|
||||
-- If reset asserted, on timer expiry clear reset.
|
||||
if RESET_MACHINEni = '0' and RESET_MACHINE_TIMER = 0 then
|
||||
RESET_MACHINEni <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- CMT Register 2, for bits 0,2,3 & 4, they set an active bit, then upon read it is reset.
|
||||
--
|
||||
if CMT_BUS_OUT(APSS_STOP) /= CMT_BUS_OUT_LAST(APSS_STOP) and CMT_BUS_OUT(APSS_STOP) = '1' then
|
||||
REGISTER_CMT2(4) <= CMT_BUS_OUT(APSS_STOP);
|
||||
end if;
|
||||
--if CMT_BUS_OUT(APSS_PLAY) /= CMT_BUS_OUT_LAST(APSS_PLAY) and CMT_BUS_OUT(APSS_PLAY) = '1' then
|
||||
REGISTER_CMT2(3) <= CMT_BUS_OUT(APSS_PLAY);
|
||||
--end if;
|
||||
if CMT_BUS_OUT(APSS_EJECT) /= CMT_BUS_OUT_LAST(APSS_EJECT) and CMT_BUS_OUT(APSS_EJECT) = '1' then
|
||||
REGISTER_CMT2(2) <= '1';
|
||||
end if;
|
||||
REGISTER_CMT2(1) <= CMT_BUS_OUT(APSS_DIR);
|
||||
if CMT_BUS_OUT(APSS_SEEK) /= CMT_BUS_OUT_LAST(APSS_SEEK) and CMT_BUS_OUT(APSS_SEEK) = '1' then
|
||||
REGISTER_CMT2(0) <= '1';
|
||||
end if;
|
||||
CMT_BUS_OUT_LAST <= CMT_BUS_OUT;
|
||||
READ_STATUS <= (others => '0');
|
||||
|
||||
-- For reading of registers, if no specific signal is required, just read back the output latch.
|
||||
--
|
||||
-- if IOP_CSn = '0' and IOP_CS_LASTn = "110" and IOP_RDn = '0' then
|
||||
if IOP_CSn = '0' and IOP_RDn = '0' then
|
||||
|
||||
case IOP_ADDR(3 downto 0) is
|
||||
when "0000" => IOP_DIN <= REGISTER_MODEL; READ_STATUS(0) <= '1';
|
||||
when "0001" => IOP_DIN <= REGISTER_DISPLAY; READ_STATUS(1) <= '1';
|
||||
when "0010" => IOP_DIN <= REGISTER_DISPLAY2; READ_STATUS(2) <= '1';
|
||||
when "0011" => IOP_DIN <= REGISTER_DISPLAY3; READ_STATUS(3) <= '1';
|
||||
when "0100" => IOP_DIN <= REGISTER_CPU; READ_STATUS(4) <= '1';
|
||||
when "0101" => IOP_DIN <= REGISTER_AUDIO; READ_STATUS(5) <= '1';
|
||||
when "0110" => IOP_DIN <= REGISTER_CMT; READ_STATUS(6) <= '1'; -- CMT = Config register, readback configuration value.
|
||||
when "0111" => IOP_DIN <= REGISTER_CMT2; READ_STATUS(7) <= '1'; -- CMT 2 = APSS status register, read only.
|
||||
when "1000" => IOP_DIN <= CMT_BUS_OUT(7 downto 0); READ_STATUS(8) <= '1'; -- CMT 3 = CMT status register, read only.
|
||||
when "1001" => IOP_DIN <= REGISTER_USERROM; READ_STATUS(9) <= '1';
|
||||
when "1010" => IOP_DIN <= REGISTER_FDCROM; READ_STATUS(10) <= '1';
|
||||
when "1011" => IOP_DIN <= REGISTER_SWITCHES; READ_STATUS(11) <= '1';
|
||||
when "1100" => IOP_DIN <= REGISTER_12; READ_STATUS(12) <= '1';
|
||||
when "1101" => IOP_DIN <= REGISTER_13; READ_STATUS(13) <= '1';
|
||||
when "1110" => IOP_DIN <= REGISTER_14; READ_STATUS(14) <= '1';
|
||||
when "1111" => IOP_DIN <= REGISTER_CTRL; READ_STATUS(15) <= '1'; -- Read = STATUS
|
||||
end case;
|
||||
end if;
|
||||
-- For writing of registers, just assign the input bus to the register.
|
||||
-- if IOP_CSn = '0' and IOP_CS_LASTn = "100" and IOP_WRn = '0' then
|
||||
if IOP_CSn = '0' and IOP_WRn = '0' then
|
||||
|
||||
case IOP_ADDR(3 downto 0) is
|
||||
when "0000" =>
|
||||
-- Assign the model data to the register and preset the default display hardware.
|
||||
REGISTER_MODEL <= IOP_DOUT(7 downto 0);
|
||||
case IOP_DOUT(3 downto 0) is
|
||||
when "0100" | "0101" | "0110" =>
|
||||
REGISTER_DISPLAY <= REGISTER_DISPLAY(7 downto 3) & "010";
|
||||
when others =>
|
||||
REGISTER_DISPLAY <= REGISTER_DISPLAY(7 downto 3) & "000";
|
||||
end case;
|
||||
when "0001" =>
|
||||
REGISTER_DISPLAY <= IOP_DOUT(7 downto 0);
|
||||
|
||||
when "0010" =>
|
||||
-- Check the sanity, certain address ranges are blocked by the underlying machine.
|
||||
--
|
||||
if IOP_DOUT(7 downto 4) /= "1111" and IOP_DOUT(7 downto 4) /= "1110" and IOP_DOUT(7 downto 4) /= "1101" then
|
||||
REGISTER_DISPLAY2 <= IOP_DOUT(7 downto 0);
|
||||
end if;
|
||||
|
||||
when "0011" => REGISTER_DISPLAY3<= IOP_DOUT(7 downto 0);
|
||||
|
||||
when "0100" => REGISTER_CPU <= IOP_DOUT(7 downto 0);
|
||||
when "0101" => REGISTER_AUDIO <= IOP_DOUT(7 downto 0);
|
||||
when "0110" => REGISTER_CMT <= IOP_DOUT(7 downto 0);
|
||||
when "0111" => REGISTER_CMT2 <= IOP_DOUT(7 downto 0);
|
||||
when "1000" => REGISTER_CMT3 <= IOP_DOUT(7 downto 0);
|
||||
when "1001" => REGISTER_USERROM <= IOP_DOUT(7 downto 0);
|
||||
when "1010" => REGISTER_FDCROM <= IOP_DOUT(7 downto 0);
|
||||
when "1011" => REGISTER_SWITCHES<= IOP_DOUT(7 downto 0);
|
||||
when "1100" => REGISTER_12 <= IOP_DOUT(7 downto 0);
|
||||
when "1101" => REGISTER_13 <= IOP_DOUT(7 downto 0);
|
||||
when "1110" => REGISTER_14 <= IOP_DOUT(7 downto 0);
|
||||
when "1111" =>
|
||||
REGISTER_CTRL <= IOP_DOUT(7 downto 1) & '0';
|
||||
if IOP_DOUT(0) = '1' then
|
||||
RESET_MACHINEni <= '0';
|
||||
RESET_MACHINE_TIMER <= (others => '1');
|
||||
end if;
|
||||
|
||||
end case;
|
||||
end if;
|
||||
|
||||
-- Trigger an external reset, hold for several clock cycles to synchronise the reset with the primary reset controller.
|
||||
--
|
||||
if RESET_MACHINE_TIMER /= 0 then
|
||||
RESET_MACHINE_TIMER <= RESET_MACHINE_TIMER - 1;
|
||||
end if;
|
||||
|
||||
-- If reset asserted, on timer expiry clear reset.
|
||||
if RESET_MACHINEni = '0' and RESET_MACHINE_TIMER = 0 then
|
||||
RESET_MACHINEni <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Edge detection due to different clock domains.
|
||||
-- IOP_CS_LASTn := IOP_CS_LASTn(1 downto 0) & IOP_CSn;
|
||||
end if;
|
||||
|
||||
@@ -98,6 +98,7 @@ entity mz80b_hw is
|
||||
CS_RAMn : out std_logic; -- RAM Select
|
||||
CS_VRAMn : out std_logic; -- VRAM Select
|
||||
CS_GRAMn : out std_logic; -- MZ80B/MZ2000/MZ2200 GRAM Option Select
|
||||
CS_FDDn : out std_logic; -- Floppy disk controller select.
|
||||
-- CS_IO_GFBn : out std_logic; -- Graphics Framebuffer IO Select range
|
||||
CS_IO_Gn : out std_logic; -- Graphics Options IO Select range
|
||||
CS_IO_CTRLn : out std_logic; -- PPI/PIO control register select.
|
||||
@@ -283,7 +284,42 @@ begin
|
||||
OUT2 => open
|
||||
);
|
||||
|
||||
-- Z80 PIO used for keyboard, RAM and Video control.
|
||||
-- -- Z80 PIO used for keyboard, RAM and Video control.
|
||||
-- --
|
||||
-- PIO0 : entity work.z8420
|
||||
-- port map (
|
||||
-- -- System
|
||||
-- RSTn => T80_RSTn, -- Only Power On Reset
|
||||
-- -- Z80 Bus Signals
|
||||
-- CLK => CLKBUS(CKMASTER),
|
||||
-- ENA => CLKBUS(CKENCPU),
|
||||
-- BASEL => T80_A16(1),
|
||||
-- CDSEL => T80_A16(0),
|
||||
-- CE => CS_IO_Z80PIOn,
|
||||
-- RDn => T80_RDn,
|
||||
-- WRn => T80_WRn,
|
||||
-- IORQn => T80_IORQn,
|
||||
-- M1n => T80_M1n and T80_RSTn,
|
||||
-- DI => T80_DO,
|
||||
-- DO => PIO_DO,
|
||||
-- IEI => '1',
|
||||
-- IEO => open,
|
||||
-- INTn => Z80PIO_INTn,
|
||||
-- -- PORT A
|
||||
-- A_IN => (others => '0'),
|
||||
-- A_OUT => Z80PIO_PA,
|
||||
-- A_OUT_EN => (others => '1'),
|
||||
-- ARDY => open,
|
||||
-- ASTBn => '0',
|
||||
-- -- PORT B
|
||||
-- B_IN => Z80PIO_PB,
|
||||
-- B_OUT => open,
|
||||
-- B_OUT_EN => (others => '0'),
|
||||
-- BRDY => open,
|
||||
-- BSTBn => '0'
|
||||
-- );
|
||||
|
||||
-- Z80 PIO (version 1) used for keyboard, RAM and Video control.
|
||||
--
|
||||
PIO0 : entity work.z8420
|
||||
port map (
|
||||
@@ -346,39 +382,39 @@ begin
|
||||
else '0';
|
||||
LED_SHIFT_LOCK <= i8255_PA_O(5) when CONFIG(MZ80B) = '1' and i8255_PA_OEn(5) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(AUTOPLAY) <= i8255_PA_O(6) when CONFIG(MZ2000) = '1' and i8255_PA_OEn(6) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(AUTOREW) <= i8255_PA_O(5) when CONFIG(MZ2000) = '1' and i8255_PA_OEn(5) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(AUTOPLAY) <= i8255_PA_O(6) when (CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1') and i8255_PA_OEn(6) = '0'
|
||||
else '1';
|
||||
CMT_BUS_IN(AUTOREW) <= i8255_PA_O(5) when (CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1') and i8255_PA_OEn(5) = '0'
|
||||
else '1';
|
||||
CMT_BUS_IN(STOP) <= i8255_PA_O(3) when i8255_PA_OEn(3) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(PLAY) <= i8255_PA_O(2) when i8255_PA_OEn(2) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(DIRECTION) <= i8255_PA_O(1) when CONFIG(MZ80B) = '1' and i8255_PA_OEn(1) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(CMTFF) <= i8255_PA_O(1) when CONFIG(MZ2000) = '1' and i8255_PA_OEn(1) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(CMTFF) <= i8255_PA_O(1) when (CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1') and i8255_PA_OEn(1) = '0'
|
||||
else '1';
|
||||
CMT_BUS_IN(REEL_MOTOR) <= i8255_PA_O(0) when CONFIG(MZ80B) = '1' and i8255_PA_OEn(0) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(CMTREW) <= i8255_PA_O(0) when CONFIG(MZ2000) = '1' and i8255_PA_OEn(0) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(CMTREW) <= i8255_PA_O(0) when (CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1') and i8255_PA_OEn(0) = '0'
|
||||
else '1';
|
||||
|
||||
|
||||
-- PPI Port B - Input connections.
|
||||
--
|
||||
i8255_PB_I(7) <= KEYB_BREAKDETECT;
|
||||
i8255_PB_I(6) <= CMT_BUS_OUT(WRITEBIT); -- CMT Writing bit, MZ reading.
|
||||
i8255_PB_I(5) <= CMT_BUS_OUT(TAPEREADY); -- Tape is loaded in deck when L (0).
|
||||
i8255_PB_I(4) <= CMT_BUS_OUT(WRITEREADY); -- Prohibit Write/Record when L (0).
|
||||
i8255_PB_I(3) <= CMT_BUS_OUT(ENDOFTAPE) when CONFIG(MZ2000) = '1' -- End of tape detected.
|
||||
i8255_PB_I(6) <= CMT_BUS_OUT(WRITEBIT); -- CMT Writing bit, MZ reading.
|
||||
i8255_PB_I(5) <= CMT_BUS_OUT(TAPEREADY); -- Tape is loaded in deck when L (0).
|
||||
i8255_PB_I(4) <= CMT_BUS_OUT(WRITEREADY); -- Prohibit Write/Record when L (0).
|
||||
i8255_PB_I(3) <= CMT_BUS_OUT(ENDOFTAPE) when (CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1') -- End of tape detected.
|
||||
else '1';
|
||||
i8255_PB_I(2 downto 1) <= (others => '1');
|
||||
i8255_PB_I(0) <= VBLANK;
|
||||
|
||||
-- PPI allow readback of output signals.
|
||||
--
|
||||
i8255_PC_I(7) <= CMT_BUS_IN(READBIT); -- Data written to cassette.
|
||||
i8255_PC_I(6) <= CMT_BUS_IN(WRITEENABLE); -- Cassette write enable (record).
|
||||
i8255_PC_I(7) <= CMT_BUS_IN(READBIT); -- Data written to cassette.
|
||||
i8255_PC_I(6) <= CMT_BUS_IN(WRITEENABLE); -- Cassette write enable (record).
|
||||
i8255_PC_I(5) <= CMT_BUS_IN(SEEK) when CONFIG(MZ80B) = '1'
|
||||
else
|
||||
CMT_BUS_IN(KINH);
|
||||
@@ -396,9 +432,9 @@ begin
|
||||
else '0';
|
||||
CMT_BUS_IN(SEEK) <= i8255_PC_O(5) when CONFIG(MZ80B) = '1' and i8255_PC_OEn(5) = '0'
|
||||
else
|
||||
i8255_PA_O(7) when CONFIG(MZ2000) = '1' and i8255_PA_OEn(7) = '0'
|
||||
i8255_PA_O(7) when (CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1') and i8255_PA_OEn(7) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(KINH) <= i8255_PC_O(5) when CONFIG(MZ2000) = '1' and i8255_PC_OEn(5) = '0'
|
||||
CMT_BUS_IN(KINH) <= i8255_PC_O(5) when (CONFIG(MZ2000) = '1' or CONFIG(MZ2200) = '1') and i8255_PC_OEn(5) = '0'
|
||||
else '0';
|
||||
CMT_BUS_IN(EJECT) <= i8255_PC_O(4) when i8255_PC_OEn(4) = '0'
|
||||
else '0';
|
||||
@@ -537,6 +573,8 @@ begin
|
||||
else '1';
|
||||
CS_IO_Gni <= '0' when T80_IORQn = '0' and T80_A16(7 downto 2) = "111101" and T80_WRn = '0' -- IO Range for Graphics registers.
|
||||
else '1';
|
||||
CS_FDDn <= '0' when T80_IORQn = '0' and T80_A16(7 downto 3) = "11011" and T80_A16(3 downto 0) /= "1111" -- Floppy Range D8-DE.
|
||||
else '1';
|
||||
-- CS_IO_GFBni <= '0' when T80_IORQn = '0' and T80_A16(7 downto 3) = CONFIG(GRAMIOADDR) and T80_WRn = '0' -- IO Range for Graphics framebuffer register controlled by mctrl register.
|
||||
-- else '1';
|
||||
-- CS_IO_GRAMENABLEn <= '0' when CS_IO_GFBni = '0' and T80_A16(2 downto 0) = "100" -- IO Addr base+4 sets C000 -> FFFF map to Graphics RAM.
|
||||
@@ -613,11 +651,17 @@ begin
|
||||
|
||||
-- Audio output. Choose between generated sound and CMT pulse audio.
|
||||
--
|
||||
AUDIO_L <= (others => SOUND) when CONFIG(AUDIOSRC) = '0' -- Sound Output Left
|
||||
AUDIO_L <= SOUND&SOUND&SOUND&SOUND & X"000" when CONFIG(AUDIOSRC) = '0' and CONFIG(MZ_B) = '1' -- Sound Output Left
|
||||
else
|
||||
(others => CMT_BUS_OUT(WRITEBIT));
|
||||
AUDIO_R <= (others => SOUND) when CONFIG(AUDIOSRC) = '0' -- Sound Output Right
|
||||
CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT) & X"000"
|
||||
when CONFIG(AUDIOSRC) = '1' and CONFIG(MZ_B) = '1'
|
||||
else
|
||||
(others => CMT_BUS_OUT(READBIT));
|
||||
(others => '0');
|
||||
AUDIO_R <= SOUND&SOUND&SOUND&SOUND & X"000" when CONFIG(AUDIOSRC) = '0' and CONFIG(MZ_B) = '1' -- Sound Output Right
|
||||
else
|
||||
CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT) & X"000"
|
||||
when CONFIG(AUDIOSRC) = '1' and CONFIG(MZ_B) = '1'
|
||||
else
|
||||
(others => '0');
|
||||
|
||||
end rtl;
|
||||
|
||||
@@ -100,6 +100,7 @@ entity mz80k_hw is
|
||||
CS_VRAMn : out std_logic; -- VRAM Select
|
||||
CS_PITn : out std_logic; -- 8253 write to mirror output onto the physical 8253 IC.
|
||||
CS_MEM_Gn : out std_logic; -- Memory Peripherals Select
|
||||
CS_FDDn : out std_logic; -- Floppy disk controller select.
|
||||
CS_IO_Gn : out std_logic; -- I/O Peripherals Select
|
||||
CS_GRAMn : out std_logic; -- GRAM Select
|
||||
DATA_AVAILn : out std_logic; -- Data available to be read from module.
|
||||
@@ -128,7 +129,7 @@ entity mz80k_hw is
|
||||
IOP_CSn : in std_logic; -- Chip select from the I/O Processor decoding.
|
||||
IOP_WRn : in std_logic; -- Write Enable.
|
||||
IOP_RDn : in std_logic; -- Read Enable.
|
||||
IOP_ADDR : in std_logic_vector(3 downto 0); -- Address bus.
|
||||
IOP_ADDR : in std_logic_vector(5 downto 0); -- Address bus.
|
||||
IOP_DOUT : in std_logic_vector(7 downto 0); -- Data into the mctrl unit.
|
||||
IOP_DIN : out std_logic_vector(7 downto 0) -- Data out from the mctrl unit.
|
||||
);
|
||||
@@ -206,6 +207,10 @@ signal CS_RAMni : std_logic;
|
||||
signal VGATEni : std_logic; -- Video Output Enable
|
||||
signal T80_IWRn : std_logic;
|
||||
signal T80_INTni : std_logic;
|
||||
signal MUX_RDn : std_logic;
|
||||
signal MUX_WRn : std_logic;
|
||||
signal MUX_DOUT : std_logic_vector(7 downto 0);
|
||||
signal MUX_ADDR : std_logic_vector(1 downto 0);
|
||||
--
|
||||
-- PPI
|
||||
--
|
||||
@@ -216,7 +221,9 @@ signal INTMSK : std_logic; -- EISU
|
||||
--
|
||||
signal DOPIT : std_logic_vector(7 downto 0);
|
||||
signal SOUND_ENABLE : std_logic;
|
||||
signal PIT_GATE0 : std_logic;
|
||||
signal SOUND_PULSE_X2 : std_logic;
|
||||
signal SOUND_PULSE_X1 : std_logic;
|
||||
signal SOUND : std_logic;
|
||||
signal INTX : std_logic;
|
||||
--
|
||||
@@ -227,6 +234,11 @@ signal Z80PIO_INTn : std_logic;
|
||||
signal Z80PIO_PA : std_logic_vector(7 downto 0);
|
||||
signal Z80PIO_PB : std_logic_vector(7 downto 0);
|
||||
--
|
||||
-- Joystick
|
||||
--
|
||||
signal MZ800_JOYSTB1n : std_logic;
|
||||
signal MZ800_JOYSTB2n : std_logic;
|
||||
--
|
||||
-- SN76489 Programmable Sound Generator.
|
||||
--
|
||||
signal PSG_0_OUT : unsigned(13 downto 0); -- PSG mono channel on MZ-800, Left channel on MZ-1500,
|
||||
@@ -259,6 +271,7 @@ signal SWIN : std_logic_vector(3 downto 0);
|
||||
-- Debug
|
||||
--
|
||||
signal PULSECPU : std_logic;
|
||||
signal TESTME : unsigned(15 downto 0) := "1100110000000000";
|
||||
|
||||
--
|
||||
-- Components
|
||||
@@ -353,12 +366,12 @@ begin
|
||||
RESET => T80_RSTi,
|
||||
CLK => CLKBUS(CKMASTER),
|
||||
ENA => CLKBUS(CKENCPU), --'1',
|
||||
ADDR => T80_ADDR(1 downto 0),
|
||||
DI => T80_DO,
|
||||
ADDR => MUX_ADDR,
|
||||
DI => MUX_DOUT,
|
||||
DO => DOPPI,
|
||||
CSn => CS_8255n,
|
||||
RDn => T80_RDn,
|
||||
WRn => T80_WRn,
|
||||
RDn => MUX_RDn,
|
||||
WRn => MUX_WRn,
|
||||
|
||||
PA_I => i8255_PA_O,
|
||||
PA_O => i8255_PA_O,
|
||||
@@ -380,14 +393,14 @@ begin
|
||||
RST => T80_RSTi,
|
||||
CLK => CLKBUS(CKMASTER),
|
||||
ENA => CLKBUS(CKENCPU),
|
||||
A => T80_ADDR(1 downto 0),
|
||||
DI => T80_DO,
|
||||
A => MUX_ADDR,
|
||||
DI => MUX_DOUT,
|
||||
DO => DOPIT,
|
||||
CSn => CS_8254n,
|
||||
WRn => T80_WRn,
|
||||
RDn => T80_RDn,
|
||||
WRn => MUX_WRn,
|
||||
RDn => MUX_RDn,
|
||||
CLK0 => CLKBUS(CKSOUND),
|
||||
GATE0 => SOUND_ENABLE,
|
||||
GATE0 => PIT_GATE0,
|
||||
OUT0 => SOUND_PULSE_X2,
|
||||
CLK1 => CLKBUS(CKRTC),
|
||||
GATE1 => '1',
|
||||
@@ -400,28 +413,38 @@ begin
|
||||
-- Z80 PIO on MZ800 used for printer, horizontal blanking interrupt and 8253 interrupt.
|
||||
-- on MZ1500 used for printer and interrupts from the 8253 timer Channel 0/2.
|
||||
--
|
||||
PIO0 : entity work.z8420
|
||||
PIO0 : entity work.z8420_v2
|
||||
port map (
|
||||
-- System
|
||||
RSTn => T80_RSTn, -- Only Power On Reset
|
||||
|
||||
-- Z80 Bus Signals
|
||||
CLK => CLKBUS(CKMASTER),
|
||||
ENA => CLKBUS(CKENCPU),
|
||||
BASEL => T80_ADDR(1),
|
||||
CDSEL => T80_ADDR(0),
|
||||
BASEL => MUX_ADDR(0),
|
||||
CDSEL => not MUX_ADDR(1),
|
||||
CE => CS_PIOn,
|
||||
RDn => T80_RDn,
|
||||
WRn => T80_WRn,
|
||||
RDn => MUX_RDn,
|
||||
WRn => MUX_WRn,
|
||||
IORQn => T80_IORQn,
|
||||
M1n => T80_M1n and T80_RSTn,
|
||||
DI => T80_DO,
|
||||
DI => MUX_DOUT,
|
||||
DO => DOPIO,
|
||||
IEI => '1',
|
||||
IEO => open,
|
||||
INTn => Z80PIO_INTn,
|
||||
|
||||
A => Z80PIO_PA, -- Printer control not currently used, only 8253 and horizontal blanking interrupts used.
|
||||
B => Z80PIO_PB -- Printer output, not currently used.
|
||||
-- PORT A
|
||||
A_IN => Z80PIO_PA, -- Printer control not currently used, only 8253 and horizontal blanking interrupts used.
|
||||
A_OUT => open,
|
||||
A_OUT_EN => (others => '0'),
|
||||
ARDY => open,
|
||||
ASTBn => '0',
|
||||
-- PORT B
|
||||
B_IN => (others => '0'),
|
||||
B_OUT => Z80PIO_PB, -- Printer output, not currently used.
|
||||
B_OUT_EN => (others => '1'),
|
||||
BRDY => open,
|
||||
BSTBn => '0'
|
||||
);
|
||||
|
||||
-- MZ-800 Mono PSG.
|
||||
@@ -441,9 +464,9 @@ begin
|
||||
clk_i => CLKBUS(CKMASTER), -- System clock
|
||||
en_clk_psg_i => CLKBUS(CKENCPU), -- PSG clock enable
|
||||
ce_n_i => CS_PSG0n, -- chip enable, active low
|
||||
wr_n_i => T80_WRn, -- write enable, active low
|
||||
wr_n_i => MUX_WRn, -- write enable, active low
|
||||
ready_o => PSG_READY0n, -- low during I/O operations
|
||||
data_i => T80_DO,
|
||||
data_i => MUX_DOUT,
|
||||
ch_a_o => open,
|
||||
ch_b_o => open,
|
||||
ch_c_o => open,
|
||||
@@ -468,9 +491,9 @@ begin
|
||||
clk_i => CLKBUS(CKMASTER), -- System clock
|
||||
en_clk_psg_i => CLKBUS(CKENCPU), -- PSG clock enable
|
||||
ce_n_i => CS_PSG1n, -- chip enable, active low
|
||||
wr_n_i => T80_WRn, -- write enable, active low
|
||||
wr_n_i => MUX_WRn, -- write enable, active low
|
||||
ready_o => PSG_READY1n, -- low during I/O operations
|
||||
data_i => T80_DO,
|
||||
data_i => MUX_DOUT,
|
||||
ch_a_o => open,
|
||||
ch_b_o => open,
|
||||
ch_c_o => open,
|
||||
@@ -480,10 +503,50 @@ begin
|
||||
);
|
||||
|
||||
-- I/O Processor bus.
|
||||
IOP_DIN <= "01011100";
|
||||
IOP_DIN <= DOPPI when IOP_ADDR(5 downto 2) = "0000" -- Read from 8255
|
||||
else
|
||||
DOPIT when IOP_ADDR(5 downto 2) = "0001" -- Read from 8254
|
||||
else
|
||||
DO367 when IOP_ADDR(5 downto 2) = "0010" -- Read from LS367
|
||||
else
|
||||
X"00" when IOP_ADDR(5 downto 2) = "0011" -- Read from MZ-800 Joystick port
|
||||
else
|
||||
DOPIO when IOP_ADDR(5 downto 2) = "0100" -- Read from MZ-800 Z80 PIO
|
||||
else
|
||||
std_logic_vector(TESTME(7 downto 0)) when IOP_ADDR(5 downto 2) = "1110"
|
||||
else
|
||||
std_logic_vector(TESTME(15 downto 8)) when IOP_ADDR(5 downto 2) = "1111"
|
||||
else "01011100";
|
||||
|
||||
|
||||
process( CLKBUS(CKMASTER), T80_RSTn )
|
||||
begin
|
||||
if T80_RSTn = '0' then
|
||||
TESTME <= "0000000010101010";
|
||||
|
||||
elsif CLKBUS(CKMASTER)'event and CLKBUS(CKMASTER)='1' then
|
||||
if Z80PIO_INTn = '0' then
|
||||
TESTME(7 downto 0) <= unsigned(DOPIO);
|
||||
TESTME(14 downto 8) <= TESTME(14 downto 8) + 1;
|
||||
end if;
|
||||
TESTME(15) <= SOUND_PULSE_X2;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Parent signals onto local wires.
|
||||
--
|
||||
MUX_RDn <= '0' when IOP_RDn = '0' and IOP_CSn = '0'
|
||||
else
|
||||
T80_RDn;
|
||||
MUX_WRn <= '0' when IOP_WRn = '0' and IOP_CSn = '0'
|
||||
else
|
||||
T80_WRn;
|
||||
MUX_DOUT <= IOP_DOUT when IOP_CSn = '0'
|
||||
else
|
||||
T80_DO;
|
||||
MUX_ADDR <= IOP_ADDR(1 downto 0) when IOP_CSn = '0'
|
||||
else
|
||||
T80_ADDR(1 downto 0);
|
||||
T80_BUSRQn <= '1';
|
||||
T80_NMIn <= '1';
|
||||
T80_WAITn <= '0' when MODE_MZ800 = '1' and PSG_READY0n = '0'
|
||||
@@ -529,23 +592,27 @@ begin
|
||||
else '1';
|
||||
INTMSK <= i8255_PC_O(2) when i8255_PC_OEn(2) = '0'
|
||||
else '1';
|
||||
VGATEni <= i8255_PC_O(0) when i8255_PC_OEn(0) = '0'
|
||||
VGATEni <= i8255_PC_O(0) when i8255_PC_OEn(0) = '0' and CONFIG(MZ_A) = '1'
|
||||
else '1';
|
||||
KEYB_SCAN <= i8255_PA_O(3 downto 0) when i8255_PA_OEn(3 downto 0) /= "1111"
|
||||
else "0000"; -- Keyboard scan lines out.
|
||||
KEYB_STALL <= '1'; --i8255_PA_O(4) when i8255_PA_OEn(4) = '0'
|
||||
--else '0'; -- Keyboard Stall out.
|
||||
i8255_PB_I <= KEYB_DATA; -- Keyboard scan data in.
|
||||
MZ800_JOYSTB1n <= i8255_PA_O(4) when i8255_PA_OEn(4) = '0' -- Joystick strobe 1 on MZ-800
|
||||
else '1';
|
||||
MZ800_JOYSTB2n <= i8255_PA_O(5) when i8255_PA_OEn(5) = '0' -- Joystick strobe 2 on MZ-800
|
||||
else '1';
|
||||
|
||||
--
|
||||
-- PIO Signals.
|
||||
--
|
||||
Z80PIO_PA(0) <= '1'; -- Printer /RDA
|
||||
Z80PIO_PA(0) <= '0'; -- Printer /RDA
|
||||
Z80PIO_PA(1) <= '1'; -- Printer /STA
|
||||
Z80PIO_PA(2) <= '0'; -- GND
|
||||
Z80PIO_PA(3) <= '0'; -- GND
|
||||
Z80PIO_PA(4) <= not SOUND_PULSE_X2; -- 8253 Interrupt.
|
||||
Z80PIO_PA(5) <= VBLANK when CONFIG(MZ800) = '1' -- Manual indicates this should be the Horizontal Blanking yet schematic shows it connected to the vertical blanking.
|
||||
Z80PIO_PA(5) <= VBLANK when CONFIG(MZ800) = '1' -- Manual indicates this should be the Horizontal Blanking yet schematic shows it connected to the vertical blanking.
|
||||
else
|
||||
INTX when CONFIG(MZ1500) = '1' -- Duplication of the 8253 Timer 2 interrupt but masked/enabled in the PIO rather than the 8255.
|
||||
else
|
||||
@@ -561,13 +628,15 @@ begin
|
||||
else
|
||||
X"00" when CS_JOYSTKn = '0' -- Read from MZ-800 Joystick port
|
||||
else
|
||||
DOPIO when CS_PIOn = '0' -- Read from MZ-800 Z80 PIO
|
||||
DOPIO when CS_PIOn = '0' or (T80_M1n = '0' and T80_IORQn = '0' and CONFIG(MZ800) = '1') -- Read from MZ-800 Z80 PIO
|
||||
else
|
||||
(others=>'1');
|
||||
|
||||
-- Indicate when data is available for reading.
|
||||
--
|
||||
DATA_AVAILn <= '0' when T80_RDn = '0' and (CS_8255n ='0' or CS_8254n ='0' or CS_LS367n = '0' or CS_PIOn = '0' or CS_JOYSTKn = '0')
|
||||
DATA_AVAILn <= '0' when MUX_RDn = '0' and (CS_8255n ='0' or CS_8254n ='0' or CS_LS367n = '0' or CS_PIOn = '0' or CS_JOYSTKn = '0')
|
||||
else
|
||||
'0' when T80_M1n = '0' and T80_IORQn = '0' and CONFIG(MZ800) = '1'
|
||||
else '1';
|
||||
|
||||
-- The MZ-800 can change the mode between MZ-800 and MZ-700 by writing to the GD LSI. We thus setup the mode signals accordingly.
|
||||
@@ -639,42 +708,70 @@ begin
|
||||
CS_8255n <= '0' when CS_IO_DXn = '0' and T80_ADDR(3 downto 2) = "00" and MODE_MZ800 = '1' -- MZ800 8255 PPI
|
||||
else
|
||||
'0' when CS_Eni = '0' and T80_ADDR(11 downto 2) = "0000000000" and MODE_MZ800 = '0' -- 8255
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0000" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_8254n <= '0' when CS_IO_DXn = '0' and T80_ADDR(3 downto 2) = "01" and MODE_MZ800 = '1' -- MZ800 8254 PIT
|
||||
else
|
||||
'0' when CS_Eni = '0' and T80_ADDR(11 downto 2) = "0000000001" and MODE_MZ800 = '0' -- 8254
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0001" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_PITn <= '0' when CS_8254n = '0' or CS_LS367n = '0' -- 8254/LS367 mirrored externally.
|
||||
else '1';
|
||||
CS_LS367n <= '0' when CS_Eni = '0' and T80_ADDR(11 downto 2) = "0000000010" and MODE_MZ800 = '0' -- LS367
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0010" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_ESWPn <= '0' when CONFIG(MZ_A) = '1' and CS_Eni = '0' and T80_RDn = '0' and T80_ADDR(11 downto 5) = "0000000" -- ROM/RAM Swap
|
||||
else '1';
|
||||
CS_JOYSTKn <= '0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 1) = "-00" and CONFIG(MZ800) = '1' -- MZ-800 Joystick ports.
|
||||
CS_JOYSTKn <= '0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 1) = "000" and CONFIG(MZ800) = '1' -- MZ-800 Joystick ports.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0011" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_PIOn <= '0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 2) = "11" and CONFIG(MZ800) = '1' -- MZ-800 Z80 PIO Printer Interface.
|
||||
else
|
||||
'0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 2) = "11" and CONFIG(MZ1500) = '1' -- MZ-1500 Z80 PIO Printer Interface.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0100" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_FDDn <= '0' when CS_IO_DXn = '0' and T80_ADDR(3) = '1' and T80_ADDR(3 downto 0) /= "1111" -- Floppy range D8-DE
|
||||
else '1';
|
||||
CS_PSG0n <= '0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 0) = "0010" and CONFIG(MZ800) = '1' -- MZ-800 Programmable Sound Generator.
|
||||
else
|
||||
'0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 0) = "0010" and CONFIG(MZ1500) = '1' -- MZ-1500 Programmable Sound Generator Left Channel.
|
||||
else
|
||||
'0' when CS_IO_EXn = '0' and T80_ADDR(3 downto 0) = "1001" and CONFIG(MZ1500) = '1' -- MZ-1500 Programmable Sound Generator Left Channel - simultaneous write to both channels.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0101" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_PSG1n <= '0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 0) = "0011" and CONFIG(MZ1500) = '1' -- MZ-1500 Programmable Sound Generator Right Channel.
|
||||
else
|
||||
'0' when CS_IO_EXn = '0' and T80_ADDR(3 downto 0) = "1001" and CONFIG(MZ1500) = '1' -- MZ-1500 Programmable Sound Generator Right Channel - simultaneous write to both channels.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0110" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_GCRTCn <= '0' when CS_IO_CXn = '0' and T80_ADDR(3 downto 0) = "1111" and CONFIG(MZ800) = '1' -- MZ-800 CRT Control Register select.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "0111" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_GDMDn <= '0' when CS_IO_CXn = '0' and T80_ADDR(3 downto 0) = "1110" and CONFIG(MZ800) = '1' -- MZ-800 CRT Mode Register select.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "1000" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_GRFn <= '0' when CS_IO_CXn = '0' and T80_ADDR(3 downto 0) = "1101" and CONFIG(MZ800) = '1' -- MZ-800 CRT Read Format Register select.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "1001" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_GWFn <= '0' when CS_IO_CXn = '0' and T80_ADDR(3 downto 0) = "1100" and CONFIG(MZ800) = '1' -- MZ-800 CRT Write Format Register select.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "1010" -- External access by I/O processor.
|
||||
else '1';
|
||||
CS_GPALLETn <= '0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 0) = "0000" and CONFIG(MZ800) = '1' -- MZ-800 CRT Pallet Register select.
|
||||
else
|
||||
'0' when CS_IO_FXn = '0' and T80_ADDR(3 downto 0) = "0001" and CONFIG(MZ1500) = '1' -- MZ-1500 CRT Pallet Register select.
|
||||
else
|
||||
'0' when IOP_CSn = '0' and IOP_ADDR(5 downto 2) = "1011" -- External access by I/O processor.
|
||||
else '1';
|
||||
|
||||
|
||||
@@ -714,14 +811,14 @@ begin
|
||||
or
|
||||
( T80_ADDR(15 downto 11) = "11101" -- E800 -> EFFF User ROM memory.
|
||||
and
|
||||
(CONFIG(USERROM) and CONFIG(CURRENTMACHINE)) /= "00000000000" -- Active machine has the user rom enabled.
|
||||
CONFIG(USERROM) = '1' -- Active machine has the user rom enabled.
|
||||
and
|
||||
(MZ_HIGH_RAM_ENABLE = '0' or (MZ_HIGH_RAM_ENABLE = '1' and MZ_HIGH_RAM_INHIBIT = '1')) -- High RAM is not enabled.
|
||||
)
|
||||
or
|
||||
( T80_ADDR(15 downto 12) = "1111"
|
||||
and
|
||||
(CONFIG(FDCROM) and CONFIG(CURRENTMACHINE)) /= "00000000000" -- Active machine has the fdc rom enabled.
|
||||
CONFIG(FDCROM) = '1' -- Active machine has the fdc rom enabled.
|
||||
and
|
||||
(MZ_HIGH_RAM_ENABLE = '0' or (MZ_HIGH_RAM_ENABLE = '1' and MZ_HIGH_RAM_INHIBIT = '1')) -- F000 -> FFFF FDC ROM memory.
|
||||
)
|
||||
@@ -752,8 +849,11 @@ begin
|
||||
) and T80_MREQn = '0' and CONFIG(MZ800) = '1' and MODE_MZ700 = '1'
|
||||
else '1';
|
||||
--
|
||||
CS_RAMni <= '1' when ( MZ_800_CGROM_ENABLE = '1' and T80_ADDR(15 downto 12)="0001" and T80_MREQn='0' and CONFIG(MZ800) = '1' and GDMD_REG(3) = '1' )
|
||||
CS_RAMni <= '1' when ( MZ_800_CGROM_ENABLE = '1' and T80_ADDR(15 downto 12)="0001" and T80_MREQn='0' and CONFIG(MZ800) = '1' and GDMD_REG(3) = '1' ) -- Disable RAM when CGROM portion of BIOS ROM paged in.
|
||||
else
|
||||
'1' when ( MZ_800_CGRAM_ENABLE = '1' and T80_ADDR(15 downto 12)="1100" and T80_MREQn='0' and CONFIG(MZ800) = '1' and GDMD_REG(3) = '1' ) -- Disable RAM when CGRAM paged in.
|
||||
else
|
||||
-- MZ80K..MZ700
|
||||
'0' when ( ( (T80_ADDR(15 downto 12)="0000")
|
||||
and
|
||||
( (CONFIG(MZ_A)='1' and MZ_MEMORY_SWAP='1' and CONFIG(RAMINSTALLED) = OPT_STDRAM) -- 0000 -> 0FFF MZ80A memory swapped.
|
||||
@@ -799,6 +899,7 @@ begin
|
||||
)
|
||||
and T80_MREQn='0' and MODE_MZ800 = '0'
|
||||
else
|
||||
-- MZ800
|
||||
'0' when (
|
||||
( MZ_800_RAM_ENABLE(0) = '1' and T80_ADDR(15 downto 12)="0000")
|
||||
or
|
||||
@@ -828,9 +929,9 @@ begin
|
||||
or
|
||||
( MZ_800_RAM_ENABLE(13) = '1' and T80_ADDR(15 downto 12)="1101")
|
||||
or
|
||||
( MZ_800_INHIBIT(14) = '0' and MZ_800_RAM_ENABLE(14) = '1' and T80_ADDR(15 downto 12)="1110")
|
||||
( MZ_800_RAM_ENABLE(14) = '1' and T80_ADDR(15 downto 12)="1110" and MZ_800_INHIBIT(14) = '0')
|
||||
or
|
||||
( MZ_800_INHIBIT(15) = '0' and MZ_800_RAM_ENABLE(14) = '1' and T80_ADDR(15 downto 12)="1111")
|
||||
( MZ_800_RAM_ENABLE(15) = '1' and T80_ADDR(15 downto 12)="1111" and MZ_800_INHIBIT(15) = '0')
|
||||
) and T80_MREQn='0' and MODE_MZ800 = '1'
|
||||
else '1';
|
||||
|
||||
@@ -895,7 +996,7 @@ begin
|
||||
|
||||
-- MZ700 - Latch wether to enable RAM or ROM at 0000->0FFF.
|
||||
--
|
||||
process( T80_RSTi, CLKBUS(CKMASTER), T80_WRn, CS_IO_E0n, CS_IO_E2n, CS_IO_E4n ) begin
|
||||
process( T80_RSTi, CLKBUS(CKMASTER), MUX_WRn, CS_IO_E0n, CS_IO_E2n, CS_IO_E4n ) begin
|
||||
if(T80_RSTi = '1') then
|
||||
MZ_LOW_RAM_ENABLE <= '0';
|
||||
|
||||
@@ -903,7 +1004,7 @@ begin
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
|
||||
if T80_WRn = '0' then
|
||||
if MUX_WRn = '0' then
|
||||
if(CS_IO_E0n = '0') then
|
||||
MZ_LOW_RAM_ENABLE <= '1';
|
||||
|
||||
@@ -921,7 +1022,7 @@ begin
|
||||
|
||||
-- MZ700 - Latch wether to enable I/O or RAM at D000->FFFF.
|
||||
--
|
||||
process( T80_RSTi, CLKBUS(CKMASTER), T80_WRn, CS_IO_E1n, CS_IO_E3n, CS_IO_E4n, MZ_HIGH_RAM_INHIBIT ) begin
|
||||
process( T80_RSTi, CLKBUS(CKMASTER), MUX_WRn, CS_IO_E1n, CS_IO_E3n, CS_IO_E4n, MZ_HIGH_RAM_INHIBIT ) begin
|
||||
if(T80_RSTi = '1') then
|
||||
MZ_HIGH_RAM_ENABLE <= '0';
|
||||
MZ_INHIBIT_RESET <= '0';
|
||||
@@ -930,7 +1031,7 @@ begin
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
|
||||
if T80_WRn = '0' then
|
||||
if MUX_WRn = '0' then
|
||||
if(CS_IO_E1n = '0' and MZ_HIGH_RAM_INHIBIT = '0') then
|
||||
MZ_HIGH_RAM_ENABLE <= '1';
|
||||
|
||||
@@ -951,7 +1052,7 @@ begin
|
||||
|
||||
-- MZ700 - Latch wether to inhibit all functionality at D000->FFFF.
|
||||
--
|
||||
process( T80_RSTi, CLKBUS(CKMASTER), T80_WRn, CS_IO_E5n, CS_IO_E6n, MZ_INHIBIT_RESET ) begin
|
||||
process( T80_RSTi, CLKBUS(CKMASTER), MUX_WRn, CS_IO_E5n, CS_IO_E6n, MZ_INHIBIT_RESET ) begin
|
||||
if(T80_RSTi = '1') then
|
||||
MZ_HIGH_RAM_INHIBIT <= '0';
|
||||
|
||||
@@ -959,7 +1060,7 @@ begin
|
||||
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
|
||||
if T80_WRn = '0' then
|
||||
if MUX_WRn = '0' then
|
||||
if(CS_IO_E5n = '0') then
|
||||
MZ_HIGH_RAM_INHIBIT <= '1';
|
||||
|
||||
@@ -976,11 +1077,9 @@ begin
|
||||
-- a 16 bit map to indicate which is valid, a 1 indicates the 4K block for that device is active.
|
||||
-- Priority: INHIBIT, ROM, CGROM, VRAM, RAM
|
||||
--
|
||||
process( T80_RSTi, CLKBUS, T80_RDn, T80_WRn, CS_IO_E0n, CS_IO_E1n, CS_IO_E2n, CS_IO_E3n, CS_IO_E4n, CS_IO_E5n, CS_IO_E6n, CS_GCRTCn, CS_GDMDn, CS_GRFn, CS_GWFn ) begin
|
||||
process( T80_RSTi, CLKBUS, MUX_RDn, MUX_WRn, CS_IO_E0n, CS_IO_E1n, CS_IO_E2n, CS_IO_E3n, CS_IO_E4n, CS_IO_E5n, CS_IO_E6n, CS_GCRTCn, CS_GDMDn, CS_GRFn, CS_GWFn ) begin
|
||||
if(T80_RSTi = '1') then
|
||||
MZ_800_ROM_ENABLE <= (others => '0');
|
||||
MZ_800_RAM_ENABLE <= (others => '0');
|
||||
MZ_800_CGROM_ENABLE <= '0';
|
||||
MZ_800_VRAM_ENABLE <= (others => '0');
|
||||
MZ_800_INHIBIT <= (others => '0');
|
||||
|
||||
@@ -1017,7 +1116,7 @@ begin
|
||||
if CLKBUS(CKENCPU) = '1' then
|
||||
|
||||
-- Write (OUT) latches.
|
||||
if T80_WRn = '0' then
|
||||
if MUX_WRn = '0' then
|
||||
-- 0000:7FFF to DRAM
|
||||
if CS_IO_E0n = '0' then
|
||||
MZ_800_RAM_ENABLE(7 downto 0) <= "11111111";
|
||||
@@ -1067,7 +1166,7 @@ begin
|
||||
-- 8000:BFFF to VRAM depending upon option.
|
||||
MZ_800_VRAM_ENABLE(9 downto 8) <= "11";
|
||||
MZ_800_RAM_ENABLE(9 downto 8) <= "00";
|
||||
if GDMD_REG(2) = '1' then
|
||||
if GDMD_REG(3 downto 2) = "01" then
|
||||
MZ_800_VRAM_ENABLE(11 downto 10) <= "11";
|
||||
MZ_800_RAM_ENABLE(11 downto 10) <= "00";
|
||||
else
|
||||
@@ -1090,24 +1189,24 @@ begin
|
||||
|
||||
-- Graphics Display LSI CRT Control Register.
|
||||
elsif CS_GCRTCn = '0' then
|
||||
GCRTC_REG <= T80_DO;
|
||||
GCRTC_REG <= MUX_DOUT;
|
||||
|
||||
-- Graphics Display LSI CRT Mode Register.
|
||||
elsif CS_GDMDn = '0' then
|
||||
GDMD_REG <= T80_DO;
|
||||
GDMD_REG <= MUX_DOUT;
|
||||
|
||||
-- Graphics Display LSI Read Format Register.
|
||||
elsif CS_GRFn = '0' then
|
||||
GRF_REG <= T80_DO;
|
||||
GRF_REG <= MUX_DOUT;
|
||||
|
||||
-- Graphics Display LSI Write Format Register.
|
||||
elsif CS_GWFn = '0' then
|
||||
GWF_REG <= T80_DO;
|
||||
GWF_REG <= MUX_DOUT;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- Read (IN) latches.
|
||||
if T80_RDn = '0' then
|
||||
if MUX_RDn = '0' then
|
||||
if(CS_IO_E0n = '0') then
|
||||
-- 1000:1FFF to CGROM
|
||||
MZ_800_CGROM_ENABLE <= '1';
|
||||
@@ -1120,7 +1219,7 @@ begin
|
||||
-- 8000:BFFF to VRAM depending upon option.
|
||||
MZ_800_VRAM_ENABLE(9 downto 8) <= "11";
|
||||
MZ_800_RAM_ENABLE(9 downto 8) <= "00";
|
||||
if GDMD_REG(2) = '1' then
|
||||
if GDMD_REG(3 downto 2) = "01" then
|
||||
MZ_800_VRAM_ENABLE(11 downto 10) <= "11";
|
||||
MZ_800_RAM_ENABLE(11 downto 10) <= "00";
|
||||
else
|
||||
@@ -1188,39 +1287,72 @@ begin
|
||||
--
|
||||
-- Sound gate control
|
||||
--
|
||||
process( CLKBUS(CKMASTER), T80_WRn, CS_LS367n, T80_RSTn ) begin
|
||||
process( CLKBUS(CKMASTER), MUX_WRn, CS_LS367n, T80_RSTn ) begin
|
||||
if( T80_RSTn = '0' ) then
|
||||
SOUND_ENABLE <= '0';
|
||||
|
||||
elsif CLKBUS(CKMASTER)'event and CLKBUS(CKMASTER) = '1' then
|
||||
|
||||
if CLKBUS(CKENPERIPH) = '1' and T80_WRn = '0' and CS_LS367n = '0' then
|
||||
SOUND_ENABLE <= T80_DO(0);
|
||||
if CONFIG(MZ800) = '1' then
|
||||
if i8255_PC_OEn(0) = '0' then
|
||||
SOUND_ENABLE <= i8255_PC_O(0);
|
||||
end if;
|
||||
|
||||
if MODE_MZ800 = '1' then
|
||||
PIT_GATE0 <= '1';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- MZ-80A/MZ-700 sound control. MZ-800 in MZ-700 mode also has values updated.
|
||||
if CLKBUS(CKENPERIPH) = '1' and MUX_WRn = '0' and CS_LS367n = '0' and (CONFIG(MZ_A) = '1' or MODE_MZ700 = '1') then
|
||||
if CONFIG(MZ800) = '0' then
|
||||
SOUND_ENABLE <= MUX_DOUT(0);
|
||||
end if;
|
||||
PIT_GATE0 <= MUX_DOUT(0);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- On MZ80K..700 the 8253 Gate 0 control enables/disables the sound. On the MZ800 in 700 mode this is the same, in 800 mode
|
||||
-- the timer is used as an interrupt event timer and the gate needs to be permanently enabled.
|
||||
--
|
||||
--PIT_GATE0 <= '1' when MODE_MZ800 = '1'
|
||||
-- else
|
||||
-- SOUND_ENABLE;
|
||||
|
||||
-- Audio output. Choose between generated sound and CMT pulse audio.
|
||||
--
|
||||
AUDIO_L <= PSG_0_OUT & "00" when (MODE_MZ800 = '1' or CONFIG(MZ1500) = '1') and CONFIG(AUDIOSRC) = '0' -- Left channel is the PSG output in MZ800/MZ1500 mode.
|
||||
else
|
||||
SOUND&SOUND&SOUND&SOUND & X"000" when CONFIG(AUDIOSRC) = '0' -- Timer sound Output Left
|
||||
'0'&SOUND&SOUND&SOUND & X"000" when CONFIG(AUDIOSRC) = '0' and SOUND_ENABLE = '1' and CONFIG(MZ_K) = '1' -- Timer sound Output Left
|
||||
else
|
||||
(others => CMT_BUS_OUT(WRITEBIT));
|
||||
CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT) & X"000"
|
||||
when CONFIG(AUDIOSRC) = '1' and CONFIG(MZ_K) = '1'
|
||||
else
|
||||
(others => '0');
|
||||
AUDIO_R <= PSG_1_OUT & "00" when CONFIG(MZ1500) = '1' and CONFIG(AUDIOSRC) = '0' -- Right channel PSG in MZ1500 mode.
|
||||
else
|
||||
SOUND&SOUND&SOUND&SOUND & X"000" when CONFIG(AUDIOSRC) = '0' -- Timer sound Output Right
|
||||
'0'&SOUND&SOUND&SOUND & X"000" when CONFIG(AUDIOSRC) = '0' and SOUND_ENABLE = '1' and CONFIG(MZ_K) = '1' -- Timer sound Output Right
|
||||
else
|
||||
(others => CMT_BUS_OUT(READBIT));
|
||||
CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT)&CMT_BUS_OUT(WRITEBIT) & X"000"
|
||||
when CONFIG(AUDIOSRC) = '1' and CONFIG(MZ_K) = '1'
|
||||
else
|
||||
(others => '0');
|
||||
|
||||
-- The signal coming out of the 8254 is not a square wave and twice the frequency. The addition of a flip-flop to divide the
|
||||
-- frequency by 2 results in a square wave of the correct audio frequency.
|
||||
-- The signal coming out of the 8254 on an MZ-80A is not a square wave and twice the frequency. The addition of a flip-flop to divide the
|
||||
-- frequency by 2 results in a square wave of the correct audio frequency. Other models output a frequency wave.
|
||||
process( SOUND_PULSE_X2 ) begin
|
||||
if( SOUND_PULSE_X2'event and SOUND_PULSE_X2 = '1' ) then
|
||||
SOUND <= not SOUND;
|
||||
SOUND_PULSE_X1 <= not SOUND_PULSE_X1;
|
||||
end if;
|
||||
if CONFIG(MZ_A) = '1' then
|
||||
SOUND <= SOUND_PULSE_X1;
|
||||
else
|
||||
SOUND <= SOUND_PULSE_X2;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- MZ80 BLNK signal, enabled by VGATE being active and HBLANK pulsing. If HBLANK stops pulsing for more
|
||||
-- than 32ms, then BLNK goes inactive.
|
||||
--
|
||||
@@ -1229,7 +1361,7 @@ begin
|
||||
variable HBLANKLAST : std_logic;
|
||||
begin
|
||||
if T80_RSTn = '0' then
|
||||
BLNKn <= '1';
|
||||
BLNKn <= '1';
|
||||
TCOUNT := (others=>'0');
|
||||
|
||||
elsif CLKBUS(CKMASTER)'event and CLKBUS(CKMASTER)='1' then
|
||||
|
||||
908
FPGA/SW700/v1.3/emuMZ/sn76489_audio.vhd
Normal file
908
FPGA/SW700/v1.3/emuMZ/sn76489_audio.vhd
Normal file
@@ -0,0 +1,908 @@
|
||||
--
|
||||
-- SN76489 Complex Sound Generator
|
||||
-- Matthew Hagerty
|
||||
-- July 2020
|
||||
-- https://dnotq.io
|
||||
--
|
||||
|
||||
-- Released under the 3-Clause BSD License:
|
||||
--
|
||||
-- Copyright 2020 Matthew Hagerty (matthew <at> dnotq <dot> io)
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary 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.
|
||||
--
|
||||
-- 3. Neither the name of the copyright holder nor the names of its
|
||||
-- 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 COPYRIGHT HOLDER 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.
|
||||
|
||||
--
|
||||
-- A huge amount of effort has gone into making this core as accurate as
|
||||
-- possible to the real IC, while at the same time making it usable in all
|
||||
-- digital SoC designs, i.e. retro-computer and game systems, etc. Design
|
||||
-- elements from the real IC were used and implemented when possible, with any
|
||||
-- work-around or changes noted along with the reasons.
|
||||
--
|
||||
-- Synthesized and FPGA proven:
|
||||
--
|
||||
-- * Xilinx Spartan-6 LX16, SoC 21.477MHz system clock, 3.58MHz clock-enable.
|
||||
--
|
||||
--
|
||||
-- References:
|
||||
--
|
||||
-- * The SN76489 datasheet
|
||||
-- * Insight gained from the AY-3-8910/YM-2149 die-shot and reverse-engineered
|
||||
-- schematics (similar audio chips from the same era).
|
||||
-- * Real hardware (SN76489 in a ColecoVision game console).
|
||||
-- * Chip quirks, use, and abuse details from friends and retro enthusiasts.
|
||||
--
|
||||
--
|
||||
-- Generates:
|
||||
--
|
||||
-- * Unsigned 12-bit output for each channel.
|
||||
-- * Unsigned 14-bit summation of the four channels.
|
||||
-- * Signed 14-bit PCM summation of the four channels, with each channel
|
||||
-- converted to -/+ zero-centered level or -/+ full-range level.
|
||||
--
|
||||
-- The tone counters are period-limited to prevent the very high frequency
|
||||
-- outputs that the original IC is capable of producing. Frequencies above
|
||||
-- 20KHz cause problems in all-digital systems with sampling rates around
|
||||
-- 44.1KHz to 48KHz. The primary use of these high frequencies was as a
|
||||
-- carrier for amplitude modulated (AM) audio. The high frequency would be
|
||||
-- filtered out by external electronics, leaving only the low frequency audio.
|
||||
--
|
||||
-- When the tone counters are limited, the output square-wave is disabled, but
|
||||
-- the amplitude can still be changed, which allows the A.M. technique to still
|
||||
-- work in a digital Soc.
|
||||
--
|
||||
-- I/O requires at least two clock-enable cycles. This could be modified to
|
||||
-- operate faster, i.e. based on the input-clock directly. All inputs are
|
||||
-- registered at the system-clock rate.
|
||||
--
|
||||
-- Optionally simulates the original 32-clock (clock-enable) I/O cycle.
|
||||
--
|
||||
-- The SN76489 does not have an external reset and the original IC "wakes up"
|
||||
-- generating a tone. This implementation sets the default output level to
|
||||
-- full attenuation (silent output). If the original functionality is desired,
|
||||
-- modify the channel period and level register initial values.
|
||||
|
||||
--
|
||||
-- Basic I/O interface use:
|
||||
--
|
||||
-- Set-up data on data_i.
|
||||
-- Set ce_n_i and wr_n_i low.
|
||||
-- Observe ready_o and wait for it to become high.
|
||||
-- Set wr_n_i high, if done writing to the chip set ce_n_i high.
|
||||
|
||||
--
|
||||
-- Version history:
|
||||
--
|
||||
-- July 21 2020
|
||||
-- V1.0. Release. SoC tested.
|
||||
--
|
||||
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity sn76489_audio is
|
||||
generic -- 0 = normal I/O, 32 clocks per write
|
||||
-- 1 = fast I/O, around 2 clocks per write
|
||||
( FAST_IO_G : std_logic := '0'
|
||||
|
||||
-- Minimum allowable period count (see comments further
|
||||
-- down for more information), recommended:
|
||||
-- 6 18643.46Hz First audible count.
|
||||
-- 17 6580.04Hz Counts at 16 are known to be used for
|
||||
-- amplitude-modulation.
|
||||
; MIN_PERIOD_CNT_G : integer := 6
|
||||
);
|
||||
port
|
||||
( clk_i : in std_logic -- System clock
|
||||
; en_clk_psg_i : in std_logic -- PSG clock enable
|
||||
; ce_n_i : in std_logic -- chip enable, active low
|
||||
; wr_n_i : in std_logic -- write enable, active low
|
||||
; ready_o : out std_logic -- low during I/O operations
|
||||
; data_i : in std_logic_vector(7 downto 0)
|
||||
; ch_a_o : out unsigned(11 downto 0)
|
||||
; ch_b_o : out unsigned(11 downto 0)
|
||||
; ch_c_o : out unsigned(11 downto 0)
|
||||
; noise_o : out unsigned(11 downto 0)
|
||||
; mix_audio_o : out unsigned(13 downto 0)
|
||||
; pcm14s_o : out unsigned(13 downto 0)
|
||||
);
|
||||
end sn76489_audio;
|
||||
|
||||
architecture rtl of sn76489_audio is
|
||||
|
||||
-- Registered I/O.
|
||||
signal ce_n_r : std_logic := '1';
|
||||
signal wr_n_r : std_logic := '1';
|
||||
signal din_r : unsigned(7 downto 0) := x"00";
|
||||
signal ready_r : std_logic := '1';
|
||||
signal ready_x : std_logic;
|
||||
|
||||
-- I/O FSM.
|
||||
type io_state_t is (IO_IDLE, IO_OP, IO_WAIT);
|
||||
signal io_state_r : io_state_t := IO_IDLE;
|
||||
signal io_state_x : io_state_t;
|
||||
signal io_cnt_r : unsigned(4 downto 0) := (others => '0');
|
||||
signal io_cnt_x : unsigned(4 downto 0);
|
||||
signal en_reg_wr_s : std_logic;
|
||||
|
||||
-- Register file.
|
||||
signal reg_addr_r : unsigned(2 downto 0) := (others => '0');
|
||||
signal reg_sel_s : unsigned(2 downto 0);
|
||||
|
||||
signal ch_a_period_r : unsigned(9 downto 0) := (others => '0');
|
||||
signal ch_a_period_x : unsigned(9 downto 0);
|
||||
signal ch_a_level_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal ch_a_level_x : unsigned(11 downto 0);
|
||||
|
||||
signal ch_b_period_r : unsigned(9 downto 0) := (others => '0');
|
||||
signal ch_b_period_x : unsigned(9 downto 0);
|
||||
signal ch_b_level_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal ch_b_level_x : unsigned(11 downto 0);
|
||||
|
||||
signal ch_c_period_r : unsigned(9 downto 0) := (others => '0');
|
||||
signal ch_c_period_x : unsigned(9 downto 0);
|
||||
signal ch_c_level_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal ch_c_level_x : unsigned(11 downto 0);
|
||||
|
||||
signal noise_ctrl_r : std_logic := '0';
|
||||
signal noise_ctrl_x : std_logic;
|
||||
signal noise_shift_r : unsigned(1 downto 0) := (others => '0');
|
||||
signal noise_shift_x : unsigned(1 downto 0);
|
||||
signal noise_level_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal noise_level_x : unsigned(11 downto 0);
|
||||
signal noise_rst_r : std_logic := '0';
|
||||
signal noise_rst_x : std_logic;
|
||||
|
||||
-- Clock conditioning counters and enables.
|
||||
signal clk_div16_r : unsigned(3 downto 0) := (others => '0');
|
||||
signal clk_div16_x : unsigned(3 downto 0);
|
||||
signal en_cnt_r : std_logic := '0';
|
||||
signal en_cnt_x : std_logic;
|
||||
|
||||
-- Channel tone counters.
|
||||
signal ch_a_cnt_r : unsigned(9 downto 0) := (others => '0');
|
||||
signal ch_a_cnt_x : unsigned(9 downto 0);
|
||||
signal flatline_a_s : std_logic;
|
||||
signal tone_a_r : std_logic := '1';
|
||||
signal tone_a_x : std_logic;
|
||||
|
||||
signal ch_b_cnt_r : unsigned(9 downto 0) := (others => '0');
|
||||
signal ch_b_cnt_x : unsigned(9 downto 0);
|
||||
signal flatline_b_s : std_logic;
|
||||
signal tone_b_r : std_logic := '1';
|
||||
signal tone_b_x : std_logic;
|
||||
|
||||
signal ch_c_cnt_r : unsigned(9 downto 0) := (others => '0');
|
||||
signal ch_c_cnt_x : unsigned(9 downto 0);
|
||||
signal flatline_c_s : std_logic;
|
||||
signal tone_c_r : std_logic := '1';
|
||||
signal tone_c_x : std_logic;
|
||||
signal c_ff_r : std_logic := '1';
|
||||
signal c_ff_x : std_logic;
|
||||
|
||||
-- Noise counter.
|
||||
signal noise_cnt_r : unsigned(6 downto 0) := (others => '0');
|
||||
signal noise_cnt_x : unsigned(6 downto 0);
|
||||
signal noise_ff_r : std_logic := '1';
|
||||
signal noise_ff_x : std_logic;
|
||||
|
||||
-- 15-bit Noise LFSR.
|
||||
signal noise_lfsr_r : std_logic_vector(14 downto 0) := b"100_0000_0000_0000";
|
||||
signal noise_lfsr_x : std_logic_vector(14 downto 0);
|
||||
signal noise_fb_s : std_logic;
|
||||
signal noise_s : std_logic;
|
||||
|
||||
-- Amplitude / Attenuation control.
|
||||
signal level_a_s : unsigned(11 downto 0);
|
||||
signal level_b_s : unsigned(11 downto 0);
|
||||
signal level_c_s : unsigned(11 downto 0);
|
||||
signal level_n_s : unsigned(11 downto 0);
|
||||
|
||||
-- DAC.
|
||||
signal dac_a_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal dac_b_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal dac_c_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal dac_n_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal sum_audio_r : unsigned(13 downto 0) := (others => '0');
|
||||
|
||||
-- Digital to Analogue Output-level lookup table ROM.
|
||||
--
|
||||
-- The 4-bit level from the channel register is used as an index into a
|
||||
-- calculated table of values that represent the equivalent voltage.
|
||||
--
|
||||
-- The output scale is amplitude logarithmic.
|
||||
--
|
||||
-- ln10 = Natural logarithm of 10, ~= 2.302585
|
||||
-- amp = Amplitude in voltage, 0.2, 1.45, etc.
|
||||
-- dB = decibel value in dB, -1.5, -3, etc.
|
||||
--
|
||||
-- dB = 20 * log(amp) / ln10
|
||||
-- amp = 10 ^ (dB / 20)
|
||||
--
|
||||
-- -1.5dB = 0.8413951416
|
||||
-- -2.0dB = 0.7943282347
|
||||
-- -3.0dB = 0.7079457843
|
||||
--
|
||||
-- The datasheet defines 16 attenuation steps that are -2.0dB apart.
|
||||
--
|
||||
-- 1V reference values based on sixteen 2.0dB steps:
|
||||
--
|
||||
-- 1.0000, 0.7943, 0.6310, 0.5012, 0.3981, 0.3162, 0.2512, 0.1995,
|
||||
-- 0.1585, 0.1259, 0.1000, 0.0794, 0.0631, 0.0501, 0.0398, 0.0316
|
||||
--
|
||||
-- A 7-bit number (0..128) can support a scaled version of the reference
|
||||
-- list without having any duplicate values, but the difference is small at
|
||||
-- the bottom-end. Duplicate values means several volume levels produce the
|
||||
-- same output level, and is not accurate.
|
||||
--
|
||||
-- Using using a 12-bit output value means the four channels can be summed
|
||||
-- into a 14-bit value without overflow, and leaves room for adjustments if
|
||||
-- converting to something like 16-bit PCM. The 12-bit values also provide
|
||||
-- a nicer curve, and are easier to initialize in VHDL.
|
||||
--
|
||||
-- The lowest volume level needs to go to 0 in a digital SoC to prevent
|
||||
-- noise that would be filtered in a real system with external electronics.
|
||||
|
||||
signal dac_level_s : unsigned(11 downto 0);
|
||||
|
||||
type dacrom_type is array (0 to 15) of unsigned(11 downto 0);
|
||||
signal dacrom_ar : dacrom_type := (
|
||||
-- 4095,3253,2584,2052,1630,1295,1029, 817,
|
||||
-- 649, 516, 409, 325, 258, 205, 163, 129 (forced to 0)
|
||||
x"FFF",x"CB5",x"A18",x"804",x"65E",x"50F",x"405",x"331",
|
||||
x"289",x"204",x"199",x"145",x"102",x"0CD",x"0A3",x"000");
|
||||
|
||||
-- PCM signed 14-bit.
|
||||
signal sign_a_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal sign_a_x : unsigned(11 downto 0);
|
||||
signal sign_b_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal sign_b_x : unsigned(11 downto 0);
|
||||
signal sign_c_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal sign_c_x : unsigned(11 downto 0);
|
||||
signal sign_n_r : unsigned(11 downto 0) := (others => '0');
|
||||
signal sign_n_x : unsigned(11 downto 0);
|
||||
signal pcm14s_r : unsigned(13 downto 0) := (others => '0');
|
||||
|
||||
begin
|
||||
|
||||
-- Register the input data at the full clock rate.
|
||||
process ( clk_i ) begin
|
||||
if rising_edge(clk_i) then
|
||||
ce_n_r <= ce_n_i;
|
||||
wr_n_r <= wr_n_i;
|
||||
din_r <= unsigned(data_i);
|
||||
-- Ready is very fast so the external CPU will see the signal
|
||||
-- in time to extend the I/O operation.
|
||||
ready_r <= ready_x;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Registered output.
|
||||
ready_o <= ready_r;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- External bus cycle FSM.
|
||||
--
|
||||
-- The SN76489 can only be written (registers cannot be read back), and
|
||||
-- only when the chip is selected.
|
||||
--
|
||||
-- A write operation takes 32 clock cycles. A fast-IO mode is available
|
||||
-- if legacy timing is not important.
|
||||
|
||||
bus_io : process
|
||||
( ce_n_r, wr_n_r
|
||||
, io_state_r, io_cnt_r, ready_r
|
||||
) begin
|
||||
|
||||
io_state_x <= io_state_r;
|
||||
io_cnt_x <= io_cnt_r;
|
||||
ready_x <= ready_r;
|
||||
en_reg_wr_s <= '0';
|
||||
|
||||
case io_state_r is
|
||||
|
||||
when IO_IDLE =>
|
||||
-- Wait for CE_n and WR_n.
|
||||
if ce_n_r = '0' and wr_n_r = '0' then
|
||||
io_state_x <= IO_OP;
|
||||
ready_x <= '0';
|
||||
|
||||
if FAST_IO_G = '1' then
|
||||
-- No delay.
|
||||
io_cnt_x <= (others => '0');
|
||||
else
|
||||
-- The real IC takes 32 cycles for an I/O operation.
|
||||
io_cnt_x <= to_unsigned(31, io_cnt_x'length);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when IO_OP =>
|
||||
if io_cnt_r = 0 then
|
||||
io_state_x <= IO_WAIT;
|
||||
en_reg_wr_s <= '1';
|
||||
ready_x <= '1';
|
||||
else
|
||||
io_cnt_x <= io_cnt_r - 1;
|
||||
end if;
|
||||
|
||||
when IO_WAIT =>
|
||||
-- The CPU must end the write-cycle; fine if CE_n is still asserted.
|
||||
if wr_n_r = '1' then
|
||||
io_state_x <= IO_IDLE;
|
||||
end if;
|
||||
|
||||
end case;
|
||||
end process;
|
||||
|
||||
|
||||
process
|
||||
( clk_i, en_clk_psg_i
|
||||
) begin
|
||||
if rising_edge(clk_i) then
|
||||
if en_clk_psg_i = '1' then
|
||||
io_state_r <= io_state_x;
|
||||
io_cnt_r <= io_cnt_x;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- Registers. Setting the channel tone period requires two writes to set
|
||||
-- the full 10-bit value. Bit numbering is n..0, which is *BACKWARDS* from
|
||||
-- TI's bit numbering during this era.
|
||||
--
|
||||
-- 7654 3210
|
||||
-- R0 1000 PPPP Channel A tone period 3..0.
|
||||
-- 0-PP PPPP Channel A tone period 9..4.
|
||||
-- R1 1001 AAAA Channel A attenuation.
|
||||
-- R2 1010 PPPP Channel B tone period 3..0.
|
||||
-- 0-PP PPPP Channel B tone period 9..4.
|
||||
-- R3 1011 AAAA Channel B attenuation.
|
||||
-- R4 1100 PPPP Channel C tone period 3..0.
|
||||
-- 0-PP PPPP Channel C tone period 9..4.
|
||||
-- R5 1101 AAAA Channel C attenuation.
|
||||
-- R6 1110 -F-- Noise feedback, 0=periodic, 1=white noise
|
||||
-- 1110 --SS Noise shift rate, 00=N/512, 01=N/1024, 10=N/2048, 11=Channel C
|
||||
-- R7 1111 AAAA Noise attenuation.
|
||||
|
||||
-- The register last written is latched, so any bytes written with a '0' in
|
||||
-- the MS-bit will go to the same register.
|
||||
|
||||
-- The output-level is converted to the equivalent DAC value and stored as
|
||||
-- as the look-up result, rather than the 4-bit level index. This allows
|
||||
-- sharing of the ROM lookup table, and uses less FPGA resources.
|
||||
|
||||
dac_level_s <= dacrom_ar(to_integer(unsigned(din_r(3 downto 0))));
|
||||
|
||||
register_file : process
|
||||
( din_r, reg_addr_r, reg_sel_s, dac_level_s, en_reg_wr_s
|
||||
, ch_a_period_r, ch_a_level_r
|
||||
, ch_b_period_r, ch_b_level_r
|
||||
, ch_c_period_r, ch_c_level_r
|
||||
, noise_ctrl_r, noise_level_r, noise_shift_r
|
||||
) begin
|
||||
|
||||
-- Register writes go to the specified register, data writes go to the
|
||||
-- previously written register.
|
||||
if din_r(7) = '0' then
|
||||
reg_sel_s <= reg_addr_r;
|
||||
else
|
||||
reg_sel_s <= din_r(6 downto 4);
|
||||
end if;
|
||||
|
||||
ch_a_period_x <= ch_a_period_r;
|
||||
ch_a_level_x <= ch_a_level_r;
|
||||
ch_b_period_x <= ch_b_period_r;
|
||||
ch_b_level_x <= ch_b_level_r;
|
||||
ch_c_period_x <= ch_c_period_r;
|
||||
ch_c_level_x <= ch_c_level_r;
|
||||
|
||||
noise_ctrl_x <= noise_ctrl_r;
|
||||
noise_shift_x <= noise_shift_r;
|
||||
noise_level_x <= noise_level_r;
|
||||
noise_rst_x <= '0';
|
||||
|
||||
|
||||
case reg_sel_s is
|
||||
|
||||
when "000" =>
|
||||
if din_r(7) = '0' then
|
||||
ch_a_period_x <= din_r(5 downto 0) & ch_a_period_r(3 downto 0);
|
||||
else
|
||||
ch_a_period_x <= ch_a_period_r(9 downto 4) & din_r(3 downto 0);
|
||||
end if;
|
||||
|
||||
when "001" =>
|
||||
ch_a_level_x <= dac_level_s;
|
||||
|
||||
when "010" =>
|
||||
if din_r(7) = '0' then
|
||||
ch_b_period_x <= din_r(5 downto 0) & ch_b_period_r(3 downto 0);
|
||||
else
|
||||
ch_b_period_x <= ch_b_period_r(9 downto 4) & din_r(3 downto 0);
|
||||
end if;
|
||||
|
||||
when "011" =>
|
||||
ch_b_level_x <= dac_level_s;
|
||||
|
||||
when "100" =>
|
||||
if din_r(7) = '0' then
|
||||
ch_c_period_x <= din_r(5 downto 0) & ch_c_period_r(3 downto 0);
|
||||
else
|
||||
ch_c_period_x <= ch_c_period_r(9 downto 4) & din_r(3 downto 0);
|
||||
end if;
|
||||
|
||||
when "101" =>
|
||||
ch_c_level_x <= dac_level_s;
|
||||
|
||||
when "110" =>
|
||||
noise_ctrl_x <= din_r(2);
|
||||
noise_shift_x <= din_r(1 downto 0);
|
||||
-- Writing to the noise control register resets the LFSR to its
|
||||
-- initialization value.
|
||||
noise_rst_x <= en_reg_wr_s;
|
||||
|
||||
-- "111"
|
||||
when others =>
|
||||
noise_level_x <= dac_level_s;
|
||||
|
||||
null;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
|
||||
process
|
||||
( clk_i, en_clk_psg_i
|
||||
) begin
|
||||
if rising_edge(clk_i) then
|
||||
if en_clk_psg_i = '1' then
|
||||
|
||||
noise_rst_r <= noise_rst_x;
|
||||
|
||||
if en_reg_wr_s = '1' then
|
||||
-- Latch the register when the write specifies a register.
|
||||
reg_addr_r <= reg_sel_s;
|
||||
|
||||
ch_a_period_r <= ch_a_period_x;
|
||||
ch_a_level_r <= ch_a_level_x;
|
||||
ch_b_period_r <= ch_b_period_x;
|
||||
ch_b_level_r <= ch_b_level_x;
|
||||
ch_c_period_r <= ch_c_period_x;
|
||||
ch_c_level_r <= ch_c_level_x;
|
||||
|
||||
noise_ctrl_r <= noise_ctrl_x;
|
||||
noise_shift_r <= noise_shift_x;
|
||||
noise_level_r <= noise_level_x;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- Clock conditioning. Reduce the input clock to provide the divide by
|
||||
-- sixteen clock-phases.
|
||||
--
|
||||
|
||||
clk_div16_x <= clk_div16_r + 1;
|
||||
en_cnt_x <= '1' when clk_div16_r = 0 else '0';
|
||||
|
||||
process
|
||||
( clk_i, en_clk_psg_i
|
||||
) begin
|
||||
if rising_edge(clk_i) then
|
||||
if en_clk_psg_i = '1' then
|
||||
clk_div16_r <= clk_div16_x;
|
||||
en_cnt_r <= en_cnt_x;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- Channel tone counters. The counters *always* count.
|
||||
--
|
||||
-- The counters count *down* and load the period when they reach zero. The
|
||||
-- zero-check-and-load are all part of the same cycle. An implementation in
|
||||
-- C might look like this:
|
||||
--
|
||||
-- {
|
||||
-- if ( counter == 0 ) {
|
||||
-- tone = !tone;
|
||||
-- counter = period;
|
||||
-- }
|
||||
--
|
||||
-- counter--;
|
||||
-- }
|
||||
--
|
||||
-- With the period work-around described below:
|
||||
--
|
||||
-- {
|
||||
-- if ( counter == 0 )
|
||||
-- {
|
||||
-- if ( period > 0 and period < 6 ) {
|
||||
-- tone = 1;
|
||||
-- } else {
|
||||
-- tone = !tone;
|
||||
-- }
|
||||
--
|
||||
-- counter = period;
|
||||
-- }
|
||||
--
|
||||
-- counter--;
|
||||
-- }
|
||||
--
|
||||
-- This also demonstrates why changing the tone period will not take effect
|
||||
-- until the next cycle of the counter. Interestingly, the same counter is
|
||||
-- used in the AY-3-8910 and YM-2149, only slightly modified to count up
|
||||
-- (actually, in silicon both up and down counters are present
|
||||
-- simultaneously) and reset on a >= period condition.
|
||||
--
|
||||
|
||||
-- Amplitude Modulation.
|
||||
--
|
||||
-- With a typical 3.5MHz to 4.0MHz (max) input clock, the main-clock divide
|
||||
-- by sixteen produces a 223.72KHz clock into the tone counters. With small
|
||||
-- period counts, frequencies *well over* the human hearing range can be
|
||||
-- produced.
|
||||
--
|
||||
-- The problem with the frequencies over 20KHz is, in a digital SoC the high
|
||||
-- frequencies do not filter out like they do when the output is connected
|
||||
-- to an external low-pass filter and inductive load (speaker), like they
|
||||
-- are with the real IC.
|
||||
--
|
||||
-- In an all digital system with digital audio, the generated frequencies
|
||||
-- should never be more than the Nyquist frequency (twice the sample rate).
|
||||
-- Typical sample rates are 44.1KHz or 48KHz, so any frequency over 20KHz
|
||||
-- should not be output (and is not audible to a human anyway).
|
||||
--
|
||||
-- The work-around here is to flat-line the toggle flip-flop for any tone
|
||||
-- counter with a period that produces a frequency over the Nyquist rate.
|
||||
-- This change still allows the technique of modulating the output with
|
||||
-- rapid volume level changes.
|
||||
--
|
||||
-- Based on a typical PSG clock of 3.58MHz for a Z80-based system, the
|
||||
-- period counts that cause frequencies above 20KHz are:
|
||||
--
|
||||
-- f = CLK / (32 * Count)
|
||||
--
|
||||
-- Clk 3,579,545Hz 2.793651ns
|
||||
--
|
||||
-- Cnt Frequency Period
|
||||
-- 1 111860.78Hz 8.9396us
|
||||
-- 2 55930.39Hz 17.8793us
|
||||
-- 3 37286.92Hz 26.8190us
|
||||
-- 4 27965.19Hz 35.7587us
|
||||
-- 5 22372.15Hz 44.6984us
|
||||
-- ---------------------------
|
||||
-- 6 18643.46Hz 53.6381us First audible count.
|
||||
-- 7 15980.11Hz 62.5777us
|
||||
-- 8 13982.59Hz 71.5174us
|
||||
-- 9 12428.97Hz 80.4571us
|
||||
-- 10 11186.07Hz 89.3968us
|
||||
-- 11 10169.16Hz 98.3365us
|
||||
-- 12 9321.73Hz 107.2762us
|
||||
-- 13 8604.67Hz 116.2158us
|
||||
-- 14 7990.05Hz 125.1555us
|
||||
-- 15 7457.38Hz 134.0952us
|
||||
-- 16 6991.29Hz 143.0349us Used by some software for level-modulation.
|
||||
-- ---------------------------
|
||||
-- 17 6580.04Hz 151.9746us
|
||||
-- ...
|
||||
-- 0 109.23Hz 9.1542ms A count of zero is the maximum period.
|
||||
--
|
||||
-- While a count of 6 is technically the Nyquist cut-off, some game software
|
||||
-- is known to use a period of 16 as the base frequency for the amplitude
|
||||
-- modulation hack. While audible, the 7KHz tone is not very musical, and
|
||||
-- causes a harsh (if not painful) undertone to the sound being created with
|
||||
-- the amplitude modulation.
|
||||
--
|
||||
-- Suffice to say, setting the flat-line cut-off to 16 should not affect the
|
||||
-- audio for most software in any negative way, but can help some software
|
||||
-- sound better.
|
||||
|
||||
|
||||
-- A channel counter and tone flip-flop.
|
||||
ch_a_cnt_x <=
|
||||
-- Load uses count-enable next-state look-ahead when counter is 0.
|
||||
ch_a_period_r when (en_cnt_x = '1' and ch_a_cnt_r = 0) else
|
||||
-- Counting uses the current-state.
|
||||
ch_a_cnt_r - 1 when en_cnt_r = '1' else
|
||||
ch_a_cnt_r;
|
||||
|
||||
flatline_a_s <=
|
||||
'1' when ch_a_period_r > 0 and ch_a_period_r < MIN_PERIOD_CNT_G else
|
||||
'0';
|
||||
|
||||
tone_a_x <=
|
||||
-- Flat-line the output for counts that produce frequencies > 20KHz.
|
||||
'1' when flatline_a_s = '1' else
|
||||
-- Toggle channel tone flip-flop when the counter reaches 0.
|
||||
-- Same look-ahead condition as the counter-load.
|
||||
not tone_a_r when (en_cnt_x = '1' and ch_a_cnt_r = 0) else
|
||||
tone_a_r;
|
||||
|
||||
-- B channel counter and tone flip-flop.
|
||||
ch_b_cnt_x <=
|
||||
ch_b_period_r when (en_cnt_x = '1' and ch_b_cnt_r = 0) else
|
||||
ch_b_cnt_r - 1 when en_cnt_r = '1' else
|
||||
ch_b_cnt_r;
|
||||
|
||||
flatline_b_s <=
|
||||
'1' when ch_b_period_r > 0 and ch_b_period_r < MIN_PERIOD_CNT_G else
|
||||
'0';
|
||||
|
||||
tone_b_x <=
|
||||
'1' when flatline_b_s = '1' else
|
||||
not tone_b_r when (en_cnt_x = '1' and ch_b_cnt_r = 0) else
|
||||
tone_b_r;
|
||||
|
||||
-- C channel counter and tone flip-flop.
|
||||
ch_c_cnt_x <=
|
||||
ch_c_period_r when (en_cnt_x = '1' and ch_c_cnt_r = 0) else
|
||||
ch_c_cnt_r - 1 when en_cnt_r = '1' else
|
||||
ch_c_cnt_r;
|
||||
|
||||
flatline_c_s <=
|
||||
'1' when ch_c_period_r > 0 and ch_c_period_r < MIN_PERIOD_CNT_G else
|
||||
'0';
|
||||
|
||||
tone_c_x <= flatline_c_s or c_ff_r;
|
||||
|
||||
-- The work-around to limit high frequency outputs interferes with Channel-C
|
||||
-- being able to clock the noise shift register. This is a work-around to
|
||||
-- that work-around, to always have an output from Channel-C that can be
|
||||
-- used to clock the noise shift register.
|
||||
c_ff_x <=
|
||||
not c_ff_r when (en_cnt_x = '1' and ch_c_cnt_r = 0) else
|
||||
c_ff_r;
|
||||
|
||||
|
||||
process
|
||||
( clk_i, en_clk_psg_i
|
||||
) begin
|
||||
if rising_edge(clk_i) then
|
||||
|
||||
if en_clk_psg_i = '1' then
|
||||
ch_a_cnt_r <= ch_a_cnt_x;
|
||||
tone_a_r <= tone_a_x;
|
||||
|
||||
ch_b_cnt_r <= ch_b_cnt_x;
|
||||
tone_b_r <= tone_b_x;
|
||||
|
||||
ch_c_cnt_r <= ch_c_cnt_x;
|
||||
tone_c_r <= tone_c_x;
|
||||
c_ff_r <= c_ff_x;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- Noise period counter. A continuous counter to further divide the input
|
||||
-- clock by 32, 64, or 128. The output goes to a selector, controlled by the
|
||||
-- noise register, to choose one of the three rates, or the output flip-flop
|
||||
-- of channel C, to drive the LFSR.
|
||||
|
||||
noise_cnt_x <=
|
||||
noise_cnt_r + 1 when en_cnt_r = '1' else
|
||||
noise_cnt_r;
|
||||
|
||||
with noise_shift_r select
|
||||
noise_ff_x <= -- N = PSG input clock, typical 3.58MHz.
|
||||
noise_cnt_r(4) when "00", -- N / 512 = approx 6991.2988Hz 143.034us
|
||||
noise_cnt_r(5) when "01", -- N / 1024 = approx 3495.6494Hz 286.069us
|
||||
noise_cnt_r(6) when "10", -- N / 2048 = approx 1747.8247Hz 572.139us
|
||||
c_ff_r when others; -- "11" -- Channel C tone as the clock.
|
||||
|
||||
|
||||
-- The noise can be periodic or white depending on the feedback-bit in the
|
||||
-- noise control register. 0 = periodic, which just disables the XOR of the
|
||||
-- LFSR and loops the single initialization bit through the shift register.
|
||||
--
|
||||
-- Noise 15-bit right-shift LFSR with taps at 0 and 1, LS-bit is the output.
|
||||
-- Reset loads the LFSR with 0x4000 to prevent lock-up. The same pattern
|
||||
-- can be obtained with a left-shift, taps at 13 and 14, MS-bit output.
|
||||
--
|
||||
-- Accurate implementation in C, no branching:
|
||||
--
|
||||
-- uint32_t lfsr;
|
||||
-- uint8_t noise_bit;
|
||||
--
|
||||
-- // A 15-input NOR gate ensures init with 100_0000_0000_0000
|
||||
-- lfsr = (1 << 14);
|
||||
--
|
||||
-- // Taps at 0 and 1, mask result.
|
||||
-- int32_t fb = ((lfsr >> 0) ^ (lfsr >> 1)) & 1;
|
||||
--
|
||||
-- // Right-shift, feedback bit to the most-significant bit.
|
||||
-- lfsr = (lfsr >> 1) | (fb << 14);
|
||||
--
|
||||
-- noise_bit = (lfsr & 1);
|
||||
--
|
||||
|
||||
noise_fb_s <=
|
||||
(noise_ctrl_r and noise_lfsr_r(1)) xor noise_lfsr_r(0);
|
||||
noise_lfsr_x <= noise_fb_s & noise_lfsr_r(14 downto 1);
|
||||
noise_s <= noise_lfsr_r(0);
|
||||
|
||||
|
||||
process
|
||||
( clk_i, en_clk_psg_i, noise_rst_r
|
||||
) begin
|
||||
if rising_edge(clk_i) then
|
||||
|
||||
-- ** NOTE: This reset is active high.
|
||||
if noise_rst_r = '1' then
|
||||
noise_cnt_r <= (others => '0');
|
||||
noise_ff_r <= '1';
|
||||
noise_lfsr_r <= b"100_0000_0000_0000";
|
||||
|
||||
elsif en_clk_psg_i = '1' then
|
||||
noise_cnt_r <= noise_cnt_x;
|
||||
noise_ff_r <= noise_ff_x;
|
||||
-- Look-ahead rising-edge detect the noise flip-flop.
|
||||
if noise_ff_r = '0' and noise_ff_x = '1' then
|
||||
noise_lfsr_r <= noise_lfsr_x;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- Amplitude / Attenuation control. The amplitude of each channel is
|
||||
-- controlled by the channel's 4-bit attenuation register.
|
||||
--
|
||||
-- The "level" in the SN76489 is an amount of attenuation, and the channel's
|
||||
-- level has already been converted into its DAC level. When the tone
|
||||
-- flip-flop is '0', the most attenuation (minimum DAC level) is output.
|
||||
|
||||
level_a_s <=
|
||||
(others => '0') when tone_a_r = '0' else
|
||||
ch_a_level_r;
|
||||
|
||||
level_b_s <=
|
||||
(others => '0') when tone_b_r = '0' else
|
||||
ch_b_level_r;
|
||||
|
||||
level_c_s <=
|
||||
(others => '0') when tone_c_r = '0' else
|
||||
ch_c_level_r;
|
||||
|
||||
level_n_s <=
|
||||
(others => '0') when noise_s = '0' else
|
||||
noise_level_r;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- Output registers and unsigned summation. If the level had not already
|
||||
-- been converted to the output level, this would also be the DAC section.
|
||||
--
|
||||
|
||||
ch_a_o <= dac_a_r;
|
||||
ch_b_o <= dac_b_r;
|
||||
ch_c_o <= dac_c_r;
|
||||
noise_o <= dac_n_r;
|
||||
mix_audio_o <= sum_audio_r;
|
||||
|
||||
process
|
||||
( clk_i, en_clk_psg_i
|
||||
) begin
|
||||
if rising_edge(clk_i) then
|
||||
if en_clk_psg_i = '1' then
|
||||
|
||||
dac_a_r <= level_a_s;
|
||||
dac_b_r <= level_b_s;
|
||||
dac_c_r <= level_c_s;
|
||||
dac_n_r <= level_n_s;
|
||||
|
||||
-- Sum the audio channels.
|
||||
sum_audio_r <= ("00" & level_a_s) + ("00" & level_b_s) +
|
||||
("00" & level_c_s) + ("00" & level_n_s);
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
-- -----------------------------------------------------------------------
|
||||
--
|
||||
-- Signed zero-centered 14-bit PCM.
|
||||
--
|
||||
|
||||
-- Make a -/+ level value depending on the tone state. When the flat-line
|
||||
-- work-around for frequencies over the Nyquist rate is in effect, adjust
|
||||
-- the unsigned level-range to a signed-level range.
|
||||
--
|
||||
-- signed_level =
|
||||
-- level - (range / 2) when flat-line
|
||||
--
|
||||
-- otherwise, -/+ zero-centered square-wave:
|
||||
--
|
||||
-- signed_level =
|
||||
-- -(level / 2) when tone == 0
|
||||
-- (level / 2) when tone == 1
|
||||
|
||||
sign_a_x <=
|
||||
ch_a_level_r - x"800" when flatline_a_s = '1' else
|
||||
("1" & (not ch_a_level_r(11 downto 1))) + 1 when tone_a_r = '0' else
|
||||
("0" & ch_a_level_r(11 downto 1));
|
||||
|
||||
sign_b_x <=
|
||||
ch_b_level_r - x"800" when flatline_b_s = '1' else
|
||||
("1" & (not ch_b_level_r(11 downto 1))) + 1 when tone_b_r = '0' else
|
||||
("0" & ch_b_level_r(11 downto 1));
|
||||
|
||||
sign_c_x <=
|
||||
ch_c_level_r - x"800" when flatline_c_s = '1' else
|
||||
("1" & (not ch_c_level_r(11 downto 1))) + 1 when tone_c_r = '0' else
|
||||
("0" & ch_c_level_r(11 downto 1));
|
||||
|
||||
sign_n_x <=
|
||||
("1" & (not noise_level_r(11 downto 1))) + 1 when noise_s = '0' else
|
||||
("0" & noise_level_r(11 downto 1));
|
||||
|
||||
|
||||
pcm14s_o <= pcm14s_r;
|
||||
|
||||
|
||||
process
|
||||
( clk_i, en_clk_psg_i
|
||||
) begin
|
||||
if rising_edge(clk_i) then
|
||||
if en_clk_psg_i = '1' then
|
||||
|
||||
sign_a_r <= sign_a_x;
|
||||
sign_b_r <= sign_b_x;
|
||||
sign_c_r <= sign_c_x;
|
||||
sign_n_r <= sign_n_x;
|
||||
|
||||
-- Sum to signed 14-bit and left-align to signed 16-bit.
|
||||
pcm14s_r <=
|
||||
(sign_a_r(11) & sign_a_r(11) & sign_a_r) +
|
||||
(sign_b_r(11) & sign_b_r(11) & sign_b_r) +
|
||||
(sign_c_r(11) & sign_c_r(11) & sign_c_r) +
|
||||
(sign_n_r(11) & sign_n_r(11) & sign_n_r);
|
||||
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end rtl;
|
||||
@@ -67,6 +67,8 @@ entity snd is
|
||||
SND_ADDR : out std_logic_vector(15 downto 0);
|
||||
SND_DOUT : out std_logic_vector(7 downto 0);
|
||||
SND_DIN : in std_logic_vector(7 downto 0);
|
||||
SND_INIT_HW : in std_logic;
|
||||
SND_INIT_DONEn : out std_logic;
|
||||
|
||||
-- Arbiter control signals
|
||||
SND_GRANTn : in std_logic;
|
||||
@@ -121,6 +123,7 @@ architecture RTL of snd is
|
||||
signal SND_FIFO_WEN : std_logic;
|
||||
signal SND_FIFO_WR : natural range 0 to CACHE_SIZE;
|
||||
signal SND_FIFO_RD : natural range 0 to CACHE_SIZE;
|
||||
signal SND_INITi : std_logic;
|
||||
signal MB_STATE : integer range 0 to 3;
|
||||
|
||||
-- Digital to Analogue converter and mixer.
|
||||
@@ -166,6 +169,7 @@ begin
|
||||
Z80_WR_LASTn <= '1';
|
||||
SND_DATA <= (others => '0');
|
||||
SND_RD_DATA <= (others => '0');
|
||||
SND_INITi <= SND_INIT_HW;
|
||||
|
||||
elsif rising_edge(CLKBUS(CKMASTER)) then
|
||||
|
||||
@@ -315,8 +319,8 @@ begin
|
||||
AudioLeft := (others => '0');
|
||||
AudioRight := (others => '0');
|
||||
else
|
||||
AudioLeft := shift_right(AudioMixLeft, to_integer(unsigned(not CONFIG(AUDIOVOL))));
|
||||
AudioRight := shift_right(AudioMixRight, to_integer(unsigned(not CONFIG(AUDIOVOL))));
|
||||
AudioLeft := AudioMixLeft / (to_integer(unsigned(not CONFIG(AUDIOVOL)))+1); --shift_right(AudioMixLeft, to_integer(unsigned(not CONFIG(AUDIOVOL))));
|
||||
AudioRight := AudioMixRight / (to_integer(unsigned(not CONFIG(AUDIOVOL)))+1); --shift_right(AudioMixRight, to_integer(unsigned(not CONFIG(AUDIOVOL))));
|
||||
end if;
|
||||
|
||||
-- Assign computed digital sound value to DAC outputs.
|
||||
@@ -330,14 +334,14 @@ begin
|
||||
-- to ascertain a required voltage level.
|
||||
DACL : sigma_delta_dac
|
||||
generic map (
|
||||
MSBI => 15, -- Highest bit number.
|
||||
MSBI => 23, -- Highest bit number.
|
||||
INV => 1 -- Invert
|
||||
)
|
||||
port map
|
||||
(
|
||||
CLK => CLKBUS(CKMASTER),
|
||||
RESET => not RSTn,
|
||||
DACin => SND_DAC_LEFT,
|
||||
DACin => SND_DAC_LEFT & X"00",
|
||||
DACout => SND_AUDIO_LEFT
|
||||
);
|
||||
|
||||
@@ -346,14 +350,14 @@ begin
|
||||
-- to ascertain a required voltage level.
|
||||
DACR : sigma_delta_dac
|
||||
generic map (
|
||||
MSBI => 15, -- Highest bit number.
|
||||
MSBI => 23, -- Highest bit number.
|
||||
INV => 1 -- Invert
|
||||
)
|
||||
port map
|
||||
(
|
||||
CLK => CLKBUS(CKMASTER),
|
||||
RESET => not RSTn,
|
||||
DACin => SND_DAC_RIGHT,
|
||||
DACin => SND_DAC_RIGHT & X"00",
|
||||
DACout => SND_AUDIO_RIGHT
|
||||
);
|
||||
|
||||
@@ -364,5 +368,6 @@ begin
|
||||
SND_IORQn <= SND_IORQni;
|
||||
SND_M1n <= SND_M1ni;
|
||||
SND_BUSYn <= SND_BUSYni;
|
||||
SND_INIT_DONEn <= SND_INITi;
|
||||
|
||||
end RTL;
|
||||
|
||||
1153
FPGA/SW700/v1.3/emuMZ/wd1793/wd1793.vhd
Normal file
1153
FPGA/SW700/v1.3/emuMZ/wd1793/wd1793.vhd
Normal file
File diff suppressed because it is too large
Load Diff
125
FPGA/SW700/v1.3/emuMZ/z8420/Interrupt_v2.vhd
Normal file
125
FPGA/SW700/v1.3/emuMZ/z8420/Interrupt_v2.vhd
Normal file
@@ -0,0 +1,125 @@
|
||||
--
|
||||
-- Interrupt_v2.vhd
|
||||
--
|
||||
-- Z80 Daisy-Chain Interrupt Logic for FPGA
|
||||
--
|
||||
-- Nibbles Lab. 2013-2014
|
||||
--
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.STD_LOGIC_ARITH.ALL;
|
||||
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
||||
|
||||
entity Interrupt_v2 is
|
||||
Port (
|
||||
-- System Signal
|
||||
RESET : in std_logic;
|
||||
-- CPU Signals
|
||||
DI : in std_logic_vector(7 downto 0);
|
||||
IORQn : in std_logic; -- same as Z80
|
||||
RDn : in std_logic; -- same as Z80
|
||||
M1n : in std_logic; -- same as Z80
|
||||
IEI : in std_logic; -- same as Z80
|
||||
IEO : out std_logic; -- same as Z80
|
||||
INTOn : out std_logic;
|
||||
-- Control Signals
|
||||
VECTEN : out std_logic;
|
||||
INTI : in std_logic;
|
||||
INTEN : in std_logic
|
||||
);
|
||||
end Interrupt_v2;
|
||||
|
||||
architecture Behavioral of Interrupt_v2 is
|
||||
|
||||
-----------------------------------------------------------------------------------
|
||||
-- Signals
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
signal IREQ : std_logic;
|
||||
signal IRES : std_logic;
|
||||
signal INTR : std_logic;
|
||||
signal IAUTH : std_logic;
|
||||
signal AUTHRES : std_logic;
|
||||
signal IED1 : std_logic;
|
||||
signal IED2 : std_logic;
|
||||
signal ICB : std_logic;
|
||||
signal I4D : std_logic;
|
||||
signal FETCH : std_logic;
|
||||
signal INTA : std_logic;
|
||||
signal IENB : std_logic;
|
||||
signal iINT : std_logic;
|
||||
signal iIEO : std_logic;
|
||||
|
||||
begin
|
||||
|
||||
--
|
||||
-- External signals
|
||||
--
|
||||
INTOn <= iINT;
|
||||
IEO <= iIEO;
|
||||
|
||||
--
|
||||
-- Internal signals
|
||||
--
|
||||
iINT <= '0' when IEI='1' and IREQ='1' and IAUTH='0' else '1';
|
||||
iIEO <= not (((not IED1) and IREQ) or IAUTH or (not IEI));
|
||||
INTA <= ((not M1n ) and (not IORQn ) and IEI);
|
||||
AUTHRES <= RESET or (IEI and IED2 and I4D);
|
||||
FETCH <= M1n or RDn ;
|
||||
IRES <= RESET or INTA;
|
||||
INTR <= M1n and (INTI and INTEN);
|
||||
VECTEN <= '1' when INTA='1' and IEI='1' and IAUTH='1' else '0';
|
||||
|
||||
--
|
||||
-- Keep Interrupt Request
|
||||
--
|
||||
process( IRES, INTR ) begin
|
||||
if IRES='1' then
|
||||
IREQ <= '0';
|
||||
elsif INTR'event and INTR='1' then
|
||||
IREQ <= '1';
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--
|
||||
-- Interrupt Authentication
|
||||
--
|
||||
process( AUTHRES, INTA ) begin
|
||||
if AUTHRES='1' then
|
||||
IAUTH <= '0';
|
||||
elsif INTA'event and INTA='1' then
|
||||
IAUTH <= IREQ;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--
|
||||
-- Fetch 'RETI'
|
||||
--
|
||||
process( RESET, FETCH ) begin
|
||||
if RESET='1' then
|
||||
IED1 <= '0';
|
||||
IED2 <= '0';
|
||||
ICB <= '0';
|
||||
I4D <= '0';
|
||||
elsif FETCH'event and FETCH='1' then
|
||||
IED2 <= IED1;
|
||||
if DI=X"ED" and ICB='0' then
|
||||
IED1 <= '1';
|
||||
else
|
||||
IED1 <= '0';
|
||||
end if;
|
||||
if DI=X"CB" then
|
||||
ICB <= '1';
|
||||
else
|
||||
ICB <= '0';
|
||||
end if;
|
||||
if DI=X"4D" then
|
||||
I4D <= IEI;
|
||||
else
|
||||
I4D <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end Behavioral;
|
||||
379
FPGA/SW700/v1.3/emuMZ/z8420/z8420_v2.vhd
Normal file
379
FPGA/SW700/v1.3/emuMZ/z8420/z8420_v2.vhd
Normal file
@@ -0,0 +1,379 @@
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
--
|
||||
-- Name: z8420_v2.vhd
|
||||
-- Created: Original design, 2005-2014, Updates Dec 2021.
|
||||
-- Author(s): Nibbles Lab, Philip Smart
|
||||
-- Description: Sharp MZ series PWM Tape Interface.
|
||||
-- This module interfaces the emulation to physical sound generation hardware. On the
|
||||
-- MZ-80K series this is generally an 8253 timer, on the MZ-80B series this is a digital
|
||||
-- bit except the MZ-800 which uses an additional single PSG, the MZ-1500 which uses
|
||||
-- twin PSG's and the MZ-2500 which uses a Yamaha PSG.
|
||||
-- This module either outputs sound by controlling underlying host hardware or it
|
||||
-- mixes a digital sound representation to be output by the FPGA for use with the
|
||||
-- host hardware.
|
||||
-- Credits:
|
||||
-- Copyright: Nibbles Lab. 2005-2014 - Original work.
|
||||
-- (c) 2018-22 Philip Smart <philip.smart@net2net.org> - Enhancements
|
||||
--
|
||||
-- History: Oct 2021 - Initial write of the module.
|
||||
-- Dec 2021 - Added Audio inputs and Sigma Delta DAC's to create PWM output.
|
||||
-- Hardware used is selected via the AUDIOHW option, either writing
|
||||
-- to the underlying host hardware or using the onboard FPGA hardware.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- 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->.
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
--
|
||||
-- z8420_v2.vhd
|
||||
--
|
||||
-- Zilog Z80PIO partiality compatible module
|
||||
-- for MZ-80B on FPGA
|
||||
--
|
||||
-- Port A : Output, mode 0 only
|
||||
-- Port B : Input, mode 0 only
|
||||
--
|
||||
-- Nibbles Lab. 2005-2014
|
||||
--
|
||||
|
||||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
use IEEE.STD_LOGIC_ARITH.ALL;
|
||||
use IEEE.STD_LOGIC_UNSIGNED.ALL;
|
||||
|
||||
entity z8420_v2 is
|
||||
Port (
|
||||
-- System
|
||||
RSTn : in std_logic; -- Only Power On Reset
|
||||
-- Z80 Bus Signals
|
||||
CLK : in std_logic;
|
||||
ENA : in std_logic;
|
||||
BASEL : in std_logic;
|
||||
CDSEL : in std_logic;
|
||||
CE : in std_logic;
|
||||
RDn : in std_logic;
|
||||
WRn : in std_logic;
|
||||
IORQn : in std_logic;
|
||||
M1n : in std_logic;
|
||||
DI : in std_logic_vector(7 downto 0);
|
||||
DO : out std_logic_vector(7 downto 0);
|
||||
IEI : in std_logic;
|
||||
IEO : out std_logic;
|
||||
INTn : out std_logic;
|
||||
-- Port
|
||||
A_IN : in std_logic_vector(7 downto 0);
|
||||
A_OUT : out std_logic_vector(7 downto 0);
|
||||
A_OUT_EN : in std_logic_vector(7 downto 0);
|
||||
ARDY : out std_logic;
|
||||
ASTBn : in std_logic;
|
||||
B_IN : in std_logic_vector(7 downto 0);
|
||||
B_OUT : out std_logic_vector(7 downto 0);
|
||||
B_OUT_EN : in std_logic_vector(7 downto 0);
|
||||
BRDY : out std_logic;
|
||||
BSTBn : in std_logic
|
||||
);
|
||||
end z8420_v2;
|
||||
|
||||
architecture Behavioral of z8420_v2 is
|
||||
|
||||
--
|
||||
-- Signal conditioners.
|
||||
--
|
||||
signal WR_LAST : std_logic_vector(1 downto 0);
|
||||
--
|
||||
-- Port Selecter
|
||||
--
|
||||
signal SELAD : std_logic;
|
||||
signal SELBD : std_logic;
|
||||
signal SELAC : std_logic;
|
||||
signal SELBC : std_logic;
|
||||
--
|
||||
-- Port Register
|
||||
--
|
||||
signal AREG : std_logic_vector(7 downto 0); -- Output Register (Port A)
|
||||
signal DIRA : std_logic_vector(7 downto 0); -- Data Direction (Port A)
|
||||
signal DDWA : std_logic; -- Prepare for Data Direction (Port A)
|
||||
signal IMWA : std_logic_vector(7 downto 0); -- Interrupt Mask Word (Port A)
|
||||
signal MFA : std_logic; -- Mask Follows (Port A)
|
||||
signal VECTA : std_logic_vector(7 downto 0); -- Interrupt Vector (Port A)
|
||||
signal MODEA : std_logic_vector(1 downto 0); -- Mode Word (Port A)
|
||||
signal HLA : std_logic; -- High/Low (Port A)
|
||||
signal AOA : std_logic; -- AND/OR (Port A)
|
||||
signal BREG : std_logic_vector(7 downto 0); -- Output Register (Port B)
|
||||
signal DIRB : std_logic_vector(7 downto 0); -- Data Direction (Port B)
|
||||
signal DDWB : std_logic; -- Prepare for Data Direction (Port B)
|
||||
signal IMWB : std_logic_vector(7 downto 0); -- Interrupt Mask Word (Port B)
|
||||
signal MFB : std_logic; -- Mask Follows (Port B)
|
||||
signal VECTB : std_logic_vector(7 downto 0); -- Interrupt Vector (Port B)
|
||||
signal MODEB : std_logic_vector(1 downto 0); -- Mode Word (Port B)
|
||||
signal HLB : std_logic; -- High/Low (Port B)
|
||||
signal AOB : std_logic; -- AND/OR (Port B)
|
||||
--
|
||||
-- Interrupt
|
||||
--
|
||||
signal VECTENA : std_logic;
|
||||
signal EIA : std_logic; -- Interrupt Enable (Port A)
|
||||
signal MINTA : std_logic_vector(7 downto 0);
|
||||
signal INTA : std_logic;
|
||||
signal INT0n : std_logic;
|
||||
signal VECTENB : std_logic;
|
||||
signal EIB : std_logic; -- Interrupt Enable (Port B)
|
||||
signal MINTB : std_logic_vector(7 downto 0);
|
||||
signal INTB : std_logic;
|
||||
signal INT1n : std_logic;
|
||||
|
||||
--
|
||||
-- Components
|
||||
--
|
||||
component Interrupt is
|
||||
Port (
|
||||
-- System Signal
|
||||
RESET : in std_logic;
|
||||
-- CPU Signals
|
||||
DI : in std_logic_vector(7 downto 0);
|
||||
IORQn : in std_logic; -- same as Z80
|
||||
RDn : in std_logic; -- same as Z80
|
||||
M1n : in std_logic; -- same as Z80
|
||||
IEI : in std_logic; -- same as Z80
|
||||
IEO : out std_logic; -- same as Z80
|
||||
INTOn : out std_logic;
|
||||
-- Control Signals
|
||||
VECTEN : out std_logic;
|
||||
INTI : in std_logic;
|
||||
INTEN : in std_logic
|
||||
);
|
||||
end component;
|
||||
|
||||
begin
|
||||
|
||||
--
|
||||
-- Instantiation
|
||||
--
|
||||
INT0 : Interrupt port map (
|
||||
-- System Signal
|
||||
RESET => not RSTn,
|
||||
-- CPU Signals
|
||||
DI => DI,
|
||||
IORQn => IORQn,
|
||||
RDn => RDn,
|
||||
M1n => M1n,
|
||||
IEI => IEI,
|
||||
IEO => IEO,
|
||||
INTOn => INT0n,
|
||||
-- Control Signals
|
||||
VECTEN => VECTENA,
|
||||
INTI => INTA,
|
||||
INTEN => EIA
|
||||
);
|
||||
|
||||
INT1 : Interrupt port map (
|
||||
-- System Signal
|
||||
RESET => not RSTn ,
|
||||
-- CPU Signals
|
||||
DI => DI,
|
||||
IORQn => IORQn,
|
||||
RDn => RDn,
|
||||
M1n => M1n,
|
||||
IEI => IEI,
|
||||
IEO => IEO,
|
||||
INTOn => INT1n,
|
||||
-- Control Signals
|
||||
VECTEN => VECTENB,
|
||||
INTI => INTB,
|
||||
INTEN => EIB
|
||||
);
|
||||
|
||||
--
|
||||
-- Port select for Output
|
||||
--
|
||||
SELAD <= '1' when BASEL='0' and CDSEL='0' else '0';
|
||||
SELBD <= '1' when BASEL='1' and CDSEL='0' else '0';
|
||||
SELAC <= '1' when BASEL='0' and CDSEL='1' else '0';
|
||||
SELBC <= '1' when BASEL='1' and CDSEL='1' else '0';
|
||||
|
||||
--
|
||||
-- Control Register programming.
|
||||
--
|
||||
process( RSTn , CLK, ENA ) begin
|
||||
if RSTn ='0' then
|
||||
AREG <= (others=>'0');
|
||||
MODEA <= "01";
|
||||
DDWA <= '0';
|
||||
MFA <= '0';
|
||||
EIA <= '0';
|
||||
BREG <=(others=>'0');
|
||||
MODEB <= "01";
|
||||
DDWB <= '0';
|
||||
MFB <= '0';
|
||||
EIB <= '0';
|
||||
elsif CLK'event and CLK='0' then
|
||||
if ENA = '1' then
|
||||
|
||||
-- Writes clock cycle can be greater than 1 clock so limit to the falling edge.
|
||||
WR_LAST <= WR_LAST(0) & WRn;
|
||||
|
||||
if CE='0' and WRn ='0' and WR_LAST = "11" then
|
||||
if SELAD='1' then
|
||||
AREG <= DI;
|
||||
end if;
|
||||
if SELBD='1' then
|
||||
BREG <= DI;
|
||||
end if;
|
||||
|
||||
-- Port A
|
||||
if SELAC='1' then
|
||||
-- If the define data word is set, store the byte as the direction map of each bit.
|
||||
if DDWA='1' then
|
||||
DIRA <= DI;
|
||||
DDWA <= '0';
|
||||
|
||||
-- If the MASK setting bit is set, store the byte as the interrupt mask.
|
||||
elsif MFA='1' then
|
||||
IMWA <= DI;
|
||||
MFA <= '0';
|
||||
|
||||
-- Set the interrupt Vector.
|
||||
elsif DI(0)='0' then
|
||||
VECTA <= DI;
|
||||
|
||||
-- Set the mode.
|
||||
elsif DI(3 downto 0)="1111" then
|
||||
MODEA <= DI(7 downto 6);
|
||||
DDWA <= DI(7) and DI(6); -- Bidirectional mode requires a follow up byte to define bit direction.
|
||||
|
||||
-- Set the interrupt control word. AOA, HLA and MFA only applicable in Mode 3.
|
||||
elsif DI(3 downto 0)="0111" then
|
||||
MFA <= DI(4); -- Setting of this bit requires a follow on MASK to be sent.
|
||||
HLA <= DI(5);
|
||||
AOA <= DI(6);
|
||||
EIA <= DI(7);
|
||||
|
||||
-- Enable/Disable interrupt, D7 = 0 = Disable, = 1 = Enable.
|
||||
elsif DI(3 downto 0)="0011" then
|
||||
EIA <= DI(7);
|
||||
end if;
|
||||
end if;
|
||||
-- Port B
|
||||
if SELBC='1' then
|
||||
-- If the define data word is set, store the byte as the direction map of each bit.
|
||||
if DDWB='1' then
|
||||
DIRB <= DI;
|
||||
DDWB <= '0';
|
||||
|
||||
-- If the MASK setting bit is set, store the byte as the interrupt mask.
|
||||
elsif MFB='1' then
|
||||
IMWB <= DI;
|
||||
MFB <= '0';
|
||||
|
||||
-- Set the interrupt Vector.
|
||||
elsif DI(0)='0' then
|
||||
VECTB <= DI;
|
||||
|
||||
-- Set the mode.
|
||||
elsif DI(3 downto 0)="1111" then
|
||||
MODEB <= DI(7 downto 6);
|
||||
DDWB <= DI(7) and DI(6);
|
||||
|
||||
-- Set the interrupt control word. AOA, HLA and MFA only applicable in Mode 3.
|
||||
elsif DI(3 downto 0)="0111" then
|
||||
MFB <= DI(4);
|
||||
HLB <= DI(5);
|
||||
AOB <= DI(6);
|
||||
EIB <= DI(7);
|
||||
|
||||
-- Enable/Disable interrupt, D7 = 0 = Disable, = 1 = Enable.
|
||||
elsif DI(3 downto 0)="0011" then
|
||||
EIB <= DI(7);
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
--
|
||||
-- Input select
|
||||
--
|
||||
DO <= VECTA when VECTENA='1'
|
||||
else
|
||||
VECTB when VECTENB='1'
|
||||
else
|
||||
A_IN when RDn = '0' and CE = '0' and SELAD = '1' and MODEA = "01"
|
||||
else
|
||||
A_IN when RDn = '0' and CE = '0' and SELAD = '1' and MODEA = "10" and ASTBn = '1'
|
||||
else
|
||||
A_IN and DIRA when RDn = '0' and CE = '0' and SELAD = '1' and MODEA = "11"
|
||||
else
|
||||
AREG when RDn = '0' and CE = '0' and SELAD = '1' and MODEA = "00"
|
||||
else
|
||||
B_IN when RDn = '0' and CE = '0' and SELBD = '1' and MODEB = "01"
|
||||
else
|
||||
B_IN when RDn = '0' and CE = '0' and SELBD = '1' and MODEB = "10" and ASTBn = '1'
|
||||
else
|
||||
B_IN and DIRB when RDn = '0' and CE = '0' and SELBD = '1' and MODEB = "11"
|
||||
else
|
||||
BREG when RDn = '0' and CE = '0' and SELBD = '1' and MODEB = "00"
|
||||
else
|
||||
VECTA when RDn = '0' and CE = '0' and SELAC = '1'
|
||||
else
|
||||
MFA & HLA & AOA & EIA & MODEA & '0' & A_IN(4) when RDn = '0' and CE = '0' and SELBC = '1'
|
||||
else (others => '0');
|
||||
|
||||
-- Tristate outputs dependent upon mode and configuration.
|
||||
OUTA : for I in 0 to 7 generate
|
||||
A_OUT(I) <= AREG(I) when MODEA = "00" and A_OUT_EN(I) = '1'
|
||||
else
|
||||
AREG(I) when MODEA = "10" and A_OUT_EN(I) = '1' and ASTBn = '0'
|
||||
else
|
||||
AREG(I) when DIRA(I) = '0' and A_OUT_EN(I) = '1'
|
||||
else 'Z';
|
||||
end generate OUTA;
|
||||
OUTB : for I in 0 to 7 generate
|
||||
B_OUT(I) <= BREG(I) when MODEB = "00" and B_OUT_EN(I) = '1'
|
||||
else
|
||||
BREG(I) when MODEB = "10" and B_OUT_EN(I) = '1' and BSTBn = '0'
|
||||
else
|
||||
BREG(I) when DIRB(I) = '0' and B_OUT_EN(I) = '1'
|
||||
else 'Z';
|
||||
end generate OUTB;
|
||||
|
||||
--
|
||||
-- Interrupt masking, Mode 3.
|
||||
--
|
||||
INTMASK : for I in 0 to 7 generate
|
||||
-- MINTA(I) <= '1' when (A_IN(I) = HLA) and (IMWA(I) = '0') and AOA='0'
|
||||
-- else
|
||||
-- '1' when (A_IN(I) = HLA) or IMWA(I);
|
||||
MINTA(I) <= (A_IN(I) xnor HLA) and (not IMWA(I)) when AOA='0'
|
||||
else
|
||||
(A_IN(I) xnor HLA) or IMWA(I);
|
||||
MINTB(I) <= (B_IN(I) xnor HLB) and (not IMWB(I)) when AOB='0'
|
||||
else
|
||||
(B_IN(I) xnor HLB) or IMWB(I);
|
||||
end generate INTMASK;
|
||||
|
||||
--
|
||||
-- Interrupt select
|
||||
--
|
||||
--INTA <= '1' when A_IN(4) = '0' else '0'; --MINTA(7) or MINTA(6) or MINTA(5) or MINTA(4) or MINTA(3) or MINTA(2) or MINTA(1) or MINTA(0) when AOA='0'
|
||||
INTA <= MINTA(7) or MINTA(6) or MINTA(5) or MINTA(4) or MINTA(3) or MINTA(2) or MINTA(1) or MINTA(0) when AOA='0'
|
||||
else
|
||||
MINTA(7) and MINTA(6) and MINTA(5) and MINTA(4) and MINTA(3) and MINTA(2) and MINTA(1) and MINTA(0);
|
||||
INTB <= MINTB(7) or MINTB(6) or MINTB(5) or MINTB(4) or MINTB(3) or MINTB(2) or MINTB(1) or MINTB(0) when AOB='0'
|
||||
else
|
||||
MINTB(7) and MINTB(6) and MINTB(5) and MINTB(4) and MINTB(3) and MINTB(2) and MINTB(1) and MINTB(0);
|
||||
|
||||
-- Combine interrupts, any negative state goes through to the CPU.
|
||||
INTn <= INT0n and INT1n;
|
||||
|
||||
end Behavioral;
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -184,15 +184,28 @@ fi
|
||||
|
||||
# Create necessary directories on the SD card and clean them out.
|
||||
#for dir in TZFS MZF MZ80K MZ80A MZ80B MZ700 MZ800 MZ1500 MZ2000 CPM MSBAS MSCAS
|
||||
for dir in TZFS MZF MZ80K MZ80A MZ80B MZ80C MZ700 MZ800 MZ1200 MZ1500 MZ2000 CPM MSBAS MSCAS BASIC
|
||||
for dir in BASIC MSBAS MSCAS CPM DSK MZF TZFS
|
||||
do
|
||||
# Clean out the directories to avoid old files being used.
|
||||
if [[ "${media}x" != "x" ]]; then
|
||||
mkdir -p $media/${dir}/;
|
||||
if [ -d $media/${dir} ]; then
|
||||
rm -f $media/${dir}/*;
|
||||
rm -fr $media/${dir}/*;
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "${dir}" = "DSK" ]] || [[ "${dir}" = "MZF" ]]; then
|
||||
for subdir in MZ80K MZ80C MZ1200 MZ80A MZ700 MZ700-2 MZ1500 MZ800 MZ80B MZ2000 MZ2200 MZ2500
|
||||
do
|
||||
# Clean out the directories to avoid old files being used.
|
||||
if [[ "${media}x" != "x" ]]; then
|
||||
mkdir -p $media/${dir}/${subdir}/;
|
||||
if [ -d $media/${dir}/${subdir} ]; then
|
||||
rm -f $media/${dir}/${subdir}/*;
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# Manually copy required files.
|
||||
@@ -228,18 +241,34 @@ cp -fup ${rootdir}/${softwaredir}/roms/mz2000_cgrom.rom $media/TZ
|
||||
cp -fup ${rootdir}/${softwaredir}/roms/cpm22.bin $media/CPM/;
|
||||
cp -fup ${rootdir}/${softwaredir}/CPM/SDC16M/RAW/* $media/CPM/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/Common/* $media/MZF/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80K/* $media/MZ80K/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80A/* $media/MZ80A/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80B/* $media/MZ80B/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80C/* $media/MZ80C/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-700/* $media/MZ700/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-800/* $media/MZ800/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-1200/* $media/MZ1200/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-1500/* $media/MZ1500/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-2000/* $media/MZ2000/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80K/* $media/MZF/MZ80K/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80A/* $media/MZF/MZ80A/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80B/* $media/MZF/MZ80B/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-80C/* $media/MZF/MZ80C/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-700/* $media/MZF/MZ700/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-700-2/* $media/MZF/MZ700-2/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-800/* $media/MZF/MZ800/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-1200/* $media/MZF/MZ1200/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-1500/* $media/MZF/MZ1500/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-2000/* $media/MZF/MZ2000/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-2200/* $media/MZF/MZ2200/;
|
||||
cp -fup ${rootdir}/${softwaredir}/MZF/MZ-2500/* $media/MZF/MZ2500/;
|
||||
cp -fup ${rootdir}/${softwaredir}/BAS/* $media/MSBAS/;
|
||||
cp -fup ${rootdir}/${softwaredir}/CAS/* $media/MSCAS/
|
||||
cp -fup ${rootdir}/${softwaredir}/Basic/* $media/BASIC/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-80K/* $media/DSK/MZ80K/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-80A/* $media/DSK/MZ80A/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-80B/* $media/DSK/MZ80B/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-80C/* $media/DSK/MZ80C/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-700/* $media/DSK/MZ700/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-800/* $media/DSK/MZ800/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-1200/* $media/DSK/MZ1200/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-1500/* $media/DSK/MZ1500/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-2000/* $media/DSK/MZ2000/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-2200/* $media/DSK/MZ2200/;
|
||||
cp -fup ${rootdir}/${softwaredir}/DSK/MZ-2500/* $media/DSK/MZ2500/;
|
||||
|
||||
|
||||
|
||||
|
||||
echo "Done, TZFS, CPM and host programs copied to SD card."
|
||||
|
||||
Reference in New Issue
Block a user