Alpha release candidate rc1
This commit is contained in:
23
.gitignore
vendored
23
.gitignore
vendored
@@ -1719,4 +1719,27 @@ software/FusionX/src/z80drv/z80drv.ko
|
|||||||
software/FusionX/src/z80drv/z80drv.mod.c
|
software/FusionX/src/z80drv/z80drv.mod.c
|
||||||
software/FusionX/host/
|
software/FusionX/host/
|
||||||
software/FusionX/src/z80drv/sharpbiter
|
software/FusionX/src/z80drv/sharpbiter
|
||||||
|
CPLD/v1.0/MZ2000/tzpuFusionX.vhd.bak
|
||||||
|
CPLD/v1.0/MZ2000/tzpuFusionX.vhd.new
|
||||||
|
CPLD/v1.0/MZ700/tzpuFusionX.vhd.old
|
||||||
|
CPLD/v1.0/MZ80A/tzpuFusionX.vhd.bak
|
||||||
|
software/FusionX/src/ttymz/Makefile.kmod
|
||||||
|
software/FusionX/src/ttymz/z80io.h.old
|
||||||
|
software/FusionX/src/z80drv/1
|
||||||
|
software/FusionX/src/z80drv/2
|
||||||
|
software/FusionX/src/z80drv/Makefile.mod
|
||||||
|
software/FusionX/src/z80drv/Makefile.x
|
||||||
|
software/FusionX/src/z80drv/Z80.c.old3
|
||||||
|
software/FusionX/src/z80drv/Zeta.old3/
|
||||||
|
software/FusionX/src/z80drv/integral.h
|
||||||
|
software/FusionX/src/z80drv/src.mz2000/
|
||||||
|
software/FusionX/src/z80drv/src.mz80a/
|
||||||
|
software/FusionX/src/z80drv/src.pcw/
|
||||||
|
software/FusionX/src/z80drv/src/PCW8256_boot.hex
|
||||||
|
software/FusionX/src/z80drv/src/PCW8256_boot.rom
|
||||||
|
software/FusionX/src/z80drv/src/ccc
|
||||||
|
software/FusionX/src/z80drv/src/k64fcpu.c.hld
|
||||||
|
software/FusionX/src/z80drv/src/z80driver.c.bad
|
||||||
|
software/FusionX/src/z80drv/src/z80vhw_rfs.c.bad
|
||||||
|
CPLD/v1.0/MZ2000.old/
|
||||||
|
|
||||||
|
|||||||
@@ -127,10 +127,10 @@ set_location_assignment PIN_21 -to VSOM_RSV[1]
|
|||||||
# SOM Control Signals
|
# SOM Control Signals
|
||||||
# ===================
|
# ===================
|
||||||
set_location_assignment PIN_28 -to VSOM_READY
|
set_location_assignment PIN_28 -to VSOM_READY
|
||||||
set_location_assignment PIN_18 -to VSOM_LTSTATE
|
set_location_assignment PIN_19 -to VSOM_LTSTATE
|
||||||
set_location_assignment PIN_27 -to VSOM_BUSRQ
|
set_location_assignment PIN_27 -to VSOM_BUSRQ
|
||||||
set_location_assignment PIN_26 -to VSOM_BUSACK
|
set_location_assignment PIN_26 -to VSOM_BUSACK
|
||||||
set_location_assignment PIN_19 -to VSOM_INT
|
set_location_assignment PIN_18 -to VSOM_INT
|
||||||
set_location_assignment PIN_22 -to VSOM_NMI
|
set_location_assignment PIN_22 -to VSOM_NMI
|
||||||
set_location_assignment PIN_25 -to VSOM_WAIT
|
set_location_assignment PIN_25 -to VSOM_WAIT
|
||||||
set_location_assignment PIN_23 -to VSOM_RESET
|
set_location_assignment PIN_23 -to VSOM_RESET
|
||||||
|
|||||||
@@ -2,16 +2,17 @@
|
|||||||
--
|
--
|
||||||
-- Name: tzpuFusionX.vhd
|
-- Name: tzpuFusionX.vhd
|
||||||
-- Version: MZ-2000
|
-- Version: MZ-2000
|
||||||
-- Created: June 2020
|
-- Created: Jan 2023
|
||||||
-- Author(s): Philip Smart
|
-- Author(s): Philip Smart
|
||||||
-- Description: tzpuFusionX CPLD logic definition file.
|
-- Description: tzpuFusionX CPLD logic definition file.
|
||||||
-- This module contains the definition of the tzpuFusionX project plus enhancements
|
-- This module contains the definition of the tzpuFusionX project plus enhancements
|
||||||
-- for the MZ-2000.
|
-- for the MZ-2000.
|
||||||
--
|
--
|
||||||
-- Credits:
|
-- Credits:
|
||||||
-- Copyright: (c) 2018-22 Philip Smart <philip.smart@net2net.org>
|
-- Copyright: (c) 2018-23 Philip Smart <philip.smart@net2net.org>
|
||||||
--
|
--
|
||||||
-- History: Oct 2022 - Initial write for the MZ-2000.
|
-- History: Jan 2023 v1.0 - Initial write for the MZ-2000.
|
||||||
|
-- Apr 2023 v1.1 - Updates from the PCW8256 development.
|
||||||
--
|
--
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
-- This source file is free software: you can redistribute it and-or modify
|
-- This source file is free software: you can redistribute it and-or modify
|
||||||
@@ -128,7 +129,7 @@ end entity;
|
|||||||
|
|
||||||
architecture rtl of cpld512 is
|
architecture rtl of cpld512 is
|
||||||
|
|
||||||
-- Finite State Machine states.
|
-- Z80 Finite State Machine states.
|
||||||
type SOMFSMState is
|
type SOMFSMState is
|
||||||
(
|
(
|
||||||
IdleCycle,
|
IdleCycle,
|
||||||
@@ -174,6 +175,14 @@ architecture rtl of cpld512 is
|
|||||||
BusReqCycle
|
BusReqCycle
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Controller FSM states.
|
||||||
|
type CTRLFSMState is
|
||||||
|
(
|
||||||
|
CTRLCMD_Idle,
|
||||||
|
CTRLCMD_ReadIOWrite,
|
||||||
|
CTRLCMD_ReadIOWrite_1
|
||||||
|
);
|
||||||
|
|
||||||
-- CPU Interface internal signals.
|
-- CPU Interface internal signals.
|
||||||
signal Z80_BUSRQni : std_logic;
|
signal Z80_BUSRQni : std_logic;
|
||||||
signal Z80_INTni : std_logic;
|
signal Z80_INTni : std_logic;
|
||||||
@@ -185,7 +194,6 @@ architecture rtl of cpld512 is
|
|||||||
signal Z80_HALTni : std_logic;
|
signal Z80_HALTni : std_logic;
|
||||||
signal Z80_M1ni : std_logic;
|
signal Z80_M1ni : std_logic;
|
||||||
signal Z80_RFSHni : std_logic;
|
signal Z80_RFSHni : std_logic;
|
||||||
signal Z80_DATAi : std_logic_vector(7 downto 0);
|
|
||||||
signal Z80_BUSRQ_ACKni : std_logic;
|
signal Z80_BUSRQ_ACKni : std_logic;
|
||||||
|
|
||||||
-- Internal CPU state control.
|
-- Internal CPU state control.
|
||||||
@@ -203,9 +211,10 @@ architecture rtl of cpld512 is
|
|||||||
|
|
||||||
-- Refresh control.
|
-- Refresh control.
|
||||||
signal FSM_STATE : SOMFSMState := IdleCycle;
|
signal FSM_STATE : SOMFSMState := IdleCycle;
|
||||||
signal NEW_SPI_CMD : std_logic := '0';
|
signal CTRL_STATE : CTRLFSMState := CTRLCMD_Idle;
|
||||||
|
signal NEW_SPI_DATA : std_logic := '0';
|
||||||
signal VCPU_CS_EDGE : std_logic_vector(1 downto 0) := "11";
|
signal VCPU_CS_EDGE : std_logic_vector(1 downto 0) := "11";
|
||||||
signal AUTOREFRESH_CNT : integer range 0 to 7;
|
signal AUTOREFRESH_CNT : integer range 0 to 63;
|
||||||
signal FSM_STATUS : std_logic := '0';
|
signal FSM_STATUS : std_logic := '0';
|
||||||
signal FSM_CHECK_WAIT : std_logic := '0';
|
signal FSM_CHECK_WAIT : std_logic := '0';
|
||||||
signal FSM_WAIT_ACTIVE : std_logic := '0';
|
signal FSM_WAIT_ACTIVE : std_logic := '0';
|
||||||
@@ -229,11 +238,12 @@ architecture rtl of cpld512 is
|
|||||||
signal SPI_RX_SREG : std_logic_vector(7 downto 0); -- RX Shift Register
|
signal SPI_RX_SREG : std_logic_vector(7 downto 0); -- RX Shift Register
|
||||||
signal SPI_TX_DATA : std_logic_vector(31 downto 0); -- Data to transmit.
|
signal SPI_TX_DATA : std_logic_vector(31 downto 0); -- Data to transmit.
|
||||||
signal SPI_RX_DATA : std_logic_vector(31 downto 0); -- Data received.
|
signal SPI_RX_DATA : std_logic_vector(31 downto 0); -- Data received.
|
||||||
signal SPI_BIT_CNT : integer range 0 to 16; -- Count of bits tx/rx'd.
|
signal SPI_BIT_CNT : integer range 0 to 7; -- Count of bits tx/rx'd.
|
||||||
signal SPI_FRAME_CNT : integer range 0 to 4; -- Number of frames received (8bit chunks).
|
signal SPI_FRAME_CNT : integer range 0 to 4; -- Number of frames received (8bit chunks).
|
||||||
|
|
||||||
-- SPI Command interface.
|
-- SPI Command interface.
|
||||||
signal SOM_CMD : std_logic_vector(7 downto 0) := (others => '0');
|
signal SOM_CMD : std_logic_vector(7 downto 0) := (others => '0');
|
||||||
|
signal SOM_PARAM_CNT : integer range 0 to 3;
|
||||||
signal SPI_NEW_DATA : std_logic;
|
signal SPI_NEW_DATA : std_logic;
|
||||||
signal SPI_PROCESSING : std_logic;
|
signal SPI_PROCESSING : std_logic;
|
||||||
signal SPI_CPU_ADDR : std_logic_vector(15 downto 0) := (others => '0');
|
signal SPI_CPU_ADDR : std_logic_vector(15 downto 0) := (others => '0');
|
||||||
@@ -275,7 +285,7 @@ begin
|
|||||||
-- On the second edge, if occurring within 1 second of the first, the PM_RESET signal to the SOM is triggered, held low for 1 second,
|
-- On the second edge, if occurring within 1 second of the first, the PM_RESET signal to the SOM is triggered, held low for 1 second,
|
||||||
-- forcing the SOM to reboot.
|
-- forcing the SOM to reboot.
|
||||||
SYSRESET: process( Z80_CLKi, Z80_RESETn )
|
SYSRESET: process( Z80_CLKi, Z80_RESETn )
|
||||||
variable timer1 : integer range 0 to 354000 := 0;
|
variable timer1 : integer range 0 to 400000 := 0;
|
||||||
variable timer100 : integer range 0 to 10 := 0;
|
variable timer100 : integer range 0 to 10 := 0;
|
||||||
variable timerPMReset : integer range 0 to 10 := 0;
|
variable timerPMReset : integer range 0 to 10 := 0;
|
||||||
variable resetCount : integer range 0 to 3 := 0;
|
variable resetCount : integer range 0 to 3 := 0;
|
||||||
@@ -311,7 +321,7 @@ begin
|
|||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- 100ms interval.
|
-- 100ms interval.
|
||||||
if(timer1 = 354000) then
|
if(timer1 = 400000) then
|
||||||
timer100 := timer100 + 1;
|
timer100 := timer100 + 1;
|
||||||
|
|
||||||
if(timer100 >= 10) then
|
if(timer100 >= 10) then
|
||||||
@@ -340,8 +350,11 @@ begin
|
|||||||
-- SPI Slave input. Receive command and data from the SOM.
|
-- SPI Slave input. Receive command and data from the SOM.
|
||||||
SPI_INPUT : process(VSOM_SPI_CLK)
|
SPI_INPUT : process(VSOM_SPI_CLK)
|
||||||
begin
|
begin
|
||||||
|
-- Chip Select inactive, disable process and reset control flags.
|
||||||
|
if(VSOM_SPI_CSn = '1') then
|
||||||
|
|
||||||
-- SPI_CLK_POLARITY='0' => falling edge; SPI_CLK_POLARITY='1' => rising edge
|
-- SPI_CLK_POLARITY='0' => falling edge; SPI_CLK_POLARITY='1' => rising edge
|
||||||
if(VSOM_SPI_CLK'event and VSOM_SPI_CLK = SPI_CLK_POLARITY) then
|
elsif(VSOM_SPI_CLK'event and VSOM_SPI_CLK = SPI_CLK_POLARITY) then
|
||||||
if(VSOM_SPI_CSn = '0') then
|
if(VSOM_SPI_CSn = '0') then
|
||||||
SPI_RX_SREG <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
SPI_RX_SREG <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
||||||
|
|
||||||
@@ -356,7 +369,7 @@ begin
|
|||||||
elsif(SPI_SHIFT_EN = '1' and SPI_FRAME_CNT = 3 and SPI_BIT_CNT = 0) then
|
elsif(SPI_SHIFT_EN = '1' and SPI_FRAME_CNT = 3 and SPI_BIT_CNT = 0) then
|
||||||
SPI_RX_DATA(23 downto 16) <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
SPI_RX_DATA(23 downto 16) <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
||||||
|
|
||||||
elsif(SPI_SHIFT_EN = '1' and SPI_FRAME_CNT = 4 and SPI_BIT_CNT = 0) then
|
elsif(SPI_FRAME_CNT = 4 and SPI_BIT_CNT = 0) then
|
||||||
SPI_RX_DATA(31 downto 24) <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
SPI_RX_DATA(31 downto 24) <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
@@ -366,18 +379,22 @@ begin
|
|||||||
-- SPI Slave output. Return the current data set as selected by the input signals XACT.
|
-- SPI Slave output. Return the current data set as selected by the input signals XACT.
|
||||||
SPI_OUTPUT : process(VSOM_SPI_CLK,VSOM_SPI_CSn,SPI_TX_DATA)
|
SPI_OUTPUT : process(VSOM_SPI_CLK,VSOM_SPI_CSn,SPI_TX_DATA)
|
||||||
begin
|
begin
|
||||||
|
-- Chip Select inactive, disable process and reset control flags.
|
||||||
if(VSOM_SPI_CSn = '1') then
|
if(VSOM_SPI_CSn = '1') then
|
||||||
SPI_SHIFT_EN <= '0';
|
SPI_SHIFT_EN <= '0';
|
||||||
SPI_BIT_CNT <= 15;
|
SPI_BIT_CNT <= 7;
|
||||||
|
|
||||||
-- SPI_CLK_POLARITY='0' => falling edge; SPI_CLK_POLARITY='1' => risinge edge
|
-- SPI_CLK_POLARITY='0' => falling edge; SPI_CLK_POLARITY='1' => risinge edge
|
||||||
elsif(VSOM_SPI_CLK'event and VSOM_SPI_CLK = not SPI_CLK_POLARITY) then
|
elsif(VSOM_SPI_CLK'event and VSOM_SPI_CLK = not SPI_CLK_POLARITY) then
|
||||||
|
-- Each clock reset the shift enable and done flag in preparation for the next cycle.
|
||||||
SPI_SHIFT_EN <= '1';
|
SPI_SHIFT_EN <= '1';
|
||||||
|
|
||||||
|
-- Bit count decrements to detect when last bit of byte is sent.
|
||||||
if(SPI_BIT_CNT > 0) then
|
if(SPI_BIT_CNT > 0) then
|
||||||
SPI_BIT_CNT <= SPI_BIT_CNT - 1;
|
SPI_BIT_CNT <= SPI_BIT_CNT - 1;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
|
-- Shift out the next bit.
|
||||||
VSOM_SPI_MISO <= SPI_TX_SREG(6);
|
VSOM_SPI_MISO <= SPI_TX_SREG(6);
|
||||||
SPI_TX_SREG <= SPI_TX_SREG(5 downto 0) & '0';
|
SPI_TX_SREG <= SPI_TX_SREG(5 downto 0) & '0';
|
||||||
|
|
||||||
@@ -392,6 +409,7 @@ begin
|
|||||||
SPI_FRAME_CNT<= 1;
|
SPI_FRAME_CNT<= 1;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(7);
|
VSOM_SPI_MISO<= SPI_TX_DATA(7);
|
||||||
SPI_TX_SREG <= SPI_TX_DATA(6 downto 0);
|
SPI_TX_SREG <= SPI_TX_DATA(6 downto 0);
|
||||||
|
-- Increment frame count for each word received. We handle 8bit (1 frame), 16bit (2 frames) or 32bit (4 frames) reception.
|
||||||
elsif(SPI_FRAME_CNT = 1) then
|
elsif(SPI_FRAME_CNT = 1) then
|
||||||
SPI_FRAME_CNT<= 2;
|
SPI_FRAME_CNT<= 2;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(15);
|
VSOM_SPI_MISO<= SPI_TX_DATA(15);
|
||||||
@@ -400,13 +418,14 @@ begin
|
|||||||
SPI_FRAME_CNT<= 3;
|
SPI_FRAME_CNT<= 3;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(23);
|
VSOM_SPI_MISO<= SPI_TX_DATA(23);
|
||||||
SPI_TX_SREG <= SPI_TX_DATA(22 downto 16);
|
SPI_TX_SREG <= SPI_TX_DATA(22 downto 16);
|
||||||
else
|
elsif(SPI_FRAME_CNT = 3) then
|
||||||
-- Increment frame count for each word received. We handle 8bit (1 frame), 16bit (2 frames) or 32bit (4 frames) reception.
|
-- Increment frame count for each word received. We handle 8bit (1 frame), 16bit (2 frames) or 32bit (4 frames) reception.
|
||||||
SPI_FRAME_CNT<= 4;
|
SPI_FRAME_CNT<= 4;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(31);
|
VSOM_SPI_MISO<= SPI_TX_DATA(31);
|
||||||
SPI_TX_SREG <= SPI_TX_DATA(30 downto 24);
|
SPI_TX_SREG <= SPI_TX_DATA(30 downto 24);
|
||||||
|
else
|
||||||
|
SPI_FRAME_CNT<= 0;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
SPI_BIT_CNT <= 7;
|
SPI_BIT_CNT <= 7;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
@@ -424,6 +443,7 @@ begin
|
|||||||
AUTOREFRESH <= '0';
|
AUTOREFRESH <= '0';
|
||||||
SPI_LOOPBACK_TEST <= '0';
|
SPI_LOOPBACK_TEST <= '0';
|
||||||
SOM_CMD <= (others => '0');
|
SOM_CMD <= (others => '0');
|
||||||
|
SOM_PARAM_CNT <= 0;
|
||||||
SPI_CPU_ADDR <= (others => '0');
|
SPI_CPU_ADDR <= (others => '0');
|
||||||
SPI_NEW_DATA <= '0';
|
SPI_NEW_DATA <= '0';
|
||||||
|
|
||||||
@@ -432,6 +452,7 @@ begin
|
|||||||
-- for 8bit, 16bit and 32bit transmissions.
|
-- for 8bit, 16bit and 32bit transmissions.
|
||||||
-- The packet is formatted as follows:
|
-- The packet is formatted as follows:
|
||||||
--
|
--
|
||||||
|
-- < SPI_CPU_ADDR > < SPI_CPU_DATA >< SOM_CMD>
|
||||||
-- < SPI_FRAME_CNT=4 >< SPI_FRAME=3 > < SPI_FRAME_CNT=2 >< SPI_FRAME_CNT=1>
|
-- < SPI_FRAME_CNT=4 >< SPI_FRAME=3 > < SPI_FRAME_CNT=2 >< SPI_FRAME_CNT=1>
|
||||||
-- < 16bit Z80 Address > < Z80 Data ><Command=00..80>
|
-- < 16bit Z80 Address > < Z80 Data ><Command=00..80>
|
||||||
-- 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
-- 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||||
@@ -441,66 +462,110 @@ begin
|
|||||||
--
|
--
|
||||||
elsif(VSOM_SPI_CSn'event and VSOM_SPI_CSn = '1') then
|
elsif(VSOM_SPI_CSn'event and VSOM_SPI_CSn = '1') then
|
||||||
|
|
||||||
-- Command is always located in the upper byte of frame 1.
|
-- If active, decrement parameter count. Parameters sent after a command are not considered as commands.
|
||||||
SOM_CMD <= SPI_RX_DATA(7 downto 0);
|
if(SOM_PARAM_CNT > 0) then
|
||||||
|
SOM_PARAM_CNT <= SOM_PARAM_CNT - 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
-- Toggle flag to indicate new data arrived.
|
-- Process if command, store parameters.
|
||||||
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
if(SOM_PARAM_CNT = 0) then
|
||||||
|
-- Command is always located in the upper byte of frame 1.
|
||||||
|
SOM_CMD <= SPI_RX_DATA(7 downto 0);
|
||||||
|
|
||||||
-- Process the command. Some commands require the FSM, others can be serviced immediately.
|
-- Toggle flag to indicate new data arrived.
|
||||||
case SPI_RX_DATA(7 downto 0) is
|
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
||||||
|
|
||||||
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
-- Process the command. Some commands require the FSM, others can be serviced immediately.
|
||||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
case SPI_RX_DATA(7 downto 0) is
|
||||||
X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" | -- Write
|
|
||||||
X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" | -- Read
|
|
||||||
X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" | -- WriteIO
|
|
||||||
X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" | -- ReadIO
|
|
||||||
X"38" | X"39" | X"3A" | X"3B" | X"3C" | X"3D" | X"3E" | X"3F" | --
|
|
||||||
X"40" | X"41" | X"42" | X"43" | X"44" | X"45" | X"46" | X"47" | --
|
|
||||||
X"48" | X"49" | X"4A" | X"4B" | X"4C" | X"4D" | X"4E" | X"4F" =>
|
|
||||||
|
|
||||||
-- Direct address set.
|
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
||||||
if(SPI_FRAME_CNT = 4) then
|
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
||||||
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" | -- Write
|
||||||
else
|
X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" | -- Read
|
||||||
-- if(SPI_CPU_ADDR >= X"D010" and SPI_CPU_ADDR < X"D020") then
|
X"48" | X"49" | X"4A" | X"4B" | X"4C" | X"4D" | X"4E" | X"4F" =>
|
||||||
-- SPI_CPU_ADDR <= std_logic_vector(X"D020" + unsigned(SPI_RX_DATA(2 downto 0)));
|
|
||||||
-- else
|
|
||||||
SPI_CPU_ADDR <= std_logic_vector(unsigned(SPI_CPU_ADDR) + unsigned(SPI_RX_DATA(2 downto 0)));
|
|
||||||
-- end if;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if(SPI_FRAME_CNT > 1) then
|
-- Direct address set.
|
||||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
if(SPI_FRAME_CNT = 4) then
|
||||||
end if;
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
else
|
||||||
|
SPI_CPU_ADDR <= std_logic_vector(unsigned(SPI_CPU_ADDR) + unsigned(SPI_RX_DATA(2 downto 0)));
|
||||||
|
end if;
|
||||||
|
|
||||||
-- SETSIGSET1: Set control lines directly.
|
if(SPI_FRAME_CNT > 1) then
|
||||||
when X"F0" =>
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
VIDEO_SRCi <= SPI_RX_DATA(8);
|
end if;
|
||||||
MONO_VIDEO_SRCi <= SPI_RX_DATA(9);
|
|
||||||
AUDIO_SRC_Li <= SPI_RX_DATA(10);
|
|
||||||
AUDIO_SRC_Ri <= SPI_RX_DATA(11);
|
|
||||||
VBUS_ENi <= SPI_RX_DATA(12);
|
|
||||||
VGA_BLANKn <= not SPI_RX_DATA(13);
|
|
||||||
|
|
||||||
-- Enable auto refresh DRAM cycle.
|
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" => -- WriteIO
|
||||||
when X"F1" =>
|
|
||||||
AUTOREFRESH <= '1';
|
|
||||||
|
|
||||||
-- Disable auto refresh DRAM cycle.
|
-- Direct address set.
|
||||||
when X"F2" =>
|
if(SPI_FRAME_CNT = 4) then
|
||||||
AUTOREFRESH <= '0';
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
else
|
||||||
|
SPI_CPU_ADDR <= X"000" & '0' & std_logic_vector(unsigned(SPI_RX_DATA(2 downto 0)));
|
||||||
|
end if;
|
||||||
|
|
||||||
-- SETLOOPBACK: Enable loopback test mode.
|
if(SPI_FRAME_CNT > 1) then
|
||||||
when X"FE" =>
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
SPI_LOOPBACK_TEST<= '1';
|
end if;
|
||||||
|
|
||||||
-- No action, called to retrieve status.
|
when X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" | -- ReadIO
|
||||||
when X"00" | X"FF" =>
|
X"38" | X"39" | X"3A" | X"3B" | X"3C" | X"3D" | X"3E" | X"3F" => -- ReadIO-Write
|
||||||
|
|
||||||
when others =>
|
-- Direct address set.
|
||||||
end case;
|
if(SPI_FRAME_CNT = 4) then
|
||||||
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
elsif(SPI_FRAME_CNT = 2) then
|
||||||
|
SPI_CPU_ADDR <= X"00" & SPI_RX_DATA(15 downto 8);
|
||||||
|
else
|
||||||
|
SPI_CPU_ADDR <= X"000" & '0' & std_logic_vector(unsigned(SPI_RX_DATA(2 downto 0)));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if(SPI_FRAME_CNT > 1) then
|
||||||
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- ReadIO-Write, Read-WriteIO commands require target address, so indicate parameter needed.
|
||||||
|
if(SPI_RX_DATA(7 downto 0) >= X"38" and SPI_RX_DATA(7 downto 0) < X"40") then
|
||||||
|
SOM_PARAM_CNT <= 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- SETSIGSET1: Set control lines directly.
|
||||||
|
when X"F0" =>
|
||||||
|
VIDEO_SRCi <= SPI_RX_DATA(8);
|
||||||
|
MONO_VIDEO_SRCi <= SPI_RX_DATA(9);
|
||||||
|
AUDIO_SRC_Li <= SPI_RX_DATA(10);
|
||||||
|
AUDIO_SRC_Ri <= SPI_RX_DATA(11);
|
||||||
|
VBUS_ENi <= SPI_RX_DATA(12);
|
||||||
|
VGA_BLANKn <= not SPI_RX_DATA(13);
|
||||||
|
|
||||||
|
-- Enable auto refresh DRAM cycle.
|
||||||
|
when X"F1" =>
|
||||||
|
AUTOREFRESH <= '1';
|
||||||
|
|
||||||
|
-- Disable auto refresh DRAM cycle.
|
||||||
|
when X"F2" =>
|
||||||
|
AUTOREFRESH <= '0';
|
||||||
|
|
||||||
|
-- SETLOOPBACK: Enable loopback test mode.
|
||||||
|
when X"FE" =>
|
||||||
|
SPI_LOOPBACK_TEST<= '1';
|
||||||
|
|
||||||
|
-- No action, called to retrieve status.
|
||||||
|
when X"00" | X"FF" =>
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
end case;
|
||||||
|
else
|
||||||
|
-- Store parameter depending on number of frames, either ADDR+DATA, ADDR or DATA.
|
||||||
|
if(SPI_FRAME_CNT = 4) then
|
||||||
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
|
elsif(SPI_FRAME_CNT = 2) then
|
||||||
|
SPI_CPU_ADDR <= SPI_RX_DATA(15 downto 0);
|
||||||
|
else
|
||||||
|
SPI_CPU_DATA <= SPI_RX_DATA(7 downto 0);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
end process;
|
end process;
|
||||||
|
|
||||||
@@ -561,9 +626,9 @@ begin
|
|||||||
CPU_DATA_EN <= '0';
|
CPU_DATA_EN <= '0';
|
||||||
CPU_DATA_IN <= (others => '0');
|
CPU_DATA_IN <= (others => '0');
|
||||||
REFRESH_ADDR <= (others => '0');
|
REFRESH_ADDR <= (others => '0');
|
||||||
AUTOREFRESH_CNT <= 7;
|
AUTOREFRESH_CNT <= 63;
|
||||||
IPAR <= (others => '0');
|
IPAR <= (others => '0');
|
||||||
NEW_SPI_CMD <= '0';
|
NEW_SPI_DATA <= '0';
|
||||||
VCPU_CS_EDGE <= "11";
|
VCPU_CS_EDGE <= "11";
|
||||||
SPI_PROCESSING <= '0';
|
SPI_PROCESSING <= '0';
|
||||||
|
|
||||||
@@ -580,98 +645,12 @@ begin
|
|||||||
|
|
||||||
-- New command, set flag as the signal is only 1 clock wide.
|
-- New command, set flag as the signal is only 1 clock wide.
|
||||||
if(SPI_LOOPBACK_TEST = '0' and VSOM_SPI_CSn = '1' and VCPU_CS_EDGE = "01") then
|
if(SPI_LOOPBACK_TEST = '0' and VSOM_SPI_CSn = '1' and VCPU_CS_EDGE = "01") then
|
||||||
NEW_SPI_CMD <= '1';
|
NEW_SPI_DATA <= '1';
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- Whenever we return to Idle or just prior to Refresh from a Fetch cycle set all control signals to default.
|
-- Decrement refresh counter on each Z80 cycle, thus when idle and time expired, a refresh can be performed within parameters (256 cycles in 4ms).
|
||||||
if(FSM_STATE = IdleCycle or FSM_STATE = RefreshCycle) then
|
if(AUTOREFRESH = '1' and AUTOREFRESH_CNT /= 0 and Z80_CLK_RE = '1') then
|
||||||
CPU_DATA_EN <= '0';
|
AUTOREFRESH_CNT <= AUTOREFRESH_CNT - 1;
|
||||||
Z80_MREQni <= '1';
|
|
||||||
Z80_IORQni <= '1';
|
|
||||||
Z80_RDni <= '1';
|
|
||||||
Z80_WRni <= '1';
|
|
||||||
Z80_M1ni <= '1';
|
|
||||||
FSM_STATUS <= '0';
|
|
||||||
Z80_RFSHni <= '1';
|
|
||||||
|
|
||||||
-- Auto DRAM refresh cycles. When enabled, every 7 host clock cycles, a 2 cycle refresh period commences.
|
|
||||||
-- This will be overriden if the SPI receives a new command.
|
|
||||||
--
|
|
||||||
if AUTOREFRESH = '1' and FSM_STATE = IdleCycle then
|
|
||||||
AUTOREFRESH_CNT <= AUTOREFRESH_CNT - 1;
|
|
||||||
if(AUTOREFRESH_CNT = 0) then
|
|
||||||
FSM_STATE <= RefreshCycle_3;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- If new command has been given and the FSM enters idle state, load up new command for processing.
|
|
||||||
if(NEW_SPI_CMD = '1' and FSM_STATE = IdleCycle and Z80_CLK_RE = '1') then
|
|
||||||
NEW_SPI_CMD <= '0';
|
|
||||||
|
|
||||||
-- Store new address and data for this command.
|
|
||||||
CPU_ADDR <= SPI_CPU_ADDR;
|
|
||||||
if(SPI_CPU_DATA /= CPU_DATA_OUT) then
|
|
||||||
CPU_DATA_OUT <= SPI_CPU_DATA;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- Process the SOM command. The SPI_REGISTER executes non FSM commands and stores FSM
|
|
||||||
-- data prior to this execution block, which fires 1 cycle later on the same control clock.
|
|
||||||
-- If the command is not for the FSM then the READY mechanism is held for one
|
|
||||||
-- further cycle before going inactive.
|
|
||||||
case SOM_CMD is
|
|
||||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" =>
|
|
||||||
-- Initiate a Fetch Cycle.
|
|
||||||
FSM_STATE <= FetchCycle;
|
|
||||||
|
|
||||||
when X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" =>
|
|
||||||
|
|
||||||
-- Set the Z80 data bus value and initiate a Write Cycle.
|
|
||||||
FSM_STATE <= WriteCycle;
|
|
||||||
|
|
||||||
when X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" =>
|
|
||||||
-- Initiate a Read Cycle.
|
|
||||||
FSM_STATE <= ReadCycle;
|
|
||||||
|
|
||||||
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" =>
|
|
||||||
-- Set the Z80 data bus value and initiate an IO Write Cycle.
|
|
||||||
-- The SOM should set 15:8 to the B register value.
|
|
||||||
FSM_STATE <= WriteIOCycle;
|
|
||||||
|
|
||||||
when X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" =>
|
|
||||||
-- Initiate a Read IO Cycle.
|
|
||||||
FSM_STATE <= ReadIOCycle;
|
|
||||||
|
|
||||||
when X"50" =>
|
|
||||||
-- Register a Halt state.
|
|
||||||
FSM_STATE <= HaltCycle;
|
|
||||||
|
|
||||||
when X"51" =>
|
|
||||||
-- Initiate a refresh cycle.
|
|
||||||
FSM_STATE <= RefreshCycle_3;
|
|
||||||
|
|
||||||
when X"E0" =>
|
|
||||||
-- Initiate a Halt Cycle.
|
|
||||||
FSM_STATE <= HaltCycle;
|
|
||||||
|
|
||||||
-- Set the Refresh Address register.
|
|
||||||
when X"E1" =>
|
|
||||||
REFRESH_ADDR <= CPU_DATA_OUT;
|
|
||||||
|
|
||||||
-- Set the Interrupt Page Address Register.
|
|
||||||
when X"E2" =>
|
|
||||||
IPAR <= CPU_DATA_OUT;
|
|
||||||
|
|
||||||
when others =>
|
|
||||||
end case;
|
|
||||||
|
|
||||||
-- Toggle the processing flag to negate the new data flag. Used to indicate device is busy.
|
|
||||||
if(SPI_NEW_DATA /= SPI_PROCESSING) then
|
|
||||||
SPI_PROCESSING <= not SPI_PROCESSING;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- FSM Status bit. When processing a command it is set, cleared when idle. Used by SOM to determine command completion.
|
|
||||||
FSM_STATUS <= '1';
|
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- Refresh status bit. Indicates a Refresh cycle is under way.
|
-- Refresh status bit. Indicates a Refresh cycle is under way.
|
||||||
@@ -686,7 +665,143 @@ begin
|
|||||||
FSM_WAIT_ACTIVE <= '1';
|
FSM_WAIT_ACTIVE <= '1';
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- On each Z80 edge we advance the FSM to recreate the Z80 external signal transactions.
|
-- Whenever we return to Idle or just prior to Refresh from a Fetch cycle set all control signals to default.
|
||||||
|
if((FSM_STATE = IdleCycle or FSM_STATE = RefreshCycle) and Z80_CLK_RE = '1') then
|
||||||
|
CPU_DATA_EN <= '0';
|
||||||
|
Z80_MREQni <= '1';
|
||||||
|
Z80_IORQni <= '1';
|
||||||
|
Z80_RDni <= '1';
|
||||||
|
Z80_WRni <= '1';
|
||||||
|
Z80_M1ni <= '1';
|
||||||
|
FSM_STATUS <= '0';
|
||||||
|
Z80_RFSHni <= '1';
|
||||||
|
|
||||||
|
-- Auto DRAM refresh cycles. When enabled, every 15.6us a refresh period commences.
|
||||||
|
-- This period may be extended if the SPI receives a new command.
|
||||||
|
--
|
||||||
|
if AUTOREFRESH = '1' and FSM_STATE = IdleCycle then
|
||||||
|
if(AUTOREFRESH_CNT = 0) then
|
||||||
|
FSM_STATE <= RefreshCycle_3;
|
||||||
|
FSM_STATUS<= '1';
|
||||||
|
-- 4164 DRAM = 256 cycles in 4ms.
|
||||||
|
AUTOREFRESH_CNT <= 63;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
-- CPLD Macro Command Finite State Machine.
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Controller state machine.
|
||||||
|
-- When idle, accept and process SPI commands which can lead to a controller macro command.
|
||||||
|
case CTRL_STATE is
|
||||||
|
|
||||||
|
when CTRLCMD_Idle =>
|
||||||
|
-- If new command has been given and the FSM enters idle state, load up new command for processing.
|
||||||
|
if(NEW_SPI_DATA = '1' and FSM_STATE = IdleCycle and Z80_CLK_RE = '1') then
|
||||||
|
|
||||||
|
-- Store new address and data for this command.
|
||||||
|
if(NEW_SPI_DATA = '1') then
|
||||||
|
CPU_ADDR <= SPI_CPU_ADDR;
|
||||||
|
CPU_DATA_OUT <= SPI_CPU_DATA;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Process the SOM command. The SPI_REGISTER executes non FSM commands and stores FSM
|
||||||
|
-- data prior to this execution block, which fires 1 cycle later on the same control clock.
|
||||||
|
-- If the command is not for the FSM then the READY mechanism is held for one
|
||||||
|
-- further cycle before going inactive.
|
||||||
|
case SOM_CMD is
|
||||||
|
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" =>
|
||||||
|
-- Initiate a Fetch Cycle.
|
||||||
|
FSM_STATE <= FetchCycle;
|
||||||
|
|
||||||
|
when X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" =>
|
||||||
|
|
||||||
|
-- Set the Z80 data bus value and initiate a Write Cycle.
|
||||||
|
FSM_STATE <= WriteCycle;
|
||||||
|
|
||||||
|
when X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" =>
|
||||||
|
-- Initiate a Read Cycle.
|
||||||
|
FSM_STATE <= ReadCycle;
|
||||||
|
|
||||||
|
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" =>
|
||||||
|
-- Set the Z80 data bus value and initiate an IO Write Cycle.
|
||||||
|
-- The SOM should set 15:8 to the B register value.
|
||||||
|
FSM_STATE <= WriteIOCycle;
|
||||||
|
|
||||||
|
when X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" =>
|
||||||
|
-- Initiate a Read IO Cycle.
|
||||||
|
FSM_STATE <= ReadIOCycle;
|
||||||
|
|
||||||
|
when X"38" | X"39" | X"3A" | X"3B" | X"3C" | X"3D" | X"3E" | X"3F" =>
|
||||||
|
-- Initiate a read IO write memory cycle via the controller FSM.
|
||||||
|
CTRL_STATE <= CTRLCMD_ReadIOWrite;
|
||||||
|
FSM_STATE <= ReadIOCycle;
|
||||||
|
|
||||||
|
when X"50" =>
|
||||||
|
-- Register a Halt state.
|
||||||
|
FSM_STATE <= HaltCycle;
|
||||||
|
|
||||||
|
when X"51" =>
|
||||||
|
-- Initiate a refresh cycle.
|
||||||
|
FSM_STATE <= RefreshCycle_3;
|
||||||
|
|
||||||
|
when X"E0" =>
|
||||||
|
-- Initiate a Halt Cycle.
|
||||||
|
FSM_STATE <= HaltCycle;
|
||||||
|
|
||||||
|
-- Set the Refresh Address register.
|
||||||
|
when X"E1" =>
|
||||||
|
REFRESH_ADDR <= CPU_DATA_OUT;
|
||||||
|
|
||||||
|
-- Set the Interrupt Page Address Register.
|
||||||
|
when X"E2" =>
|
||||||
|
IPAR <= CPU_DATA_OUT;
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
end case;
|
||||||
|
|
||||||
|
-- Toggle the processing flag to negate the new data flag. Used to indicate device is busy.
|
||||||
|
if(SPI_NEW_DATA /= SPI_PROCESSING) then
|
||||||
|
SPI_PROCESSING<= not SPI_PROCESSING;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Clear new data flag ready for next cmd/param transfer.
|
||||||
|
NEW_SPI_DATA <= '0';
|
||||||
|
|
||||||
|
-- FSM Status bit. When processing a command it is set, cleared when idle. Used by SOM to determine command completion.
|
||||||
|
FSM_STATUS <= '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when CTRLCMD_ReadIOWrite =>
|
||||||
|
if(NEW_SPI_DATA = '1' and FSM_STATE = IdleCycle and Z80_CLK_RE = '1') then
|
||||||
|
NEW_SPI_DATA <= '0';
|
||||||
|
CPU_DATA_EN <= '0';
|
||||||
|
Z80_IORQni <= '1';
|
||||||
|
Z80_RDni <= '1';
|
||||||
|
Z80_RFSHni <= '1';
|
||||||
|
CPU_ADDR <= SPI_CPU_ADDR;
|
||||||
|
CPU_DATA_OUT <= CPU_DATA_IN;
|
||||||
|
FSM_STATE <= WriteCycle;
|
||||||
|
CTRL_STATE <= CTRLCMD_ReadIOWrite_1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when CTRLCMD_ReadIOWrite_1 =>
|
||||||
|
if(FSM_STATE = WriteCycle_31) then
|
||||||
|
CTRL_STATE <= CTRLCMD_Idle;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
CTRL_STATE <= CTRLCMD_Idle;
|
||||||
|
|
||||||
|
end case;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
-- Z80 Finite State Machine.
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- On each Z80 edge we advance the Z80 FSM to recreate the Z80 external signal transactions.
|
||||||
if(Z80_CLK_TGL = '1') then
|
if(Z80_CLK_TGL = '1') then
|
||||||
|
|
||||||
-- The FSM advances to the next stage on each Z80 edge unless in Idle state.
|
-- The FSM advances to the next stage on each Z80 edge unless in Idle state.
|
||||||
@@ -704,7 +819,7 @@ begin
|
|||||||
|
|
||||||
when IdleCycle =>
|
when IdleCycle =>
|
||||||
CPU_LAST_T_STATE <= '1';
|
CPU_LAST_T_STATE <= '1';
|
||||||
-- FSM_STATE <= IdleCycle;
|
FSM_STATUS <= '0';
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
-- Z80 Fetch Cycle.
|
-- Z80 Fetch Cycle.
|
||||||
@@ -727,7 +842,7 @@ begin
|
|||||||
|
|
||||||
when FetchCycle_30 =>
|
when FetchCycle_30 =>
|
||||||
-- To meet the timing diagrams, just after Rising edge on T3 clear signals. Data wont be available until
|
-- To meet the timing diagrams, just after Rising edge on T3 clear signals. Data wont be available until
|
||||||
-- a short period before the falling edge of T3 (could be an MZ-2000 design restriction or the Z80 timing diagrams are a bit out).
|
-- a short period before the falling edge of T3.
|
||||||
FSM_STATE <= RefreshCycle;
|
FSM_STATE <= RefreshCycle;
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -736,18 +851,18 @@ begin
|
|||||||
when RefreshCycle =>
|
when RefreshCycle =>
|
||||||
-- Latch data from mainboard.
|
-- Latch data from mainboard.
|
||||||
CPU_DATA_IN <= Z80_DATA;
|
CPU_DATA_IN <= Z80_DATA;
|
||||||
FSM_STATUS <= '0';
|
|
||||||
Z80_RFSHni <= '0';
|
Z80_RFSHni <= '0';
|
||||||
|
|
||||||
when RefreshCycle_11 =>
|
when RefreshCycle_11 =>
|
||||||
-- Falling edge of T3 activates the MREQ line.
|
-- Falling edge of T3 activates the MREQ line.
|
||||||
Z80_MREQni <= '0';
|
Z80_MREQni <= '0';
|
||||||
|
FSM_STATUS <= '0';
|
||||||
|
|
||||||
when RefreshCycle_20 =>
|
when RefreshCycle_20 =>
|
||||||
|
|
||||||
when RefreshCycle_21 =>
|
when RefreshCycle_21 =>
|
||||||
Z80_MREQni <= '1';
|
Z80_MREQni <= '1';
|
||||||
REFRESH_ADDR(6 downto 0) <= REFRESH_ADDR(6 downto 0) + 1;
|
REFRESH_ADDR <= REFRESH_ADDR + 1;
|
||||||
FSM_STATE <= IdleCycle;
|
FSM_STATE <= IdleCycle;
|
||||||
|
|
||||||
when RefreshCycle_3 =>
|
when RefreshCycle_3 =>
|
||||||
@@ -769,7 +884,7 @@ begin
|
|||||||
when WriteCycle_21 =>
|
when WriteCycle_21 =>
|
||||||
Z80_WRni <= '0';
|
Z80_WRni <= '0';
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= WriteCycle_20;
|
FSM_STATE <= WriteCycle_20;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when WriteCycle_30 =>
|
when WriteCycle_30 =>
|
||||||
@@ -794,7 +909,7 @@ begin
|
|||||||
|
|
||||||
when ReadCycle_21 =>
|
when ReadCycle_21 =>
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= ReadCycle_20;
|
FSM_STATE <= ReadCycle_20;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when ReadCycle_30 =>
|
when ReadCycle_30 =>
|
||||||
@@ -805,7 +920,6 @@ begin
|
|||||||
FSM_STATUS <= '0';
|
FSM_STATUS <= '0';
|
||||||
FSM_STATE <= IdleCycle;
|
FSM_STATE <= IdleCycle;
|
||||||
|
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
-- Z80 IO Write Cycle.
|
-- Z80 IO Write Cycle.
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -825,7 +939,7 @@ begin
|
|||||||
|
|
||||||
when WriteIOCycle_31 =>
|
when WriteIOCycle_31 =>
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= WriteIOCycle_20;
|
FSM_STATE <= WriteIOCycle_30;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when WriteIOCycle_40 =>
|
when WriteIOCycle_40 =>
|
||||||
@@ -854,7 +968,7 @@ begin
|
|||||||
|
|
||||||
when ReadIOCycle_31 =>
|
when ReadIOCycle_31 =>
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= ReadIOCycle_20;
|
FSM_STATE <= ReadIOCycle_30;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when ReadIOCycle_40 =>
|
when ReadIOCycle_40 =>
|
||||||
@@ -902,8 +1016,6 @@ begin
|
|||||||
Z80_DATA <= CPU_DATA_OUT when Z80_BUSRQ_ACKni = '1' and CPU_DATA_EN = '1'
|
Z80_DATA <= CPU_DATA_OUT when Z80_BUSRQ_ACKni = '1' and CPU_DATA_EN = '1'
|
||||||
else
|
else
|
||||||
(others => 'Z');
|
(others => 'Z');
|
||||||
-- Z80_DATAi <= Z80_DATA when Z80_RDn = '0'
|
|
||||||
-- else (others => '1');
|
|
||||||
Z80_RDn <= Z80_RDni when Z80_BUSRQ_ACKni = '1'
|
Z80_RDn <= Z80_RDni when Z80_BUSRQ_ACKni = '1'
|
||||||
else 'Z';
|
else 'Z';
|
||||||
Z80_WRn <= Z80_WRni when Z80_BUSRQ_ACKni = '1'
|
Z80_WRn <= Z80_WRni when Z80_BUSRQ_ACKni = '1'
|
||||||
@@ -944,7 +1056,7 @@ begin
|
|||||||
|
|
||||||
-- Signal mirrors.
|
-- Signal mirrors.
|
||||||
VSOM_READY <= '0' when FSM_STATUS='1' or SPI_NEW_DATA /= SPI_PROCESSING
|
VSOM_READY <= '0' when FSM_STATUS='1' or SPI_NEW_DATA /= SPI_PROCESSING
|
||||||
else '1'; -- FSM Ready (1), Busy (0)
|
else '1'; -- FSM Ready (1), Busy (0)
|
||||||
VSOM_LTSTATE <= '1' when CPU_LAST_T_STATE = '1' -- Last T-State in current cycle.
|
VSOM_LTSTATE <= '1' when CPU_LAST_T_STATE = '1' -- Last T-State in current cycle.
|
||||||
else '0';
|
else '0';
|
||||||
VSOM_BUSRQ <= not Z80_BUSRQn; -- Host device requesting Z80 Bus.
|
VSOM_BUSRQ <= not Z80_BUSRQn; -- Host device requesting Z80 Bus.
|
||||||
@@ -982,4 +1094,8 @@ begin
|
|||||||
--VGA_PXL_CLK <= CLK_50M;
|
--VGA_PXL_CLK <= CLK_50M;
|
||||||
MONO_PXL_CLK <= VGA_PXL_CLK;
|
MONO_PXL_CLK <= VGA_PXL_CLK;
|
||||||
|
|
||||||
|
-- Currently unassigned.
|
||||||
|
VGA_COLR <= '0';
|
||||||
|
MONO_RSV <= '0';
|
||||||
|
|
||||||
end architecture;
|
end architecture;
|
||||||
|
|||||||
4
CPLD/v1.0/MZ700/build/tzpuFusionX_MZ700.qsf
vendored
4
CPLD/v1.0/MZ700/build/tzpuFusionX_MZ700.qsf
vendored
@@ -127,10 +127,10 @@ set_location_assignment PIN_21 -to VSOM_RSV[1]
|
|||||||
# SOM Control Signals
|
# SOM Control Signals
|
||||||
# ===================
|
# ===================
|
||||||
set_location_assignment PIN_28 -to VSOM_READY
|
set_location_assignment PIN_28 -to VSOM_READY
|
||||||
set_location_assignment PIN_18 -to VSOM_LTSTATE
|
set_location_assignment PIN_19 -to VSOM_LTSTATE
|
||||||
set_location_assignment PIN_27 -to VSOM_BUSRQ
|
set_location_assignment PIN_27 -to VSOM_BUSRQ
|
||||||
set_location_assignment PIN_26 -to VSOM_BUSACK
|
set_location_assignment PIN_26 -to VSOM_BUSACK
|
||||||
set_location_assignment PIN_19 -to VSOM_INT
|
set_location_assignment PIN_18 -to VSOM_INT
|
||||||
set_location_assignment PIN_22 -to VSOM_NMI
|
set_location_assignment PIN_22 -to VSOM_NMI
|
||||||
set_location_assignment PIN_25 -to VSOM_WAIT
|
set_location_assignment PIN_25 -to VSOM_WAIT
|
||||||
set_location_assignment PIN_23 -to VSOM_RESET
|
set_location_assignment PIN_23 -to VSOM_RESET
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
|||||||
-- Feb 2023 v1.1 - Updates, after numerous tests to try and speed up the Z80 transaction
|
-- Feb 2023 v1.1 - Updates, after numerous tests to try and speed up the Z80 transaction
|
||||||
-- from SSD202 issuing a command to data being returned. Source now
|
-- from SSD202 issuing a command to data being returned. Source now
|
||||||
-- different to the MZ-700/MZ-2000 so will need back porting.
|
-- different to the MZ-700/MZ-2000 so will need back porting.
|
||||||
|
-- Apr 2023 v1.2 - Updated from the PCW8256 development.
|
||||||
--
|
--
|
||||||
---------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
-- This source file is free software: you can redistribute it and-or modify
|
-- This source file is free software: you can redistribute it and-or modify
|
||||||
@@ -131,7 +132,7 @@ end entity;
|
|||||||
|
|
||||||
architecture rtl of cpld512 is
|
architecture rtl of cpld512 is
|
||||||
|
|
||||||
-- Finite State Machine states.
|
-- Z80 Finite State Machine states.
|
||||||
type SOMFSMState is
|
type SOMFSMState is
|
||||||
(
|
(
|
||||||
IdleCycle,
|
IdleCycle,
|
||||||
@@ -177,6 +178,14 @@ architecture rtl of cpld512 is
|
|||||||
BusReqCycle
|
BusReqCycle
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Controller FSM states.
|
||||||
|
type CTRLFSMState is
|
||||||
|
(
|
||||||
|
CTRLCMD_Idle,
|
||||||
|
CTRLCMD_ReadIOWrite,
|
||||||
|
CTRLCMD_ReadIOWrite_1
|
||||||
|
);
|
||||||
|
|
||||||
-- CPU Interface internal signals.
|
-- CPU Interface internal signals.
|
||||||
signal Z80_BUSRQni : std_logic;
|
signal Z80_BUSRQni : std_logic;
|
||||||
signal Z80_INTni : std_logic;
|
signal Z80_INTni : std_logic;
|
||||||
@@ -188,7 +197,6 @@ architecture rtl of cpld512 is
|
|||||||
signal Z80_HALTni : std_logic;
|
signal Z80_HALTni : std_logic;
|
||||||
signal Z80_M1ni : std_logic;
|
signal Z80_M1ni : std_logic;
|
||||||
signal Z80_RFSHni : std_logic;
|
signal Z80_RFSHni : std_logic;
|
||||||
signal Z80_DATAi : std_logic_vector(7 downto 0);
|
|
||||||
signal Z80_BUSRQ_ACKni : std_logic;
|
signal Z80_BUSRQ_ACKni : std_logic;
|
||||||
|
|
||||||
-- Internal CPU state control.
|
-- Internal CPU state control.
|
||||||
@@ -206,14 +214,15 @@ architecture rtl of cpld512 is
|
|||||||
|
|
||||||
-- Refresh control.
|
-- Refresh control.
|
||||||
signal FSM_STATE : SOMFSMState := IdleCycle;
|
signal FSM_STATE : SOMFSMState := IdleCycle;
|
||||||
signal NEW_SPI_CMD : std_logic := '0';
|
signal CTRL_STATE : CTRLFSMState := CTRLCMD_Idle;
|
||||||
|
signal NEW_SPI_DATA : std_logic := '0';
|
||||||
signal VCPU_CS_EDGE : std_logic_vector(1 downto 0) := "11";
|
signal VCPU_CS_EDGE : std_logic_vector(1 downto 0) := "11";
|
||||||
signal AUTOREFRESH_CNT : integer range 0 to 7;
|
signal AUTOREFRESH_CNT : integer range 0 to 31;
|
||||||
signal FSM_STATUS : std_logic := '0';
|
signal FSM_STATUS : std_logic := '0';
|
||||||
signal FSM_CHECK_WAIT : std_logic := '0';
|
signal FSM_CHECK_WAIT : std_logic := '0';
|
||||||
signal FSM_WAIT_ACTIVE : std_logic := '0';
|
signal FSM_WAIT_ACTIVE : std_logic := '0';
|
||||||
signal RFSH_STATUS : std_logic := '0';
|
signal RFSH_STATUS : std_logic := '0';
|
||||||
signal REFRESH_ADDR : std_logic_vector(7 downto 0);
|
signal REFRESH_ADDR : std_logic_vector(6 downto 0);
|
||||||
signal IPAR : std_logic_vector(7 downto 0);
|
signal IPAR : std_logic_vector(7 downto 0);
|
||||||
signal AUTOREFRESH : std_logic;
|
signal AUTOREFRESH : std_logic;
|
||||||
|
|
||||||
@@ -232,11 +241,12 @@ architecture rtl of cpld512 is
|
|||||||
signal SPI_RX_SREG : std_logic_vector(7 downto 0); -- RX Shift Register
|
signal SPI_RX_SREG : std_logic_vector(7 downto 0); -- RX Shift Register
|
||||||
signal SPI_TX_DATA : std_logic_vector(31 downto 0); -- Data to transmit.
|
signal SPI_TX_DATA : std_logic_vector(31 downto 0); -- Data to transmit.
|
||||||
signal SPI_RX_DATA : std_logic_vector(31 downto 0); -- Data received.
|
signal SPI_RX_DATA : std_logic_vector(31 downto 0); -- Data received.
|
||||||
signal SPI_BIT_CNT : integer range 0 to 16; -- Count of bits tx/rx'd.
|
signal SPI_BIT_CNT : integer range 0 to 7; -- Count of bits tx/rx'd.
|
||||||
signal SPI_FRAME_CNT : integer range 0 to 4; -- Number of frames received (8bit chunks).
|
signal SPI_FRAME_CNT : integer range 0 to 4; -- Number of frames received (8bit chunks).
|
||||||
|
|
||||||
-- SPI Command interface.
|
-- SPI Command interface.
|
||||||
signal SOM_CMD : std_logic_vector(7 downto 0) := (others => '0');
|
signal SOM_CMD : std_logic_vector(7 downto 0) := (others => '0');
|
||||||
|
signal SOM_PARAM_CNT : integer range 0 to 3;
|
||||||
signal SPI_NEW_DATA : std_logic;
|
signal SPI_NEW_DATA : std_logic;
|
||||||
signal SPI_PROCESSING : std_logic;
|
signal SPI_PROCESSING : std_logic;
|
||||||
signal SPI_CPU_ADDR : std_logic_vector(15 downto 0) := (others => '0');
|
signal SPI_CPU_ADDR : std_logic_vector(15 downto 0) := (others => '0');
|
||||||
@@ -340,8 +350,11 @@ begin
|
|||||||
-- SPI Slave input. Receive command and data from the SOM.
|
-- SPI Slave input. Receive command and data from the SOM.
|
||||||
SPI_INPUT : process(VSOM_SPI_CLK)
|
SPI_INPUT : process(VSOM_SPI_CLK)
|
||||||
begin
|
begin
|
||||||
|
-- Chip Select inactive, disable process and reset control flags.
|
||||||
|
if(VSOM_SPI_CSn = '1') then
|
||||||
|
|
||||||
-- SPI_CLK_POLARITY='0' => falling edge; SPI_CLK_POLARITY='1' => rising edge
|
-- SPI_CLK_POLARITY='0' => falling edge; SPI_CLK_POLARITY='1' => rising edge
|
||||||
if(VSOM_SPI_CLK'event and VSOM_SPI_CLK = SPI_CLK_POLARITY) then
|
elsif(VSOM_SPI_CLK'event and VSOM_SPI_CLK = SPI_CLK_POLARITY) then
|
||||||
if(VSOM_SPI_CSn = '0') then
|
if(VSOM_SPI_CSn = '0') then
|
||||||
SPI_RX_SREG <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
SPI_RX_SREG <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
||||||
|
|
||||||
@@ -396,6 +409,7 @@ begin
|
|||||||
SPI_FRAME_CNT<= 1;
|
SPI_FRAME_CNT<= 1;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(7);
|
VSOM_SPI_MISO<= SPI_TX_DATA(7);
|
||||||
SPI_TX_SREG <= SPI_TX_DATA(6 downto 0);
|
SPI_TX_SREG <= SPI_TX_DATA(6 downto 0);
|
||||||
|
-- Increment frame count for each word received. We handle 8bit (1 frame), 16bit (2 frames) or 32bit (4 frames) reception.
|
||||||
elsif(SPI_FRAME_CNT = 1) then
|
elsif(SPI_FRAME_CNT = 1) then
|
||||||
SPI_FRAME_CNT<= 2;
|
SPI_FRAME_CNT<= 2;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(15);
|
VSOM_SPI_MISO<= SPI_TX_DATA(15);
|
||||||
@@ -404,13 +418,14 @@ begin
|
|||||||
SPI_FRAME_CNT<= 3;
|
SPI_FRAME_CNT<= 3;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(23);
|
VSOM_SPI_MISO<= SPI_TX_DATA(23);
|
||||||
SPI_TX_SREG <= SPI_TX_DATA(22 downto 16);
|
SPI_TX_SREG <= SPI_TX_DATA(22 downto 16);
|
||||||
else
|
elsif(SPI_FRAME_CNT = 3) then
|
||||||
-- Increment frame count for each word received. We handle 8bit (1 frame), 16bit (2 frames) or 32bit (4 frames) reception.
|
-- Increment frame count for each word received. We handle 8bit (1 frame), 16bit (2 frames) or 32bit (4 frames) reception.
|
||||||
SPI_FRAME_CNT<= 4;
|
SPI_FRAME_CNT<= 4;
|
||||||
VSOM_SPI_MISO<= SPI_TX_DATA(31);
|
VSOM_SPI_MISO<= SPI_TX_DATA(31);
|
||||||
SPI_TX_SREG <= SPI_TX_DATA(30 downto 24);
|
SPI_TX_SREG <= SPI_TX_DATA(30 downto 24);
|
||||||
|
else
|
||||||
|
SPI_FRAME_CNT<= 0;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
SPI_BIT_CNT <= 7;
|
SPI_BIT_CNT <= 7;
|
||||||
end if;
|
end if;
|
||||||
end if;
|
end if;
|
||||||
@@ -428,6 +443,7 @@ begin
|
|||||||
AUTOREFRESH <= '0';
|
AUTOREFRESH <= '0';
|
||||||
SPI_LOOPBACK_TEST <= '0';
|
SPI_LOOPBACK_TEST <= '0';
|
||||||
SOM_CMD <= (others => '0');
|
SOM_CMD <= (others => '0');
|
||||||
|
SOM_PARAM_CNT <= 0;
|
||||||
SPI_CPU_ADDR <= (others => '0');
|
SPI_CPU_ADDR <= (others => '0');
|
||||||
SPI_NEW_DATA <= '0';
|
SPI_NEW_DATA <= '0';
|
||||||
|
|
||||||
@@ -446,66 +462,110 @@ begin
|
|||||||
--
|
--
|
||||||
elsif(VSOM_SPI_CSn'event and VSOM_SPI_CSn = '1') then
|
elsif(VSOM_SPI_CSn'event and VSOM_SPI_CSn = '1') then
|
||||||
|
|
||||||
-- Command is always located in the upper byte of frame 1.
|
-- If active, decrement parameter count. Parameters sent after a command are not considered as commands.
|
||||||
SOM_CMD <= SPI_RX_DATA(7 downto 0);
|
if(SOM_PARAM_CNT > 0) then
|
||||||
|
SOM_PARAM_CNT <= SOM_PARAM_CNT - 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
-- Toggle flag to indicate new data arrived.
|
-- Process if command, store parameters.
|
||||||
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
if(SOM_PARAM_CNT = 0) then
|
||||||
|
-- Command is always located in the upper byte of frame 1.
|
||||||
|
SOM_CMD <= SPI_RX_DATA(7 downto 0);
|
||||||
|
|
||||||
-- Process the command. Some commands require the FSM, others can be serviced immediately.
|
-- Toggle flag to indicate new data arrived.
|
||||||
case SPI_RX_DATA(7 downto 0) is
|
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
||||||
|
|
||||||
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
-- Process the command. Some commands require the FSM, others can be serviced immediately.
|
||||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
case SPI_RX_DATA(7 downto 0) is
|
||||||
X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" | -- Write
|
|
||||||
X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" | -- Read
|
|
||||||
X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" | -- WriteIO
|
|
||||||
X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" | -- ReadIO
|
|
||||||
X"38" | X"39" | X"3A" | X"3B" | X"3C" | X"3D" | X"3E" | X"3F" | --
|
|
||||||
X"40" | X"41" | X"42" | X"43" | X"44" | X"45" | X"46" | X"47" | --
|
|
||||||
X"48" | X"49" | X"4A" | X"4B" | X"4C" | X"4D" | X"4E" | X"4F" =>
|
|
||||||
|
|
||||||
-- Direct address set.
|
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
||||||
if(SPI_FRAME_CNT = 4) then
|
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
||||||
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" | -- Write
|
||||||
else
|
X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" | -- Read
|
||||||
-- if(SPI_CPU_ADDR >= X"D010" and SPI_CPU_ADDR < X"D020") then
|
X"48" | X"49" | X"4A" | X"4B" | X"4C" | X"4D" | X"4E" | X"4F" =>
|
||||||
-- SPI_CPU_ADDR <= std_logic_vector(X"D020" + unsigned(SPI_RX_DATA(2 downto 0)));
|
|
||||||
-- else
|
|
||||||
SPI_CPU_ADDR <= std_logic_vector(unsigned(SPI_CPU_ADDR) + unsigned(SPI_RX_DATA(2 downto 0)));
|
|
||||||
-- end if;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
if(SPI_FRAME_CNT > 1) then
|
-- Direct address set.
|
||||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
if(SPI_FRAME_CNT = 4) then
|
||||||
end if;
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
else
|
||||||
|
SPI_CPU_ADDR <= std_logic_vector(unsigned(SPI_CPU_ADDR) + unsigned(SPI_RX_DATA(2 downto 0)));
|
||||||
|
end if;
|
||||||
|
|
||||||
-- SETSIGSET1: Set control lines directly.
|
if(SPI_FRAME_CNT > 1) then
|
||||||
when X"F0" =>
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
VIDEO_SRCi <= SPI_RX_DATA(8);
|
end if;
|
||||||
MONO_VIDEO_SRCi <= SPI_RX_DATA(9);
|
|
||||||
AUDIO_SRC_Li <= SPI_RX_DATA(10);
|
|
||||||
AUDIO_SRC_Ri <= SPI_RX_DATA(11);
|
|
||||||
VBUS_ENi <= SPI_RX_DATA(12);
|
|
||||||
VGA_BLANKn <= not SPI_RX_DATA(13);
|
|
||||||
|
|
||||||
-- Enable auto refresh DRAM cycle.
|
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" => -- WriteIO
|
||||||
when X"F1" =>
|
|
||||||
AUTOREFRESH <= '1';
|
|
||||||
|
|
||||||
-- Disable auto refresh DRAM cycle.
|
-- Direct address set.
|
||||||
when X"F2" =>
|
if(SPI_FRAME_CNT = 4) then
|
||||||
AUTOREFRESH <= '0';
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
else
|
||||||
|
SPI_CPU_ADDR <= X"000" & '0' & std_logic_vector(unsigned(SPI_RX_DATA(2 downto 0)));
|
||||||
|
end if;
|
||||||
|
|
||||||
-- SETLOOPBACK: Enable loopback test mode.
|
if(SPI_FRAME_CNT > 1) then
|
||||||
when X"FE" =>
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
SPI_LOOPBACK_TEST<= '1';
|
end if;
|
||||||
|
|
||||||
-- No action, called to retrieve status.
|
when X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" | -- ReadIO
|
||||||
when X"00" | X"FF" =>
|
X"38" | X"39" | X"3A" | X"3B" | X"3C" | X"3D" | X"3E" | X"3F" => -- ReadIO-Write
|
||||||
|
|
||||||
when others =>
|
-- Direct address set.
|
||||||
end case;
|
if(SPI_FRAME_CNT = 4) then
|
||||||
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
elsif(SPI_FRAME_CNT = 2) then
|
||||||
|
SPI_CPU_ADDR <= X"00" & SPI_RX_DATA(15 downto 8);
|
||||||
|
else
|
||||||
|
SPI_CPU_ADDR <= X"000" & '0' & std_logic_vector(unsigned(SPI_RX_DATA(2 downto 0)));
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if(SPI_FRAME_CNT > 1) then
|
||||||
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- ReadIO-Write, Read-WriteIO commands require target address, so indicate parameter needed.
|
||||||
|
if(SPI_RX_DATA(7 downto 0) >= X"38" and SPI_RX_DATA(7 downto 0) < X"40") then
|
||||||
|
SOM_PARAM_CNT <= 1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- SETSIGSET1: Set control lines directly.
|
||||||
|
when X"F0" =>
|
||||||
|
VIDEO_SRCi <= SPI_RX_DATA(8);
|
||||||
|
MONO_VIDEO_SRCi <= SPI_RX_DATA(9);
|
||||||
|
AUDIO_SRC_Li <= SPI_RX_DATA(10);
|
||||||
|
AUDIO_SRC_Ri <= SPI_RX_DATA(11);
|
||||||
|
VBUS_ENi <= SPI_RX_DATA(12);
|
||||||
|
VGA_BLANKn <= not SPI_RX_DATA(13);
|
||||||
|
|
||||||
|
-- Enable auto refresh DRAM cycle.
|
||||||
|
when X"F1" =>
|
||||||
|
AUTOREFRESH <= '1';
|
||||||
|
|
||||||
|
-- Disable auto refresh DRAM cycle.
|
||||||
|
when X"F2" =>
|
||||||
|
AUTOREFRESH <= '0';
|
||||||
|
|
||||||
|
-- SETLOOPBACK: Enable loopback test mode.
|
||||||
|
when X"FE" =>
|
||||||
|
SPI_LOOPBACK_TEST<= '1';
|
||||||
|
|
||||||
|
-- No action, called to retrieve status.
|
||||||
|
when X"00" | X"FF" =>
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
end case;
|
||||||
|
else
|
||||||
|
-- Store parameter depending on number of frames, either ADDR+DATA, ADDR or DATA.
|
||||||
|
if(SPI_FRAME_CNT = 4) then
|
||||||
|
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||||
|
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||||
|
elsif(SPI_FRAME_CNT = 2) then
|
||||||
|
SPI_CPU_ADDR <= SPI_RX_DATA(15 downto 0);
|
||||||
|
else
|
||||||
|
SPI_CPU_DATA <= SPI_RX_DATA(7 downto 0);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
end if;
|
end if;
|
||||||
end process;
|
end process;
|
||||||
|
|
||||||
@@ -566,9 +626,9 @@ begin
|
|||||||
CPU_DATA_EN <= '0';
|
CPU_DATA_EN <= '0';
|
||||||
CPU_DATA_IN <= (others => '0');
|
CPU_DATA_IN <= (others => '0');
|
||||||
REFRESH_ADDR <= (others => '0');
|
REFRESH_ADDR <= (others => '0');
|
||||||
AUTOREFRESH_CNT <= 7;
|
AUTOREFRESH_CNT <= 31;
|
||||||
IPAR <= (others => '0');
|
IPAR <= (others => '0');
|
||||||
NEW_SPI_CMD <= '0';
|
NEW_SPI_DATA <= '0';
|
||||||
VCPU_CS_EDGE <= "11";
|
VCPU_CS_EDGE <= "11";
|
||||||
SPI_PROCESSING <= '0';
|
SPI_PROCESSING <= '0';
|
||||||
|
|
||||||
@@ -585,99 +645,12 @@ begin
|
|||||||
|
|
||||||
-- New command, set flag as the signal is only 1 clock wide.
|
-- New command, set flag as the signal is only 1 clock wide.
|
||||||
if(SPI_LOOPBACK_TEST = '0' and VSOM_SPI_CSn = '1' and VCPU_CS_EDGE = "01") then
|
if(SPI_LOOPBACK_TEST = '0' and VSOM_SPI_CSn = '1' and VCPU_CS_EDGE = "01") then
|
||||||
NEW_SPI_CMD <= '1';
|
NEW_SPI_DATA <= '1';
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- Whenever we return to Idle or just prior to Refresh from a Fetch cycle set all control signals to default.
|
-- Decrement refresh counter on each Z80 cycle, thus when idle and time expired, a refresh can be performed within parameters (256 cycles in 4ms).
|
||||||
if((FSM_STATE = IdleCycle or FSM_STATE = RefreshCycle) and Z80_CLK_TGL = '1') then
|
if(AUTOREFRESH = '1' and AUTOREFRESH_CNT /= 0 and Z80_CLK_RE = '1') then
|
||||||
CPU_DATA_EN <= '0';
|
AUTOREFRESH_CNT <= AUTOREFRESH_CNT - 1;
|
||||||
Z80_MREQni <= '1';
|
|
||||||
Z80_IORQni <= '1';
|
|
||||||
Z80_RDni <= '1';
|
|
||||||
Z80_WRni <= '1';
|
|
||||||
Z80_M1ni <= '1';
|
|
||||||
FSM_STATUS <= '0';
|
|
||||||
Z80_RFSHni <= '1';
|
|
||||||
|
|
||||||
-- Auto DRAM refresh cycles. When enabled, every 7 host clock cycles, a 2 cycle refresh period commences.
|
|
||||||
-- This will be overriden if the SPI receives a new command.
|
|
||||||
--
|
|
||||||
if AUTOREFRESH = '1' and FSM_STATE = IdleCycle then
|
|
||||||
AUTOREFRESH_CNT <= AUTOREFRESH_CNT - 1;
|
|
||||||
if(AUTOREFRESH_CNT = 0) then
|
|
||||||
FSM_STATE <= RefreshCycle_3;
|
|
||||||
FSM_STATUS<= '1';
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- If new command has been given and the FSM enters idle state, load up new command for processing.
|
|
||||||
if(NEW_SPI_CMD = '1' and FSM_STATE = IdleCycle and Z80_CLK_RE = '1') then
|
|
||||||
NEW_SPI_CMD <= '0';
|
|
||||||
|
|
||||||
-- Store new address and data for this command.
|
|
||||||
CPU_ADDR <= SPI_CPU_ADDR;
|
|
||||||
if(SPI_CPU_DATA /= CPU_DATA_OUT) then
|
|
||||||
CPU_DATA_OUT <= SPI_CPU_DATA;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- Process the SOM command. The SPI_REGISTER executes non FSM commands and stores FSM
|
|
||||||
-- data prior to this execution block, which fires 1 cycle later on the same control clock.
|
|
||||||
-- If the command is not for the FSM then the READY mechanism is held for one
|
|
||||||
-- further cycle before going inactive.
|
|
||||||
case SOM_CMD is
|
|
||||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" =>
|
|
||||||
-- Initiate a Fetch Cycle.
|
|
||||||
FSM_STATE <= FetchCycle;
|
|
||||||
|
|
||||||
when X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" =>
|
|
||||||
|
|
||||||
-- Set the Z80 data bus value and initiate a Write Cycle.
|
|
||||||
FSM_STATE <= WriteCycle;
|
|
||||||
|
|
||||||
when X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" =>
|
|
||||||
-- Initiate a Read Cycle.
|
|
||||||
FSM_STATE <= ReadCycle;
|
|
||||||
|
|
||||||
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" =>
|
|
||||||
-- Set the Z80 data bus value and initiate an IO Write Cycle.
|
|
||||||
-- The SOM should set 15:8 to the B register value.
|
|
||||||
FSM_STATE <= WriteIOCycle;
|
|
||||||
|
|
||||||
when X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" =>
|
|
||||||
-- Initiate a Read IO Cycle.
|
|
||||||
FSM_STATE <= ReadIOCycle;
|
|
||||||
|
|
||||||
when X"50" =>
|
|
||||||
-- Register a Halt state.
|
|
||||||
FSM_STATE <= HaltCycle;
|
|
||||||
|
|
||||||
when X"51" =>
|
|
||||||
-- Initiate a refresh cycle.
|
|
||||||
FSM_STATE <= RefreshCycle_3;
|
|
||||||
|
|
||||||
when X"E0" =>
|
|
||||||
-- Initiate a Halt Cycle.
|
|
||||||
FSM_STATE <= HaltCycle;
|
|
||||||
|
|
||||||
-- Set the Refresh Address register.
|
|
||||||
when X"E1" =>
|
|
||||||
REFRESH_ADDR <= CPU_DATA_OUT;
|
|
||||||
|
|
||||||
-- Set the Interrupt Page Address Register.
|
|
||||||
when X"E2" =>
|
|
||||||
IPAR <= CPU_DATA_OUT;
|
|
||||||
|
|
||||||
when others =>
|
|
||||||
end case;
|
|
||||||
|
|
||||||
-- Toggle the processing flag to negate the new data flag. Used to indicate device is busy.
|
|
||||||
if(SPI_NEW_DATA /= SPI_PROCESSING) then
|
|
||||||
SPI_PROCESSING <= not SPI_PROCESSING;
|
|
||||||
end if;
|
|
||||||
|
|
||||||
-- FSM Status bit. When processing a command it is set, cleared when idle. Used by SOM to determine command completion.
|
|
||||||
FSM_STATUS <= '1';
|
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- Refresh status bit. Indicates a Refresh cycle is under way.
|
-- Refresh status bit. Indicates a Refresh cycle is under way.
|
||||||
@@ -692,7 +665,143 @@ begin
|
|||||||
FSM_WAIT_ACTIVE <= '1';
|
FSM_WAIT_ACTIVE <= '1';
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
-- On each Z80 edge we advance the FSM to recreate the Z80 external signal transactions.
|
-- Whenever we return to Idle or just prior to Refresh from a Fetch cycle set all control signals to default.
|
||||||
|
if((FSM_STATE = IdleCycle or FSM_STATE = RefreshCycle) and Z80_CLK_RE = '1') then
|
||||||
|
CPU_DATA_EN <= '0';
|
||||||
|
Z80_MREQni <= '1';
|
||||||
|
Z80_IORQni <= '1';
|
||||||
|
Z80_RDni <= '1';
|
||||||
|
Z80_WRni <= '1';
|
||||||
|
Z80_M1ni <= '1';
|
||||||
|
FSM_STATUS <= '0';
|
||||||
|
Z80_RFSHni <= '1';
|
||||||
|
|
||||||
|
-- Auto DRAM refresh cycles. When enabled, every 15.6us a refresh period commences.
|
||||||
|
-- This period may be extended if the SPI receives a new command.
|
||||||
|
--
|
||||||
|
if AUTOREFRESH = '1' and FSM_STATE = IdleCycle then
|
||||||
|
if(AUTOREFRESH_CNT = 0) then
|
||||||
|
FSM_STATE <= RefreshCycle_3;
|
||||||
|
FSM_STATUS<= '1';
|
||||||
|
-- 4116 DRAM = 128 cycles in 2ms.
|
||||||
|
AUTOREFRESH_CNT <= 31;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
-- CPLD Macro Command Finite State Machine.
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Controller state machine.
|
||||||
|
-- When idle, accept and process SPI commands which can lead to a controller macro command.
|
||||||
|
case CTRL_STATE is
|
||||||
|
|
||||||
|
when CTRLCMD_Idle =>
|
||||||
|
-- If new command has been given and the FSM enters idle state, load up new command for processing.
|
||||||
|
if(NEW_SPI_DATA = '1' and FSM_STATE = IdleCycle and Z80_CLK_RE = '1') then
|
||||||
|
|
||||||
|
-- Store new address and data for this command.
|
||||||
|
if(NEW_SPI_DATA = '1') then
|
||||||
|
CPU_ADDR <= SPI_CPU_ADDR;
|
||||||
|
CPU_DATA_OUT <= SPI_CPU_DATA;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Process the SOM command. The SPI_REGISTER executes non FSM commands and stores FSM
|
||||||
|
-- data prior to this execution block, which fires 1 cycle later on the same control clock.
|
||||||
|
-- If the command is not for the FSM then the READY mechanism is held for one
|
||||||
|
-- further cycle before going inactive.
|
||||||
|
case SOM_CMD is
|
||||||
|
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" =>
|
||||||
|
-- Initiate a Fetch Cycle.
|
||||||
|
FSM_STATE <= FetchCycle;
|
||||||
|
|
||||||
|
when X"18" | X"19" | X"1A" | X"1B" | X"1C" | X"1D" | X"1E" | X"1F" =>
|
||||||
|
|
||||||
|
-- Set the Z80 data bus value and initiate a Write Cycle.
|
||||||
|
FSM_STATE <= WriteCycle;
|
||||||
|
|
||||||
|
when X"20" | X"21" | X"22" | X"23" | X"24" | X"25" | X"26" | X"27" =>
|
||||||
|
-- Initiate a Read Cycle.
|
||||||
|
FSM_STATE <= ReadCycle;
|
||||||
|
|
||||||
|
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" =>
|
||||||
|
-- Set the Z80 data bus value and initiate an IO Write Cycle.
|
||||||
|
-- The SOM should set 15:8 to the B register value.
|
||||||
|
FSM_STATE <= WriteIOCycle;
|
||||||
|
|
||||||
|
when X"30" | X"31" | X"32" | X"33" | X"34" | X"35" | X"36" | X"37" =>
|
||||||
|
-- Initiate a Read IO Cycle.
|
||||||
|
FSM_STATE <= ReadIOCycle;
|
||||||
|
|
||||||
|
when X"38" | X"39" | X"3A" | X"3B" | X"3C" | X"3D" | X"3E" | X"3F" =>
|
||||||
|
-- Initiate a read IO write memory cycle via the controller FSM.
|
||||||
|
CTRL_STATE <= CTRLCMD_ReadIOWrite;
|
||||||
|
FSM_STATE <= ReadIOCycle;
|
||||||
|
|
||||||
|
when X"50" =>
|
||||||
|
-- Register a Halt state.
|
||||||
|
FSM_STATE <= HaltCycle;
|
||||||
|
|
||||||
|
when X"51" =>
|
||||||
|
-- Initiate a refresh cycle.
|
||||||
|
FSM_STATE <= RefreshCycle_3;
|
||||||
|
|
||||||
|
when X"E0" =>
|
||||||
|
-- Initiate a Halt Cycle.
|
||||||
|
FSM_STATE <= HaltCycle;
|
||||||
|
|
||||||
|
-- Set the Refresh Address register.
|
||||||
|
when X"E1" =>
|
||||||
|
REFRESH_ADDR <= CPU_DATA_OUT(6 downto 0);
|
||||||
|
|
||||||
|
-- Set the Interrupt Page Address Register.
|
||||||
|
when X"E2" =>
|
||||||
|
IPAR <= CPU_DATA_OUT;
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
end case;
|
||||||
|
|
||||||
|
-- Toggle the processing flag to negate the new data flag. Used to indicate device is busy.
|
||||||
|
if(SPI_NEW_DATA /= SPI_PROCESSING) then
|
||||||
|
SPI_PROCESSING<= not SPI_PROCESSING;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
-- Clear new data flag ready for next cmd/param transfer.
|
||||||
|
NEW_SPI_DATA <= '0';
|
||||||
|
|
||||||
|
-- FSM Status bit. When processing a command it is set, cleared when idle. Used by SOM to determine command completion.
|
||||||
|
FSM_STATUS <= '1';
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when CTRLCMD_ReadIOWrite =>
|
||||||
|
if(NEW_SPI_DATA = '1' and FSM_STATE = IdleCycle and Z80_CLK_RE = '1') then
|
||||||
|
NEW_SPI_DATA <= '0';
|
||||||
|
CPU_DATA_EN <= '0';
|
||||||
|
Z80_IORQni <= '1';
|
||||||
|
Z80_RDni <= '1';
|
||||||
|
Z80_RFSHni <= '1';
|
||||||
|
CPU_ADDR <= SPI_CPU_ADDR;
|
||||||
|
CPU_DATA_OUT <= CPU_DATA_IN;
|
||||||
|
FSM_STATE <= WriteCycle;
|
||||||
|
CTRL_STATE <= CTRLCMD_ReadIOWrite_1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when CTRLCMD_ReadIOWrite_1 =>
|
||||||
|
if(FSM_STATE = WriteCycle_31) then
|
||||||
|
CTRL_STATE <= CTRLCMD_Idle;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
when others =>
|
||||||
|
CTRL_STATE <= CTRLCMD_Idle;
|
||||||
|
|
||||||
|
end case;
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
-- Z80 Finite State Machine.
|
||||||
|
--------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- On each Z80 edge we advance the Z80 FSM to recreate the Z80 external signal transactions.
|
||||||
if(Z80_CLK_TGL = '1') then
|
if(Z80_CLK_TGL = '1') then
|
||||||
|
|
||||||
-- The FSM advances to the next stage on each Z80 edge unless in Idle state.
|
-- The FSM advances to the next stage on each Z80 edge unless in Idle state.
|
||||||
@@ -711,7 +820,6 @@ begin
|
|||||||
when IdleCycle =>
|
when IdleCycle =>
|
||||||
CPU_LAST_T_STATE <= '1';
|
CPU_LAST_T_STATE <= '1';
|
||||||
FSM_STATUS <= '0';
|
FSM_STATUS <= '0';
|
||||||
-- FSM_STATE <= IdleCycle;
|
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
-- Z80 Fetch Cycle.
|
-- Z80 Fetch Cycle.
|
||||||
@@ -734,7 +842,7 @@ begin
|
|||||||
|
|
||||||
when FetchCycle_30 =>
|
when FetchCycle_30 =>
|
||||||
-- To meet the timing diagrams, just after Rising edge on T3 clear signals. Data wont be available until
|
-- To meet the timing diagrams, just after Rising edge on T3 clear signals. Data wont be available until
|
||||||
-- a short period before the falling edge of T3 (could be an MZ-80A design restriction or the Z80 timing diagrams are a bit out).
|
-- a short period before the falling edge of T3.
|
||||||
FSM_STATE <= RefreshCycle;
|
FSM_STATE <= RefreshCycle;
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -754,7 +862,7 @@ begin
|
|||||||
|
|
||||||
when RefreshCycle_21 =>
|
when RefreshCycle_21 =>
|
||||||
Z80_MREQni <= '1';
|
Z80_MREQni <= '1';
|
||||||
REFRESH_ADDR(6 downto 0) <= REFRESH_ADDR(6 downto 0) + 1;
|
REFRESH_ADDR <= REFRESH_ADDR + 1;
|
||||||
FSM_STATE <= IdleCycle;
|
FSM_STATE <= IdleCycle;
|
||||||
|
|
||||||
when RefreshCycle_3 =>
|
when RefreshCycle_3 =>
|
||||||
@@ -776,7 +884,7 @@ begin
|
|||||||
when WriteCycle_21 =>
|
when WriteCycle_21 =>
|
||||||
Z80_WRni <= '0';
|
Z80_WRni <= '0';
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= WriteCycle_20;
|
FSM_STATE <= WriteCycle_20;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when WriteCycle_30 =>
|
when WriteCycle_30 =>
|
||||||
@@ -801,7 +909,7 @@ begin
|
|||||||
|
|
||||||
when ReadCycle_21 =>
|
when ReadCycle_21 =>
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= ReadCycle_20;
|
FSM_STATE <= ReadCycle_20;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when ReadCycle_30 =>
|
when ReadCycle_30 =>
|
||||||
@@ -812,7 +920,6 @@ begin
|
|||||||
FSM_STATUS <= '0';
|
FSM_STATUS <= '0';
|
||||||
FSM_STATE <= IdleCycle;
|
FSM_STATE <= IdleCycle;
|
||||||
|
|
||||||
|
|
||||||
-----------------------------
|
-----------------------------
|
||||||
-- Z80 IO Write Cycle.
|
-- Z80 IO Write Cycle.
|
||||||
-----------------------------
|
-----------------------------
|
||||||
@@ -832,7 +939,7 @@ begin
|
|||||||
|
|
||||||
when WriteIOCycle_31 =>
|
when WriteIOCycle_31 =>
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= WriteIOCycle_20;
|
FSM_STATE <= WriteIOCycle_30;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when WriteIOCycle_40 =>
|
when WriteIOCycle_40 =>
|
||||||
@@ -861,7 +968,7 @@ begin
|
|||||||
|
|
||||||
when ReadIOCycle_31 =>
|
when ReadIOCycle_31 =>
|
||||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||||
FSM_STATE <= ReadIOCycle_20;
|
FSM_STATE <= ReadIOCycle_30;
|
||||||
end if;
|
end if;
|
||||||
|
|
||||||
when ReadIOCycle_40 =>
|
when ReadIOCycle_40 =>
|
||||||
@@ -901,7 +1008,7 @@ begin
|
|||||||
Z80_CLKi <= not Z80_CLK;
|
Z80_CLKi <= not Z80_CLK;
|
||||||
|
|
||||||
-- CPU Interface tri-state control based on acknowledged bus request.
|
-- CPU Interface tri-state control based on acknowledged bus request.
|
||||||
Z80_ADDR <= IPAR & REFRESH_ADDR when Z80_RFSHni = '0'
|
Z80_ADDR <= IPAR & '0' & REFRESH_ADDR when Z80_RFSHni = '0'
|
||||||
else
|
else
|
||||||
CPU_ADDR when Z80_BUSRQ_ACKni = '1'
|
CPU_ADDR when Z80_BUSRQ_ACKni = '1'
|
||||||
else
|
else
|
||||||
@@ -909,8 +1016,6 @@ begin
|
|||||||
Z80_DATA <= CPU_DATA_OUT when Z80_BUSRQ_ACKni = '1' and CPU_DATA_EN = '1'
|
Z80_DATA <= CPU_DATA_OUT when Z80_BUSRQ_ACKni = '1' and CPU_DATA_EN = '1'
|
||||||
else
|
else
|
||||||
(others => 'Z');
|
(others => 'Z');
|
||||||
-- Z80_DATAi <= Z80_DATA when Z80_RDn = '0'
|
|
||||||
-- else (others => '1');
|
|
||||||
Z80_RDn <= Z80_RDni when Z80_BUSRQ_ACKni = '1'
|
Z80_RDn <= Z80_RDni when Z80_BUSRQ_ACKni = '1'
|
||||||
else 'Z';
|
else 'Z';
|
||||||
Z80_WRn <= Z80_WRni when Z80_BUSRQ_ACKni = '1'
|
Z80_WRn <= Z80_WRni when Z80_BUSRQ_ACKni = '1'
|
||||||
@@ -951,7 +1056,7 @@ begin
|
|||||||
|
|
||||||
-- Signal mirrors.
|
-- Signal mirrors.
|
||||||
VSOM_READY <= '0' when FSM_STATUS='1' or SPI_NEW_DATA /= SPI_PROCESSING
|
VSOM_READY <= '0' when FSM_STATUS='1' or SPI_NEW_DATA /= SPI_PROCESSING
|
||||||
else '1'; -- FSM Ready (1), Busy (0)
|
else '1'; -- FSM Ready (1), Busy (0)
|
||||||
VSOM_LTSTATE <= '1' when CPU_LAST_T_STATE = '1' -- Last T-State in current cycle.
|
VSOM_LTSTATE <= '1' when CPU_LAST_T_STATE = '1' -- Last T-State in current cycle.
|
||||||
else '0';
|
else '0';
|
||||||
VSOM_BUSRQ <= not Z80_BUSRQn; -- Host device requesting Z80 Bus.
|
VSOM_BUSRQ <= not Z80_BUSRQn; -- Host device requesting Z80 Bus.
|
||||||
|
|||||||
1083
CPLD/v1.0/PCW8256/tzpuFusionX.vhd
Normal file
1083
CPLD/v1.0/PCW8256/tzpuFusionX.vhd
Normal file
File diff suppressed because it is too large
Load Diff
227
CPLD/v1.0/PCW8256/tzpuFusionX_Toplevel.vhd
Normal file
227
CPLD/v1.0/PCW8256/tzpuFusionX_Toplevel.vhd
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- Name: tzpuFusionX_Toplevel.vhd
|
||||||
|
-- Version: Amstrad PCW-8256
|
||||||
|
-- Created: Mar 2023
|
||||||
|
-- Author(s): Philip Smart
|
||||||
|
-- Description: tzpuFusionX CPLD Top Level module.
|
||||||
|
--
|
||||||
|
-- This module contains the basic pin definition of the CPLD<->logic needed in the
|
||||||
|
-- project which targets the MZ-80A host.
|
||||||
|
--
|
||||||
|
-- Credits:
|
||||||
|
-- Copyright: (c) 2018-23 Philip Smart <philip.smart@net2net.org>
|
||||||
|
--
|
||||||
|
-- History: Nov 2022 v1.0 - Initial write for the MZ-2000, adaption to the MZ-80A.
|
||||||
|
-- Feb 2023 v1.1 - Updates, after numerous tests to try and speed up the Z80 transaction
|
||||||
|
-- from SSD202 issuing a command to data being returned. Source now
|
||||||
|
-- different to the MZ-700/MZ-2000 so will need back porting.
|
||||||
|
-- Mar 2023 v1.0 - Snapshot taken from MZ-80A source for the Amstrad PCW-8256 version.
|
||||||
|
-- Version reset to v1.0 for the Amstrad.
|
||||||
|
--
|
||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
-- 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.
|
||||||
|
--
|
||||||
|
-- along with this program. If not, see <http:--www.gnu.org-licenses->.
|
||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
library IEEE;
|
||||||
|
use IEEE.std_logic_1164.all;
|
||||||
|
use IEEE.numeric_std.all;
|
||||||
|
use work.tzpuFusionX_pkg.all;
|
||||||
|
library altera;
|
||||||
|
use altera.altera_syn_attributes.all;
|
||||||
|
|
||||||
|
entity tzpuFusionX_PCW8256 is
|
||||||
|
port (
|
||||||
|
-- Z80 Address Bus
|
||||||
|
Z80_ADDR : inout std_logic_vector(15 downto 0);
|
||||||
|
|
||||||
|
-- Z80 Data Bus
|
||||||
|
Z80_DATA : inout std_logic_vector(7 downto 0);
|
||||||
|
|
||||||
|
-- Z80 Control signals.
|
||||||
|
Z80_BUSRQn : in std_logic;
|
||||||
|
Z80_BUSAKn : out std_logic;
|
||||||
|
Z80_INTn : in std_logic;
|
||||||
|
Z80_IORQn : inout std_logic;
|
||||||
|
Z80_MREQn : inout std_logic;
|
||||||
|
Z80_NMIn : in std_logic;
|
||||||
|
Z80_RDn : inout std_logic;
|
||||||
|
Z80_WRn : inout std_logic;
|
||||||
|
Z80_RESETn : in std_logic; -- Host CPU Reset signal, also CPLD reset.
|
||||||
|
Z80_HALTn : out std_logic;
|
||||||
|
Z80_WAITn : in std_logic;
|
||||||
|
Z80_M1n : inout std_logic;
|
||||||
|
Z80_RFSHn : inout std_logic;
|
||||||
|
|
||||||
|
-- SOM SPI
|
||||||
|
VSOM_SPI_CSn : in std_logic; -- SPI Slave Select
|
||||||
|
VSOM_SPI_CLK : in std_logic; -- SPI Clock
|
||||||
|
VSOM_SPI_MOSI : in std_logic; -- SPI Master Output Slave Input
|
||||||
|
VSOM_SPI_MISO : out std_logic; -- SPI Master Input Slave Output
|
||||||
|
|
||||||
|
-- SOM Parallel Bus.
|
||||||
|
VSOM_DATA_OUT : out std_logic_vector(7 downto 0); -- Address/Data bus for CPLD control registers.
|
||||||
|
VSOM_HBYTE : in std_logic; -- Parallel Bus High (1)/Low (0) byte.
|
||||||
|
VSOM_READY : out std_logic; -- FSM Ready (1), Busy (0)
|
||||||
|
VSOM_LTSTATE : out std_logic; -- Last T-State in current cycle, 1 = active.
|
||||||
|
VSOM_BUSRQ : out std_logic; -- Host device requesting Z80 Bus.
|
||||||
|
VSOM_BUSACK : out std_logic; -- Host device granted Z80 Bus
|
||||||
|
VSOM_INT : out std_logic; -- Z80 INT signal
|
||||||
|
VSOM_NMI : out std_logic; -- Z80 NMI signal
|
||||||
|
VSOM_WAIT : out std_logic; -- Z80 WAIT signal
|
||||||
|
VSOM_RESET : out std_logic; -- Z80 RESET signal
|
||||||
|
VSOM_RSV : out std_logic_vector(1 downto 1); -- Reserved pins.
|
||||||
|
|
||||||
|
-- SOM Control Signals
|
||||||
|
PM_RESET : out std_logic; -- Reset SOM
|
||||||
|
|
||||||
|
-- VGA_Palette Control
|
||||||
|
VGA_R : in std_logic_vector(9 downto 7); -- Signals used for detecting blank or no video output.
|
||||||
|
VGA_G : in std_logic_vector(9 downto 7);
|
||||||
|
VGA_B : in std_logic_vector(9 downto 8);
|
||||||
|
|
||||||
|
-- VGA Control Signals
|
||||||
|
VGA_PXL_CLK : in std_logic; -- VGA Pixel clock for DAC conversion.
|
||||||
|
VGA_DISPEN : in std_logic; -- Displayed Enabled (SOM video output).
|
||||||
|
VGA_VSYNCn : in std_logic; -- SOM VSync.
|
||||||
|
VGA_HSYNCn : in std_logic; -- SOM HSync.
|
||||||
|
VGA_COLR : out std_logic; -- COLR colour carrier frequency.
|
||||||
|
VGA_CSYNCn : out std_logic; -- VGA Composite Sync.
|
||||||
|
VGA_BLANKn : out std_logic; -- VGA Blank detected.
|
||||||
|
|
||||||
|
-- CRT Control Signals
|
||||||
|
MONO_PXL_CLK : out std_logic; -- Mono CRT pixel clock for DAC conversion.
|
||||||
|
MONO_BLANKn : out std_logic; -- Mono CRT Blank (no active pixel) detection.
|
||||||
|
MONO_CSYNCn : out std_logic; -- Mono CRT composite sync.
|
||||||
|
MONO_RSV : out std_logic;
|
||||||
|
|
||||||
|
-- CRT Lower Chrominance Control
|
||||||
|
MONO_R : out std_logic_vector(2 downto 0); -- Signals to fine tune Red level of monochrome chrominance.
|
||||||
|
MONO_G : out std_logic_vector(2 downto 0); -- Signals to fine tune Green level of monochrome chrominance.
|
||||||
|
MONO_B : out std_logic_vector(2 downto 1); -- Signals to fine tune Blue level of monochrome chrominance.
|
||||||
|
|
||||||
|
-- MUX Control Signals
|
||||||
|
VIDEO_SRC : out std_logic; -- Select video source, Mainboard or SOM.
|
||||||
|
MONO_VIDEO_SRC : out std_logic; -- Select crt video source, Mainboard or SOM.
|
||||||
|
AUDIO_SRC_L : out std_logic; -- Select Audio Source Left Channel, Mainboard or SOM.
|
||||||
|
AUDIO_SRC_R : out std_logic; -- Select Audio Source Right Channel, Mainboard or SOM.
|
||||||
|
|
||||||
|
-- Mainboard Reset Signals
|
||||||
|
MB_RESETn : in std_logic; -- Motherboard Reset pressed.
|
||||||
|
MB_IPLn : in std_logic; -- Motherboard IPL pressed.
|
||||||
|
|
||||||
|
-- USB Power Control
|
||||||
|
VBUS_EN : out std_logic; -- USB Enable Power Output
|
||||||
|
|
||||||
|
-- Clocks.
|
||||||
|
Z80_CLK : in std_logic; -- Host CPU Clock
|
||||||
|
CLK_50M : in std_logic -- 50MHz oscillator.
|
||||||
|
);
|
||||||
|
END entity;
|
||||||
|
|
||||||
|
architecture rtl of tzpuFusionX_PCW8256 is
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
cpldl512Toplevel : entity work.cpld512
|
||||||
|
generic map (
|
||||||
|
SPI_CLK_POLARITY => '0'
|
||||||
|
)
|
||||||
|
port map
|
||||||
|
(
|
||||||
|
-- Z80 Address Bus
|
||||||
|
Z80_ADDR => Z80_ADDR,
|
||||||
|
|
||||||
|
-- Z80 Data Bus
|
||||||
|
Z80_DATA => Z80_DATA,
|
||||||
|
|
||||||
|
-- Z80 Control signals.
|
||||||
|
Z80_BUSRQn => Z80_BUSRQn,
|
||||||
|
Z80_BUSAKn => Z80_BUSAKn,
|
||||||
|
Z80_INTn => Z80_INTn,
|
||||||
|
Z80_IORQn => Z80_IORQn,
|
||||||
|
Z80_MREQn => Z80_MREQn,
|
||||||
|
Z80_NMIn => Z80_NMIn,
|
||||||
|
Z80_RDn => Z80_RDn,
|
||||||
|
Z80_WRn => Z80_WRn,
|
||||||
|
Z80_RESETn => Z80_RESETn,
|
||||||
|
Z80_HALTn => Z80_HALTn,
|
||||||
|
Z80_WAITn => Z80_WAITn,
|
||||||
|
Z80_M1n => Z80_M1n,
|
||||||
|
Z80_RFSHn => Z80_RFSHn,
|
||||||
|
|
||||||
|
-- SOM SPI
|
||||||
|
VSOM_SPI_CSn => VSOM_SPI_CSn, -- SPI Slave Select
|
||||||
|
VSOM_SPI_CLK => VSOM_SPI_CLK, -- SPI Clock
|
||||||
|
VSOM_SPI_MOSI => VSOM_SPI_MOSI, -- SPI Master Output Slave Input
|
||||||
|
VSOM_SPI_MISO => VSOM_SPI_MISO, -- SPI Master Input Slave Output
|
||||||
|
|
||||||
|
-- SOM Parallel Bus.
|
||||||
|
VSOM_DATA_OUT => VSOM_DATA_OUT, -- Address/Data bus for CPLD control registers.
|
||||||
|
VSOM_HBYTE => VSOM_HBYTE, -- Parallel Bus High (1)/Low (0) byte.
|
||||||
|
VSOM_READY => VSOM_READY, -- FSM Ready (1), Busy (0)
|
||||||
|
VSOM_LTSTATE => VSOM_LTSTATE, -- Last T-State in current cycle.
|
||||||
|
VSOM_BUSRQ => VSOM_BUSRQ, -- Host device requesting Z80 Bus.
|
||||||
|
VSOM_BUSACK => VSOM_BUSACK, -- Host device granted Z80 Bus
|
||||||
|
VSOM_INT => VSOM_INT, -- Z80 INT signal
|
||||||
|
VSOM_NMI => VSOM_NMI, -- Z80 NMI signal
|
||||||
|
VSOM_WAIT => VSOM_WAIT, -- Z80 WAIT signal
|
||||||
|
VSOM_RESET => VSOM_RESET, -- Z80 RESET signal
|
||||||
|
VSOM_RSV => VSOM_RSV, -- Reserved pins.
|
||||||
|
|
||||||
|
-- SOM Control Signals
|
||||||
|
PM_RESET => PM_RESET, -- Reset SOM
|
||||||
|
|
||||||
|
-- VGA_Palette Control
|
||||||
|
VGA_R => VGA_R, -- Signals used for detecting blank or no video output.
|
||||||
|
VGA_G => VGA_G,
|
||||||
|
VGA_B => VGA_B,
|
||||||
|
|
||||||
|
-- VGA Control Signals
|
||||||
|
VGA_PXL_CLK => VGA_PXL_CLK, -- VGA Pixel clock for DAC conversion.
|
||||||
|
VGA_DISPEN => VGA_DISPEN, -- Displayed Enabled (SOM video output).
|
||||||
|
VGA_VSYNCn => VGA_VSYNCn, -- SOM VSync.
|
||||||
|
VGA_HSYNCn => VGA_HSYNCn, -- SOM HSync.
|
||||||
|
VGA_COLR => VGA_COLR, -- COLR colour carrier frequency.
|
||||||
|
VGA_CSYNCn => VGA_CSYNCn, -- VGA Composite Sync.
|
||||||
|
VGA_BLANKn => VGA_BLANKn, -- VGA Blank detected.
|
||||||
|
|
||||||
|
-- CRT Control Signals
|
||||||
|
MONO_PXL_CLK => MONO_PXL_CLK, -- Mono CRT pixel clock for DAC conversion.
|
||||||
|
MONO_BLANKn => MONO_BLANKn, -- Mono CRT Blank (no active pixel) detection.
|
||||||
|
MONO_CSYNCn => MONO_CSYNCn, -- Mono CRT composite sync.
|
||||||
|
MONO_RSV => MONO_RSV,
|
||||||
|
|
||||||
|
-- CRT Lower Chrominance Control
|
||||||
|
MONO_R => MONO_R, -- Signals to fine tune Red level of monochrome chrominance.
|
||||||
|
MONO_G => MONO_G, -- Signals to fine tune Green level of monochrome chrominance.
|
||||||
|
MONO_B => MONO_B, -- Signals to fine tune Blue level of monochrome chrominance.
|
||||||
|
|
||||||
|
-- MUX Control Signals
|
||||||
|
VIDEO_SRC => VIDEO_SRC, -- Select video source, Mainboard or SOM.
|
||||||
|
MONO_VIDEO_SRC => MONO_VIDEO_SRC, -- Select crt video source, Mainboard or SOM.
|
||||||
|
AUDIO_SRC_L => AUDIO_SRC_L, -- Select Audio Source Left Channel, Mainboard or SOM.
|
||||||
|
AUDIO_SRC_R => AUDIO_SRC_R, -- Select Audio Source Right Channel, Mainboard or SOM.
|
||||||
|
|
||||||
|
-- Mainboard Reset Signals=> MONO_R,
|
||||||
|
MB_RESETn => MB_RESETn, -- Motherboard Reset pressed.
|
||||||
|
MB_IPLn => MB_IPLn, -- Motherboard IPL pressed.
|
||||||
|
|
||||||
|
-- USB Power Control
|
||||||
|
VBUS_EN => VBUS_EN, -- USB Enable Power Output
|
||||||
|
|
||||||
|
-- Clocks.
|
||||||
|
Z80_CLK => Z80_CLK, -- Host CPU Clock
|
||||||
|
CLK_50M => CLK_50M -- 50MHz oscillator.
|
||||||
|
);
|
||||||
|
|
||||||
|
end architecture;
|
||||||
227
CPLD/v1.0/PCW8256/tzpuFusionX_pkg.vhd
Normal file
227
CPLD/v1.0/PCW8256/tzpuFusionX_pkg.vhd
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
--
|
||||||
|
-- Name: tzpuFusionX_pkg.vhd
|
||||||
|
-- Created: Mar 2023
|
||||||
|
-- Author(s): Philip Smart
|
||||||
|
-- Description: tzpuFusionX CPLD configuration file.
|
||||||
|
--
|
||||||
|
-- This module contains parameters for the CPLD in the tzpuFusionX project
|
||||||
|
-- which targets the Amstrad PCW8256 host.
|
||||||
|
--
|
||||||
|
-- Credits:
|
||||||
|
-- Copyright: (c) 2018-23 Philip Smart <philip.smart@net2net.org>
|
||||||
|
--
|
||||||
|
-- History: Nov 2022 v1.0 - Initial write for the MZ-2000, adaption to the MZ-80A.
|
||||||
|
-- Feb 2023 v1.1 - Updates, after numerous tests to try and speed up the Z80 transaction
|
||||||
|
-- from SSD202 issuing a command to data being returned. Source now
|
||||||
|
-- different to the MZ-700/MZ-2000 so will need back porting.
|
||||||
|
-- Mar 2023 v1.0 - Snapshot taken from MZ-80A source for the Amstrad PCW-8256 version.
|
||||||
|
-- Version reset to v1.0 for the Amstrad.
|
||||||
|
--
|
||||||
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
-- 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.numeric_std.all;
|
||||||
|
use ieee.math_real.all;
|
||||||
|
|
||||||
|
package tzpuFusionX_pkg is
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Constants
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Potential logic state constants.
|
||||||
|
constant YES : std_logic := '1';
|
||||||
|
constant NO : std_logic := '0';
|
||||||
|
constant HI : std_logic := '1';
|
||||||
|
constant LO : std_logic := '0';
|
||||||
|
constant ONE : std_logic := '1';
|
||||||
|
constant ZERO : std_logic := '0';
|
||||||
|
constant HIZ : std_logic := 'Z';
|
||||||
|
|
||||||
|
-- CPLD Command instructions.
|
||||||
|
constant CPLD_CMD_RESET_HOST : integer := 1;
|
||||||
|
constant CPLD_CMD_HOLD_HOST_BUS : integer := 2;
|
||||||
|
constant CPLD_CMD_RELEASE_HOST_BUS: integer := 3;
|
||||||
|
|
||||||
|
-- Target hardware modes.
|
||||||
|
constant MODE_MZ80K : integer := 0;
|
||||||
|
constant MODE_MZ80C : integer := 1;
|
||||||
|
constant MODE_MZ1200 : integer := 2;
|
||||||
|
constant MODE_MZ80A : integer := 3;
|
||||||
|
constant MODE_MZ700 : integer := 4;
|
||||||
|
constant MODE_MZ800 : integer := 5;
|
||||||
|
constant MODE_MZ80B : integer := 6;
|
||||||
|
constant MODE_MZ2000 : integer := 7;
|
||||||
|
constant MODE_PCW8256 : integer := 8;
|
||||||
|
|
||||||
|
-- Memory management modes.
|
||||||
|
constant TZMM_ORIG : integer := 00; -- Original Sharp mode, no tranZPUter features are selected except the I/O control registers (default: 0x60-063).
|
||||||
|
constant TZMM_BOOT : integer := 01; -- Original mode but E800-EFFF is mapped to tranZPUter RAM so TZFS can be booted.
|
||||||
|
constant TZMM_TZFS : integer := 02; -- TZFS main memory configuration. all memory is in tranZPUter RAM, E800-FFFF is used by TZFS, SA1510 is at 0000-1000 and RAM is 1000-CFFF, 64K Block 0 selected.
|
||||||
|
constant TZMM_TZFS2 : integer := 03; -- TZFS main memory configuration. all memory is in tranZPUter RAM, E800-EFFF is used by TZFS, SA1510 is at 0000-1000 and RAM is 1000-CFFF, 64K Block 0 selected, F000-FFFF is in 64K Block 1.
|
||||||
|
constant TZMM_TZFS3 : integer := 04; -- TZFS main memory configuration. all memory is in tranZPUter RAM, E800-EFFF is used by TZFS, SA1510 is at 0000-1000 and RAM is 1000-CFFF, 64K Block 0 selected, F000-FFFF is in 64K Block 2.
|
||||||
|
constant TZMM_TZFS4 : integer := 05; -- TZFS main memory configuration. all memory is in tranZPUter RAM, E800-EFFF is used by TZFS, SA1510 is at 0000-1000 and RAM is 1000-CFFF, 64K Block 0 selected, F000-FFFF is in 64K Block 3.
|
||||||
|
constant TZMM_CPM : integer := 06; -- CPM main memory configuration, all memory on the tranZPUter board, 64K block 4 selected. Special case for F3C0:F3FF & F7C0:F7FF (floppy disk paging vectors) which resides on the mainboard.
|
||||||
|
constant TZMM_CPM2 : integer := 07; -- CPM main memory configuration, F000-FFFF are on the tranZPUter board in block 4, 0040-CFFF and E800-EFFF are in block 5, mainboard for D000-DFFF (video), E000-E800 (Memory control) selected.
|
||||||
|
-- Special case for 0000:003F (interrupt vectors) which resides in block 4, F3FE:F3FF & F7FE:F7FF (floppy disk paging vectors) which resides on the mainboard.
|
||||||
|
constant TZMM_COMPAT : integer := 08; -- Compatibility monitor mode, monitor ROM on mainboard, RAM on tranZPUter in Block 0 1000-CFFF.
|
||||||
|
constant TZMM_HOSTACCESS : integer := 09; -- Monitor ROM 0000-0FFF and Main DRAM 0x1000-0xD000, video and memory mapped I/O are on the host machine, User/Floppy ROM E800-FFFF are in tranZPUter memory.
|
||||||
|
constant TZMM_MZ700_0 : integer := 10; -- MZ700 Mode - 0000:0FFF is on the tranZPUter board in block 6, 1000:CFFF is on the tranZPUter board in block 0, D000:FFFF is on the mainboard.
|
||||||
|
constant TZMM_MZ700_1 : integer := 11; -- MZ700 Mode - 0000:0FFF is on the tranZPUter board in block 0, 1000:CFFF is on the tranZPUter board in block 0, D000:FFFF is on the tranZPUter in block 6.
|
||||||
|
constant TZMM_MZ700_2 : integer := 12; -- MZ700 Mode - 0000:0FFF is on the tranZPUter board in block 6, 1000:CFFF is on the tranZPUter board in block 0, D000:FFFF is on the tranZPUter in block 6.
|
||||||
|
constant TZMM_MZ700_3 : integer := 13; -- MZ700 Mode - 0000:0FFF is on the tranZPUter board in block 0, 1000:CFFF is on the tranZPUter board in block 0, D000:FFFF is inaccessible.
|
||||||
|
constant TZMM_MZ700_4 : integer := 14; -- MZ700 Mode - 0000:0FFF is on the tranZPUter board in block 6, 1000:CFFF is on the tranZPUter board in block 0, D000:FFFF is inaccessible.
|
||||||
|
constant TZMM_MZ800 : integer := 15; -- MZ800 Mode - Running on MZ800 hardware, configuration set according to MZ700/MZ800 mode.
|
||||||
|
constant TZMM_MZ2000 : integer := 16; -- MZ2000 Mode - Running on MZ2000 hardware, configuration set according to runtime configuration registers.
|
||||||
|
constant TZMM_FPGA : integer := 21; -- Open up access for the K64F to the FPGA resources such as memory. All other access to RAM or mainboard is blocked.
|
||||||
|
constant TZMM_TZPUM : integer := 22; -- Everything in on mainboard, no access to tranZPUter memory.
|
||||||
|
constant TZMM_TZPU : integer := 23; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||||
|
constant TZMM_TZPU0 : integer := 24; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||||
|
constant TZMM_TZPU1 : integer := 25; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 1 is selected.
|
||||||
|
constant TZMM_TZPU2 : integer := 26; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 2 is selected.
|
||||||
|
constant TZMM_TZPU3 : integer := 27; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 3 is selected.
|
||||||
|
constant TZMM_TZPU4 : integer := 28; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 4 is selected.
|
||||||
|
constant TZMM_TZPU5 : integer := 29; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 5 is selected.
|
||||||
|
constant TZMM_TZPU6 : integer := 30; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 6 is selected.
|
||||||
|
constant TZMM_TZPU7 : integer := 31; -- Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 7 is selected.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Configurable parameters.
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Target hardware.
|
||||||
|
constant CPLD_HOST_HW : integer := MODE_PCW8256;
|
||||||
|
|
||||||
|
-- Target video hardware.
|
||||||
|
constant CPLD_HAS_FPGA_VIDEO : std_logic := '1';
|
||||||
|
|
||||||
|
-- Version of hdl.
|
||||||
|
constant CPLD_VERSION : integer := 2;
|
||||||
|
|
||||||
|
-- Clock source for the secondary clock. If a K64F is installed then enable it otherwise use the onboard oscillator.
|
||||||
|
--
|
||||||
|
constant USE_K64F_CTL_CLOCK : integer := 1;
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Function prototypes
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Find the maximum of two integers.
|
||||||
|
function IntMax(a : in integer; b : in integer) return integer;
|
||||||
|
|
||||||
|
-- Find the number of bits required to represent an integer.
|
||||||
|
function log2ceil(arg : positive) return natural;
|
||||||
|
|
||||||
|
-- Function to calculate the number of whole 'clock' cycles in a given time period, the period being in ns.
|
||||||
|
function clockTicks(period : in integer; clock : in integer) return integer;
|
||||||
|
|
||||||
|
-- Function to reverse the order of the bits in a standard logic vector.
|
||||||
|
-- ie. 1010 becomes 0101
|
||||||
|
function reverse_vector(slv:std_logic_vector) return std_logic_vector;
|
||||||
|
|
||||||
|
-- Function to convert an integer (0 or 1) into std_logic.
|
||||||
|
--
|
||||||
|
function to_std_logic(i : in integer) return std_logic;
|
||||||
|
|
||||||
|
-- Function to return the value of a bit as an integer for array indexing etc.
|
||||||
|
function bit_to_integer( s : std_logic ) return natural;
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Records
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Components
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
end tzpuFusionX_pkg;
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
-- Function definitions.
|
||||||
|
------------------------------------------------------------
|
||||||
|
package body tzpuFusionX_pkg is
|
||||||
|
|
||||||
|
-- Find the maximum of two integers.
|
||||||
|
function IntMax(a : in integer; b : in integer) return integer is
|
||||||
|
begin
|
||||||
|
if a > b then
|
||||||
|
return a;
|
||||||
|
else
|
||||||
|
return b;
|
||||||
|
end if;
|
||||||
|
return a;
|
||||||
|
end function IntMax;
|
||||||
|
|
||||||
|
-- Find the number of bits required to represent an integer.
|
||||||
|
function log2ceil(arg : positive) return natural is
|
||||||
|
variable tmp : positive := 1;
|
||||||
|
variable log : natural := 0;
|
||||||
|
begin
|
||||||
|
if arg = 1 then
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
while arg > tmp loop
|
||||||
|
tmp := tmp * 2;
|
||||||
|
log := log + 1;
|
||||||
|
end loop;
|
||||||
|
return log;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
-- Function to calculate the number of whole 'clock' cycles in a given time period, the period being in ns.
|
||||||
|
function clockTicks(period : in integer; clock : in integer) return integer is
|
||||||
|
variable ticks : real;
|
||||||
|
variable fracTicks : real;
|
||||||
|
begin
|
||||||
|
ticks := (Real(period) * Real(clock)) / 1000000000.0;
|
||||||
|
fracTicks := ticks - CEIL(ticks);
|
||||||
|
if fracTicks > 0.0001 then
|
||||||
|
return Integer(CEIL(ticks + 1.0));
|
||||||
|
else
|
||||||
|
return Integer(CEIL(ticks));
|
||||||
|
end if;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
function reverse_vector(slv:std_logic_vector) return std_logic_vector is
|
||||||
|
variable target : std_logic_vector(slv'high downto slv'low);
|
||||||
|
begin
|
||||||
|
for idx in slv'high downto slv'low loop
|
||||||
|
target(idx) := slv(slv'low + (slv'high-idx));
|
||||||
|
end loop;
|
||||||
|
return target;
|
||||||
|
end reverse_vector;
|
||||||
|
|
||||||
|
function to_std_logic(i : in integer) return std_logic is
|
||||||
|
begin
|
||||||
|
if i = 0 then
|
||||||
|
return '0';
|
||||||
|
end if;
|
||||||
|
return '1';
|
||||||
|
end function;
|
||||||
|
|
||||||
|
-- Function to return the value of a bit as an integer for array indexing etc.
|
||||||
|
function bit_to_integer( s : std_logic ) return natural is
|
||||||
|
begin
|
||||||
|
if s = '1' then
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
end if;
|
||||||
|
end function;
|
||||||
|
end package body;
|
||||||
BIN
software/FusionX/bin/k64fcpu
vendored
BIN
software/FusionX/bin/k64fcpu
vendored
Binary file not shown.
BIN
software/FusionX/bin/sharpbiter
vendored
BIN
software/FusionX/bin/sharpbiter
vendored
Binary file not shown.
BIN
software/FusionX/bin/z80ctrl
vendored
BIN
software/FusionX/bin/z80ctrl
vendored
Binary file not shown.
BIN
software/FusionX/modules/ttymzdrv.ko
vendored
BIN
software/FusionX/modules/ttymzdrv.ko
vendored
Binary file not shown.
BIN
software/FusionX/modules/z80drv.ko
vendored
BIN
software/FusionX/modules/z80drv.ko
vendored
Binary file not shown.
46
software/FusionX/src/ttymz/Makefile
vendored
46
software/FusionX/src/ttymz/Makefile
vendored
@@ -1,15 +1,17 @@
|
|||||||
# Select the target host.
|
# Select the target host.
|
||||||
#MODEL := MZ2000
|
#MODEL := MZ2000
|
||||||
#MODEL := MZ700
|
#MODEL := MZ700
|
||||||
#DEBUG := y
|
#MODEL := MZ80A
|
||||||
MODEL := MZ80A
|
#MODEL := PCW8XXX
|
||||||
|
#MODEL := PCW9XXX
|
||||||
KERNEL := $(PWD)/../../../linux/kernel
|
KERNEL := $(PWD)/../../../linux/kernel
|
||||||
FUSIONX := $(PWD)/../..
|
FUSIONX := $(PWD)/../..
|
||||||
CROSS := arm-linux-gnueabihf-
|
CROSS := arm-linux-gnueabihf-
|
||||||
|
CTRLINC = -IZeta/API -IZ80/API -DTARGET_HOST_$(MODEL)=1
|
||||||
|
|
||||||
|
ccflags-y = -O2 -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__ -DTARGET_HOST_$(MODEL)=1
|
||||||
ifeq ($(DEBUG),y)
|
ifeq ($(DEBUG),y)
|
||||||
ccflags-y += -DTTYMZ_DEBUG
|
ccflags-y += -DTTYMZ_DEBUG
|
||||||
else
|
|
||||||
ccflags-y += -O2 -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__
|
|
||||||
endif
|
endif
|
||||||
obj-m += ttymzdrv.o
|
obj-m += ttymzdrv.o
|
||||||
ttymzdrv-objs += ttymz.o z80io.o sharpmz.o
|
ttymzdrv-objs += ttymz.o z80io.o sharpmz.o
|
||||||
@@ -18,16 +20,42 @@ ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_gpio.
|
|||||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
||||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables.o
|
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables.o
|
||||||
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
@echo "Specify target host, ie. make <host>"
|
||||||
|
@echo "Supported hosts: MZ80A, MZ700, MZ2000, PCW8XXX, PCW9XXX"
|
||||||
|
|
||||||
|
MZ80A: MODEL_MZ80A
|
||||||
|
MZ700: MODEL_MZ700
|
||||||
|
MZ2000: MODEL_MZ2000
|
||||||
|
PCW8XXX: MODEL_PCW8XXX
|
||||||
|
PCW9XXX: MODEL_PCW9XXX
|
||||||
|
|
||||||
|
MODEL_MZ80A:
|
||||||
|
$(MAKE) MODEL=MZ80A BUILD_MZ80A
|
||||||
|
MODEL_MZ700:
|
||||||
|
$(MAKE) MODEL=MZ700 BUILD_MZ700
|
||||||
|
MODEL_MZ2000:
|
||||||
|
$(MAKE) MODEL=MZ2000 BUILD_MZ2000
|
||||||
|
MODEL_PCW8XXX:
|
||||||
|
$(MAKE) MODEL=PCW8XXX BUILD_PCW8XXX
|
||||||
|
MODEL_PCW9XXX:
|
||||||
|
$(MAKE) MODEL=PCW8XXX BUILD_PCW9XXX
|
||||||
|
|
||||||
|
BUILD_MZ80A: kmod
|
||||||
|
BUILD_MZ700: kmod
|
||||||
|
BUILD_MZ2000: kmod
|
||||||
|
BUILD_PCW8XXX: kmod
|
||||||
|
BUILD_PCW9XXX: kmod
|
||||||
|
|
||||||
|
kmod:
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Build TTYMZ driver for host: $(MODEL)"
|
@echo "Build TTYMZ driver for host: $(MODEL)"
|
||||||
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
||||||
@echo ""
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@echo "Copy kernel driver..."
|
@echo "Copy kernel driver..."
|
||||||
@cp ttymz.ko $(FUSIONX)/modules/
|
@cp ttymzdrv.ko $(FUSIONX)/modules/
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
make -C $(KERNEL) M=$(PWD) clean
|
make -C $(KERNEL) M=$(PWD) clean
|
||||||
|
@rm -f ttymz
|
||||||
|
|||||||
@@ -542,21 +542,21 @@ static t_scanCodeMap scanCodeMap[] = {
|
|||||||
CTRL_G , // ^G F7
|
CTRL_G , // ^G F7
|
||||||
CTRL_H , // ^H F8
|
CTRL_H , // ^H F8
|
||||||
// S5 28 - 2F
|
// S5 28 - 2F
|
||||||
NOKEY ,
|
HOTKEY_ORIGINAL, // 1 - Hotkey to invoke original mode.
|
||||||
NOKEY ,
|
HOTKEY_RFS40, // 2 - Hotkey to invoke RFS 40 mode.
|
||||||
NOKEY ,
|
HOTKEY_TZFS, // 3 - Hotkey to invoke TZFS mode.
|
||||||
NOKEY ,
|
HOTKEY_LINUX, // 4 - Hotkey to invoke Linux mode.
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
// S6 30 - 37 (ERROR? 7 VALUES ONLY!!)
|
// S6 30 - 37 (ERROR? 7 VALUES ONLY!!)
|
||||||
NOKEY , // ^YEN E6
|
NOKEY , // ^YEN E6
|
||||||
CTRL_CAPPA , // ^ EF
|
CTRL_CAPPA , // ^ EF
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
CTRL_UNDSCR , // ^,
|
CTRL_UNDSCR , // ^,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
// S7 - 38 - 3F
|
// S7 - 38 - 3F
|
||||||
@@ -567,22 +567,22 @@ static t_scanCodeMap scanCodeMap[] = {
|
|||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
CTRL_SLASH , // ^/ EE
|
CTRL_SLASH , // ^/ EE
|
||||||
// S8 40 - 47 - modifier keys.
|
// S8 40 - 47 - modifier keys.
|
||||||
NOKEY , // BREAK - CTRL+BREAK - not yet assigned
|
NOKEY , // BREAK - CTRL+BREAK - not yet assigned
|
||||||
NOKEY , // CTRL
|
NOKEY , // CTRL
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY , // SHIFT
|
NOKEY , // SHIFT
|
||||||
// S9 48 - 4F - Function keys.
|
// S9 48 - 4F - Function keys.
|
||||||
FUNC1 , // Function key F1
|
FUNC1 , // Function key F1
|
||||||
FUNC2 , // Function key F2
|
FUNC2 , // Function key F2
|
||||||
FUNC3 , // Function key F3
|
FUNC3 , // Function key F3
|
||||||
FUNC4 , // Function key F4
|
FUNC4 , // Function key F4
|
||||||
FUNC5 , // Function key F5
|
FUNC5 , // Function key F5
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY ,
|
NOKEY ,
|
||||||
NOKEY
|
NOKEY
|
||||||
@@ -681,8 +681,8 @@ static t_scanCodeMap scanCodeMap[] = {
|
|||||||
NOKEY
|
NOKEY
|
||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
#if (TARGET_HOST_MZ80A == 1)
|
#elif (TARGET_HOST_MZ80A == 1)
|
||||||
static t_scanCodeMap scanCodeMap[] = {
|
static t_scanCodeMap scanCodeMap[] = {
|
||||||
// MZ_80A NO SHIFT
|
// MZ_80A NO SHIFT
|
||||||
{{
|
{{
|
||||||
@@ -1151,6 +1151,477 @@ static t_scanCodeMap scanCodeMap[] = {
|
|||||||
}}
|
}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#elif (TARGET_HOST_MZ2000 == 1)
|
||||||
|
static t_scanCodeMap scanCodeMap[] = {
|
||||||
|
// MZ_2000 NO SHIFT
|
||||||
|
{{
|
||||||
|
// S0 00 - 07
|
||||||
|
NOKEY , // BREAK/CTRL
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
GRAPHKEY , // GRAPH
|
||||||
|
NOKEY , // SHIFT
|
||||||
|
// S1 08 - 0F
|
||||||
|
'2' , // 2
|
||||||
|
'1' , // 1
|
||||||
|
'w' , // w
|
||||||
|
'q' , // q
|
||||||
|
'a' , // a
|
||||||
|
BACKS , // DELETE
|
||||||
|
NOKEY , // NULL
|
||||||
|
'z' , // z
|
||||||
|
// S2 10 - 17
|
||||||
|
'4' , // 4
|
||||||
|
'3' , // 3
|
||||||
|
'r' , // r
|
||||||
|
'e' , // e
|
||||||
|
'd' , // d
|
||||||
|
's' , // s
|
||||||
|
'x' , // x
|
||||||
|
'c' , // c
|
||||||
|
// S3 18 - 1F
|
||||||
|
'6' , // 6
|
||||||
|
'5' , // 5
|
||||||
|
'y' , // y
|
||||||
|
't' , // t
|
||||||
|
'g' , // g
|
||||||
|
'f' , // f
|
||||||
|
'v' , // v
|
||||||
|
'b' , // b
|
||||||
|
// S4 20 - 27
|
||||||
|
'8' , // 8
|
||||||
|
'7' , // 7
|
||||||
|
'i' , // i
|
||||||
|
'u' , // u
|
||||||
|
'j' , // j
|
||||||
|
'h' , // h
|
||||||
|
'n' , // n
|
||||||
|
' ' , // SPACE
|
||||||
|
// S5 28 - 2F
|
||||||
|
'0' , // 0
|
||||||
|
'9' , // 9
|
||||||
|
'p' , // p
|
||||||
|
'o' , // o
|
||||||
|
'l' , // l
|
||||||
|
'k' , // k
|
||||||
|
',' , // ,
|
||||||
|
'm' , // m
|
||||||
|
// S6 30 - 37
|
||||||
|
'^' , // ^
|
||||||
|
'-' , // -
|
||||||
|
'[' , // [
|
||||||
|
'@' , // @
|
||||||
|
':' , // :
|
||||||
|
';' , // ;
|
||||||
|
'/' , // /
|
||||||
|
'.' , // .
|
||||||
|
// S7 38 - 3F
|
||||||
|
HOMEKEY , // HOME.
|
||||||
|
'\\' , // Backslash
|
||||||
|
CURSRIGHT, // CURSOR RIGHT
|
||||||
|
CURSUP , // CURSOR UP
|
||||||
|
CR , // CR
|
||||||
|
']' , // ]
|
||||||
|
NOKEY , //
|
||||||
|
'?' , // ?
|
||||||
|
// S8 40 - 47 - Keypad keys.
|
||||||
|
'8' , // Keypad 8
|
||||||
|
'7' , // 7
|
||||||
|
'5' , // 5
|
||||||
|
'4' , // 4
|
||||||
|
'2' , // 2
|
||||||
|
'1' , // 1
|
||||||
|
DBLZERO , // 00
|
||||||
|
'0' , // 0
|
||||||
|
// S9 48 - 4F - Keypad keys.
|
||||||
|
'+' , // +
|
||||||
|
'0' , // 9
|
||||||
|
'-' , // -
|
||||||
|
'6' , // 6
|
||||||
|
NOKEY , //
|
||||||
|
'3' , // 3
|
||||||
|
NOKEY ,
|
||||||
|
'.' // .
|
||||||
|
}},
|
||||||
|
// MZ_2000 CAPS LOCK
|
||||||
|
{{
|
||||||
|
// S0 00 - 07
|
||||||
|
NOKEY , // BREAK/CTRL
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
ALPHAKEY , // GRAPH
|
||||||
|
NOKEY , // SHIFT
|
||||||
|
// S1 08 - 0F
|
||||||
|
'2' , // 2
|
||||||
|
'1' , // 1
|
||||||
|
'W' , // W
|
||||||
|
'Q' , // Q
|
||||||
|
'A' , // A
|
||||||
|
BACKS , // DELETE
|
||||||
|
NOKEY , // NULL
|
||||||
|
'Z' , // Z
|
||||||
|
// S2 10 - 17
|
||||||
|
'4' , // 4
|
||||||
|
'3' , // 3
|
||||||
|
'R' , // R
|
||||||
|
'E' , // E
|
||||||
|
'D' , // D
|
||||||
|
'S' , // S
|
||||||
|
'X' , // X
|
||||||
|
'C' , // C
|
||||||
|
// S3 18 - 1F
|
||||||
|
'6' , // 6
|
||||||
|
'5' , // 5
|
||||||
|
'Y' , // Y
|
||||||
|
'T' , // T
|
||||||
|
'G' , // G
|
||||||
|
'F' , // F
|
||||||
|
'V' , // V
|
||||||
|
'B' , // B
|
||||||
|
// S4 20 - 27
|
||||||
|
'8' , // 8
|
||||||
|
'7' , // 7
|
||||||
|
'I' , // I
|
||||||
|
'U' , // U
|
||||||
|
'J' , // J
|
||||||
|
'H' , // H
|
||||||
|
'N' , // N
|
||||||
|
' ' , // SPACE
|
||||||
|
// S5 28 - 2F
|
||||||
|
'0' , // 0
|
||||||
|
'9' , // 9
|
||||||
|
'P' , // P
|
||||||
|
'O' , // O
|
||||||
|
'L' , // L
|
||||||
|
'K' , // K
|
||||||
|
',' , // ,
|
||||||
|
'M' , // M
|
||||||
|
// S6 30 - 37
|
||||||
|
'^' , // ^
|
||||||
|
'-' , // -
|
||||||
|
'[' , // [
|
||||||
|
'@' , // @
|
||||||
|
':' , // :
|
||||||
|
';' , // ;
|
||||||
|
'/' , // /
|
||||||
|
'.' , // .
|
||||||
|
// S7 38 - 3F
|
||||||
|
HOMEKEY , // HOME.
|
||||||
|
'\\' , // Backslash
|
||||||
|
CURSRIGHT, // CURSOR RIGHT
|
||||||
|
CURSUP , // CURSOR UP
|
||||||
|
CR , // CR
|
||||||
|
']' , // ]
|
||||||
|
NOKEY , //
|
||||||
|
'?' , // ?
|
||||||
|
// S8 40 - 47 - Keypad keys.
|
||||||
|
'8' , // Keypad 8
|
||||||
|
'7' , // 7
|
||||||
|
'5' , // 5
|
||||||
|
'4' , // 4
|
||||||
|
'2' , // 2
|
||||||
|
'1' , // 1
|
||||||
|
DBLZERO , // 00
|
||||||
|
'0' , // 0
|
||||||
|
// S9 48 - 4F - Keypad keys.
|
||||||
|
'+' , // +
|
||||||
|
'0' , // 9
|
||||||
|
'-' , // -
|
||||||
|
'6' , // 6
|
||||||
|
NOKEY , //
|
||||||
|
'3' , // 3
|
||||||
|
NOKEY ,
|
||||||
|
'.' // .
|
||||||
|
}},
|
||||||
|
// MZ_2000 SHIFT LOCK.
|
||||||
|
{{
|
||||||
|
// S0 00 - 07
|
||||||
|
NOKEY , // BREAK/CTRL
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
ALPHAKEY , // GRAPH
|
||||||
|
NOKEY , // SHIFT
|
||||||
|
// S1 08 - 0F
|
||||||
|
'"' , // "
|
||||||
|
'!' , // !
|
||||||
|
'W' , // W
|
||||||
|
'Q' , // Q
|
||||||
|
'A' , // A
|
||||||
|
INSERT , // INSERT
|
||||||
|
NOKEY , // NULL
|
||||||
|
'Z' , // Z
|
||||||
|
// S2 10 - 17
|
||||||
|
'$' , // $
|
||||||
|
'#' , // #
|
||||||
|
'R' , // R
|
||||||
|
'E' , // E
|
||||||
|
'D' , // D
|
||||||
|
'S' , // S
|
||||||
|
'X' , // X
|
||||||
|
'C' , // C
|
||||||
|
// S3 18 - 1F
|
||||||
|
'&' , // &
|
||||||
|
'%' , // %
|
||||||
|
'Y' , // Y
|
||||||
|
'T' , // T
|
||||||
|
'G' , // G
|
||||||
|
'F' , // F
|
||||||
|
'V' , // V
|
||||||
|
'B' , // B
|
||||||
|
// S4 20 - 27
|
||||||
|
'(' , // (
|
||||||
|
'\'' , // '
|
||||||
|
'I' , // I
|
||||||
|
'U' , // U
|
||||||
|
'J' , // J
|
||||||
|
'H' , // H
|
||||||
|
'N' , // N
|
||||||
|
' ' , // SPACE
|
||||||
|
// S5 28 - 2F
|
||||||
|
'_' , // _
|
||||||
|
')' , // )
|
||||||
|
'P' , // P
|
||||||
|
'O' , // O
|
||||||
|
'L' , // L
|
||||||
|
'K' , // K
|
||||||
|
'<' , // <
|
||||||
|
'M' , // M
|
||||||
|
// S6 30 - 37
|
||||||
|
'~' , // ~
|
||||||
|
'=' , // =
|
||||||
|
'{' , // {
|
||||||
|
'`' , // `
|
||||||
|
'*' , // *
|
||||||
|
'+' , // +
|
||||||
|
NOKEY , //
|
||||||
|
'>' , // >
|
||||||
|
// S7 38 - 3F
|
||||||
|
CLRKEY , // CLR.
|
||||||
|
'|' , // |
|
||||||
|
CURSLEFT , // CURSOR LEFT
|
||||||
|
CURSDOWN , // CURSOR DOWN
|
||||||
|
CR , // CR
|
||||||
|
'}' , // }
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
// S8 40 - 47 - Keypad keys.
|
||||||
|
'8' , // Keypad 8
|
||||||
|
'7' , // 7
|
||||||
|
'5' , // 5
|
||||||
|
'4' , // 4
|
||||||
|
'2' , // 2
|
||||||
|
'1' , // 1
|
||||||
|
DBLZERO , // 00
|
||||||
|
'0' , // 0
|
||||||
|
// S9 48 - 4F - Keypad keys.
|
||||||
|
'+' , // +
|
||||||
|
'0' , // 9
|
||||||
|
'-' , // -
|
||||||
|
'6' , // 6
|
||||||
|
NOKEY , //
|
||||||
|
'3' , // 3
|
||||||
|
NOKEY ,
|
||||||
|
'.' // .
|
||||||
|
}},
|
||||||
|
// MZ_2000 CONTROL CODE
|
||||||
|
{{
|
||||||
|
// S0 00 - 07
|
||||||
|
NOKEY , // BREAK/CTRL
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
ALPHAGRAPHKEY, // GRAPH
|
||||||
|
NOKEY , // SHIFT
|
||||||
|
// S1 08 - 0F
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_W , // CTRL_W
|
||||||
|
CTRL_Q , // CTRL_Q
|
||||||
|
CTRL_A , // CTRL_A
|
||||||
|
DELETE , // DELETE
|
||||||
|
NOKEY , // NULL
|
||||||
|
CTRL_Z , // CTRL_Z
|
||||||
|
// S2 10 - 17
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_R , // CTRL_R
|
||||||
|
CTRL_E , // CTRL_E
|
||||||
|
CTRL_D , // CTRL_D
|
||||||
|
CTRL_S , // CTRL_S
|
||||||
|
CTRL_X , // CTRL_X
|
||||||
|
CTRL_C , // CTRL_C
|
||||||
|
// S3 18 - 1F
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_Y , // CTRL_Y
|
||||||
|
CTRL_T , // CTRL_T
|
||||||
|
CTRL_G , // CTRL_G
|
||||||
|
CTRL_F , // CTRL_F
|
||||||
|
CTRL_V , // CTRL_V
|
||||||
|
CTRL_B , // CTRL_B
|
||||||
|
// S4 20 - 27
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_I , // CTRL_I
|
||||||
|
CTRL_U , // CTRL_U
|
||||||
|
CTRL_J , // CTRL_J
|
||||||
|
CTRL_H , // CTRL_H
|
||||||
|
CTRL_N , // CTRL_N
|
||||||
|
' ' , // SPACE
|
||||||
|
// S5 28 - 2F
|
||||||
|
CTRL_UNDSCR, // CTRL+_
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_P , // CTRL_P
|
||||||
|
CTRL_O , // CTRL_O
|
||||||
|
CTRL_L , // CTRL_L
|
||||||
|
CTRL_K , // CTRL_K
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_M , // CTRL_M
|
||||||
|
// S6 30 - 37
|
||||||
|
CTRL_CAPPA, // CTRL+^
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_LB , // CTRL+[
|
||||||
|
CTRL_AT , // CTRL+@
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_SLASH, // CTRL+/
|
||||||
|
NOKEY , //
|
||||||
|
// S7 38 - 3F
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
CTRL_RB , // CTRL+]
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
// S8 40 - 47 - Keypad keys.
|
||||||
|
NOKEY , // Keypad 8
|
||||||
|
NOKEY , // 7
|
||||||
|
NOKEY , // 5
|
||||||
|
HOTKEY_LINUX, // 4 - Hotkey to invoke Linux mode.
|
||||||
|
HOTKEY_RFS40, // 2 - Hotkey to invoke RFS 40 mode.
|
||||||
|
HOTKEY_RFS80, // 1 - Hotkey to invoke RFS 80 mode.
|
||||||
|
NOKEY , // 00
|
||||||
|
HOTKEY_ORIGINAL, // 0 - Hotkey to invoke original mode.
|
||||||
|
// S9 48 - 4F - Keypad keys.
|
||||||
|
NOKEY , // +
|
||||||
|
NOKEY , // 9
|
||||||
|
NOKEY , // -
|
||||||
|
NOKEY , // 6
|
||||||
|
NOKEY , //
|
||||||
|
HOTKEY_TZFS, // 3 - Hotkey to invoke TZFS mode.
|
||||||
|
NOKEY ,
|
||||||
|
NOKEY // .
|
||||||
|
}},
|
||||||
|
// MZ_2000 KANA
|
||||||
|
{{
|
||||||
|
// S0 00 - 07
|
||||||
|
NOKEY , // BREAK/CTRL
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
NOKEY , //
|
||||||
|
GRAPHKEY , // DAKU TEN
|
||||||
|
NOKEY , //
|
||||||
|
// S1 08 - 0F
|
||||||
|
0x35 , // HA
|
||||||
|
0x77 , // TA
|
||||||
|
0xD7 , // WA
|
||||||
|
0xB3 , // YO
|
||||||
|
0xB7 , // HANDAKU
|
||||||
|
NOKEY ,
|
||||||
|
NOKEY ,
|
||||||
|
NOKEY ,
|
||||||
|
// S2 10 - 17
|
||||||
|
0x7C , // KA
|
||||||
|
0x70 , // KE
|
||||||
|
0x41 , // SHI
|
||||||
|
0x31 , // KO
|
||||||
|
0x39 , // HI
|
||||||
|
0xA6 , // TE
|
||||||
|
0x78 , // KI
|
||||||
|
0xDD , // CHI
|
||||||
|
// S3 18 - 1F
|
||||||
|
0x3D , // FU
|
||||||
|
0x5D , // MI
|
||||||
|
0x6C , // MU
|
||||||
|
0x56 , // ME
|
||||||
|
0x1D , // RHI
|
||||||
|
0x33 , // RA
|
||||||
|
0xD5 , // HE
|
||||||
|
0xB1 , // HO
|
||||||
|
// S4 20 - 27
|
||||||
|
0x46 , // SA
|
||||||
|
0x6E , // TO
|
||||||
|
0xD9 , // THU
|
||||||
|
0x48 , // SU
|
||||||
|
0x74 , // KU
|
||||||
|
0x43 , // SE
|
||||||
|
0x4C , // SO
|
||||||
|
0x73 , // MA
|
||||||
|
// S5 28 - 2F
|
||||||
|
0x3F , // A
|
||||||
|
0x36 , // I
|
||||||
|
0x7E , // U
|
||||||
|
0x3B , // E
|
||||||
|
0x7A , // O
|
||||||
|
0x1E , // NA
|
||||||
|
0x5F , // NI
|
||||||
|
0xA2 , // NU
|
||||||
|
// S6 30 - 37
|
||||||
|
0xD3 , // YO
|
||||||
|
0x9F , // YU
|
||||||
|
0xD1 , // YA
|
||||||
|
0x00 , // SPACE
|
||||||
|
0x9D , // NO
|
||||||
|
0xA3 , // NE
|
||||||
|
0xD0 , // RU
|
||||||
|
0xB9 , // RE
|
||||||
|
// S7 38 - 3F
|
||||||
|
0xC6 , // ?CLR
|
||||||
|
0xC5 , // ?HOME
|
||||||
|
0xC2 , // ?CURSOR UP
|
||||||
|
0xC1 , // ?CURSOR DOWN
|
||||||
|
0xC3 , // ?CURSOR RIGHT
|
||||||
|
0xC4 , // ?CURSOR LEFT
|
||||||
|
0xBB , // DASH
|
||||||
|
0xBE , // RO
|
||||||
|
// S8 40 - 47 - Keypad keys.
|
||||||
|
'8' , // Keypad 8
|
||||||
|
'7' , // 7
|
||||||
|
'5' , // 5
|
||||||
|
'4' , // 4
|
||||||
|
'2' , // 2
|
||||||
|
'1' , // 1
|
||||||
|
DBLZERO , // 00
|
||||||
|
'0' , // 0
|
||||||
|
// S9 48 - 4F - Keypad keys.
|
||||||
|
'+' , // +
|
||||||
|
'0' , // 9
|
||||||
|
'-' , // -
|
||||||
|
'6' , // 6
|
||||||
|
NOKEY , //
|
||||||
|
'3' , // 3
|
||||||
|
NOKEY ,
|
||||||
|
'.' // .
|
||||||
|
}}
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown host, no keyboard map configured."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Mapping table of sharp special control keys to ANSI ESCape sequences.
|
// Mapping table of sharp special control keys to ANSI ESCape sequences.
|
||||||
@@ -1203,8 +1674,36 @@ static t_ansiKeyMap ansiKeySeq[] = {
|
|||||||
|
|
||||||
// Colour map for the Ansi Terminal.
|
// Colour map for the Ansi Terminal.
|
||||||
const unsigned char ansiColourMap[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
const unsigned char ansiColourMap[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||||
#endif
|
|
||||||
#if (TARGET_HOST_MZ80A == 1)
|
#elif (TARGET_HOST_MZ80A == 1)
|
||||||
|
// Static structures for controlling and managing hardware features.
|
||||||
|
// Display control structure. Used to manage the display including the Ansi Terminal.
|
||||||
|
const t_displayBuffer displayDefault = { .displayAttr = 0x71, .backingRow = 0, .displayCol = 0, .displayRow = 0, .maxBackingRow = (VC_DISPLAY_BUFFER_SIZE / VC_MAX_COLUMNS),
|
||||||
|
.maxDisplayRow = VC_MAX_ROWS, .maxBackingCol = 80, .useAnsiTerm = 1, .lineWrap = 0, .inDebug = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Keyboard control structure. Used to manage keyboard sweep, mapping and store.
|
||||||
|
const t_keyboard keyboardDefault = { .holdTimer = 0L, .autorepeat = 0, .mode = KEYB_LOWERCASE, .cursorOn = 1, .flashTimer = 0L, .keyBuf[0] = 0x00, .keyBufPtr = 0,
|
||||||
|
.mode = KEYB_LOWERCASE, .dualmode = KEYB_DUAL_GRAPH
|
||||||
|
};
|
||||||
|
|
||||||
|
// Audio control structure. Used to manage audio output.
|
||||||
|
const t_audio audioDefault = { .audioStopTimer = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// AnsiTerminal control structure. Used to manage the inbuilt Ansi Terminal.
|
||||||
|
const t_AnsiTerm ansitermDefault = { .state = ANSITERM_ESC, .charcnt = 0, .paramcnt = 0, .setDisplayMode = 0, .setExtendedMode = 0, .saveRow = 0, .saveCol = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Module control structure.
|
||||||
|
const t_control ctrlDefault = { .suspendIO = 0, .debug = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// Colour map for the Ansi Terminal.
|
||||||
|
const unsigned char ansiColourMap[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||||
|
|
||||||
|
#elif (TARGET_HOST_MZ2000 == 1)
|
||||||
// Static structures for controlling and managing hardware features.
|
// Static structures for controlling and managing hardware features.
|
||||||
// Display control structure. Used to manage the display including the Ansi Terminal.
|
// Display control structure. Used to manage the display including the Ansi Terminal.
|
||||||
const t_displayBuffer displayDefault = { .displayAttr = 0x71, .backingRow = 0, .displayCol = 0, .displayRow = 0, .maxBackingRow = (VC_DISPLAY_BUFFER_SIZE / VC_MAX_COLUMNS),
|
const t_displayBuffer displayDefault = { .displayAttr = 0x71, .backingRow = 0, .displayCol = 0, .displayRow = 0, .maxBackingRow = (VC_DISPLAY_BUFFER_SIZE / VC_MAX_COLUMNS),
|
||||||
@@ -1249,6 +1748,11 @@ static t_ansiKeyMap ansiKeySeq[] = {
|
|||||||
//
|
//
|
||||||
uint8_t mzInitMBHardware(void)
|
uint8_t mzInitMBHardware(void)
|
||||||
{
|
{
|
||||||
|
#if (TARGET_HOST_MZ700 == 1)
|
||||||
|
// Ensure memory paging is set to default.
|
||||||
|
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
#endif
|
||||||
|
|
||||||
// From the 1Z-013A monitor code, initialise the 8255 PIO.
|
// From the 1Z-013A monitor code, initialise the 8255 PIO.
|
||||||
//
|
//
|
||||||
WRITE_HARDWARE(1, MBADDR_KEYPF, 0x8A); // 10001010 CTRL WORD MODE0
|
WRITE_HARDWARE(1, MBADDR_KEYPF, 0x8A); // 10001010 CTRL WORD MODE0
|
||||||
@@ -1312,10 +1816,11 @@ void mzBeep(uint32_t freq, uint32_t timeout)
|
|||||||
// Locals.
|
// Locals.
|
||||||
#if (TARGET_HOST_MZ80A == 1)
|
#if (TARGET_HOST_MZ80A == 1)
|
||||||
uint16_t freqDiv = TIMER_8253_MZ80A_FREQ/(freq*2);
|
uint16_t freqDiv = TIMER_8253_MZ80A_FREQ/(freq*2);
|
||||||
#else
|
#elif (TARGET_HOST_MZ700 == 1)
|
||||||
uint16_t freqDiv = TIMER_8253_MZ700_FREQ/freq;
|
uint16_t freqDiv = TIMER_8253_MZ700_FREQ/freq;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (TARGET_HOST_MZ2000 == 0)
|
||||||
// Setup the 8253 Timer 0 to output a sound, enable output to amplifier and set timeout.
|
// Setup the 8253 Timer 0 to output a sound, enable output to amplifier and set timeout.
|
||||||
WRITE_HARDWARE(0, MBADDR_CONTF, 0x34 ); // Timer 0 to square wave generator, load LSB first.
|
WRITE_HARDWARE(0, MBADDR_CONTF, 0x34 ); // Timer 0 to square wave generator, load LSB first.
|
||||||
WRITE_HARDWARE(0, MBADDR_CONT0, (freqDiv&0xff) );
|
WRITE_HARDWARE(0, MBADDR_CONT0, (freqDiv&0xff) );
|
||||||
@@ -1324,6 +1829,7 @@ void mzBeep(uint32_t freq, uint32_t timeout)
|
|||||||
|
|
||||||
// Set a 500ms timeout on the sound to create beep effect.
|
// Set a 500ms timeout on the sound to create beep effect.
|
||||||
audio.audioStopTimer = timeout == 0 ? 11 : (timeout/10)+1; // Each unit is 10ms, valid range 1..n
|
audio.audioStopTimer = timeout == 0 ? 11 : (timeout/10)+1; // Each unit is 10ms, valid range 1..n
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2964,8 +3470,33 @@ uint8_t mzSweepKeys(void)
|
|||||||
{
|
{
|
||||||
keyboard.shiftKey = 0;
|
keyboard.shiftKey = 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#if (TARGET_HOST_MZ80A == 1)
|
#elif (TARGET_HOST_MZ80A == 1)
|
||||||
|
// Check for modifiers.
|
||||||
|
//
|
||||||
|
if((keyboard.scanbuf[0][0] & 0x01) == 0)
|
||||||
|
{
|
||||||
|
keyboard.shiftKey = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
keyboard.shiftKey = 0;
|
||||||
|
}
|
||||||
|
if((keyboard.scanbuf[0][0] & 0x80) == 0 && keyboard.shiftKey == 0)
|
||||||
|
{
|
||||||
|
keyboard.ctrlKey = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
keyboard.ctrlKey = 0;
|
||||||
|
}
|
||||||
|
if((keyboard.scanbuf[0][0] & 0x80) == 0 && keyboard.shiftKey == 1)
|
||||||
|
{
|
||||||
|
keyboard.breakKey = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
keyboard.breakKey = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif (TARGET_HOST_MZ2000 == 1)
|
||||||
// Check for modifiers.
|
// Check for modifiers.
|
||||||
//
|
//
|
||||||
if((keyboard.scanbuf[0][0] & 0x01) == 0)
|
if((keyboard.scanbuf[0][0] & 0x01) == 0)
|
||||||
|
|||||||
348
software/FusionX/src/ttymz/sharpmz.h
vendored
348
software/FusionX/src/ttymz/sharpmz.h
vendored
@@ -36,182 +36,210 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
// Build time target. Overrides if compile time definition given.
|
||||||
#define TARGET_HOST_MZ2000 0 // MZ2000
|
#if defined(TARGET_HOST_MZ700)
|
||||||
#define TARGET_HOST_MZ80A 1 // MZ80A
|
#define TARGET_HOST_MZ700 1
|
||||||
|
#define TARGET_HOST_MZ2000 0
|
||||||
|
#define TARGET_HOST_MZ80A 0
|
||||||
|
#define TARGET_HOST_PCW 0
|
||||||
|
#elif defined(TARGET_HOST_MZ2000)
|
||||||
|
#define TARGET_HOST_MZ2000 1
|
||||||
|
#define TARGET_HOST_MZ700 0
|
||||||
|
#define TARGET_HOST_MZ80A 0
|
||||||
|
#define TARGET_HOST_PCW 0
|
||||||
|
#elif defined(TARGET_HOST_MZ80A)
|
||||||
|
#define TARGET_HOST_MZ80A 1
|
||||||
|
#define TARGET_HOST_MZ2000 0
|
||||||
|
#define TARGET_HOST_MZ700 0
|
||||||
|
#define TARGET_HOST_PCW 0
|
||||||
|
#elif defined(TARGET_HOST_PCW8XXX) || defined(TARGET_HOST_PCW9XXX)
|
||||||
|
#define TARGET_HOST_PCW 1
|
||||||
|
#define TARGET_HOST_MZ2000 0
|
||||||
|
#define TARGET_HOST_MZ700 0
|
||||||
|
#define TARGET_HOST_MZ80A 0
|
||||||
|
#else
|
||||||
|
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
||||||
|
#define TARGET_HOST_MZ2000 0 // MZ2000
|
||||||
|
#define TARGET_HOST_MZ80A 0 // MZ80A
|
||||||
|
#define TARGET_HOST_PCW 0 // Amstrad PCW8XXX/9XXX
|
||||||
|
#endif
|
||||||
|
|
||||||
// Video display constants.
|
// Video display constants.
|
||||||
#define VC_MAX_ROWS 25 // Maximum number of rows on display.
|
#define VC_MAX_ROWS 25 // Maximum number of rows on display.
|
||||||
#define VC_MAX_COLUMNS 80 // Maximum number of columns on display.
|
#if defined(TARGET_HOST_MZ700)
|
||||||
#define VC_MAX_BUFFER_ROWS 50 // Maximum number of backing store rows for scrollback feature.
|
#define VC_MAX_COLUMNS 40 // Maximum number of columns on display.
|
||||||
#define VC_DISPLAY_BUFFER_SIZE VC_MAX_COLUMNS * VC_MAX_BUFFER_ROWS // Size of the display buffer for scrollback.
|
#else
|
||||||
|
#define VC_MAX_COLUMNS 80 // Maximum number of columns on display.
|
||||||
|
#endif
|
||||||
|
#define VC_MAX_BUFFER_ROWS 50 // Maximum number of backing store rows for scrollback feature.
|
||||||
|
#define VC_DISPLAY_BUFFER_SIZE VC_MAX_COLUMNS * VC_MAX_BUFFER_ROWS // Size of the display buffer for scrollback.
|
||||||
|
|
||||||
// Keyboard constants.
|
// Keyboard constants.
|
||||||
#define KEYB_AUTOREPEAT_INITIAL_TIME 800 // Time in milliseconds before starting autorepeat.
|
#define KEYB_AUTOREPEAT_INITIAL_TIME 800 // Time in milliseconds before starting autorepeat.
|
||||||
#define KEYB_AUTOREPEAT_TIME 100 // Time in milliseconds between auto repeating characters.
|
#define KEYB_AUTOREPEAT_TIME 100 // Time in milliseconds between auto repeating characters.
|
||||||
#define KEYB_FLASH_TIME 350 // Time in milliseconds for the cursor flash change.
|
#define KEYB_FLASH_TIME 350 // Time in milliseconds for the cursor flash change.
|
||||||
#define CURSOR_THICK_BLOCK 0x43 // Thick block cursor for lower case CAPS OFF
|
#define CURSOR_THICK_BLOCK 0x43 // Thick block cursor for lower case CAPS OFF
|
||||||
#define CURSOR_BLOCK 0xEF // Block cursor for SHIFT Lock.
|
#define CURSOR_BLOCK 0xEF // Block cursor for SHIFT Lock.
|
||||||
#define CURSOR_UNDERLINE 0x3E // Thick underscore for CAPS Lock.
|
#define CURSOR_UNDERLINE 0x3E // Thick underscore for CAPS Lock.
|
||||||
#define MAX_KEYB_BUFFER_SIZE 32 // Maximum size of the keyboard buffer.
|
#define MAX_KEYB_BUFFER_SIZE 32 // Maximum size of the keyboard buffer.
|
||||||
|
|
||||||
// Audio constants.
|
// Audio constants.
|
||||||
#define TIMER_8253_MZ80A_FREQ 2000000 // Base input frequency of Timer 0 for square wave generation.
|
#define TIMER_8253_MZ80A_FREQ 2000000 // Base input frequency of Timer 0 for square wave generation.
|
||||||
#define TIMER_8253_MZ700 768000 // Base input frequency of Timer 0 for square wave generation.
|
#define TIMER_8253_MZ700_FREQ 768000 // Base input frequency of Timer 0 for square wave generation.
|
||||||
|
|
||||||
// Base addresses and sizes within the Video Controller.
|
// Base addresses and sizes within the Video Controller.
|
||||||
#define VIDEO_BASE_ADDR 0x000000 // Base address of the Video Controller.
|
#define VIDEO_BASE_ADDR 0x000000 // Base address of the Video Controller.
|
||||||
#define VIDEO_VRAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D000 // Base address of the character video RAM using direct addressing.
|
#define VIDEO_VRAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D000 // Base address of the character video RAM using direct addressing.
|
||||||
#define VIDEO_VRAM_SIZE 0x800 // Size of the video RAM.
|
#define VIDEO_VRAM_SIZE 0x800 // Size of the video RAM.
|
||||||
#define VIDEO_ARAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D800 // Base address of the character attribute RAM using direct addressing.
|
#define VIDEO_ARAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D800 // Base address of the character attribute RAM using direct addressing.
|
||||||
#define VIDEO_ARAM_SIZE 0x800 // Size of the attribute RAM.
|
#define VIDEO_ARAM_SIZE 0x800 // Size of the attribute RAM.
|
||||||
|
|
||||||
// Video Module control bits.
|
// Video Module control bits.
|
||||||
#define VMMODE_MASK 0xF8 // Mask to mask out video mode.
|
#define VMMODE_MASK 0xF8 // Mask to mask out video mode.
|
||||||
#define VMMODE_MZ80K 0x00 // Video mode = MZ80K
|
#define VMMODE_MZ80K 0x00 // Video mode = MZ80K
|
||||||
#define VMMODE_MZ80C 0x01 // Video mode = MZ80C
|
#define VMMODE_MZ80C 0x01 // Video mode = MZ80C
|
||||||
#define VMMODE_MZ1200 0x02 // Video mode = MZ1200
|
#define VMMODE_MZ1200 0x02 // Video mode = MZ1200
|
||||||
#define VMMODE_MZ80A 0x03 // Video mode = MZ80A
|
#define VMMODE_MZ80A 0x03 // Video mode = MZ80A
|
||||||
#define VMMODE_MZ700 0x04 // Video mode = MZ700
|
#define VMMODE_MZ700 0x04 // Video mode = MZ700
|
||||||
#define VMMODE_MZ800 0x05 // Video mode = MZ800
|
#define VMMODE_MZ800 0x05 // Video mode = MZ800
|
||||||
#define VMMODE_MZ1500 0x06 // Video mode = MZ1500
|
#define VMMODE_MZ1500 0x06 // Video mode = MZ1500
|
||||||
#define VMMODE_MZ80B 0x07 // Video mode = MZ80B
|
#define VMMODE_MZ80B 0x07 // Video mode = MZ80B
|
||||||
#define VMMODE_MZ2000 0x08 // Video mode = MZ2000
|
#define VMMODE_MZ2000 0x08 // Video mode = MZ2000
|
||||||
#define VMMODE_MZ2200 0x09 // Video mode = MZ2200
|
#define VMMODE_MZ2200 0x09 // Video mode = MZ2200
|
||||||
#define VMMODE_MZ2500 0x0A // Video mode = MZ2500
|
#define VMMODE_MZ2500 0x0A // Video mode = MZ2500
|
||||||
#define VMMODE_80CHAR 0x80 // Enable 80 character display.
|
#define VMMODE_80CHAR 0x80 // Enable 80 character display.
|
||||||
#define VMMODE_80CHAR_MASK 0x7F // Mask to filter out display width control bit.
|
#define VMMODE_80CHAR_MASK 0x7F // Mask to filter out display width control bit.
|
||||||
#define VMMODE_COLOUR 0x20 // Enable colour display.
|
#define VMMODE_COLOUR 0x20 // Enable colour display.
|
||||||
#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit.
|
#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit.
|
||||||
|
|
||||||
// Sharp MZ colour attributes.
|
// Sharp MZ colour attributes.
|
||||||
#define VMATTR_FG_BLACK 0x00 // Foreground black character attribute.
|
#define VMATTR_FG_BLACK 0x00 // Foreground black character attribute.
|
||||||
#define VMATTR_FG_BLUE 0x10 // Foreground blue character attribute.
|
#define VMATTR_FG_BLUE 0x10 // Foreground blue character attribute.
|
||||||
#define VMATTR_FG_RED 0x20 // Foreground red character attribute.
|
#define VMATTR_FG_RED 0x20 // Foreground red character attribute.
|
||||||
#define VMATTR_FG_PURPLE 0x30 // Foreground purple character attribute.
|
#define VMATTR_FG_PURPLE 0x30 // Foreground purple character attribute.
|
||||||
#define VMATTR_FG_GREEN 0x40 // Foreground green character attribute.
|
#define VMATTR_FG_GREEN 0x40 // Foreground green character attribute.
|
||||||
#define VMATTR_FG_CYAN 0x50 // Foreground cyan character attribute.
|
#define VMATTR_FG_CYAN 0x50 // Foreground cyan character attribute.
|
||||||
#define VMATTR_FG_YELLOW 0x60 // Foreground yellow character attribute.
|
#define VMATTR_FG_YELLOW 0x60 // Foreground yellow character attribute.
|
||||||
#define VMATTR_FG_WHITE 0x70 // Foreground white character attribute.
|
#define VMATTR_FG_WHITE 0x70 // Foreground white character attribute.
|
||||||
#define VMATTR_FG_MASKOUT 0x8F // Mask to filter out foreground attribute.
|
#define VMATTR_FG_MASKOUT 0x8F // Mask to filter out foreground attribute.
|
||||||
#define VMATTR_FG_MASKIN 0x70 // Mask to filter out foreground attribute.
|
#define VMATTR_FG_MASKIN 0x70 // Mask to filter out foreground attribute.
|
||||||
#define VMATTR_BG_BLACK 0x00 // Background black character attribute.
|
#define VMATTR_BG_BLACK 0x00 // Background black character attribute.
|
||||||
#define VMATTR_BG_BLUE 0x01 // Background blue character attribute.
|
#define VMATTR_BG_BLUE 0x01 // Background blue character attribute.
|
||||||
#define VMATTR_BG_RED 0x02 // Background red character attribute.
|
#define VMATTR_BG_RED 0x02 // Background red character attribute.
|
||||||
#define VMATTR_BG_PURPLE 0x03 // Background purple character attribute.
|
#define VMATTR_BG_PURPLE 0x03 // Background purple character attribute.
|
||||||
#define VMATTR_BG_GREEN 0x04 // Background green character attribute.
|
#define VMATTR_BG_GREEN 0x04 // Background green character attribute.
|
||||||
#define VMATTR_BG_CYAN 0x05 // Background cyan character attribute.
|
#define VMATTR_BG_CYAN 0x05 // Background cyan character attribute.
|
||||||
#define VMATTR_BG_YELLOW 0x06 // Background yellow character attribute.
|
#define VMATTR_BG_YELLOW 0x06 // Background yellow character attribute.
|
||||||
#define VMATTR_BG_WHITE 0x07 // Background white character attribute.
|
#define VMATTR_BG_WHITE 0x07 // Background white character attribute.
|
||||||
#define VMATTR_BG_MASKOUT 0xF8 // Mask to filter out background attribute.
|
#define VMATTR_BG_MASKOUT 0xF8 // Mask to filter out background attribute.
|
||||||
#define VMATTR_BG_MASKIN 0x07 // Mask to filter out background attribute.
|
#define VMATTR_BG_MASKIN 0x07 // Mask to filter out background attribute.
|
||||||
|
|
||||||
// Sharp MZ constants.
|
// Sharp MZ constants.
|
||||||
//
|
//
|
||||||
#define MBADDR_KEYPA 0xE000 // Mainboard 8255 Port A
|
#define MBADDR_KEYPA 0xE000 // Mainboard 8255 Port A
|
||||||
#define MBADDR_KEYPB 0xE001 // Mainboard 8255 Port B
|
#define MBADDR_KEYPB 0xE001 // Mainboard 8255 Port B
|
||||||
#define MBADDR_KEYPC 0xE002 // Mainboard 8255 Port C
|
#define MBADDR_KEYPC 0xE002 // Mainboard 8255 Port C
|
||||||
#define MBADDR_KEYPF 0xE003 // Mainboard 8255 Mode Control
|
#define MBADDR_KEYPF 0xE003 // Mainboard 8255 Mode Control
|
||||||
#define MBADDR_CSTR 0xE002 // Mainboard 8255 Port C
|
#define MBADDR_CSTR 0xE002 // Mainboard 8255 Port C
|
||||||
#define MBADDR_CSTPT 0xE003 // Mainboard 8255 Mode Control
|
#define MBADDR_CSTPT 0xE003 // Mainboard 8255 Mode Control
|
||||||
#define MBADDR_CONT0 0xE004 // Mainboard 8253 Counter 0
|
#define MBADDR_CONT0 0xE004 // Mainboard 8253 Counter 0
|
||||||
#define MBADDR_CONT1 0xE005 // Mainboard 8253 Counter 1
|
#define MBADDR_CONT1 0xE005 // Mainboard 8253 Counter 1
|
||||||
#define MBADDR_CONT2 0xE006 // Mainboard 8253 Counter 1
|
#define MBADDR_CONT2 0xE006 // Mainboard 8253 Counter 1
|
||||||
#define MBADDR_CONTF 0xE007 // Mainboard 8253 Mode Control
|
#define MBADDR_CONTF 0xE007 // Mainboard 8253 Mode Control
|
||||||
#define MBADDR_SUNDG 0xE008 // Register for reading the tempo timer status (cursor flash). horizontal blank and switching sound on/off.
|
#define MBADDR_SUNDG 0xE008 // Register for reading the tempo timer status (cursor flash). horizontal blank and switching sound on/off.
|
||||||
#define MBADDR_TEMP 0xE008 // As above, different name used in original source when writing.
|
#define MBADDR_TEMP 0xE008 // As above, different name used in original source when writing.
|
||||||
#define MBADDR_MEMSW 0xE00C // Memory swap, 0000->C000, C000->0000
|
#define MBADDR_MEMSW 0xE00C // Memory swap, 0000->C000, C000->0000
|
||||||
#define MBADDR_MEMSWR 0xE010 // Reset memory swap.
|
#define MBADDR_MEMSWR 0xE010 // Reset memory swap.
|
||||||
#define MBADDR_NRMDSP 0xE014 // Return display to normal.
|
#define MBADDR_NRMDSP 0xE014 // Return display to normal.
|
||||||
#define MBADDR_INVDSP 0xE015 // Invert display.
|
#define MBADDR_INVDSP 0xE015 // Invert display.
|
||||||
#define MBADDR_SCLDSP 0xE200 // Hardware scroll, a read to each location adds 8 to the start of the video access address therefore creating hardware scroll. 00 - reset to power up
|
#define MBADDR_SCLDSP 0xE200 // Hardware scroll, a read to each location adds 8 to the start of the video access address therefore creating hardware scroll. 00 - reset to power up
|
||||||
#define MBADDR_SCLBASE 0xE2 // High byte scroll base.
|
#define MBADDR_SCLBASE 0xE2 // High byte scroll base.
|
||||||
#define MBADDR_DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
#define MBADDR_DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||||
|
|
||||||
//Common character definitions.
|
//Common character definitions.
|
||||||
#define SCROLL 0x01 // Set scroll direction UP.
|
#define SCROLL 0x01 // Set scroll direction UP.
|
||||||
#define BELL 0x07
|
#define BELL 0x07
|
||||||
#define ENQ 0x05
|
#define ENQ 0x05
|
||||||
#define SPACE 0x20
|
#define SPACE 0x20
|
||||||
#define TAB 0x09 // TAB ACROSS (8 SPACES FOR SD-BOARD)
|
#define TAB 0x09 // TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||||
#define CR 0x0D
|
#define CR 0x0D
|
||||||
#define LF 0x0A
|
#define LF 0x0A
|
||||||
#define FF 0x0C
|
#define FF 0x0C
|
||||||
#define DELETE 0x7F
|
#define DELETE 0x7F
|
||||||
#define BACKS 0x08
|
#define BACKS 0x08
|
||||||
#define SOH 0x01 // For XModem etc.
|
#define SOH 0x01 // For XModem etc.
|
||||||
#define EOT 0x04
|
#define EOT 0x04
|
||||||
#define ACK 0x06
|
#define ACK 0x06
|
||||||
#define NAK 0x15
|
#define NAK 0x15
|
||||||
#define NUL 0x00
|
#define NUL 0x00
|
||||||
//#define NULL 0x00
|
//#define NULL 0x00
|
||||||
#define CTRL_A 0x01
|
#define CTRL_A 0x01
|
||||||
#define CTRL_B 0x02
|
#define CTRL_B 0x02
|
||||||
#define CTRL_C 0x03
|
#define CTRL_C 0x03
|
||||||
#define CTRL_D 0x04
|
#define CTRL_D 0x04
|
||||||
#define CTRL_E 0x05
|
#define CTRL_E 0x05
|
||||||
#define CTRL_F 0x06
|
#define CTRL_F 0x06
|
||||||
#define CTRL_G 0x07
|
#define CTRL_G 0x07
|
||||||
#define CTRL_H 0x08
|
#define CTRL_H 0x08
|
||||||
#define CTRL_I 0x09
|
#define CTRL_I 0x09
|
||||||
#define CTRL_J 0x0A
|
#define CTRL_J 0x0A
|
||||||
#define CTRL_K 0x0B
|
#define CTRL_K 0x0B
|
||||||
#define CTRL_L 0x0C
|
#define CTRL_L 0x0C
|
||||||
#define CTRL_M 0x0D
|
#define CTRL_M 0x0D
|
||||||
#define CTRL_N 0x0E
|
#define CTRL_N 0x0E
|
||||||
#define CTRL_O 0x0F
|
#define CTRL_O 0x0F
|
||||||
#define CTRL_P 0x10
|
#define CTRL_P 0x10
|
||||||
#define CTRL_Q 0x11
|
#define CTRL_Q 0x11
|
||||||
#define CTRL_R 0x12
|
#define CTRL_R 0x12
|
||||||
#define CTRL_S 0x13
|
#define CTRL_S 0x13
|
||||||
#define CTRL_T 0x14
|
#define CTRL_T 0x14
|
||||||
#define CTRL_U 0x15
|
#define CTRL_U 0x15
|
||||||
#define CTRL_V 0x16
|
#define CTRL_V 0x16
|
||||||
#define CTRL_W 0x17
|
#define CTRL_W 0x17
|
||||||
#define CTRL_X 0x18
|
#define CTRL_X 0x18
|
||||||
#define CTRL_Y 0x19
|
#define CTRL_Y 0x19
|
||||||
#define CTRL_Z 0x1A
|
#define CTRL_Z 0x1A
|
||||||
#define ESC 0x1B
|
#define ESC 0x1B
|
||||||
#define CTRL_SLASH 0x1C
|
#define CTRL_SLASH 0x1C
|
||||||
#define CTRL_LB 0x1B
|
#define CTRL_LB 0x1B
|
||||||
#define CTRL_RB 0x1D
|
#define CTRL_RB 0x1D
|
||||||
#define CTRL_CAPPA 0x1E
|
#define CTRL_CAPPA 0x1E
|
||||||
#define CTRL_UNDSCR 0x1F
|
#define CTRL_UNDSCR 0x1F
|
||||||
#define CTRL_AT 0x00
|
#define CTRL_AT 0x00
|
||||||
#define FUNC1 0x80
|
#define FUNC1 0x80
|
||||||
#define FUNC2 0x81
|
#define FUNC2 0x81
|
||||||
#define FUNC3 0x82
|
#define FUNC3 0x82
|
||||||
#define FUNC4 0x83
|
#define FUNC4 0x83
|
||||||
#define FUNC5 0x84
|
#define FUNC5 0x84
|
||||||
#define FUNC6 0x85
|
#define FUNC6 0x85
|
||||||
#define FUNC7 0x86
|
#define FUNC7 0x86
|
||||||
#define FUNC8 0x87
|
#define FUNC8 0x87
|
||||||
#define FUNC9 0x88
|
#define FUNC9 0x88
|
||||||
#define FUNC10 0x89
|
#define FUNC10 0x89
|
||||||
#define PAGEUP 0xE0
|
#define PAGEUP 0xE0
|
||||||
#define PAGEDOWN 0xE1
|
#define PAGEDOWN 0xE1
|
||||||
#define CURHOMEKEY 0xE2
|
#define CURHOMEKEY 0xE2
|
||||||
#define ALPHAGRAPHKEY 0xE3
|
#define ALPHAGRAPHKEY 0xE3
|
||||||
#define HOTKEY_ORIGINAL 0xE8
|
#define HOTKEY_ORIGINAL 0xE8
|
||||||
#define HOTKEY_RFS80 0xE9
|
#define HOTKEY_RFS80 0xE9
|
||||||
#define HOTKEY_RFS40 0xEA
|
#define HOTKEY_RFS40 0xEA
|
||||||
#define HOTKEY_TZFS 0xEB
|
#define HOTKEY_TZFS 0xEB
|
||||||
#define HOTKEY_LINUX 0xEC
|
#define HOTKEY_LINUX 0xEC
|
||||||
#define NOKEY 0xF0
|
#define NOKEY 0xF0
|
||||||
#define CURSRIGHT 0xF1
|
#define CURSRIGHT 0xF1
|
||||||
#define CURSLEFT 0xF2
|
#define CURSLEFT 0xF2
|
||||||
#define CURSUP 0xF3
|
#define CURSUP 0xF3
|
||||||
#define CURSDOWN 0xF4
|
#define CURSDOWN 0xF4
|
||||||
#define DBLZERO 0xF5
|
#define DBLZERO 0xF5
|
||||||
#define INSERT 0xF6
|
#define INSERT 0xF6
|
||||||
#define CLRKEY 0xF7
|
#define CLRKEY 0xF7
|
||||||
#define HOMEKEY 0xF8
|
#define HOMEKEY 0xF8
|
||||||
#define ENDKEY 0xF9
|
#define ENDKEY 0xF9
|
||||||
#define ANSITGLKEY 0xFA
|
#define ANSITGLKEY 0xFA
|
||||||
#define BREAKKEY 0xFB
|
#define BREAKKEY 0xFB
|
||||||
#define GRAPHKEY 0xFC
|
#define GRAPHKEY 0xFC
|
||||||
#define ALPHAKEY 0xFD
|
#define ALPHAKEY 0xFD
|
||||||
#define DEBUGKEY 0xFE // Special key to enable debug features such as the ANSI emulation.
|
#define DEBUGKEY 0xFE // Special key to enable debug features such as the ANSI emulation.
|
||||||
|
|
||||||
// Macros.
|
// Macros.
|
||||||
//
|
//
|
||||||
@@ -285,7 +313,7 @@ typedef struct {
|
|||||||
uint8_t dispCode;
|
uint8_t dispCode;
|
||||||
} t_dispCodeMap;
|
} t_dispCodeMap;
|
||||||
|
|
||||||
// Mapping table from keyboard scan codes to Sharp MZ-700 keys.
|
// Mapping table from keyboard scan codes to Sharp MZ keys.
|
||||||
//
|
//
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t scanCode[80];
|
uint8_t scanCode[80];
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData)
|
|||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
// Test Methods.
|
// Test Methods.
|
||||||
//--------------------------------------------------------
|
//--------------------------------------------------------
|
||||||
#ifdef INCLUDE_TEST_METHODS
|
#if defined(INCLUDE_TEST_METHODS) && INCLUDE_TEST_METHODS == 1
|
||||||
#include "z80io_test.c"
|
#include "z80io_test.c"
|
||||||
#else
|
#else
|
||||||
uint8_t z80io_Z80_TestMemory(void)
|
uint8_t z80io_Z80_TestMemory(void)
|
||||||
|
|||||||
95
software/FusionX/src/ttymz/z80io.h
vendored
95
software/FusionX/src/ttymz/z80io.h
vendored
@@ -39,7 +39,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Definitions to control compilation.
|
// Definitions to control compilation.
|
||||||
//#define INCLUDE_TEST_METHODS 0
|
#define INCLUDE_TEST_METHODS 0
|
||||||
|
|
||||||
// CPLD Commands.
|
// CPLD Commands.
|
||||||
#define CPLD_CMD_FETCH_ADDR 0x10
|
#define CPLD_CMD_FETCH_ADDR 0x10
|
||||||
@@ -82,6 +82,14 @@
|
|||||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR 0x38
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P1 0x39
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P2 0x3A
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P3 0x3B
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P4 0x3C
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P5 0x3D
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P6 0x3E
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P7 0x3F
|
||||||
#define CPLD_CMD_HALT 0x50
|
#define CPLD_CMD_HALT 0x50
|
||||||
#define CPLD_CMD_REFRESH 0x51
|
#define CPLD_CMD_REFRESH 0x51
|
||||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||||
@@ -386,8 +394,8 @@
|
|||||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
||||||
#define CPLD_Z80_INT() (MHal_RIU_REG(PAD_Z80IO_INT_ADDR) & 0x4)
|
#define CPLD_Z80_INT() (MHal_RIU_REG(PAD_Z80IO_INT_ADDR) & 0x4)
|
||||||
#define CPLD_Z80_NMI() (MHal_RIU_REG(PAD_Z80IO_NMI_ADDR) & 0x4)
|
#define CPLD_Z80_NMI() (MHal_RIU_REG(PAD_Z80IO_NMI_ADDR) & 0x4)
|
||||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
@@ -396,9 +404,18 @@
|
|||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||||
}
|
}
|
||||||
|
#define SPI_SEND_I_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||||
|
}
|
||||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
@@ -406,10 +423,9 @@
|
|||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
}
|
}
|
||||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
@@ -417,24 +433,63 @@
|
|||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
}
|
}
|
||||||
#define SPI_SEND32i(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND_P_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) != 0);\
|
||||||
pr_info("Stage 0");\
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
pr_info("Stage 1");\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
pr_info("Stage 2");\
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
timeout = MAX_CHECK_CNT; \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; }; \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
pr_info("Stage 3");\
|
}
|
||||||
|
#define SPI_SET_FRAME_SIZE() { MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND_I_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND_48(_d1_, _d2_, _d3_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 6); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d3_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d2_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+2, (uint16_t)_d1_); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };
|
|
||||||
// read 2 byte
|
// read 2 byte
|
||||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||||
// write 2 byte
|
// write 2 byte
|
||||||
|
|||||||
@@ -1,794 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80ctrl.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 Control Interface
|
|
||||||
// This file contains a command line utility tool for controlling the z80drv device
|
|
||||||
// driver. The tool allows manipulation of the emulated Z80, inspection of its
|
|
||||||
// memory and data, transmission of adhoc commands to the underlying CPLD-Z80
|
|
||||||
// gateway and loading/saving of programs and data to/from the Z80 virtual and
|
|
||||||
// host memory.
|
|
||||||
//
|
|
||||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
|
||||||
// The Z80 CPU Emulator is the heart of the Z80 device driver.
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <Z/constants/pointer.h>
|
|
||||||
#include <Z/macros/member.h>
|
|
||||||
#include <Z/macros/array.h>
|
|
||||||
#include <Z80.h>
|
|
||||||
#include "z80driver.h"
|
|
||||||
|
|
||||||
#define VERSION "1.0"
|
|
||||||
#define AUTHOR "P.D.Smart"
|
|
||||||
#define COPYRIGHT "(c) 2018-22"
|
|
||||||
|
|
||||||
// Getopt_long is buggy so we use optparse.
|
|
||||||
#define OPTPARSE_IMPLEMENTATION
|
|
||||||
#define OPTPARSE_API static
|
|
||||||
#include "optparse.h"
|
|
||||||
|
|
||||||
// Device driver name.
|
|
||||||
#define DEVICE_FILENAME "/dev/z80drv"
|
|
||||||
|
|
||||||
// Constants for the Sharp MZ80A MZF file format.
|
|
||||||
#define MZF_HEADER_SIZE 128 // Size of the MZF header.
|
|
||||||
#define MZF_ATTRIBUTE 0x00 // Code Type, 01 = Machine Code.
|
|
||||||
#define MZF_FILENAME 0x01 // Title/Name (17 bytes).
|
|
||||||
#define MZF_FILENAME_LEN 17 // Length of the filename, it is not NULL terminated, generally a CR can be taken as terminator but not guaranteed.
|
|
||||||
#define MZF_FILESIZE 0x12 // Size of program.
|
|
||||||
#define MZF_LOADADDR 0x14 // Load address of program.
|
|
||||||
#define MZF_EXECADDR 0x16 // Exec address of program.
|
|
||||||
#define MZF_COMMENT 0x18 // Comment, used for details of the file or startup code.
|
|
||||||
#define MZF_COMMENT_LEN 104 // Length of the comment field.
|
|
||||||
#define CMT_TYPE_OBJCD 0x001 // MZF contains a binary object.
|
|
||||||
#define CMT_TYPE_BTX1CD 0x002 // MZF contains a BASIC program.
|
|
||||||
#define CMT_TYPE_BTX2CD 0x005 // MZF contains a BASIC program.
|
|
||||||
#define CMT_TYPE_TZOBJCD0 0x0F8 // MZF contains a TZFS binary object for page 0.
|
|
||||||
#define CMT_TYPE_TZOBJCD1 0x0F9
|
|
||||||
#define CMT_TYPE_TZOBJCD2 0x0FA
|
|
||||||
#define CMT_TYPE_TZOBJCD3 0x0FB
|
|
||||||
#define CMT_TYPE_TZOBJCD4 0x0FC
|
|
||||||
#define CMT_TYPE_TZOBJCD5 0x0FD
|
|
||||||
#define CMT_TYPE_TZOBJCD6 0x0FE
|
|
||||||
#define CMT_TYPE_TZOBJCD7 0x0FF // MZF contains a TZFS binary object for page 7.
|
|
||||||
#define MZ_CMT_ADDR 0x10F0
|
|
||||||
|
|
||||||
// Structure to define a Sharp MZ80A MZF directory structure. This header appears at the beginning of every Sharp MZ80A tape (and more recently archived/emulator) images.
|
|
||||||
//
|
|
||||||
typedef struct __attribute__((__packed__)) {
|
|
||||||
uint8_t attr; // MZF attribute describing the file.
|
|
||||||
uint8_t fileName[MZF_FILENAME_LEN]; // Each directory entry is the size of an MZF filename.
|
|
||||||
uint16_t fileSize; // Size of file.
|
|
||||||
uint16_t loadAddr; // Load address for the file.
|
|
||||||
uint16_t execAddr; // Execution address where the Z80 starts processing.
|
|
||||||
uint8_t comment[MZF_COMMENT_LEN]; // Text comment field but often contains a startup machine code program.
|
|
||||||
} t_svcDirEnt;
|
|
||||||
|
|
||||||
// Possible commands to be issued to the Z80 driver.
|
|
||||||
enum CTRL_COMMANDS {
|
|
||||||
Z80_CMD_STOP = 0,
|
|
||||||
Z80_CMD_START = 1,
|
|
||||||
Z80_CMD_PAUSE = 2,
|
|
||||||
Z80_CMD_CONTINUE = 3,
|
|
||||||
Z80_CMD_RESET = 4,
|
|
||||||
Z80_CMD_SPEED = 5,
|
|
||||||
Z80_CMD_HOST_RAM = 6,
|
|
||||||
Z80_CMD_VIRTUAL_RAM = 7,
|
|
||||||
Z80_CMD_DUMP_MEMORY = 8,
|
|
||||||
Z80_CMD_MEMORY_TEST = 9,
|
|
||||||
CPLD_CMD_SEND_CMD = 10,
|
|
||||||
CPLD_CMD_SPI_TEST = 11,
|
|
||||||
CPLD_CMD_PRL_TEST = 12
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Shared memory between this process and the Z80 driver.
|
|
||||||
static t_Z80Ctrl *Z80Ctrl = NULL;
|
|
||||||
|
|
||||||
// Method to obtain and return the output screen width.
|
|
||||||
//
|
|
||||||
uint8_t getScreenWidth(void)
|
|
||||||
{
|
|
||||||
return(MAX_SCREEN_WIDTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct termios orig_termios;
|
|
||||||
|
|
||||||
void reset_terminal_mode()
|
|
||||||
{
|
|
||||||
tcsetattr(0, TCSANOW, &orig_termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_conio_terminal_mode()
|
|
||||||
{
|
|
||||||
struct termios new_termios;
|
|
||||||
|
|
||||||
/* take two copies - one for now, one for later */
|
|
||||||
tcgetattr(0, &orig_termios);
|
|
||||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
|
||||||
|
|
||||||
/* register cleanup handler, and set the new terminal mode */
|
|
||||||
atexit(reset_terminal_mode);
|
|
||||||
cfmakeraw(&new_termios);
|
|
||||||
tcsetattr(0, TCSANOW, &new_termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kbhit()
|
|
||||||
{
|
|
||||||
struct timeval tv = { 0L, 0L };
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(0, &fds);
|
|
||||||
return select(1, &fds, NULL, NULL, &tv) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getch(uint8_t wait)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
if(wait != 0 || (wait == 0 && kbhit()))
|
|
||||||
{
|
|
||||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void delay(int number_of_seconds)
|
|
||||||
{
|
|
||||||
// Converting time into milli_seconds
|
|
||||||
int milli_seconds = 1000 * number_of_seconds;
|
|
||||||
|
|
||||||
// Storing start time
|
|
||||||
clock_t start_time = clock();
|
|
||||||
|
|
||||||
// looping till required time is not achieved
|
|
||||||
while (clock() < start_time + milli_seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to dump out a given section of memory via the UART.
|
|
||||||
//
|
|
||||||
int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t memwidth, uint32_t dispaddr, uint8_t dispwidth)
|
|
||||||
{
|
|
||||||
uint8_t displayWidth = dispwidth;;
|
|
||||||
uint32_t pnt = memaddr;
|
|
||||||
uint32_t endAddr = memaddr + memsize;
|
|
||||||
uint32_t addr = dispaddr;
|
|
||||||
uint32_t i = 0;
|
|
||||||
//uint32_t data;
|
|
||||||
int8_t keyIn;
|
|
||||||
int result = -1;
|
|
||||||
char c = 0;
|
|
||||||
|
|
||||||
// Sanity check. memoryFlag == 0 required kernel driver to dump so we exit as it cannot be performed here.
|
|
||||||
if(memoryFlag == 0)
|
|
||||||
return(-1);
|
|
||||||
|
|
||||||
// Reconfigure terminal to allow non-blocking key input.
|
|
||||||
//
|
|
||||||
set_conio_terminal_mode();
|
|
||||||
|
|
||||||
// If not set, calculate output line width according to connected display width.
|
|
||||||
//
|
|
||||||
if(displayWidth == 0)
|
|
||||||
{
|
|
||||||
switch(getScreenWidth())
|
|
||||||
{
|
|
||||||
case 40:
|
|
||||||
displayWidth = 8;
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
displayWidth = 16;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
displayWidth = 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
printf("%08lX", addr); // print address
|
|
||||||
printf(": ");
|
|
||||||
|
|
||||||
// print hexadecimal data
|
|
||||||
for (i=0; i < displayWidth; )
|
|
||||||
{
|
|
||||||
switch(memwidth)
|
|
||||||
{
|
|
||||||
case 16:
|
|
||||||
if(pnt+i < endAddr)
|
|
||||||
printf("%04X", memoryFlag == 1 ? (uint16_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint16_t)Z80Ctrl->page[pnt+i] : (uint16_t)Z80Ctrl->iopage[pnt+i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
if(pnt+i < endAddr)
|
|
||||||
printf("%08lX", memoryFlag == 1 ? (uint32_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint32_t)Z80Ctrl->page[pnt+i] : (uint32_t)Z80Ctrl->iopage[pnt+i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 8:
|
|
||||||
default:
|
|
||||||
if(pnt+i < endAddr)
|
|
||||||
printf("%02X", memoryFlag == 1 ? (uint8_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint8_t)Z80Ctrl->page[pnt+i] : (uint8_t)Z80Ctrl->iopage[pnt+i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fputc((char)' ', stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// print ascii data
|
|
||||||
printf(" |");
|
|
||||||
|
|
||||||
// print single ascii char
|
|
||||||
for (i=0; i < displayWidth; i++)
|
|
||||||
{
|
|
||||||
c = memoryFlag == 1 ? (char)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (char)Z80Ctrl->page[pnt+i] : (char)Z80Ctrl->iopage[pnt+i];
|
|
||||||
if ((pnt+i < endAddr) && (c >= ' ') && (c <= '~'))
|
|
||||||
fputc((char)c, stdout);
|
|
||||||
else
|
|
||||||
fputc((char)' ', stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("|\r\n");
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
// Move on one row.
|
|
||||||
pnt += displayWidth;
|
|
||||||
addr += displayWidth;
|
|
||||||
|
|
||||||
// User abort (ESC), pause (Space) or all done?
|
|
||||||
//
|
|
||||||
keyIn = getch(0);
|
|
||||||
if(keyIn == ' ')
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
keyIn = getch(0);
|
|
||||||
} while(keyIn != ' ' && keyIn != 0x1b);
|
|
||||||
}
|
|
||||||
// Escape key pressed, exit with 0 to indicate this to caller.
|
|
||||||
if (keyIn == 0x1b)
|
|
||||||
{
|
|
||||||
sleep(1);
|
|
||||||
result = 0;
|
|
||||||
goto memoryDumpExit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of buffer, exit the loop.
|
|
||||||
if(pnt >= (memaddr + memsize))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal exit, return -1 to show no key pressed.
|
|
||||||
memoryDumpExit:
|
|
||||||
reset_terminal_mode();
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to load a program or data file into the Z80 memory. First load into Virtual memory and then trigger a sync to bring Host RAM in line.
|
|
||||||
//
|
|
||||||
int z80load(int fdZ80, char *fileName)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
struct ioctlCmd ioctlCmd;
|
|
||||||
int ret = 0;
|
|
||||||
t_svcDirEnt mzfHeader;
|
|
||||||
|
|
||||||
// Pause the Z80.
|
|
||||||
//
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
// Open the file and read directly into the Virtual memory via the share.
|
|
||||||
FILE *ptr;
|
|
||||||
ptr = fopen(fileName, "rb");
|
|
||||||
if(ptr)
|
|
||||||
{
|
|
||||||
// First the header.
|
|
||||||
fread((uint8_t *)&mzfHeader, MZF_HEADER_SIZE, 1, ptr);
|
|
||||||
|
|
||||||
#if(TARGET_HOST_MZ700 == 1)
|
|
||||||
if(mzfHeader.loadAddr > 0x1000)
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
// Copy in the header.
|
|
||||||
memcpy((uint8_t *)&Z80Ctrl->memory[MZ_CMT_ADDR], (uint8_t *)&mzfHeader, MZF_HEADER_SIZE);
|
|
||||||
|
|
||||||
// Now read in the data.
|
|
||||||
fread(&Z80Ctrl->memory[mzfHeader.loadAddr], mzfHeader.fileSize, 1, ptr);
|
|
||||||
printf("Loaded %s, Size:%04x, Addr:%04x, Exec:%04x\n", fileName, mzfHeader.fileSize, mzfHeader.loadAddr, mzfHeader.execAddr);
|
|
||||||
#if(TARGET_HOST_MZ700 == 1)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Sync the loaded image from Virtual memory to hard memory.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_SYNC_TO_HOST_RAM;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
#if(TARGET_HOST_MZ2000 == 1)
|
|
||||||
// Set PC to 2 (NST) which switches to RUN mode and executes at 0000H
|
|
||||||
ioctlCmd.z80.pc = 2;
|
|
||||||
#endif
|
|
||||||
#if(TARGET_HOST_MZ700 == 1)
|
|
||||||
// MZ-700 just use the MZF header exec address.
|
|
||||||
ioctlCmd.z80.pc = mzfHeader.execAddr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set PC to required setting ready for run.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_SETPC;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
// Resume Z80 processing.
|
|
||||||
//
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
printf("Couldnt open file\n");
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to request basic Z80 operations.
|
|
||||||
//
|
|
||||||
int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long param3)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
struct ioctlCmd ioctlCmd;
|
|
||||||
uint32_t idx;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch(cmd)
|
|
||||||
{
|
|
||||||
case Z80_CMD_STOP:
|
|
||||||
// Use IOCTL to request Z80 to Stop (power off) processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_START:
|
|
||||||
// Use IOCTL to request Z80 to Start (power on) processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_PAUSE:
|
|
||||||
// Use IOCTL to request Z80 to pause processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_CONTINUE:
|
|
||||||
// Use IOCTL to request Z80 continue processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_RESET:
|
|
||||||
// Use IOCTL to request Z80 reset.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_SPEED:
|
|
||||||
// Check value is in range.
|
|
||||||
for(idx=1; idx < 256; idx+=idx)
|
|
||||||
{
|
|
||||||
if((uint32_t)param1 == idx) break;
|
|
||||||
}
|
|
||||||
if(idx == 256)
|
|
||||||
{
|
|
||||||
printf("Speed factor is illegal. It must be a multiple value of the original CPU clock, ie. 1x, 2x, 4x etc\n");
|
|
||||||
ret = -1;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// Use IOCTL to request Z80 cpu freq change.
|
|
||||||
ioctlCmd.speed.speedMultiplier = (uint32_t)param1;
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CPU_FREQ;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CPLD_CMD_SEND_CMD:
|
|
||||||
// Build up the IOCTL command to request the given data is sent to the CPLD.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_CPLD_CMD;
|
|
||||||
ioctlCmd.cpld.cmd = (uint32_t)param1;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_DUMP_MEMORY:
|
|
||||||
// If virtual memory, we can dump it via the shared memory segment.
|
|
||||||
if((uint8_t)param1)
|
|
||||||
{
|
|
||||||
memoryDump((uint32_t)param2, (uint32_t)param3, (uint8_t)param1, (uint8_t)param1 == 2 || (uint8_t)param1 == 3 ? 32 : 8, (uint32_t)param2, 0);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// Build an IOCTL command to get the driver to dump the memory.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_DUMP_MEMORY;
|
|
||||||
ioctlCmd.addr.start = (uint32_t)param2;
|
|
||||||
ioctlCmd.addr.end = (uint32_t)param2+(uint32_t)param3;
|
|
||||||
ioctlCmd.addr.size = (uint32_t)param3;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Z80_CMD_HOST_RAM:
|
|
||||||
// Use IOCTL to request change to host RAM.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_USE_HOST_RAM;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_VIRTUAL_RAM:
|
|
||||||
// Use IOCTL to request change to host RAM.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_USE_VIRTUAL_RAM;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_MEMORY_TEST:
|
|
||||||
// Send command to test the SPI.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_MEMTEST;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case CPLD_CMD_PRL_TEST:
|
|
||||||
// Send command to test the SPI.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_PRL_TEST;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case CPLD_CMD_SPI_TEST:
|
|
||||||
// Send command to test the SPI.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_SPI_TEST;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf("Command not supported!\n");
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to perform some simple tests on the Z80 emulator.
|
|
||||||
//
|
|
||||||
int z80test(int fdZ80)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
struct ioctlCmd ioctlCmd;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
// Stop the Z80.
|
|
||||||
//
|
|
||||||
printf("Send STOP\n");
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
FILE *ptr;
|
|
||||||
ptr = fopen("/customer/mz700.rom", "rb");
|
|
||||||
if(ptr)
|
|
||||||
{
|
|
||||||
fread(&Z80Ctrl->memory, 65536, 1, ptr);
|
|
||||||
} else printf("Couldnt open file\n");
|
|
||||||
|
|
||||||
// Configure the Z80.
|
|
||||||
//
|
|
||||||
printf("Send SETPC\n");
|
|
||||||
ioctlCmd.z80.pc = 0;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SETPC, &ioctlCmd);
|
|
||||||
|
|
||||||
memoryDump(0 , 65536, 1, 8, 0, 0);
|
|
||||||
|
|
||||||
// Start the Z80.
|
|
||||||
//
|
|
||||||
printf("Send START\n");
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
printf("Send STOP\n");
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
memoryDump(0, 65536, 1, 8, 0, 0);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output usage screen. So mamy commands you do need to be prompted!!
|
|
||||||
void showArgs(char *progName, struct optparse *options)
|
|
||||||
{
|
|
||||||
printf("%s %s %s %s\n\n", progName, VERSION, COPYRIGHT, AUTHOR);
|
|
||||||
printf("Synopsis:\n");
|
|
||||||
printf("%s --help # This help screen.\n", progName);
|
|
||||||
printf(" --cmd <command> = RESET # Reset the Z80\n");
|
|
||||||
printf(" = STOP # Stop and power off the Z80\n");
|
|
||||||
printf(" = START # Power on and start the Z80\n");
|
|
||||||
printf(" = PAUSE # Pause running Z80\n");
|
|
||||||
printf(" = CONTINUE # Continue Z80 execution\n");
|
|
||||||
printf(" = HOSTRAM # Use HOST DRAM\n");
|
|
||||||
printf(" = VIRTRAM # Use Virtual RAM\n");
|
|
||||||
printf(" = SPEED --speed <1, 2, 4, 8, 16, 32, 64, 128> # In Virtual RAM mode, set CPU speed to base clock x factor.\n");
|
|
||||||
printf(" = LOADMZF --file <mzf filename> # Load MZF file into memory.\n");
|
|
||||||
printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>]--virtual <0 - Host RAM, 1 = Virtual RAM, 2 = PageTable, 3 = IOPageTable>\n");
|
|
||||||
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
|
||||||
printf(" = Z80TEST # Perform various debugging tests\n");
|
|
||||||
printf(" = SPITEST # Perform SPI testing\n");
|
|
||||||
printf(" = PRLTEST # Perform Parallel Bus testing\n");
|
|
||||||
printf(" = Z80MEMTEST # Perform HOST memory tests.\n");
|
|
||||||
printf(" --<cmd> # Some commands can be abbreviated.\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int fdZ80;
|
|
||||||
char buff[64];
|
|
||||||
char cmd[64] = { 0 };
|
|
||||||
char fileName[256] = { 0 };
|
|
||||||
int opt;
|
|
||||||
uint32_t hexData = 0;
|
|
||||||
long speedMultiplier = 1;
|
|
||||||
long startAddr = 0x0000;
|
|
||||||
long endAddr = 0x1000;
|
|
||||||
int virtualMemory = 0;
|
|
||||||
int helpFlag = 0;
|
|
||||||
int verboseFlag = 0;
|
|
||||||
|
|
||||||
// Define parameters to be processed.
|
|
||||||
struct optparse options;
|
|
||||||
static struct optparse_long long_options[] =
|
|
||||||
{
|
|
||||||
{"help", 'h', OPTPARSE_NONE},
|
|
||||||
{"cmd", 'c', OPTPARSE_REQUIRED},
|
|
||||||
{"file", 'f', OPTPARSE_REQUIRED},
|
|
||||||
{"data", 'd', OPTPARSE_REQUIRED},
|
|
||||||
{"speed", 'S', OPTPARSE_REQUIRED},
|
|
||||||
{"virtual", 'V', OPTPARSE_REQUIRED},
|
|
||||||
{"addr", 'a', OPTPARSE_REQUIRED},
|
|
||||||
{"end", 'e', OPTPARSE_REQUIRED},
|
|
||||||
{"size", 's', OPTPARSE_REQUIRED},
|
|
||||||
{"verbose", 'v', OPTPARSE_NONE},
|
|
||||||
{"dump", '1', OPTPARSE_NONE},
|
|
||||||
{"loadmzf", '2', OPTPARSE_NONE},
|
|
||||||
{"reset", '3', OPTPARSE_NONE},
|
|
||||||
{"stop", '4', OPTPARSE_NONE},
|
|
||||||
{"start", '5', OPTPARSE_NONE},
|
|
||||||
{"pause", '6', OPTPARSE_NONE},
|
|
||||||
{"continue", '7', OPTPARSE_NONE},
|
|
||||||
{"speed", '8', OPTPARSE_NONE},
|
|
||||||
{"cpldcmd", '9', OPTPARSE_NONE},
|
|
||||||
{0}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse the command line options.
|
|
||||||
//
|
|
||||||
optparse_init(&options, argv);
|
|
||||||
while((opt = optparse_long(&options, long_options, NULL)) != -1)
|
|
||||||
{
|
|
||||||
switch(opt)
|
|
||||||
{
|
|
||||||
// Hex data.
|
|
||||||
case 'd':
|
|
||||||
// hexData = (uint32_t)strtol(options.optarg, NULL, 0);
|
|
||||||
sscanf(options.optarg, "0x%08x", &hexData);
|
|
||||||
printf("Hex data:%08x\n", hexData);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Start address for memory operations.
|
|
||||||
case 'a':
|
|
||||||
startAddr = strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("Start Addr:%04x\n", startAddr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Speed multiplication factor for CPU governor when running in virtual memory.
|
|
||||||
case 'S':
|
|
||||||
speedMultiplier = strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("Speed = base freq x %d\n", speedFactor);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// End address for memory operations.
|
|
||||||
case 'e':
|
|
||||||
endAddr = strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("End Addr:%04x\n", endAddr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Size instead of end address for memory operations.
|
|
||||||
case 's':
|
|
||||||
endAddr = startAddr + strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("End Addr:%04x\n", endAddr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Virtual memory flag, 0 = host, 1 = virtual memory, 2 = page table, 3 = iopage table.
|
|
||||||
case 'V':
|
|
||||||
virtualMemory = atoi(options.optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Filename.
|
|
||||||
case 'f':
|
|
||||||
strcpy(fileName, options.optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Command to execute.
|
|
||||||
case 'c':
|
|
||||||
strcpy(cmd, options.optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Quick command flags.
|
|
||||||
case '1':
|
|
||||||
strcpy(cmd, "DUMP");
|
|
||||||
break;
|
|
||||||
case '2':
|
|
||||||
strcpy(cmd, "LOADMZF");
|
|
||||||
break;
|
|
||||||
case '3':
|
|
||||||
strcpy(cmd, "RESET");
|
|
||||||
break;
|
|
||||||
case '4':
|
|
||||||
strcpy(cmd, "STOP");
|
|
||||||
break;
|
|
||||||
case '5':
|
|
||||||
strcpy(cmd, "START");
|
|
||||||
break;
|
|
||||||
case '6':
|
|
||||||
strcpy(cmd, "PAUSE");
|
|
||||||
break;
|
|
||||||
case '7':
|
|
||||||
strcpy(cmd, "CONTINUE");
|
|
||||||
break;
|
|
||||||
case '8':
|
|
||||||
strcpy(cmd, "SPEED");
|
|
||||||
break;
|
|
||||||
case '9':
|
|
||||||
strcpy(cmd, "CPLDCMD");
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Verbose mode.
|
|
||||||
case 'v':
|
|
||||||
verboseFlag = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Command help needed.
|
|
||||||
case 'h':
|
|
||||||
helpFlag = 1;
|
|
||||||
showArgs(argv[0], &options);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Unrecognised, show synopsis.
|
|
||||||
case '?':
|
|
||||||
showArgs(argv[0], &options);
|
|
||||||
printf("%s: %s\n", argv[0], options.errmsg);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the z80drv driver and attach to its shared memory, basically the Z80 control structure which includes the virtual Z80 memory.
|
|
||||||
fdZ80 = open(DEVICE_FILENAME, O_RDWR|O_NDELAY);
|
|
||||||
if(fdZ80 >= 0)
|
|
||||||
{
|
|
||||||
Z80Ctrl = (t_Z80Ctrl *)mmap(0, sizeof(t_Z80Ctrl), PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0);
|
|
||||||
if(Z80Ctrl == (void *)-1)
|
|
||||||
{
|
|
||||||
printf("Failed to attach to the Z80 Control structure, cannot continue, exitting....\n");
|
|
||||||
close(fdZ80);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
printf("Failed to open the Z80 Driver, exitting...\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic string to method mapping. Started off with just 1 or two but has grown, may need a table!
|
|
||||||
if(strcasecmp(cmd, "LOADMZF") == 0)
|
|
||||||
{
|
|
||||||
z80load(fdZ80, fileName);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "RESET") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_RESET, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "STOP") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_STOP, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "START") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_START, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "PAUSE") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_PAUSE, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "CONTINUE") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_CONTINUE, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "SPEED") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_SPEED, speedMultiplier, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "DUMP") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_DUMP_MEMORY, virtualMemory, startAddr, (endAddr - startAddr));
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "HOSTRAM") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_HOST_RAM, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "VIRTRAM") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_VIRTUAL_RAM, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "CPLDCMD") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, CPLD_CMD_SEND_CMD, hexData, 0, 0);
|
|
||||||
} else
|
|
||||||
|
|
||||||
// Test methods, if the code is built-in to the driver.
|
|
||||||
if(strcasecmp(cmd, "Z80TEST") == 0)
|
|
||||||
{
|
|
||||||
z80test(fdZ80);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "SPITEST") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, CPLD_CMD_SPI_TEST, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "PRLTEST") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, CPLD_CMD_PRL_TEST, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "Z80MEMTEST") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_MEMORY_TEST, 0, 0, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
showArgs(argv[0], &options);
|
|
||||||
printf("No command given, nothing done!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmap shared memory and close the device.
|
|
||||||
munmap(Z80Ctrl, sizeof(t_Z80Ctrl));
|
|
||||||
close(fdZ80);
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
326
software/FusionX/src/z80drv/MZ2000/z80driver.h
vendored
326
software/FusionX/src/z80drv/MZ2000/z80driver.h
vendored
@@ -1,326 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80driver.h
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 Driver
|
|
||||||
// This file contains the declarations used in the z80drv device driver.
|
|
||||||
//
|
|
||||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
|
||||||
// The Z80 CPU Emulator is the heart of this driver and in all ways, is compatible with
|
|
||||||
// the original Z80.
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifndef Z80DRIVER_H
|
|
||||||
#define Z80DRIVER_H
|
|
||||||
|
|
||||||
// Constants.
|
|
||||||
#define TARGET_HOST_MZ700 0
|
|
||||||
#define TARGET_HOST_MZ2000 1
|
|
||||||
#define Z80_VIRTUAL_ROM_SIZE 16384 // Sized to maximum ROM which is the MZ-800 ROM.
|
|
||||||
#define Z80_VIRTUAL_RAM_SIZE (65536 * 8) // (PAGE_SIZE * 2) // max size mmaped to userspace
|
|
||||||
#define Z80_VIRTUAL_MEMORY_SIZE Z80_VIRTUAL_RAM_SIZE + Z80_VIRTUAL_ROM_SIZE
|
|
||||||
#define Z80_MEMORY_PAGE_SIZE 16
|
|
||||||
#define MAX_SCREEN_WIDTH 132
|
|
||||||
#define DEVICE_NAME "z80drv"
|
|
||||||
#define CLASS_NAME "mogu"
|
|
||||||
|
|
||||||
// Memory and IO page types. Used to create a memory page which maps type of address space to real address space on host or virtual memory.
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_MASK 0x00FFFFFF
|
|
||||||
#define MEMORY_TYPE_REAL_MASK 0x0000FFFF
|
|
||||||
#define IO_TYPE_MASK 0x0000FFFF
|
|
||||||
#define MEMORY_TYPE_INHIBIT 0x00000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_RAM 0x80000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_ROM 0x40000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_VRAM 0x20000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_HW 0x10000000
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_RAM 0x08000000
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_ROM 0x04000000
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_HW 0x02000000
|
|
||||||
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
|
||||||
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
|
||||||
|
|
||||||
|
|
||||||
// Approximate governor delays to regulate emulated CPU speed.
|
|
||||||
// MZ-700
|
|
||||||
#if(TARGET_HOST_MZ700 == 1)
|
|
||||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
|
||||||
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
|
||||||
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
|
||||||
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
|
||||||
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
|
||||||
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
|
||||||
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
|
||||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
|
||||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
|
||||||
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
|
||||||
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
|
||||||
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
|
||||||
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
|
||||||
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
|
||||||
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
|
||||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
|
||||||
#endif
|
|
||||||
// MZ-2000
|
|
||||||
#if(TARGET_HOST_MZ2000 == 1)
|
|
||||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 243
|
|
||||||
#define INSTRUCTION_DELAY_ROM_7MHZ 122
|
|
||||||
#define INSTRUCTION_DELAY_ROM_14MHZ 61
|
|
||||||
#define INSTRUCTION_DELAY_ROM_28MHZ 30
|
|
||||||
#define INSTRUCTION_DELAY_ROM_56MHZ 15
|
|
||||||
#define INSTRUCTION_DELAY_ROM_112MHZ 7
|
|
||||||
#define INSTRUCTION_DELAY_ROM_224MHZ 3
|
|
||||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
|
||||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 218
|
|
||||||
#define INSTRUCTION_DELAY_RAM_7MHZ 112
|
|
||||||
#define INSTRUCTION_DELAY_RAM_14MHZ 56
|
|
||||||
#define INSTRUCTION_DELAY_RAM_28MHZ 28
|
|
||||||
#define INSTRUCTION_DELAY_RAM_56MHZ 14
|
|
||||||
#define INSTRUCTION_DELAY_RAM_112MHZ 7
|
|
||||||
#define INSTRUCTION_DELAY_RAM_224MHZ 3
|
|
||||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
|
||||||
#define IOCTL_CMD_Z80_STOP 's'
|
|
||||||
#define IOCTL_CMD_Z80_START 'S'
|
|
||||||
#define IOCTL_CMD_Z80_PAUSE 'P'
|
|
||||||
#define IOCTL_CMD_Z80_RESET 'R'
|
|
||||||
#define IOCTL_CMD_Z80_CONTINUE 'C'
|
|
||||||
#define IOCTL_CMD_USE_HOST_RAM 'x'
|
|
||||||
#define IOCTL_CMD_USE_VIRTUAL_RAM 'X'
|
|
||||||
#define IOCTL_CMD_DUMP_MEMORY 'M'
|
|
||||||
#define IOCTL_CMD_Z80_CPU_FREQ 'F'
|
|
||||||
#define IOCTL_CMD_CPLD_CMD 'z'
|
|
||||||
#define IOCTL_CMD_SEND _IOW('c', 'c', int32_t *)
|
|
||||||
#define IOCTL_CMD_SETPC _IOW('p', 'p', int32_t *)
|
|
||||||
#define IOCTL_CMD_SYNC_TO_HOST_RAM 'V'
|
|
||||||
#define IOCTL_CMD_SPI_TEST '1'
|
|
||||||
#define IOCTL_CMD_PRL_TEST '2'
|
|
||||||
#define IOCTL_CMD_Z80_MEMTEST '3'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Chip Select map MZ80K-MZ700.
|
|
||||||
//
|
|
||||||
// 0000 - 0FFF = CS_ROMni : R/W : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
|
||||||
// 1000 - CFFF = CS_RAMni : R/W : MZ80K/A/700 = RAM
|
|
||||||
// C000 - CFFF = CS_ROMni : R/W : MZ80A = Monitor ROM (MZ80A rom swap)
|
|
||||||
// D000 - D7FF = CS_VRAMni : R/W : MZ80K/A/700 = VRAM
|
|
||||||
// D800 - DFFF = CS_VRAMni : R/W : MZ700 = Colour VRAM (MZ700)
|
|
||||||
// E000 - E003 = CS_8255n : R/W : MZ80K/A/700 = 8255
|
|
||||||
// E004 - E007 = CS_8254n : R/W : MZ80K/A/700 = 8254
|
|
||||||
// E008 - E00B = CS_LS367n : R/W : MZ80K/A/700 = LS367
|
|
||||||
// E00C - E00F = CS_ESWPn : R : MZ80A = Memory Swap (MZ80A)
|
|
||||||
// E010 - E013 = CS_ESWPn : R : MZ80A = Reset Memory Swap (MZ80A)
|
|
||||||
// E014 = CS_E5n : R/W : MZ80A/700 = Normal CRT display (in Video Controller)
|
|
||||||
// E015 = CS_E6n : R/W : MZ80A/700 = Reverse CRT display (in Video Controller)
|
|
||||||
// E200 - E2FF = : R/W : MZ80A/700 = VRAM roll up/roll down.
|
|
||||||
// E800 - EFFF = : R/W : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
|
||||||
// F000 - F7FF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
|
||||||
// F800 - FFFF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
|
||||||
//
|
|
||||||
// Chip Select map MZ800
|
|
||||||
//
|
|
||||||
// FC - FF = CS_PIOn : R/W : MZ800/MZ1500 = Z80 PIO Printer Interface
|
|
||||||
// F2 = CS_PSG0n : W : MZ800/MZ1500 = Programable Sound Generator, MZ-800 = Mono, MZ-1500 = Left Channel
|
|
||||||
// F3 = CS_PSG1n : W : MZ1500 = Programable Sound Generator, MZ-1500 = Right Channel
|
|
||||||
// E9 = CS_PSG(X)n: W : MZ1500 = Simultaneous write to both PSG's.
|
|
||||||
// F0 - F1 = CS_JOYSTK : R : MZ800 = Joystick 1 and 2
|
|
||||||
// CC = CS_GWF : W : MZ800 = CRTC GWF Write format Register
|
|
||||||
// CD = CS_GRF : W : MZ800 = CRTC GRF Read format Register
|
|
||||||
// CE = CS_GDMD : W : MZ800 = CRTC GDMD Mode Register
|
|
||||||
// CF = CS_GCRTC : W : MZ800 = CRTC GCRTC Control Register
|
|
||||||
// D4 - D7 = CS
|
|
||||||
// D000 - DFFF
|
|
||||||
|
|
||||||
// MZ700/MZ800 memory mode switch?
|
|
||||||
//
|
|
||||||
// MZ-700 MZ-800
|
|
||||||
// |0000:0FFF|1000:1FFF|1000:CFFF|C000:CFFF|D000:FFFF |0000:7FFF|1000:1FFF|2000:7FFF|8000:BFFF|C000:CFFF|C000:DFFF|E000:FFFF
|
|
||||||
// -------------------------------------------------- ----------------------------------------------------------------------
|
|
||||||
// OUT 0xE0 = |DRAM | | | | |DRAM | | | | | |
|
|
||||||
// OUT 0xE1 = | | | | |DRAM | | | | | | |DRAM
|
|
||||||
// OUT 0xE2 = |MONITOR | | | | |MONITOR | | | | | |
|
|
||||||
// OUT 0xE3 = | | | | |Memory Mapped I/O | | | | | | |Upper MONITOR ROM
|
|
||||||
// OUT 0xE4 = |MONITOR | |DRAM | |Memory Mapped I/O |MONITOR |CGROM |DRAM |VRAM | |DRAM |Upper MONITOR ROM
|
|
||||||
// OUT 0xE5 = | | | | |Inhibit | | | | | | |Inhibit
|
|
||||||
// OUT 0xE6 = | | | | |<return> | | | | | | |<return>
|
|
||||||
// IN 0xE0 = | |CGROM* | |VRAM* | | |CGROM | |VRAM | | |
|
|
||||||
// IN 0xE1 = | |DRAM | |DRAM | | |<return> | |DRAM | | |
|
|
||||||
//
|
|
||||||
// <return> = Return to the state prior to the complimentary command being invoked.
|
|
||||||
// * = MZ-800 host only.
|
|
||||||
|
|
||||||
// Macros to lookup and test to see if a given memory block or IO byte is of a given type. Also macros to read/write to the memory block and IO byte.
|
|
||||||
#define MEMORY_BLOCK_GRANULARITY 0x800
|
|
||||||
#define MEMORY_BLOCK_SLOTS (0x10000 / MEMORY_BLOCK_GRANULARITY)
|
|
||||||
#define MEMORY_BLOCK_MASK (0x10000 - MEMORY_BLOCK_GRANULARITY)
|
|
||||||
#define MEMORY_BLOCK_SHIFT 11
|
|
||||||
#define getPageData(a) (Z80Ctrl->page[(a & 0xF800) >> MEMORY_BLOCK_SHIFT])
|
|
||||||
#define getIOPageData(a) (Z80Ctrl->iopage[(a & 0xFFFF])
|
|
||||||
#define getPageType(a, mask) (getPageData(a) & mask)
|
|
||||||
#define getPageAddr(a, mask) ((getPageData(a) & mask) + (a & (MEMORY_BLOCK_GRANULARITY-1)))
|
|
||||||
#define getIOPageType(a, mask) (getIOPageData(a) & mask)
|
|
||||||
#define getIOPageAddr(a, mask) (getIOPageData(a) & mask)
|
|
||||||
#define realAddress(a) (Z80Ctrl->page[getPageAddr(a, MEMORY_TYPE_REAL_MASK)])
|
|
||||||
#define realPort(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_MASK)
|
|
||||||
#define isPhysicalRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_RAM))
|
|
||||||
#define isPhysicalVRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_VRAM))
|
|
||||||
#define isPhysicalROM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_ROM))
|
|
||||||
#define isPhysicalMemory(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM))])
|
|
||||||
#define isPhysicalHW(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_HW))
|
|
||||||
#define isPhysical(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM)))
|
|
||||||
#define isPhysicalIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_PHYSICAL_HW)
|
|
||||||
#define isVirtualRAM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_RAM))
|
|
||||||
#define isVirtualROM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_ROM))
|
|
||||||
#define isVirtualMemory(a) (getPageType(a, (MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_RAM)))
|
|
||||||
#define isVirtualHW(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_HW))
|
|
||||||
#define isVirtualIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_VIRTUAL_HW)
|
|
||||||
#define isHW(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_VIRTUAL_HW)))
|
|
||||||
#define readVirtualRAM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ])
|
|
||||||
#define readVirtualROM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) + Z80_VIRTUAL_RAM_SIZE ])
|
|
||||||
#define writeVirtualRAM(a, d) { Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ] = d; }
|
|
||||||
#define setMemoryType(_block_,_type_,_addr_) { Z80Ctrl->page[_block_] = _type_ | _addr_; }
|
|
||||||
#define backupMemoryType(_block_) { Z80Ctrl->shadowPage[_block_] = Z80Ctrl->page[_block_]; }
|
|
||||||
#define restoreMemoryType(_block_) { Z80Ctrl->page[_block_] = Z80Ctrl->shadowPage[_block_]; }
|
|
||||||
|
|
||||||
#define IO_ADDR_E0 0xE0
|
|
||||||
#define IO_ADDR_E1 0xE1
|
|
||||||
#define IO_ADDR_E2 0xE2
|
|
||||||
#define IO_ADDR_E3 0xE3
|
|
||||||
#define IO_ADDR_E4 0xE4
|
|
||||||
#define IO_ADDR_E5 0xE5
|
|
||||||
#define IO_ADDR_E6 0xE6
|
|
||||||
#define IO_ADDR_E7 0xE7
|
|
||||||
#define IO_ADDR_E8 0xE8
|
|
||||||
#define IO_ADDR_E9 0xE9
|
|
||||||
#define IO_ADDR_EA 0xEA
|
|
||||||
#define IO_ADDR_EB 0xEB
|
|
||||||
|
|
||||||
|
|
||||||
enum Z80_RUN_STATES {
|
|
||||||
Z80_STOP = 0x00,
|
|
||||||
Z80_STOPPED = 0x01,
|
|
||||||
Z80_PAUSE = 0x02,
|
|
||||||
Z80_PAUSED = 0x03,
|
|
||||||
Z80_CONTINUE = 0x04,
|
|
||||||
Z80_RUNNING = 0x05,
|
|
||||||
};
|
|
||||||
enum Z80_MEMORY_PROFILE {
|
|
||||||
USE_PHYSICAL_RAM = 0x00,
|
|
||||||
USE_VIRTUAL_RAM = 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// Main memory, linear but indexed as though it were banks in 1K pages.
|
|
||||||
uint8_t memory[Z80_VIRTUAL_MEMORY_SIZE];
|
|
||||||
|
|
||||||
// Page pointer map.
|
|
||||||
//
|
|
||||||
// Each pointer points to a byte or block of bytes in the Z80 Memory frame, 64K Real + Banked.
|
|
||||||
// This is currently set at a block of size 0x800 per memory pointer for the MZ-700.
|
|
||||||
// The LSB of the pointer is a direct memory index to a byte or block of bytes, the upper byte of the pointer indicates type of memory space.
|
|
||||||
// 0x80<FFFFFF> - physical host RAM
|
|
||||||
// 0x40<FFFFFF> - physical host ROM
|
|
||||||
// 0x20<FFFFFF> - physical host VRAM
|
|
||||||
// 0x10<FFFFFF> - physical host hardware
|
|
||||||
// 0x08<FFFFFF> - virtual host RAM
|
|
||||||
// 0x04<FFFFFF> - virtual host ROM
|
|
||||||
// 0x02<FFFFFF> - virtual host hardware
|
|
||||||
// 16bit Input Address -> map -> Pointer to 24bit memory address + type flag.
|
|
||||||
// -> Pointer+<low bits of address> to 24bit memory address + type flag.
|
|
||||||
uint32_t page[MEMORY_BLOCK_SLOTS];
|
|
||||||
uint32_t shadowPage[MEMORY_BLOCK_SLOTS];
|
|
||||||
|
|
||||||
// I/O Page map.
|
|
||||||
//
|
|
||||||
// This is a map to indicate the use of the I/O page and allow any required remapping.
|
|
||||||
// <0x80>FF<I/O Address> - physical host hardware
|
|
||||||
// <0x40>FF<I/O Address> - virtual host hardware
|
|
||||||
// 16bit Input Address -> map -> Actual 16bit address to use + type flag.
|
|
||||||
uint32_t iopage[65536];
|
|
||||||
|
|
||||||
// Default page mode configured. This value reflects the default page and iotable map.
|
|
||||||
uint8_t defaultPageMode;
|
|
||||||
|
|
||||||
// Refresh DRAM mode. 1 = Refresh, 0 = No refresh. Only applicable when running code in virtual Kernel RAM.
|
|
||||||
uint8_t refreshDRAM;
|
|
||||||
|
|
||||||
// Inhibit mode is where certain memory ranges are inhibitted. The memory page is set to inhibit and this flag
|
|
||||||
// blocks actions which arent allowed during inhibit.
|
|
||||||
uint8_t inhibitMode;
|
|
||||||
|
|
||||||
// Address caching. Used to minimise instruction length sent to CPLD.
|
|
||||||
uint16_t z80PrevAddr;
|
|
||||||
uint16_t z80PrevPort;
|
|
||||||
|
|
||||||
#if(TARGET_HOST_MZ2000 == 1)
|
|
||||||
uint8_t lowMemorySwap;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Keyboard strobe and data. Required to detect hotkey press.
|
|
||||||
uint8_t keyportStrobe;
|
|
||||||
uint8_t keyportShiftCtrl;
|
|
||||||
uint8_t keyportHotKey;
|
|
||||||
|
|
||||||
// Governor is the delay in a 32bit loop per Z80 opcode, used to govern execution speed when using virtual memory.
|
|
||||||
// This mechanism will eventually be tied into the M/T-state calculation for a more precise delay, but at the moment,
|
|
||||||
// with the Z80 assigned to an isolated CPU, it allows time sensitive tasks such as the tape recorder to work.
|
|
||||||
// The lower the value the faster the CPU speed. Two values are present as the optimiser, seeing ROM code not changing
|
|
||||||
// is quicker than RAM (both are in the same kernel memory) as a pointer calculation needs to be made.
|
|
||||||
uint32_t cpuGovernorDelayROM;
|
|
||||||
uint32_t cpuGovernorDelayRAM;
|
|
||||||
} t_Z80Ctrl;
|
|
||||||
|
|
||||||
// IOCTL structure for passing data from user space to driver to perform commands.
|
|
||||||
//
|
|
||||||
struct z80_addr {
|
|
||||||
uint32_t start;
|
|
||||||
uint32_t end;
|
|
||||||
uint32_t size;
|
|
||||||
};
|
|
||||||
struct z80_ctrl {
|
|
||||||
uint16_t pc;
|
|
||||||
};
|
|
||||||
struct speed {
|
|
||||||
uint32_t speedMultiplier;
|
|
||||||
};
|
|
||||||
struct cpld_ctrl {
|
|
||||||
uint32_t cmd;
|
|
||||||
};
|
|
||||||
struct ioctlCmd {
|
|
||||||
int32_t cmd;
|
|
||||||
union {
|
|
||||||
struct z80_addr addr;
|
|
||||||
struct z80_ctrl z80;
|
|
||||||
struct speed speed;
|
|
||||||
struct cpld_ctrl cpld;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Prototypes.
|
|
||||||
void setupMemory(enum Z80_MEMORY_PROFILE mode);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,428 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80io.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 IO Interface
|
|
||||||
// This file contains the methods used in interfacing the SOM to the Z80 socket
|
|
||||||
// and host hardware via a CPLD.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//#include <stdio.h>
|
|
||||||
//#include <stdlib.h>
|
|
||||||
//#include <string.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <asm/uaccess.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/time.h>
|
|
||||||
#include "z80io.h"
|
|
||||||
|
|
||||||
#include <gpio_table.h>
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include <infinity2m/gpio.h>
|
|
||||||
#include <infinity2m/registers.h>
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// User space driver access.
|
|
||||||
//
|
|
||||||
//-------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Initialise the SOM hardware used to communicate with the z80 socket and host hardware.
|
|
||||||
// The SOM interfaces to a CPLD which provides voltage level translation and also encapsulates the Z80 timing cycles as recreating
|
|
||||||
// them within the SOM is much more tricky.
|
|
||||||
//
|
|
||||||
// As this is an embedded device and performance/latency are priorities, minimal structured code is used to keep call stack and
|
|
||||||
// generated code to a mimimum without relying on the optimiser.
|
|
||||||
int z80io_init(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
// Initialise GPIO. We call the HAL api to minimise time but for actual bit set/reset and read we go directly to registers to save time, increase throughput and minimise latency.
|
|
||||||
// Initialise the HAL.
|
|
||||||
MHal_GPIO_Init();
|
|
||||||
|
|
||||||
// Set the pads as GPIO devices. The HAL takes care of allocating and deallocating the padmux resources.
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_0); // Word (16bit) bidirectional bus. Default is read with data set.
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_HIGH_BYTE);
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO8); // SPIO 4wire control lines setup by the spidev driver but controlled directly in this driver.
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO9);
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO10);
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO11);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_READY);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_LTSTATE);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSRQ);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSACK);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_INT);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_NMI);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WAIT);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RESET);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RSV1);
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_0);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WRITE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set required input pads.
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_0);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_READY);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_LTSTATE);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSRQ);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSACK);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_INT);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_NMI);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_WAIT);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RESET);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RSV1);
|
|
||||||
|
|
||||||
// Set required output pads.
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_0);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_WRITE);
|
|
||||||
MHal_GPIO_Pull_High(PAD_Z80IO_WRITE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Control signals.
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_HIGH_BYTE);
|
|
||||||
MHal_GPIO_Pull_High(PAD_Z80IO_HIGH_BYTE);
|
|
||||||
|
|
||||||
// Setup the MSPI0 device.
|
|
||||||
//
|
|
||||||
// Setup control, interrupts are not used.
|
|
||||||
MSPI_WRITE(MSPI_CTRL_OFFSET, MSPI_CPU_CLOCK_1_2 | MSPI_CTRL_CPOL_LOW | MSPI_CTRL_CPHA_HIGH | MSPI_CTRL_RESET | MSPI_CTRL_ENABLE_SPI);
|
|
||||||
|
|
||||||
// Setup LSB First mode.
|
|
||||||
MSPI_WRITE(MSPI_LSB_FIRST_OFFSET, 0x0);
|
|
||||||
|
|
||||||
// Setup clock.
|
|
||||||
CLK_WRITE(MSPI0_CLK_CFG, 0x1100)
|
|
||||||
|
|
||||||
// Setup the frame size (all buffers to 8bits).
|
|
||||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET, 0xfff);
|
|
||||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET+1, 0xfff);
|
|
||||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET, 0xfff);
|
|
||||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET+1, 0xfff);
|
|
||||||
|
|
||||||
// Setup Chip Selects to inactive.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Switch Video and Audio to host.
|
|
||||||
z80io_SPI_Send16(0x00f0, NULL);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Parallel bus Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
|
|
||||||
// Methods to read data from the parallel bus.
|
|
||||||
// The CPLD returns status and Z80 data on the 8bit bus as it is marginally quicker than retrieving it over the SPI bus.
|
|
||||||
//
|
|
||||||
inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint8_t result = 0;
|
|
||||||
|
|
||||||
// Byte according to flag.
|
|
||||||
if(dataFlag)
|
|
||||||
SET_CPLD_READ_DATA()
|
|
||||||
else
|
|
||||||
SET_CPLD_READ_STATUS()
|
|
||||||
|
|
||||||
// Read the input registers and set value accordingly.
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
|
|
||||||
// Return 16bit value read from CPLD.
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16_t z80io_PRL_Read16(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint16_t result = 0;
|
|
||||||
|
|
||||||
// Low byte first.
|
|
||||||
CLEAR_CPLD_HIGH_BYTE();
|
|
||||||
|
|
||||||
// Read the input registers and set value accordingly.
|
|
||||||
result = (uint16_t)READ_CPLD_DATA_IN();
|
|
||||||
|
|
||||||
// High byte next.
|
|
||||||
SET_CPLD_HIGH_BYTE();
|
|
||||||
|
|
||||||
// Read the input registers and set value accordingly.
|
|
||||||
result |= (uint16_t)(READ_CPLD_DATA_IN() << 8);
|
|
||||||
|
|
||||||
// Return 16bit value read from CPLD.
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Parallel Bus methods were tried and tested but due to the GPIO bits being controlled by individual registers per bit, the setup time was longer
|
|
||||||
// than the transmission time of SPI. These methods are thus deprecated and a fusion of SPI and 8bit parallel is now used.
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
inline uint8_t z80io_PRL_Send8(uint8_t txData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Low byte only.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
|
||||||
|
|
||||||
// Setup data.
|
|
||||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
|
||||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
|
||||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
|
||||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
|
||||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
|
||||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
|
||||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
|
||||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
|
||||||
|
|
||||||
// Clock data.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t z80io_PRL_Send16(uint16_t txData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Low byte first.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
|
||||||
|
|
||||||
// Setup data.
|
|
||||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
|
||||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
|
||||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
|
||||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
|
||||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
|
||||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
|
||||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
|
||||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
|
||||||
|
|
||||||
// Clock data.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
|
||||||
|
|
||||||
// High byte next.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
|
||||||
|
|
||||||
// Setup high byte.
|
|
||||||
if(txData & 0x8000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
|
||||||
if(txData & 0x4000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
|
||||||
if(txData & 0x2000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
|
||||||
if(txData & 0x1000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
|
||||||
if(txData & 0x0800) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
|
||||||
if(txData & 0x0400) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
|
||||||
if(txData & 0x0200) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
|
||||||
if(txData & 0x0100) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
|
||||||
|
|
||||||
// Clock data.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// SPI Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
|
|
||||||
// Methods to send 8,16 or 32 bits. Each method is seperate to minimise logic and execution time, 8bit being most sensitive.
|
|
||||||
// Macros have also been defined for inline inclusion which dont read back the response data.
|
|
||||||
//
|
|
||||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint32_t timeout = MAX_CHECK_CNT;
|
|
||||||
|
|
||||||
// Insert data into write buffers.
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1);
|
|
||||||
|
|
||||||
// Enable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
|
||||||
|
|
||||||
// Send.
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
|
||||||
|
|
||||||
// Wait for completion.
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
|
||||||
{
|
|
||||||
if(--timeout == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Clear flag.
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
|
||||||
|
|
||||||
// Fetch data.
|
|
||||||
if(rxData != NULL) *rxData = (uint8_t)MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
|
||||||
|
|
||||||
// Done.
|
|
||||||
return(timeout == 0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint32_t timeout = MAX_CHECK_CNT;
|
|
||||||
|
|
||||||
// Insert data into write buffers.
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, txData);
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2);
|
|
||||||
|
|
||||||
// Enable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
|
||||||
|
|
||||||
// Send.
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
|
||||||
|
|
||||||
// Wait for completion.
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
|
||||||
{
|
|
||||||
if(--timeout == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Clear flag.
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
|
||||||
|
|
||||||
// Fetch data.
|
|
||||||
if(rxData != NULL) *rxData = MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
|
||||||
|
|
||||||
// Done.
|
|
||||||
return(timeout == 0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint32_t timeout = MAX_CHECK_CNT;
|
|
||||||
|
|
||||||
// Insert data into write buffers.
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)(txData >> 16));
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4);
|
|
||||||
|
|
||||||
// Enable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
|
||||||
|
|
||||||
// Send.
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
|
||||||
|
|
||||||
// Wait for completion.
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
|
||||||
{
|
|
||||||
if(--timeout == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Clear flag.
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
|
||||||
|
|
||||||
// Fetch data.
|
|
||||||
if(rxData != NULL) *rxData = (uint32_t)(MSPI_READ(MSPI_FULL_DEPLUX_RD00) | (MSPI_READ(MSPI_FULL_DEPLUX_RD02) << 16));
|
|
||||||
|
|
||||||
// Done.
|
|
||||||
return(timeout == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Test Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
#ifdef INCLUDE_TEST_METHODS
|
|
||||||
#include "z80io_test.c"
|
|
||||||
#else
|
|
||||||
uint8_t z80io_Z80_TestMemory(void)
|
|
||||||
{
|
|
||||||
pr_info("Z80 Test Memory functionality not built-in.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_SPI_Test(void)
|
|
||||||
{
|
|
||||||
pr_info("SPI Test functionality not built-in.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_PRL_Test(void)
|
|
||||||
{
|
|
||||||
pr_info("Parallel Bus Test functionality not built-in.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
483
software/FusionX/src/z80drv/MZ2000/z80io.h
vendored
483
software/FusionX/src/z80drv/MZ2000/z80io.h
vendored
@@ -1,483 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80io.h
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 IO Interface
|
|
||||||
// This file contains the declarations used in interfacing the SOM to the Z80 socket
|
|
||||||
// and host hardware via a CPLD.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifndef Z80IO_H
|
|
||||||
#define Z80IO_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Definitions to control compilation.
|
|
||||||
#define INCLUDE_TEST_METHODS 1
|
|
||||||
|
|
||||||
// CPLD Commands.
|
|
||||||
#define CPLD_CMD_FETCH_ADDR 0x10
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P1 0x11
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P2 0x12
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P3 0x13
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P4 0x14
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P5 0x15
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P6 0x16
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P7 0x17
|
|
||||||
#define CPLD_CMD_WRITE_ADDR 0x18
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P1 0x19
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P2 0x1A
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P3 0x1B
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P4 0x1C
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P5 0x1D
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P6 0x1E
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P7 0x1F
|
|
||||||
#define CPLD_CMD_READ_ADDR 0x20
|
|
||||||
#define CPLD_CMD_READ_ADDR_P1 0x21
|
|
||||||
#define CPLD_CMD_READ_ADDR_P2 0x22
|
|
||||||
#define CPLD_CMD_READ_ADDR_P3 0x23
|
|
||||||
#define CPLD_CMD_READ_ADDR_P4 0x24
|
|
||||||
#define CPLD_CMD_READ_ADDR_P5 0x25
|
|
||||||
#define CPLD_CMD_READ_ADDR_P6 0x26
|
|
||||||
#define CPLD_CMD_READ_ADDR_P7 0x27
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR 0x28
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P1 0x29
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P2 0x2A
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P3 0x2B
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P4 0x2C
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P5 0x2D
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P6 0x2E
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P7 0x2F
|
|
||||||
#define CPLD_CMD_READIO_ADDR 0x30
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P1 0x31
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P2 0x32
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P3 0x33
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P4 0x34
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
|
||||||
#define CPLD_CMD_HALT 0x50
|
|
||||||
#define CPLD_CMD_REFRESH 0x51
|
|
||||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
|
||||||
#define CPLD_CMD_SET_AUTO_REFRESH 0xF1
|
|
||||||
#define CPLD_CMD_CLEAR_AUTO_REFRESH 0xF2
|
|
||||||
#define CPLD_CMD_SET_SPI_LOOPBACK 0xFE
|
|
||||||
#define CPLD_CMD_NOP1 0x00
|
|
||||||
#define CPLD_CMD_NOP2 0xFF
|
|
||||||
|
|
||||||
|
|
||||||
// Pad numbers for using the MHal GPIO library.
|
|
||||||
#define PAD_Z80IO_IN_DATA_0 PAD_GPIO0
|
|
||||||
#define PAD_Z80IO_IN_DATA_1 PAD_GPIO1
|
|
||||||
#define PAD_Z80IO_IN_DATA_2 PAD_GPIO2
|
|
||||||
#define PAD_Z80IO_IN_DATA_3 PAD_GPIO3
|
|
||||||
#define PAD_Z80IO_IN_DATA_4 PAD_GPIO4
|
|
||||||
#define PAD_Z80IO_IN_DATA_5 PAD_GPIO5
|
|
||||||
#define PAD_Z80IO_IN_DATA_6 PAD_GPIO6
|
|
||||||
#define PAD_Z80IO_IN_DATA_7 PAD_GPIO7
|
|
||||||
#define PAD_SPIO_0 PAD_GPIO8
|
|
||||||
#define PAD_SPIO_1 PAD_GPIO9
|
|
||||||
#define PAD_SPIO_2 PAD_GPIO10
|
|
||||||
#define PAD_SPIO_3 PAD_GPIO11
|
|
||||||
#define PAD_Z80IO_HIGH_BYTE PAD_SAR_GPIO2 // Byte requiured, 0 = Low Byte, 1 = High Byte.
|
|
||||||
#define PAD_Z80IO_READY PAD_GPIO12
|
|
||||||
#define PAD_Z80IO_LTSTATE PAD_PM_IRIN // IRIN
|
|
||||||
#define PAD_Z80IO_BUSRQ PAD_GPIO13
|
|
||||||
#define PAD_Z80IO_BUSACK PAD_GPIO14
|
|
||||||
#define PAD_Z80IO_INT PAD_UART0_RX // GPIO47
|
|
||||||
#define PAD_Z80IO_NMI PAD_UART0_TX // GPIO48
|
|
||||||
#define PAD_Z80IO_WAIT PAD_HSYNC_OUT // GPIO85
|
|
||||||
#define PAD_Z80IO_RESET PAD_VSYNC_OUT // GPIO86
|
|
||||||
#define PAD_Z80IO_RSV1 PAD_SATA_GPIO // GPIO90
|
|
||||||
|
|
||||||
// Physical register addresses.
|
|
||||||
#define PAD_Z80IO_IN_DATA_0_ADDR 0x103C00
|
|
||||||
#define PAD_Z80IO_IN_DATA_1_ADDR 0x103C02
|
|
||||||
#define PAD_Z80IO_IN_DATA_2_ADDR 0x103C04
|
|
||||||
#define PAD_Z80IO_IN_DATA_3_ADDR 0x103C06
|
|
||||||
#define PAD_Z80IO_IN_DATA_4_ADDR 0x103C08
|
|
||||||
#define PAD_Z80IO_IN_DATA_5_ADDR 0x103C0A
|
|
||||||
#define PAD_Z80IO_IN_DATA_6_ADDR 0x103C0C
|
|
||||||
#define PAD_Z80IO_IN_DATA_7_ADDR 0x103C0E
|
|
||||||
#define PAD_SPIO_0_ADDR 0x103C10
|
|
||||||
#define PAD_SPIO_1_ADDR 0x103C12
|
|
||||||
#define PAD_SPIO_2_ADDR 0x103C14
|
|
||||||
#define PAD_SPIO_3_ADDR 0x103C16
|
|
||||||
#define PAD_Z80IO_HIGH_BYTE_ADDR 0x1425
|
|
||||||
#define PAD_Z80IO_READY_ADDR 0x103C18
|
|
||||||
#define PAD_Z80IO_LTSTATE_ADDR 0xF28 // IRIN
|
|
||||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
|
||||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
|
||||||
#define PAD_Z80IO_INT_ADDR 0x103C30 // GPIO47
|
|
||||||
#define PAD_Z80IO_NMI_ADDR 0x103C32 // GPIO48
|
|
||||||
#define PAD_Z80IO_WAIT_ADDR 0x103C80 // GPIO85
|
|
||||||
#define PAD_Z80IO_RESET_ADDR 0x103C82 // GPIO86
|
|
||||||
#define PAD_Z80IO_RSV1_ADDR 0x103C8A // GPIO90
|
|
||||||
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
#define PAD_Z80IO_OUT_DATA_0 PAD_GPIO12
|
|
||||||
#define PAD_Z80IO_OUT_DATA_1 PAD_GPIO13
|
|
||||||
#define PAD_Z80IO_OUT_DATA_2 PAD_GPIO14
|
|
||||||
#define PAD_Z80IO_OUT_DATA_3 PAD_UART0_RX // GPIO47
|
|
||||||
#define PAD_Z80IO_OUT_DATA_4 PAD_UART0_TX // GPIO48
|
|
||||||
#define PAD_Z80IO_OUT_DATA_5 PAD_HSYNC_OUT // GPIO85
|
|
||||||
#define PAD_Z80IO_OUT_DATA_6 PAD_VSYNC_OUT // GPIO86
|
|
||||||
#define PAD_Z80IO_OUT_DATA_7 PAD_SATA_GPIO // GPIO90
|
|
||||||
#define PAD_Z80IO_WRITE PAD_PM_IRIN // Write data clock.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
// The definitions below come from SigmaStar kernel drivers. No header file exists hence the
|
|
||||||
// duplication.
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#define SUPPORT_SPI_1 0
|
|
||||||
#define MAX_SUPPORT_BITS 16
|
|
||||||
|
|
||||||
#define BANK_TO_ADDR32(b) (b<<9)
|
|
||||||
#define BANK_SIZE 0x200
|
|
||||||
|
|
||||||
#define MS_BASE_REG_RIU_PA 0x1F000000
|
|
||||||
#define gChipBaseAddr 0xFD203C00
|
|
||||||
#define gPmSleepBaseAddr 0xFD001C00
|
|
||||||
#define gSarBaseAddr 0xFD002800
|
|
||||||
#define gRIUBaseAddr 0xFD000000
|
|
||||||
#define gMOVDMAAddr 0xFD201600
|
|
||||||
#define gClkBaseAddr 0xFD207000
|
|
||||||
#define gMspBaseAddr 0xfd222000
|
|
||||||
|
|
||||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
|
|
||||||
|
|
||||||
#define MSPI0_BANK_ADDR 0x1110
|
|
||||||
#define MSPI1_BANK_ADDR 0x1111
|
|
||||||
#define CLK__BANK_ADDR 0x1038
|
|
||||||
#define CHIPTOP_BANK_ADDR 0x101E
|
|
||||||
#define MOVDMA_BANK_ADDR 0x100B
|
|
||||||
|
|
||||||
#define BASE_REG_MSPI0_ADDR MSPI0_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111000)
|
|
||||||
#define BASE_REG_MSPI1_ADDR MSPI1_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111100)
|
|
||||||
#define BASE_REG_CLK_ADDR CLK__BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x103800)
|
|
||||||
#define BASE_REG_CHIPTOP_ADDR CHIPTOP_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x101E00)
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
// Hardware Register Capability
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
#define MSPI_WRITE_BUF_OFFSET 0x40
|
|
||||||
#define MSPI_READ_BUF_OFFSET 0x44
|
|
||||||
#define MSPI_WBF_SIZE_OFFSET 0x48
|
|
||||||
#define MSPI_RBF_SIZE_OFFSET 0x48
|
|
||||||
// read/ write buffer size
|
|
||||||
#define MSPI_RWSIZE_MASK 0xFF
|
|
||||||
#define MSPI_RSIZE_BIT_OFFSET 0x8
|
|
||||||
#define MAX_READ_BUF_SIZE 0x8
|
|
||||||
#define MAX_WRITE_BUF_SIZE 0x8
|
|
||||||
// CLK config
|
|
||||||
#define MSPI_CTRL_OFFSET 0x49
|
|
||||||
#define MSPI_CLK_CLOCK_OFFSET 0x49
|
|
||||||
#define MSPI_CLK_CLOCK_BIT_OFFSET 0x08
|
|
||||||
#define MSPI_CLK_CLOCK_MASK 0xFF
|
|
||||||
#define MSPI_CLK_PHASE_MASK 0x40
|
|
||||||
#define MSPI_CLK_PHASE_BIT_OFFSET 0x06
|
|
||||||
#define MSPI_CLK_POLARITY_MASK 0x80
|
|
||||||
#define MSPI_CLK_POLARITY_BIT_OFFSET 0x07
|
|
||||||
#define MSPI_CLK_PHASE_MAX 0x1
|
|
||||||
#define MSPI_CLK_POLARITY_MAX 0x1
|
|
||||||
#define MSPI_CLK_CLOCK_MAX 0x7
|
|
||||||
#define MSPI_CTRL_CPOL_LOW 0x00
|
|
||||||
#define MSPI_CTRL_CPOL_HIGH 0x80
|
|
||||||
#define MSPI_CTRL_CPHA_LOW 0x00
|
|
||||||
#define MSPI_CTRL_CPHA_HIGH 0x40
|
|
||||||
#define MSPI_CTRL_3WIRE 0x10
|
|
||||||
#define MSPI_CTRL_INTEN 0x04
|
|
||||||
#define MSPI_CTRL_RESET 0x02
|
|
||||||
#define MSPI_CTRL_ENABLE_SPI 0x01
|
|
||||||
// DC config
|
|
||||||
#define MSPI_DC_MASK 0xFF
|
|
||||||
#define MSPI_DC_BIT_OFFSET 0x08
|
|
||||||
#define MSPI_DC_TR_START_OFFSET 0x4A
|
|
||||||
#define MSPI_DC_TRSTART_MAX 0xFF
|
|
||||||
#define MSPI_DC_TR_END_OFFSET 0x4A
|
|
||||||
#define MSPI_DC_TREND_MAX 0xFF
|
|
||||||
#define MSPI_DC_TB_OFFSET 0x4B
|
|
||||||
#define MSPI_DC_TB_MAX 0xFF
|
|
||||||
#define MSPI_DC_TRW_OFFSET 0x4B
|
|
||||||
#define MSPI_DC_TRW_MAX 0xFF
|
|
||||||
// Frame Config
|
|
||||||
#define MSPI_FRAME_WBIT_OFFSET 0x4C
|
|
||||||
#define MSPI_FRAME_RBIT_OFFSET 0x4E
|
|
||||||
#define MSPI_FRAME_BIT_MAX 0x07
|
|
||||||
#define MSPI_FRAME_BIT_MASK 0x07
|
|
||||||
#define MSPI_FRAME_BIT_FIELD 0x03
|
|
||||||
#define MSPI_LSB_FIRST_OFFSET 0x50
|
|
||||||
#define MSPI_TRIGGER_OFFSET 0x5A
|
|
||||||
#define MSPI_DONE_OFFSET 0x5B
|
|
||||||
#define MSPI_DONE_CLEAR_OFFSET 0x5C
|
|
||||||
#define MSPI_CHIP_SELECT_OFFSET 0x5F
|
|
||||||
#define MSPI_CS1_DISABLE 0x01
|
|
||||||
#define MSPI_CS1_ENABLE 0x00
|
|
||||||
#define MSPI_CS2_DISABLE 0x02
|
|
||||||
#define MSPI_CS2_ENABLE 0x00
|
|
||||||
#define MSPI_CS3_DISABLE 0x04
|
|
||||||
#define MSPI_CS3_ENABLE 0x00
|
|
||||||
#define MSPI_CS4_DISABLE 0x08
|
|
||||||
#define MSPI_CS4_ENABLE 0x00
|
|
||||||
#define MSPI_CS5_DISABLE 0x10
|
|
||||||
#define MSPI_CS5_ENABLE 0x00
|
|
||||||
#define MSPI_CS6_DISABLE 0x20
|
|
||||||
#define MSPI_CS6_ENABLE 0x00
|
|
||||||
#define MSPI_CS7_DISABLE 0x40
|
|
||||||
#define MSPI_CS7_ENABLE 0x00
|
|
||||||
#define MSPI_CS8_DISABLE 0x80
|
|
||||||
#define MSPI_CS8_ENABLE 0x00
|
|
||||||
|
|
||||||
#define MSPI_FULL_DEPLUX_RD_CNT (0x77)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD00 (0x78)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD01 (0x78)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD02 (0x79)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD03 (0x79)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD04 (0x7a)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD05 (0x7a)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD06 (0x7b)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD07 (0x7b)
|
|
||||||
|
|
||||||
#define MSPI_FULL_DEPLUX_RD08 (0x7c)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD09 (0x7c)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD10 (0x7d)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD11 (0x7d)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD12 (0x7e)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD13 (0x7e)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD14 (0x7f)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD15 (0x7f)
|
|
||||||
|
|
||||||
//chip select bit map
|
|
||||||
#define MSPI_CHIP_SELECT_MAX 0x07
|
|
||||||
|
|
||||||
// control bit
|
|
||||||
#define MSPI_DONE_FLAG 0x01
|
|
||||||
#define MSPI_TRIGGER 0x01
|
|
||||||
#define MSPI_CLEAR_DONE 0x01
|
|
||||||
#define MSPI_INT_ENABLE 0x04
|
|
||||||
#define MSPI_RESET 0x02
|
|
||||||
#define MSPI_ENABLE 0x01
|
|
||||||
|
|
||||||
// clk_mspi0
|
|
||||||
#define MSPI0_CLK_CFG 0x33 //bit 2 ~bit 3
|
|
||||||
#define MSPI0_CLK_108M 0x00
|
|
||||||
#define MSPI0_CLK_54M 0x04
|
|
||||||
#define MSPI0_CLK_12M 0x08
|
|
||||||
#define MSPI0_CLK_MASK 0x0F
|
|
||||||
|
|
||||||
// clk_mspi1
|
|
||||||
#define MSPI1_CLK_CFG 0x33 //bit 10 ~bit 11
|
|
||||||
#define MSPI1_CLK_108M 0x0000
|
|
||||||
#define MSPI1_CLK_54M 0x0400
|
|
||||||
#define MSPI1_CLK_12M 0x0800
|
|
||||||
#define MSPI1_CLK_MASK 0x0F00
|
|
||||||
|
|
||||||
// clk_mspi
|
|
||||||
#define MSPI_CLK_CFG 0x33
|
|
||||||
#define MSPI_SELECT_0 0x0000
|
|
||||||
#define MSPI_SELECT_1 0x4000
|
|
||||||
#define MSPI_CLK_MASK 0xF000
|
|
||||||
|
|
||||||
// Clock settings
|
|
||||||
#define MSPI_CPU_CLOCK_1_2 0x0000
|
|
||||||
#define MSPI_CPU_CLOCK_1_4 0x0100
|
|
||||||
#define MSPI_CPU_CLOCK_1_8 0x0200
|
|
||||||
#define MSPI_CPU_CLOCK_1_16 0x0300
|
|
||||||
#define MSPI_CPU_CLOCK_1_32 0x0400
|
|
||||||
#define MSPI_CPU_CLOCK_1_64 0x0500
|
|
||||||
#define MSPI_CPU_CLOCK_1_128 0x0600
|
|
||||||
#define MSPI_CPU_CLOCK_1_256 0x0700
|
|
||||||
|
|
||||||
//CHITOP 101E mspi mode select
|
|
||||||
#define MSPI0_MODE 0x0C //bit0~bit1
|
|
||||||
#define MSPI0_MODE_MASK 0x07
|
|
||||||
#define MSPI1_MODE 0x0C //bit4~bit5
|
|
||||||
#define MSPI1_MODE_MASK 0x70
|
|
||||||
#define EJTAG_MODE 0xF
|
|
||||||
#define EJTAG_MODE_1 0x01
|
|
||||||
#define EJTAG_MODE_2 0x02
|
|
||||||
#define EJTAG_MODE_3 0x03
|
|
||||||
#define EJTAG_MODE_MASK 0x03
|
|
||||||
|
|
||||||
//MOVDMA 100B
|
|
||||||
#define MOV_DMA_SRC_ADDR_L 0x03
|
|
||||||
#define MOV_DMA_SRC_ADDR_H 0x04
|
|
||||||
#define MOV_DMA_DST_ADDR_L 0x05
|
|
||||||
#define MOV_DMA_DST_ADDR_H 0x06
|
|
||||||
#define MOV_DMA_BYTE_CNT_L 0x07
|
|
||||||
#define MOV_DMA_BYTE_CNT_H 0x08
|
|
||||||
#define DMA_MOVE0_IRQ_CLR 0x28
|
|
||||||
#define MOV_DMA_IRQ_FINAL_STATUS 0x2A
|
|
||||||
#define DMA_MOVE0_ENABLE 0x00
|
|
||||||
#define DMA_RW 0x50 //0 for dma write to device, 1 for dma read from device
|
|
||||||
#define DMA_READ 0x01
|
|
||||||
#define DMA_WRITE 0x00
|
|
||||||
#define DMA_DEVICE_MODE 0x51
|
|
||||||
#define DMA_DEVICE_SEL 0x52
|
|
||||||
|
|
||||||
//spi dma
|
|
||||||
#define MSPI_DMA_DATA_LENGTH_L 0x30
|
|
||||||
#define MSPI_DMA_DATA_LENGTH_H 0x31
|
|
||||||
#define MSPI_DMA_ENABLE 0x32
|
|
||||||
#define MSPI_DMA_RW_MODE 0x33
|
|
||||||
#define MSPI_DMA_WRITE 0x00
|
|
||||||
#define MSPI_DMA_READ 0x01
|
|
||||||
|
|
||||||
#define MSTAR_SPI_TIMEOUT_MS 30000
|
|
||||||
#define MSTAR_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA /*| SPI_CS_HIGH | SPI_NO_CS | SPI_LSB_FIRST*/)
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
// Macros
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define READ_BYTE(_reg) (*(volatile u8*)(_reg))
|
|
||||||
#define READ_WORD(_reg) (*(volatile u16*)(_reg))
|
|
||||||
#define READ_LONG(_reg) (*(volatile u32*)(_reg))
|
|
||||||
#define WRITE_BYTE(_reg, _val) {(*((volatile u8*)(_reg))) = (u8)(_val); }
|
|
||||||
#define WRITE_WORD(_reg, _val) {(*((volatile u16*)(_reg))) = (u16)(_val); }
|
|
||||||
#define WRITE_LONG(_reg, _val) {(*((volatile u32*)(_reg))) = (u32)(_val); }
|
|
||||||
#define WRITE_WORD_MASK(_reg, _val, _mask) {(*((volatile u16*)(_reg))) = ((*((volatile u16*)(_reg))) & ~(_mask)) | ((u16)(_val) & (_mask)); }
|
|
||||||
#define READ_CPLD_DATA_IN() ((MHal_RIU_REG(PAD_Z80IO_IN_DATA_7_ADDR) & 0x1) << 7 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_6_ADDR) & 0x1) << 6 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_5_ADDR) & 0x1) << 5 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_4_ADDR) & 0x1) << 4 |\
|
|
||||||
(MHal_RIU_REG(PAD_Z80IO_IN_DATA_3_ADDR) & 0x1) << 3 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_2_ADDR) & 0x1) << 2 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_1_ADDR) & 0x1) << 1 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_0_ADDR) & 0x1))
|
|
||||||
#define SET_CPLD_READ_DATA() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
|
||||||
#define SET_CPLD_READ_STATUS() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
|
||||||
#define SET_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
|
||||||
#define CLEAR_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
|
||||||
#define CPLD_READY() (MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1)
|
|
||||||
#define CPLD_RESET() (MHal_RIU_REG(PAD_Z80IO_RESET_ADDR) & 0x1)
|
|
||||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
|
||||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
|
||||||
}
|
|
||||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
|
||||||
}
|
|
||||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
|
||||||
}
|
|
||||||
|
|
||||||
// read 2 byte
|
|
||||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
|
||||||
// write 2 byte
|
|
||||||
//#define MSPI_WRITE(_reg_, _val_) {pr_info("PDS: MSPI_WRITE(0x%x, 0x%x, 0x%x)\n", _reg_, _val_, gMspBaseAddr + ((_reg_)<<2)); WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define MSPI_WRITE(_reg_, _val_) WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_));
|
|
||||||
//write 2 byte mask
|
|
||||||
//#define MSPI_WRITE_MASK(_reg_, _val_, mask) {pr_info("PDS: WRITE_LONG(0x%x, 0x%x, mask=0x%x)\n", _reg_, _val_, mask); WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask)); }
|
|
||||||
#define MSPI_WRITE_MASK(_reg_, _val_, mask) WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask));
|
|
||||||
|
|
||||||
#define CLK_READ(_reg_) READ_WORD(gClkBaseAddr + ((_reg_)<<2))
|
|
||||||
//#define CLK_WRITE(_reg_, _val_) {pr_info("PDS: CLK_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define CLK_WRITE(_reg_, _val_) WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_));
|
|
||||||
|
|
||||||
#define CHIPTOP_READ(_reg_) READ_WORD(gChipBaseAddr + ((_reg_)<<2))
|
|
||||||
//#define CHIPTOP_WRITE(_reg_, _val_) {pr_info("PDS: CHIPTOP_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define CHIPTOP_WRITE(_reg_, _val_) WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_));
|
|
||||||
|
|
||||||
#define MOVDMA_READ(_reg_) READ_WORD(gMOVDMAAddr + ((_reg_)<<2))
|
|
||||||
//#define MOVDMA_WRITE(_reg_, _val_) {pr_info("PDS: MOVDMA_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define MOVDMA_WRITE(_reg_, _val_) WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_));
|
|
||||||
|
|
||||||
#define _HAL_MSPI_ClearDone() MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET,MSPI_CLEAR_DONE)
|
|
||||||
#define MAX_CHECK_CNT 2000
|
|
||||||
|
|
||||||
#define MSPI_READ_INDEX 0x0
|
|
||||||
#define MSPI_WRITE_INDEX 0x1
|
|
||||||
|
|
||||||
#define SPI_MIU0_BUS_BASE 0x20000000
|
|
||||||
#define SPI_MIU1_BUS_BASE 0xFFFFFFFF
|
|
||||||
|
|
||||||
|
|
||||||
// Function definitions.
|
|
||||||
//
|
|
||||||
int z80io_init(void);
|
|
||||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData);
|
|
||||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData);
|
|
||||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData);
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
uint8_t z80io_PRL_Send8(uint8_t txData);
|
|
||||||
uint8_t z680io_PRL_Send16(uint16_t txData);
|
|
||||||
#endif
|
|
||||||
uint8_t z80io_PRL_Read8(uint8_t dataFlag);
|
|
||||||
uint16_t z80io_PRL_Read16(void);
|
|
||||||
uint8_t z80io_SPI_Test(void);
|
|
||||||
uint8_t z80io_PRL_Test(void);
|
|
||||||
uint8_t z80io_Z80_TestMemory(void);
|
|
||||||
|
|
||||||
extern void MHal_GPIO_Init(void);
|
|
||||||
extern void MHal_GPIO_Pad_Set(uint8_t u8IndexGPIO);
|
|
||||||
extern int MHal_GPIO_PadGroupMode_Set(uint32_t u32PadMode);
|
|
||||||
extern int MHal_GPIO_PadVal_Set(uint8_t u8IndexGPIO, uint32_t u32PadMode);
|
|
||||||
extern void MHal_GPIO_Pad_Oen(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Pad_Odn(uint8_t u8IndexGPIO);
|
|
||||||
extern uint8_t MHal_GPIO_Pad_Level(uint8_t u8IndexGPIO);
|
|
||||||
extern uint8_t MHal_GPIO_Pad_InOut(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Pull_High(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Pull_Low(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Set_High(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Set_Low(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_Enable_GPIO_INT(uint8_t u8IndexGPIO);
|
|
||||||
extern int MHal_GPIO_To_Irq(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Set_POLARITY(uint8_t u8IndexGPIO, uint8_t reverse);
|
|
||||||
extern void MHal_GPIO_Set_Driving(uint8_t u8IndexGPIO, uint8_t setHigh);
|
|
||||||
extern void MHal_GPIO_PAD_32K_OUT(uint8_t u8Enable);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif // Z80IO_H
|
|
||||||
@@ -1,541 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80io_test.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 IO Interface Test Methods
|
|
||||||
// This file contains the methods used to test the SOM to CPLD interface and evaluate
|
|
||||||
// it's performance. Production builds wont include these methods.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/semaphore.h>
|
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Test Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
uint8_t z80io_Z80_TestMemory(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t fullCmd;
|
|
||||||
uint8_t cmd;
|
|
||||||
struct timeval start, stop;
|
|
||||||
uint32_t iterations = 100;
|
|
||||||
uint32_t errorCount;
|
|
||||||
uint32_t idx;
|
|
||||||
long totalTime;
|
|
||||||
long bytesMSec;
|
|
||||||
uint8_t result;
|
|
||||||
spinlock_t spinLock;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
SPI_SEND8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
|
||||||
|
|
||||||
SPI_SEND32(0x00E30000 | (0x07 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E80000 | (0x82 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E20000 | (0x58 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E00000 | (0xF7 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E90000 | (0x0F << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00EB0000 | (0xCF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00EB0000 | (0xFF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
pr_info("Z80 Host Test - IO.\n");
|
|
||||||
// for(idx=0; idx < 1000000; idx++)
|
|
||||||
// {
|
|
||||||
// SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
// SPI_SEND32(0xD0000000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
// SPI_SEND32(0xD0100000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
// SPI_SEND32(0xD0200000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
// SPI_SEND32(0xD0300000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
// SPI_SEND32(0xD0400000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
// SPI_SEND32(0xD0500000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
// }
|
|
||||||
|
|
||||||
spin_lock_init(&spinLock);
|
|
||||||
pr_info("Z80 Host Test - Testing IO Write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
for(addr=0x0000; addr < 0x10000; addr++)
|
|
||||||
{
|
|
||||||
fullCmd = 0x00000000| ((uint8_t)addr) << 8 | CPLD_CMD_WRITEIO_ADDR;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
spin_lock_init(&spinLock);
|
|
||||||
pr_info("Z80 Host Test - Testing IO Read performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible IO ports and write to it.
|
|
||||||
for(addr=0x0000; addr < 0x10000; addr++)
|
|
||||||
{
|
|
||||||
fullCmd = 0x00000000 | ((uint8_t)addr) << 8 | CPLD_CMD_READIO_ADDR;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
spin_lock_init(&spinLock);
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write performance (opt).\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x1000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write/Fetch performance (opt).\n");
|
|
||||||
errorCount = 0;
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x8000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x8000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read back the same byte.
|
|
||||||
cmd = 0x10;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
if(result != (uint8_t)addr)
|
|
||||||
{
|
|
||||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write/Read performance (opt).\n");
|
|
||||||
errorCount = 0;
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x8000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x8000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read back the same byte.
|
|
||||||
cmd = 0x20;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
if(result != (uint8_t)addr)
|
|
||||||
{
|
|
||||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Fetch performance.\n");
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and read from it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x1000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x10;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x11;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Read performance (opt).\n");
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and read from it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x1000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x20;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x21;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// Go through all the accessible attribute VRAM and initialise it.
|
|
||||||
pr_info("Z80 Host Test - Testing VRAM Write performance.\n");
|
|
||||||
SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
iterations = 256*10;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(addr=0xD800; addr < 0xE000; addr++)
|
|
||||||
{
|
|
||||||
//while(CPLD_READY() == 0);
|
|
||||||
if(addr == 0xD800)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) |(0x71 << 8) | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible VRAM and write to it.
|
|
||||||
for(addr=0xD000; addr < 0xD800; addr++)
|
|
||||||
{
|
|
||||||
//while(CPLD_READY() == 0);
|
|
||||||
if(addr == 0xD000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)idx << 8) | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)((1*iterations*0x800)+0x800)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// A simple test to verify the SOM to CPLD SPI connectivity and give an estimate of its performance.
|
|
||||||
// The performance is based on the SPI setup and transmit time along with the close and received data processing.
|
|
||||||
// In real use, the driver will just send a command and generally ignore received data so increased throughput can be achieved.
|
|
||||||
//
|
|
||||||
uint8_t z80io_SPI_Test(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
struct timeval start, stop;
|
|
||||||
uint32_t iterations = 10000000;
|
|
||||||
uint32_t idx;
|
|
||||||
uint8_t rxData8;
|
|
||||||
uint16_t rxData16;
|
|
||||||
uint16_t rxData16Last;
|
|
||||||
uint32_t rxData32;
|
|
||||||
uint32_t rxData32Last;
|
|
||||||
uint32_t errorCount;
|
|
||||||
long totalTime;
|
|
||||||
long bytesMSec;
|
|
||||||
|
|
||||||
// Place the CPLD into echo test mode.
|
|
||||||
z80io_SPI_Send8(0xfe, &rxData8);
|
|
||||||
|
|
||||||
// 1st. test, 8bit.
|
|
||||||
pr_info("SPI Test - Testing 8 bit performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
z80io_SPI_Send8((uint8_t)idx, &rxData8);
|
|
||||||
if(idx > 1 && (uint8_t)(idx-1) != rxData8)
|
|
||||||
{
|
|
||||||
if(errorCount < 20)
|
|
||||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint8_t)(idx-1), rxData8 );
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 2nd. test, 16bit.
|
|
||||||
pr_info("SPI Test - Testing 16 bit performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
|
||||||
z80io_SPI_Send16((uint16_t)idx, &rxData16);
|
|
||||||
if(idx > 0 && (uint16_t)(idx-1) != (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)))
|
|
||||||
{
|
|
||||||
if(errorCount < 20)
|
|
||||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint16_t)(idx-1), (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)));
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
rxData16Last = rxData16;
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 3rd. test, 32bit.
|
|
||||||
pr_info("SPI Test - Testing 32 bit performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
z80io_SPI_Send32((uint32_t)idx, &rxData32);
|
|
||||||
if(idx > 0 && (uint32_t)(idx-1) != (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)))
|
|
||||||
{
|
|
||||||
if(errorCount < 20)
|
|
||||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint32_t)(idx-1), (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)));
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
rxData32Last = rxData32;
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(4*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to test the parallel bus, verifying integrity and assessing performance.
|
|
||||||
uint8_t z80io_PRL_Test(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
struct timeval start, stop;
|
|
||||||
uint32_t iterations = 10000000;
|
|
||||||
uint32_t idx;
|
|
||||||
uint8_t rxData8;
|
|
||||||
uint16_t rxData16;
|
|
||||||
long totalTime;
|
|
||||||
long bytesMSec;
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
uint32_t errorCount;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Place the CPLD into echo test mode.
|
|
||||||
|
|
||||||
// 1st. test, 8bit RW.
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
pr_info("Parallel Test - Testing 8 bit r/w performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Write byte and readback to compare.
|
|
||||||
z80io_PRL_Send8((uint8_t)idx);
|
|
||||||
rxData8 = z80io_PRL_Read8();
|
|
||||||
if((uint8_t)idx != rxData8)
|
|
||||||
{
|
|
||||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint8_t)(idx), rxData8);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 2nd. test, 8bit Write.
|
|
||||||
pr_info("Parallel Test - Testing 8 bit write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Write byte.
|
|
||||||
z80io_PRL_Send8((uint8_t)idx);
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 3rd. test, 8bit Read.
|
|
||||||
pr_info("Parallel Test - Testing 8 bit read performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Read byte.
|
|
||||||
rxData8 = z80io_PRL_Read8(0);
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
// 4th test, 16bit.
|
|
||||||
pr_info("Parallel Test - Testing 16 bit r/w performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
|
||||||
z80io_PRL_Send16((uint16_t)idx);
|
|
||||||
rxData16 = z80io_PRL_Read16();
|
|
||||||
if((uint16_t)idx != rxData16)
|
|
||||||
{
|
|
||||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint16_t)(idx), rxData16);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 5th test, 16bit Write.
|
|
||||||
pr_info("Parallel Test - Testing 16 bit write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Write word.
|
|
||||||
z80io_PRL_Send16((uint16_t)idx);
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 6th test, 16bit Read.
|
|
||||||
pr_info("Parallel Test - Testing 16 bit read performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Read word.
|
|
||||||
rxData16 = z80io_PRL_Read16();
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
403
software/FusionX/src/z80drv/MZ700/optparse.h
vendored
403
software/FusionX/src/z80drv/MZ700/optparse.h
vendored
@@ -1,403 +0,0 @@
|
|||||||
/* Optparse --- portable, reentrant, embeddable, getopt-like option parser
|
|
||||||
*
|
|
||||||
* This is free and unencumbered software released into the public domain.
|
|
||||||
*
|
|
||||||
* To get the implementation, define OPTPARSE_IMPLEMENTATION.
|
|
||||||
* Optionally define OPTPARSE_API to control the API's visibility
|
|
||||||
* and/or linkage (static, __attribute__, __declspec).
|
|
||||||
*
|
|
||||||
* The POSIX getopt() option parser has three fatal flaws. These flaws
|
|
||||||
* are solved by Optparse.
|
|
||||||
*
|
|
||||||
* 1) Parser state is stored entirely in global variables, some of
|
|
||||||
* which are static and inaccessible. This means only one thread can
|
|
||||||
* use getopt(). It also means it's not possible to recursively parse
|
|
||||||
* nested sub-arguments while in the middle of argument parsing.
|
|
||||||
* Optparse fixes this by storing all state on a local struct.
|
|
||||||
*
|
|
||||||
* 2) The POSIX standard provides no way to properly reset the parser.
|
|
||||||
* This means for portable code that getopt() is only good for one
|
|
||||||
* run, over one argv with one option string. It also means subcommand
|
|
||||||
* options cannot be processed with getopt(). Most implementations
|
|
||||||
* provide a method to reset the parser, but it's not portable.
|
|
||||||
* Optparse provides an optparse_arg() function for stepping over
|
|
||||||
* subcommands and continuing parsing of options with another option
|
|
||||||
* string. The Optparse struct itself can be passed around to
|
|
||||||
* subcommand handlers for additional subcommand option parsing. A
|
|
||||||
* full reset can be achieved by with an additional optparse_init().
|
|
||||||
*
|
|
||||||
* 3) Error messages are printed to stderr. This can be disabled with
|
|
||||||
* opterr, but the messages themselves are still inaccessible.
|
|
||||||
* Optparse solves this by writing an error message in its errmsg
|
|
||||||
* field. The downside to Optparse is that this error message will
|
|
||||||
* always be in English rather than the current locale.
|
|
||||||
*
|
|
||||||
* Optparse should be familiar with anyone accustomed to getopt(), and
|
|
||||||
* it could be a nearly drop-in replacement. The option string is the
|
|
||||||
* same and the fields have the same names as the getopt() global
|
|
||||||
* variables (optarg, optind, optopt).
|
|
||||||
*
|
|
||||||
* Optparse also supports GNU-style long options with optparse_long().
|
|
||||||
* The interface is slightly different and simpler than getopt_long().
|
|
||||||
*
|
|
||||||
* By default, argv is permuted as it is parsed, moving non-option
|
|
||||||
* arguments to the end. This can be disabled by setting the `permute`
|
|
||||||
* field to 0 after initialization.
|
|
||||||
*/
|
|
||||||
#ifndef OPTPARSE_H
|
|
||||||
#define OPTPARSE_H
|
|
||||||
|
|
||||||
#ifndef OPTPARSE_API
|
|
||||||
# define OPTPARSE_API
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct optparse {
|
|
||||||
char **argv;
|
|
||||||
int permute;
|
|
||||||
int optind;
|
|
||||||
int optopt;
|
|
||||||
char *optarg;
|
|
||||||
char errmsg[64];
|
|
||||||
int subopt;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum optparse_argtype {
|
|
||||||
OPTPARSE_NONE,
|
|
||||||
OPTPARSE_REQUIRED,
|
|
||||||
OPTPARSE_OPTIONAL
|
|
||||||
};
|
|
||||||
|
|
||||||
struct optparse_long {
|
|
||||||
const char *longname;
|
|
||||||
int shortname;
|
|
||||||
enum optparse_argtype argtype;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the parser state.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
void optparse_init(struct optparse *options, char **argv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the next option in the argv array.
|
|
||||||
* @param optstring a getopt()-formatted option string.
|
|
||||||
* @return the next option character, -1 for done, or '?' for error
|
|
||||||
*
|
|
||||||
* Just like getopt(), a character followed by no colons means no
|
|
||||||
* argument. One colon means the option has a required argument. Two
|
|
||||||
* colons means the option takes an optional argument.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
int optparse(struct optparse *options, const char *optstring);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles GNU-style long options in addition to getopt() options.
|
|
||||||
* This works a lot like GNU's getopt_long(). The last option in
|
|
||||||
* longopts must be all zeros, marking the end of the array. The
|
|
||||||
* longindex argument may be NULL.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
int optparse_long(struct optparse *options,
|
|
||||||
const struct optparse_long *longopts,
|
|
||||||
int *longindex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used for stepping over non-option arguments.
|
|
||||||
* @return the next non-option argument, or NULL for no more arguments
|
|
||||||
*
|
|
||||||
* Argument parsing can continue with optparse() after using this
|
|
||||||
* function. That would be used to parse the options for the
|
|
||||||
* subcommand returned by optparse_arg(). This function allows you to
|
|
||||||
* ignore the value of optind.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
char *optparse_arg(struct optparse *options);
|
|
||||||
|
|
||||||
/* Implementation */
|
|
||||||
#ifdef OPTPARSE_IMPLEMENTATION
|
|
||||||
|
|
||||||
#define OPTPARSE_MSG_INVALID "invalid option"
|
|
||||||
#define OPTPARSE_MSG_MISSING "option requires an argument"
|
|
||||||
#define OPTPARSE_MSG_TOOMANY "option takes no arguments"
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_error(struct optparse *options, const char *msg, const char *data)
|
|
||||||
{
|
|
||||||
unsigned p = 0;
|
|
||||||
const char *sep = " -- '";
|
|
||||||
while (*msg)
|
|
||||||
options->errmsg[p++] = *msg++;
|
|
||||||
while (*sep)
|
|
||||||
options->errmsg[p++] = *sep++;
|
|
||||||
while (p < sizeof(options->errmsg) - 2 && *data)
|
|
||||||
options->errmsg[p++] = *data++;
|
|
||||||
options->errmsg[p++] = '\'';
|
|
||||||
options->errmsg[p++] = '\0';
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
void
|
|
||||||
optparse_init(struct optparse *options, char **argv)
|
|
||||||
{
|
|
||||||
options->argv = argv;
|
|
||||||
options->permute = 1;
|
|
||||||
options->optind = 1;
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optarg = 0;
|
|
||||||
options->errmsg[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_is_dashdash(const char *arg)
|
|
||||||
{
|
|
||||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_is_shortopt(const char *arg)
|
|
||||||
{
|
|
||||||
return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_is_longopt(const char *arg)
|
|
||||||
{
|
|
||||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
optparse_permute(struct optparse *options, int index)
|
|
||||||
{
|
|
||||||
char *nonoption = options->argv[index];
|
|
||||||
int i;
|
|
||||||
for (i = index; i < options->optind - 1; i++)
|
|
||||||
options->argv[i] = options->argv[i + 1];
|
|
||||||
options->argv[options->optind - 1] = nonoption;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_argtype(const char *optstring, char c)
|
|
||||||
{
|
|
||||||
int count = OPTPARSE_NONE;
|
|
||||||
if (c == ':')
|
|
||||||
return -1;
|
|
||||||
for (; *optstring && c != *optstring; optstring++);
|
|
||||||
if (!*optstring)
|
|
||||||
return -1;
|
|
||||||
if (optstring[1] == ':')
|
|
||||||
count += optstring[2] == ':' ? 2 : 1;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
int
|
|
||||||
optparse(struct optparse *options, const char *optstring)
|
|
||||||
{
|
|
||||||
int type;
|
|
||||||
char *next;
|
|
||||||
char *option = options->argv[options->optind];
|
|
||||||
options->errmsg[0] = '\0';
|
|
||||||
options->optopt = 0;
|
|
||||||
options->optarg = 0;
|
|
||||||
if (option == 0) {
|
|
||||||
return -1;
|
|
||||||
} else if (optparse_is_dashdash(option)) {
|
|
||||||
options->optind++; /* consume "--" */
|
|
||||||
return -1;
|
|
||||||
} else if (!optparse_is_shortopt(option)) {
|
|
||||||
if (options->permute) {
|
|
||||||
int index = options->optind++;
|
|
||||||
int r = optparse(options, optstring);
|
|
||||||
optparse_permute(options, index);
|
|
||||||
options->optind--;
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
option += options->subopt + 1;
|
|
||||||
options->optopt = option[0];
|
|
||||||
type = optparse_argtype(optstring, option[0]);
|
|
||||||
next = options->argv[options->optind + 1];
|
|
||||||
switch (type) {
|
|
||||||
case -1: {
|
|
||||||
char str[2] = {0, 0};
|
|
||||||
str[0] = option[0];
|
|
||||||
options->optind++;
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_INVALID, str);
|
|
||||||
}
|
|
||||||
case OPTPARSE_NONE:
|
|
||||||
if (option[1]) {
|
|
||||||
options->subopt++;
|
|
||||||
} else {
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optind++;
|
|
||||||
}
|
|
||||||
return option[0];
|
|
||||||
case OPTPARSE_REQUIRED:
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optind++;
|
|
||||||
if (option[1]) {
|
|
||||||
options->optarg = option + 1;
|
|
||||||
} else if (next != 0) {
|
|
||||||
options->optarg = next;
|
|
||||||
options->optind++;
|
|
||||||
} else {
|
|
||||||
char str[2] = {0, 0};
|
|
||||||
str[0] = option[0];
|
|
||||||
options->optarg = 0;
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_MISSING, str);
|
|
||||||
}
|
|
||||||
return option[0];
|
|
||||||
case OPTPARSE_OPTIONAL:
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optind++;
|
|
||||||
if (option[1])
|
|
||||||
options->optarg = option + 1;
|
|
||||||
else
|
|
||||||
options->optarg = 0;
|
|
||||||
return option[0];
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
char *
|
|
||||||
optparse_arg(struct optparse *options)
|
|
||||||
{
|
|
||||||
char *option = options->argv[options->optind];
|
|
||||||
options->subopt = 0;
|
|
||||||
if (option != 0)
|
|
||||||
options->optind++;
|
|
||||||
return option;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_longopts_end(const struct optparse_long *longopts, int i)
|
|
||||||
{
|
|
||||||
return !longopts[i].longname && !longopts[i].shortname;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
optparse_from_long(const struct optparse_long *longopts, char *optstring)
|
|
||||||
{
|
|
||||||
char *p = optstring;
|
|
||||||
int i;
|
|
||||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
|
||||||
if (longopts[i].shortname && longopts[i].shortname < 127) {
|
|
||||||
int a;
|
|
||||||
*p++ = longopts[i].shortname;
|
|
||||||
for (a = 0; a < (int)longopts[i].argtype; a++)
|
|
||||||
*p++ = ':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unlike strcmp(), handles options containing "=". */
|
|
||||||
static int
|
|
||||||
optparse_longopts_match(const char *longname, const char *option)
|
|
||||||
{
|
|
||||||
const char *a = option, *n = longname;
|
|
||||||
if (longname == 0)
|
|
||||||
return 0;
|
|
||||||
for (; *a && *n && *a != '='; a++, n++)
|
|
||||||
if (*a != *n)
|
|
||||||
return 0;
|
|
||||||
return *n == '\0' && (*a == '\0' || *a == '=');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the part after "=", or NULL. */
|
|
||||||
static char *
|
|
||||||
optparse_longopts_arg(char *option)
|
|
||||||
{
|
|
||||||
for (; *option && *option != '='; option++);
|
|
||||||
if (*option == '=')
|
|
||||||
return option + 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_long_fallback(struct optparse *options,
|
|
||||||
const struct optparse_long *longopts,
|
|
||||||
int *longindex)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
|
|
||||||
optparse_from_long(longopts, optstring);
|
|
||||||
result = optparse(options, optstring);
|
|
||||||
if (longindex != 0) {
|
|
||||||
*longindex = -1;
|
|
||||||
if (result != -1) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; !optparse_longopts_end(longopts, i); i++)
|
|
||||||
if (longopts[i].shortname == options->optopt)
|
|
||||||
*longindex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
int
|
|
||||||
optparse_long(struct optparse *options,
|
|
||||||
const struct optparse_long *longopts,
|
|
||||||
int *longindex)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *option = options->argv[options->optind];
|
|
||||||
if (option == 0) {
|
|
||||||
return -1;
|
|
||||||
} else if (optparse_is_dashdash(option)) {
|
|
||||||
options->optind++; /* consume "--" */
|
|
||||||
return -1;
|
|
||||||
} else if (optparse_is_shortopt(option)) {
|
|
||||||
return optparse_long_fallback(options, longopts, longindex);
|
|
||||||
} else if (!optparse_is_longopt(option)) {
|
|
||||||
if (options->permute) {
|
|
||||||
int index = options->optind++;
|
|
||||||
int r = optparse_long(options, longopts, longindex);
|
|
||||||
optparse_permute(options, index);
|
|
||||||
options->optind--;
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse as long option. */
|
|
||||||
options->errmsg[0] = '\0';
|
|
||||||
options->optopt = 0;
|
|
||||||
options->optarg = 0;
|
|
||||||
option += 2; /* skip "--" */
|
|
||||||
options->optind++;
|
|
||||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
|
||||||
const char *name = longopts[i].longname;
|
|
||||||
if (optparse_longopts_match(name, option)) {
|
|
||||||
char *arg;
|
|
||||||
if (longindex)
|
|
||||||
*longindex = i;
|
|
||||||
options->optopt = longopts[i].shortname;
|
|
||||||
arg = optparse_longopts_arg(option);
|
|
||||||
if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
|
|
||||||
} if (arg != 0) {
|
|
||||||
options->optarg = arg;
|
|
||||||
} else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
|
|
||||||
options->optarg = options->argv[options->optind];
|
|
||||||
if (options->optarg == 0)
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_MISSING, name);
|
|
||||||
else
|
|
||||||
options->optind++;
|
|
||||||
}
|
|
||||||
return options->optopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_INVALID, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OPTPARSE_IMPLEMENTATION */
|
|
||||||
#endif /* OPTPARSE_H */
|
|
||||||
@@ -1,734 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80ctrl.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 Control Interface
|
|
||||||
// This file contains a command line utility tool for controlling the z80drv device
|
|
||||||
// driver. The tool allows manipulation of the emulated Z80, inspection of its
|
|
||||||
// memory and data, transmission of adhoc commands to the underlying CPLD-Z80
|
|
||||||
// gateway and loading/saving of programs and data to/from the Z80 virtual and
|
|
||||||
// host memory.
|
|
||||||
//
|
|
||||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
|
||||||
// The Z80 CPU Emulator is the heart of the Z80 device driver.
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <termios.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <Z/constants/pointer.h>
|
|
||||||
#include <Z/macros/member.h>
|
|
||||||
#include <Z/macros/array.h>
|
|
||||||
#include <Z80.h>
|
|
||||||
#include "z80driver.h"
|
|
||||||
|
|
||||||
#define VERSION "1.0"
|
|
||||||
#define AUTHOR "P.D.Smart"
|
|
||||||
#define COPYRIGHT "(c) 2018-22"
|
|
||||||
|
|
||||||
// Getopt_long is buggy so we use optparse.
|
|
||||||
#define OPTPARSE_IMPLEMENTATION
|
|
||||||
#define OPTPARSE_API static
|
|
||||||
#include "optparse.h"
|
|
||||||
|
|
||||||
// Device driver name.
|
|
||||||
#define DEVICE_FILENAME "/dev/z80drv"
|
|
||||||
|
|
||||||
// Constants for the Sharp MZ80A MZF file format.
|
|
||||||
#define MZF_HEADER_SIZE 128 // Size of the MZF header.
|
|
||||||
#define MZF_ATTRIBUTE 0x00 // Code Type, 01 = Machine Code.
|
|
||||||
#define MZF_FILENAME 0x01 // Title/Name (17 bytes).
|
|
||||||
#define MZF_FILENAME_LEN 17 // Length of the filename, it is not NULL terminated, generally a CR can be taken as terminator but not guaranteed.
|
|
||||||
#define MZF_FILESIZE 0x12 // Size of program.
|
|
||||||
#define MZF_LOADADDR 0x14 // Load address of program.
|
|
||||||
#define MZF_EXECADDR 0x16 // Exec address of program.
|
|
||||||
#define MZF_COMMENT 0x18 // Comment, used for details of the file or startup code.
|
|
||||||
#define MZF_COMMENT_LEN 104 // Length of the comment field.
|
|
||||||
#define CMT_TYPE_OBJCD 0x001 // MZF contains a binary object.
|
|
||||||
#define CMT_TYPE_BTX1CD 0x002 // MZF contains a BASIC program.
|
|
||||||
#define CMT_TYPE_BTX2CD 0x005 // MZF contains a BASIC program.
|
|
||||||
#define CMT_TYPE_TZOBJCD0 0x0F8 // MZF contains a TZFS binary object for page 0.
|
|
||||||
#define CMT_TYPE_TZOBJCD1 0x0F9
|
|
||||||
#define CMT_TYPE_TZOBJCD2 0x0FA
|
|
||||||
#define CMT_TYPE_TZOBJCD3 0x0FB
|
|
||||||
#define CMT_TYPE_TZOBJCD4 0x0FC
|
|
||||||
#define CMT_TYPE_TZOBJCD5 0x0FD
|
|
||||||
#define CMT_TYPE_TZOBJCD6 0x0FE
|
|
||||||
#define CMT_TYPE_TZOBJCD7 0x0FF // MZF contains a TZFS binary object for page 7.
|
|
||||||
#define MZ_CMT_ADDR 0x10F0
|
|
||||||
|
|
||||||
// Structure to define a Sharp MZ80A MZF directory structure. This header appears at the beginning of every Sharp MZ80A tape (and more recently archived/emulator) images.
|
|
||||||
//
|
|
||||||
typedef struct __attribute__((__packed__)) {
|
|
||||||
uint8_t attr; // MZF attribute describing the file.
|
|
||||||
uint8_t fileName[MZF_FILENAME_LEN]; // Each directory entry is the size of an MZF filename.
|
|
||||||
uint16_t fileSize; // Size of file.
|
|
||||||
uint16_t loadAddr; // Load address for the file.
|
|
||||||
uint16_t execAddr; // Execution address where the Z80 starts processing.
|
|
||||||
uint8_t comment[MZF_COMMENT_LEN]; // Text comment field but often contains a startup machine code program.
|
|
||||||
} t_svcDirEnt;
|
|
||||||
|
|
||||||
// Possible commands to be issued to the Z80 driver.
|
|
||||||
enum CTRL_COMMANDS {
|
|
||||||
Z80_CMD_STOP = 0,
|
|
||||||
Z80_CMD_START = 1,
|
|
||||||
Z80_CMD_PAUSE = 2,
|
|
||||||
Z80_CMD_CONTINUE = 3,
|
|
||||||
Z80_CMD_RESET = 4,
|
|
||||||
Z80_CMD_SPEED = 5,
|
|
||||||
Z80_CMD_HOST_RAM = 6,
|
|
||||||
Z80_CMD_VIRTUAL_RAM = 7,
|
|
||||||
Z80_CMD_DUMP_MEMORY = 8,
|
|
||||||
Z80_CMD_MEMORY_TEST = 9,
|
|
||||||
CPLD_CMD_SEND_CMD = 10,
|
|
||||||
CPLD_CMD_SPI_TEST = 11,
|
|
||||||
CPLD_CMD_PRL_TEST = 12
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Shared memory between this process and the Z80 driver.
|
|
||||||
static t_Z80Ctrl *Z80Ctrl = NULL;
|
|
||||||
|
|
||||||
// Method to obtain and return the output screen width.
|
|
||||||
//
|
|
||||||
uint8_t getScreenWidth(void)
|
|
||||||
{
|
|
||||||
return(MAX_SCREEN_WIDTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct termios orig_termios;
|
|
||||||
|
|
||||||
void reset_terminal_mode()
|
|
||||||
{
|
|
||||||
tcsetattr(0, TCSANOW, &orig_termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_conio_terminal_mode()
|
|
||||||
{
|
|
||||||
struct termios new_termios;
|
|
||||||
|
|
||||||
/* take two copies - one for now, one for later */
|
|
||||||
tcgetattr(0, &orig_termios);
|
|
||||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
|
||||||
|
|
||||||
/* register cleanup handler, and set the new terminal mode */
|
|
||||||
atexit(reset_terminal_mode);
|
|
||||||
cfmakeraw(&new_termios);
|
|
||||||
tcsetattr(0, TCSANOW, &new_termios);
|
|
||||||
}
|
|
||||||
|
|
||||||
int kbhit()
|
|
||||||
{
|
|
||||||
struct timeval tv = { 0L, 0L };
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(0, &fds);
|
|
||||||
return select(1, &fds, NULL, NULL, &tv) > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int getch(uint8_t wait)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
unsigned char c;
|
|
||||||
|
|
||||||
if(wait != 0 || (wait == 0 && kbhit()))
|
|
||||||
{
|
|
||||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void delay(int number_of_seconds)
|
|
||||||
{
|
|
||||||
// Converting time into milli_seconds
|
|
||||||
int milli_seconds = 1000 * number_of_seconds;
|
|
||||||
|
|
||||||
// Storing start time
|
|
||||||
clock_t start_time = clock();
|
|
||||||
|
|
||||||
// looping till required time is not achieved
|
|
||||||
while (clock() < start_time + milli_seconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to dump out a given section of memory via the UART.
|
|
||||||
//
|
|
||||||
int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t memwidth, uint32_t dispaddr, uint8_t dispwidth)
|
|
||||||
{
|
|
||||||
uint8_t displayWidth = dispwidth;;
|
|
||||||
uint32_t pnt = memaddr;
|
|
||||||
uint32_t endAddr = memaddr + memsize;
|
|
||||||
uint32_t addr = dispaddr;
|
|
||||||
uint32_t i = 0;
|
|
||||||
//uint32_t data;
|
|
||||||
int8_t keyIn;
|
|
||||||
int result = -1;
|
|
||||||
char c = 0;
|
|
||||||
|
|
||||||
// Sanity check. memoryFlag == 0 required kernel driver to dump so we exit as it cannot be performed here.
|
|
||||||
if(memoryFlag == 0)
|
|
||||||
return(-1);
|
|
||||||
|
|
||||||
// Reconfigure terminal to allow non-blocking key input.
|
|
||||||
//
|
|
||||||
set_conio_terminal_mode();
|
|
||||||
|
|
||||||
// If not set, calculate output line width according to connected display width.
|
|
||||||
//
|
|
||||||
if(displayWidth == 0)
|
|
||||||
{
|
|
||||||
switch(getScreenWidth())
|
|
||||||
{
|
|
||||||
case 40:
|
|
||||||
displayWidth = 8;
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
displayWidth = 16;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
displayWidth = 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
printf("%08lX", addr); // print address
|
|
||||||
printf(": ");
|
|
||||||
|
|
||||||
// print hexadecimal data
|
|
||||||
for (i=0; i < displayWidth; )
|
|
||||||
{
|
|
||||||
switch(memwidth)
|
|
||||||
{
|
|
||||||
case 16:
|
|
||||||
if(pnt+i < endAddr)
|
|
||||||
printf("%04X", memoryFlag == 1 ? (uint16_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint16_t)Z80Ctrl->page[pnt+i] : (uint16_t)Z80Ctrl->iopage[pnt+i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
if(pnt+i < endAddr)
|
|
||||||
printf("%08lX", memoryFlag == 1 ? (uint32_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint32_t)Z80Ctrl->page[pnt+i] : (uint32_t)Z80Ctrl->iopage[pnt+i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 8:
|
|
||||||
default:
|
|
||||||
if(pnt+i < endAddr)
|
|
||||||
printf("%02X", memoryFlag == 1 ? (uint8_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint8_t)Z80Ctrl->page[pnt+i] : (uint8_t)Z80Ctrl->iopage[pnt+i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
fputc((char)' ', stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
// print ascii data
|
|
||||||
printf(" |");
|
|
||||||
|
|
||||||
// print single ascii char
|
|
||||||
for (i=0; i < displayWidth; i++)
|
|
||||||
{
|
|
||||||
c = memoryFlag == 1 ? (char)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (char)Z80Ctrl->page[pnt+i] : (char)Z80Ctrl->iopage[pnt+i];
|
|
||||||
if ((pnt+i < endAddr) && (c >= ' ') && (c <= '~'))
|
|
||||||
fputc((char)c, stdout);
|
|
||||||
else
|
|
||||||
fputc((char)' ', stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("|\r\n");
|
|
||||||
fflush(stdout);
|
|
||||||
|
|
||||||
// Move on one row.
|
|
||||||
pnt += displayWidth;
|
|
||||||
addr += displayWidth;
|
|
||||||
|
|
||||||
// User abort (ESC), pause (Space) or all done?
|
|
||||||
//
|
|
||||||
keyIn = getch(0);
|
|
||||||
if(keyIn == ' ')
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
keyIn = getch(0);
|
|
||||||
} while(keyIn != ' ' && keyIn != 0x1b);
|
|
||||||
}
|
|
||||||
// Escape key pressed, exit with 0 to indicate this to caller.
|
|
||||||
if (keyIn == 0x1b)
|
|
||||||
{
|
|
||||||
sleep(1);
|
|
||||||
result = 0;
|
|
||||||
goto memoryDumpExit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// End of buffer, exit the loop.
|
|
||||||
if(pnt >= (memaddr + memsize))
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Normal exit, return -1 to show no key pressed.
|
|
||||||
memoryDumpExit:
|
|
||||||
reset_terminal_mode();
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to load a program or data file into the Z80 memory. First load into Virtual memory and then trigger a sync to bring Host RAM in line.
|
|
||||||
//
|
|
||||||
int z80load(int fdZ80, char *fileName)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
struct ioctlCmd ioctlCmd;
|
|
||||||
int ret = 0;
|
|
||||||
t_svcDirEnt mzfHeader;
|
|
||||||
|
|
||||||
// Pause the Z80.
|
|
||||||
//
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
// Open the file and read directly into the Virtual memory via the share.
|
|
||||||
FILE *ptr;
|
|
||||||
ptr = fopen(fileName, "rb");
|
|
||||||
if(ptr)
|
|
||||||
{
|
|
||||||
printf("File:%s\n", fileName);
|
|
||||||
// First the header.
|
|
||||||
fread((uint8_t *)&mzfHeader, MZF_HEADER_SIZE, 1, ptr);
|
|
||||||
printf("Load:%x\n", mzfHeader.loadAddr);
|
|
||||||
if(mzfHeader.loadAddr > 0x1000)
|
|
||||||
{
|
|
||||||
printf("Memcpy:%x,%x\n", mzfHeader.loadAddr, mzfHeader.fileSize);
|
|
||||||
// Copy in the header.
|
|
||||||
memcpy((uint8_t *)&Z80Ctrl->memory[MZ_CMT_ADDR], (uint8_t *)&mzfHeader, MZF_HEADER_SIZE);
|
|
||||||
|
|
||||||
printf("Memcpy:%x,%x\n", mzfHeader.loadAddr, mzfHeader.fileSize);
|
|
||||||
// Now read in the data.
|
|
||||||
fread(&Z80Ctrl->memory[mzfHeader.loadAddr], mzfHeader.fileSize, 1, ptr);
|
|
||||||
printf("Memcpy:%x,%x\n", mzfHeader.loadAddr, mzfHeader.fileSize);
|
|
||||||
printf("Loaded %s, Size:%04x, Addr:%04x, Exec:%04x\n", fileName, mzfHeader.fileSize, mzfHeader.loadAddr, mzfHeader.execAddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync the loaded image from Virtual memory to hard memory.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_SYNC_TO_HOST_RAM;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
// Resume Z80 processing.
|
|
||||||
//
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
printf("Couldnt open file\n");
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to request basic Z80 operations.
|
|
||||||
//
|
|
||||||
int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long param3)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
struct ioctlCmd ioctlCmd;
|
|
||||||
uint32_t idx;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch(cmd)
|
|
||||||
{
|
|
||||||
case Z80_CMD_STOP:
|
|
||||||
// Use IOCTL to request Z80 to Stop (power off) processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_START:
|
|
||||||
// Use IOCTL to request Z80 to Start (power on) processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_PAUSE:
|
|
||||||
// Use IOCTL to request Z80 to pause processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_CONTINUE:
|
|
||||||
// Use IOCTL to request Z80 continue processing.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_RESET:
|
|
||||||
// Use IOCTL to request Z80 reset.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_SPEED:
|
|
||||||
// Check value is in range.
|
|
||||||
for(idx=1; idx < 256; idx+=idx)
|
|
||||||
{
|
|
||||||
if((uint32_t)param1 == idx) break;
|
|
||||||
}
|
|
||||||
if(idx == 256)
|
|
||||||
{
|
|
||||||
printf("Speed factor is illegal. It must be a multiple value of the original CPU clock, ie. 1x, 2x, 4x etc\n");
|
|
||||||
ret = -1;
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// Use IOCTL to request Z80 cpu freq change.
|
|
||||||
ioctlCmd.speed.speedMultiplier = (uint32_t)param1;
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CPU_FREQ;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CPLD_CMD_SEND_CMD:
|
|
||||||
// Build up the IOCTL command to request the given data is sent to the CPLD.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_CPLD_CMD;
|
|
||||||
ioctlCmd.cpld.cmd = (uint32_t)param1;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_DUMP_MEMORY:
|
|
||||||
// If virtual memory, we can dump it via the shared memory segment.
|
|
||||||
if((uint8_t)param1)
|
|
||||||
{
|
|
||||||
memoryDump((uint32_t)param2, (uint32_t)param3, (uint8_t)param1, (uint8_t)param1 == 2 || (uint8_t)param1 == 3 ? 32 : 8, (uint32_t)param2, 0);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
// Build an IOCTL command to get the driver to dump the memory.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_DUMP_MEMORY;
|
|
||||||
ioctlCmd.addr.start = (uint32_t)param2;
|
|
||||||
ioctlCmd.addr.end = (uint32_t)param2+(uint32_t)param3;
|
|
||||||
ioctlCmd.addr.size = (uint32_t)param3;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Z80_CMD_HOST_RAM:
|
|
||||||
// Use IOCTL to request change to host RAM.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_USE_HOST_RAM;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_VIRTUAL_RAM:
|
|
||||||
// Use IOCTL to request change to host RAM.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_USE_VIRTUAL_RAM;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case Z80_CMD_MEMORY_TEST:
|
|
||||||
// Send command to test the SPI.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_MEMTEST;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case CPLD_CMD_PRL_TEST:
|
|
||||||
// Send command to test the SPI.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_PRL_TEST;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
case CPLD_CMD_SPI_TEST:
|
|
||||||
// Send command to test the SPI.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_SPI_TEST;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
printf("Command not supported!\n");
|
|
||||||
ret = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to perform some simple tests on the Z80 emulator.
|
|
||||||
//
|
|
||||||
int z80test(int fdZ80)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
struct ioctlCmd ioctlCmd;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
// Stop the Z80.
|
|
||||||
//
|
|
||||||
printf("Send STOP\n");
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
FILE *ptr;
|
|
||||||
ptr = fopen("/customer/mz700.rom", "rb");
|
|
||||||
if(ptr)
|
|
||||||
{
|
|
||||||
fread(&Z80Ctrl->memory, 65536, 1, ptr);
|
|
||||||
} else printf("Couldnt open file\n");
|
|
||||||
|
|
||||||
// Configure the Z80.
|
|
||||||
//
|
|
||||||
printf("Send SETPC\n");
|
|
||||||
ioctlCmd.z80.pc = 0;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SETPC, &ioctlCmd);
|
|
||||||
|
|
||||||
memoryDump(0 , 65536, 1, 8, 0, 0);
|
|
||||||
|
|
||||||
// Start the Z80.
|
|
||||||
//
|
|
||||||
printf("Send START\n");
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
delay(10);
|
|
||||||
|
|
||||||
printf("Send STOP\n");
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
|
||||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
memoryDump(0, 65536, 1, 8, 0, 0);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Output usage screen. So mamy commands you do need to be prompted!!
|
|
||||||
void showArgs(char *progName, struct optparse *options)
|
|
||||||
{
|
|
||||||
printf("%s %s %s %s\n\n", progName, VERSION, COPYRIGHT, AUTHOR);
|
|
||||||
printf("Synopsis:\n");
|
|
||||||
printf("%s --help # This help screen.\n", progName);
|
|
||||||
printf(" --cmd <command> = RESET # Reset the Z80\n");
|
|
||||||
printf(" = STOP # Stop and power off the Z80\n");
|
|
||||||
printf(" = START # Power on and start the Z80\n");
|
|
||||||
printf(" = PAUSE # Pause running Z80\n");
|
|
||||||
printf(" = CONTINUE # Continue Z80 execution\n");
|
|
||||||
printf(" = HOSTRAM # Use HOST DRAM\n");
|
|
||||||
printf(" = VIRTRAM # Use Virtual RAM\n");
|
|
||||||
printf(" = SPEED --speed <1, 2, 4, 8, 16, 32, 64, 128> # In Virtual RAM mode, set CPU speed to base clock x factor.\n");
|
|
||||||
printf(" = LOADMZF --file <mzf filename> # Load MZF file into memory.\n");
|
|
||||||
printf(" = DUMP --start <24bit addr> --end <24bit addr> --virtual <0 - Host RAM, 1 = Virtual RAM, 2 = PageTable, 3 = IOPageTable>\n");
|
|
||||||
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
|
||||||
printf(" = Z80TEST # Perform various debugging tests\n");
|
|
||||||
printf(" = SPITEST # Perform SPI testing\n");
|
|
||||||
printf(" = PRLTEST # Perform Parallel Bus testing\n");
|
|
||||||
printf(" = Z80MEMTEST # Perform HOST memory tests.\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int fdZ80;
|
|
||||||
char buff[64];
|
|
||||||
char cmd[64] = { 0 };
|
|
||||||
char fileName[256] = { 0 };
|
|
||||||
int opt;
|
|
||||||
long hexData = 0;
|
|
||||||
long speedMultiplier = 1;
|
|
||||||
long startAddr = 0x0000;
|
|
||||||
long endAddr = 0x1000;
|
|
||||||
int virtualMemory = 0;
|
|
||||||
int helpFlag = 0;
|
|
||||||
int verboseFlag = 0;
|
|
||||||
|
|
||||||
// Define parameters to be processed.
|
|
||||||
struct optparse options;
|
|
||||||
static struct optparse_long long_options[] =
|
|
||||||
{
|
|
||||||
{"help", 'h', OPTPARSE_NONE},
|
|
||||||
{"cmd", 'c', OPTPARSE_REQUIRED},
|
|
||||||
{"file", 'f', OPTPARSE_REQUIRED},
|
|
||||||
{"data", 'd', OPTPARSE_REQUIRED},
|
|
||||||
{"speed", 'S', OPTPARSE_REQUIRED},
|
|
||||||
{"virtual", 'V', OPTPARSE_REQUIRED},
|
|
||||||
{"start", 's', OPTPARSE_REQUIRED},
|
|
||||||
{"end", 'e', OPTPARSE_REQUIRED},
|
|
||||||
{"verbose", 'v', OPTPARSE_NONE},
|
|
||||||
{0}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parse the command line options.
|
|
||||||
//
|
|
||||||
optparse_init(&options, argv);
|
|
||||||
while((opt = optparse_long(&options, long_options, NULL)) != -1)
|
|
||||||
{
|
|
||||||
switch(opt)
|
|
||||||
{
|
|
||||||
// Hex data.
|
|
||||||
case 'd':
|
|
||||||
hexData = strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("Hex data:%08x\n", hexData);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Start address for memory operations.
|
|
||||||
case 's':
|
|
||||||
startAddr = strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("Start Addr:%04x\n", startAddr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Speed multiplication factor for CPU governor when running in virtual memory.
|
|
||||||
case 'S':
|
|
||||||
speedMultiplier = strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("Speed = base freq x %d\n", speedFactor);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// End address for memory operations.
|
|
||||||
case 'e':
|
|
||||||
endAddr = strtol(options.optarg, NULL, 0);
|
|
||||||
//printf("End Addr:%04x\n", endAddr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Virtual memory flag, 0 = host, 1 = virtual memory, 2 = page table, 3 = iopage table.
|
|
||||||
case 'V':
|
|
||||||
virtualMemory = atoi(options.optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Filename.
|
|
||||||
case 'f':
|
|
||||||
strcpy(fileName, options.optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Command to execute.
|
|
||||||
case 'c':
|
|
||||||
strcpy(cmd, options.optarg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Verbose mode.
|
|
||||||
case 'v':
|
|
||||||
verboseFlag = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Command help needed.
|
|
||||||
case 'h':
|
|
||||||
helpFlag = 1;
|
|
||||||
showArgs(argv[0], &options);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Unrecognised, show synopsis.
|
|
||||||
case '?':
|
|
||||||
showArgs(argv[0], &options);
|
|
||||||
printf("%s: %s\n", argv[0], options.errmsg);
|
|
||||||
return(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the z80drv driver and attach to its shared memory, basically the Z80 control structure which includes the virtual Z80 memory.
|
|
||||||
fdZ80 = open(DEVICE_FILENAME, O_RDWR|O_NDELAY);
|
|
||||||
if(fdZ80 >= 0)
|
|
||||||
{
|
|
||||||
Z80Ctrl = (t_Z80Ctrl *)mmap(0, sizeof(t_Z80Ctrl), PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0);
|
|
||||||
if(Z80Ctrl == (void *)-1)
|
|
||||||
{
|
|
||||||
printf("Failed to attach to the Z80 Control structure, cannot continue, exitting....\n");
|
|
||||||
close(fdZ80);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
printf("Failed to open the Z80 Driver, exitting...\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic string to method mapping. Started off with just 1 or two but has grown, may need a table!
|
|
||||||
if(strcasecmp(cmd, "LOADMZF") == 0)
|
|
||||||
{
|
|
||||||
z80load(fdZ80, fileName);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "RESET") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_RESET, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "STOP") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_STOP, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "START") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_START, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "PAUSE") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_PAUSE, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "CONTINUE") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_CONTINUE, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "SPEED") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_SPEED, speedMultiplier, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "DUMP") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_DUMP_MEMORY, virtualMemory, startAddr, (endAddr - startAddr));
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "HOSTRAM") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_HOST_RAM, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "VIRTRAM") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_VIRTUAL_RAM, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "CPLDCMD") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, CPLD_CMD_SEND_CMD, hexData, 0, 0);
|
|
||||||
} else
|
|
||||||
|
|
||||||
// Test methods, if the code is built-in to the driver.
|
|
||||||
if(strcasecmp(cmd, "Z80TEST") == 0)
|
|
||||||
{
|
|
||||||
z80test(fdZ80);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "SPITEST") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, CPLD_CMD_SPI_TEST, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "PRLTEST") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, CPLD_CMD_PRL_TEST, 0, 0, 0);
|
|
||||||
} else
|
|
||||||
if(strcasecmp(cmd, "Z80MEMTEST") == 0)
|
|
||||||
{
|
|
||||||
ctrlCmd(fdZ80, Z80_CMD_MEMORY_TEST, 0, 0, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
showArgs(argv[0], &options);
|
|
||||||
printf("No command given, nothing done!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmap shared memory and close the device.
|
|
||||||
munmap(Z80Ctrl, sizeof(t_Z80Ctrl));
|
|
||||||
close(fdZ80);
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
284
software/FusionX/src/z80drv/MZ700/z80driver.h
vendored
284
software/FusionX/src/z80drv/MZ700/z80driver.h
vendored
@@ -1,284 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80driver.h
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 Driver
|
|
||||||
// This file contains the declarations used in the z80drv device driver.
|
|
||||||
//
|
|
||||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
|
||||||
// The Z80 CPU Emulator is the heart of this driver and in all ways, is compatible with
|
|
||||||
// the original Z80.
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifndef Z80DRIVER_H
|
|
||||||
#define Z80DRIVER_H
|
|
||||||
|
|
||||||
// Constants.
|
|
||||||
#define Z80_VIRTUAL_ROM_SIZE 16384 // Sized to maximum ROM which is the MZ-800 ROM.
|
|
||||||
#define Z80_VIRTUAL_RAM_SIZE (65536 * 8) // (PAGE_SIZE * 2) // max size mmaped to userspace
|
|
||||||
#define Z80_VIRTUAL_MEMORY_SIZE Z80_VIRTUAL_RAM_SIZE + Z80_VIRTUAL_ROM_SIZE
|
|
||||||
#define Z80_MEMORY_PAGE_SIZE 16
|
|
||||||
#define MAX_SCREEN_WIDTH 132
|
|
||||||
#define DEVICE_NAME "z80drv"
|
|
||||||
#define CLASS_NAME "mogu"
|
|
||||||
|
|
||||||
// Memory and IO page types. Used to create a memory page which maps type of address space to real address space on host or virtual memory.
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_MASK 0x00FFFFFF
|
|
||||||
#define MEMORY_TYPE_REAL_MASK 0x0000FFFF
|
|
||||||
#define IO_TYPE_MASK 0x0000FFFF
|
|
||||||
#define MEMORY_TYPE_INHIBIT 0x00000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_RAM 0x80000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_ROM 0x40000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_VRAM 0x20000000
|
|
||||||
#define MEMORY_TYPE_PHYSICAL_HW 0x10000000
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_RAM 0x08000000
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_ROM 0x04000000
|
|
||||||
#define MEMORY_TYPE_VIRTUAL_HW 0x02000000
|
|
||||||
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
|
||||||
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
|
||||||
|
|
||||||
|
|
||||||
// Approximate governor delays to regulate emulated CPU speed.
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_3_54MHZ 253
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_7MHZ 126
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_14MHZ 63
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_28MHZ 32
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_56MHZ 16
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_112MHZ 8
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_224MHZ 4
|
|
||||||
#define MZ700_INSTRUCTION_DELAY_448MHZ 1
|
|
||||||
|
|
||||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
|
||||||
#define IOCTL_CMD_Z80_STOP 's'
|
|
||||||
#define IOCTL_CMD_Z80_START 'S'
|
|
||||||
#define IOCTL_CMD_Z80_PAUSE 'P'
|
|
||||||
#define IOCTL_CMD_Z80_RESET 'R'
|
|
||||||
#define IOCTL_CMD_Z80_CONTINUE 'C'
|
|
||||||
#define IOCTL_CMD_USE_HOST_RAM 'x'
|
|
||||||
#define IOCTL_CMD_USE_VIRTUAL_RAM 'X'
|
|
||||||
#define IOCTL_CMD_DUMP_MEMORY 'M'
|
|
||||||
#define IOCTL_CMD_Z80_CPU_FREQ 'F'
|
|
||||||
#define IOCTL_CMD_CPLD_CMD 'z'
|
|
||||||
#define IOCTL_CMD_SEND _IOW('c', 'c', int32_t *)
|
|
||||||
#define IOCTL_CMD_SETPC _IOW('p', 'p', int32_t *)
|
|
||||||
#define IOCTL_CMD_SYNC_TO_HOST_RAM 'V'
|
|
||||||
#define IOCTL_CMD_SPI_TEST '1'
|
|
||||||
#define IOCTL_CMD_PRL_TEST '2'
|
|
||||||
#define IOCTL_CMD_Z80_MEMTEST '3'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Chip Select map MZ80K-MZ700.
|
|
||||||
//
|
|
||||||
// 0000 - 0FFF = CS_ROMni : R/W : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
|
||||||
// 1000 - CFFF = CS_RAMni : R/W : MZ80K/A/700 = RAM
|
|
||||||
// C000 - CFFF = CS_ROMni : R/W : MZ80A = Monitor ROM (MZ80A rom swap)
|
|
||||||
// D000 - D7FF = CS_VRAMni : R/W : MZ80K/A/700 = VRAM
|
|
||||||
// D800 - DFFF = CS_VRAMni : R/W : MZ700 = Colour VRAM (MZ700)
|
|
||||||
// E000 - E003 = CS_8255n : R/W : MZ80K/A/700 = 8255
|
|
||||||
// E004 - E007 = CS_8254n : R/W : MZ80K/A/700 = 8254
|
|
||||||
// E008 - E00B = CS_LS367n : R/W : MZ80K/A/700 = LS367
|
|
||||||
// E00C - E00F = CS_ESWPn : R : MZ80A = Memory Swap (MZ80A)
|
|
||||||
// E010 - E013 = CS_ESWPn : R : MZ80A = Reset Memory Swap (MZ80A)
|
|
||||||
// E014 = CS_E5n : R/W : MZ80A/700 = Normal CRT display (in Video Controller)
|
|
||||||
// E015 = CS_E6n : R/W : MZ80A/700 = Reverse CRT display (in Video Controller)
|
|
||||||
// E200 - E2FF = : R/W : MZ80A/700 = VRAM roll up/roll down.
|
|
||||||
// E800 - EFFF = : R/W : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
|
||||||
// F000 - F7FF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
|
||||||
// F800 - FFFF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
|
||||||
//
|
|
||||||
// Chip Select map MZ800
|
|
||||||
//
|
|
||||||
// FC - FF = CS_PIOn : R/W : MZ800/MZ1500 = Z80 PIO Printer Interface
|
|
||||||
// F2 = CS_PSG0n : W : MZ800/MZ1500 = Programable Sound Generator, MZ-800 = Mono, MZ-1500 = Left Channel
|
|
||||||
// F3 = CS_PSG1n : W : MZ1500 = Programable Sound Generator, MZ-1500 = Right Channel
|
|
||||||
// E9 = CS_PSG(X)n: W : MZ1500 = Simultaneous write to both PSG's.
|
|
||||||
// F0 - F1 = CS_JOYSTK : R : MZ800 = Joystick 1 and 2
|
|
||||||
// CC = CS_GWF : W : MZ800 = CRTC GWF Write format Register
|
|
||||||
// CD = CS_GRF : W : MZ800 = CRTC GRF Read format Register
|
|
||||||
// CE = CS_GDMD : W : MZ800 = CRTC GDMD Mode Register
|
|
||||||
// CF = CS_GCRTC : W : MZ800 = CRTC GCRTC Control Register
|
|
||||||
// D4 - D7 = CS
|
|
||||||
// D000 - DFFF
|
|
||||||
|
|
||||||
// MZ700/MZ800 memory mode switch?
|
|
||||||
//
|
|
||||||
// MZ-700 MZ-800
|
|
||||||
// |0000:0FFF|1000:1FFF|1000:CFFF|C000:CFFF|D000:FFFF |0000:7FFF|1000:1FFF|2000:7FFF|8000:BFFF|C000:CFFF|C000:DFFF|E000:FFFF
|
|
||||||
// -------------------------------------------------- ----------------------------------------------------------------------
|
|
||||||
// OUT 0xE0 = |DRAM | | | | |DRAM | | | | | |
|
|
||||||
// OUT 0xE1 = | | | | |DRAM | | | | | | |DRAM
|
|
||||||
// OUT 0xE2 = |MONITOR | | | | |MONITOR | | | | | |
|
|
||||||
// OUT 0xE3 = | | | | |Memory Mapped I/O | | | | | | |Upper MONITOR ROM
|
|
||||||
// OUT 0xE4 = |MONITOR | |DRAM | |Memory Mapped I/O |MONITOR |CGROM |DRAM |VRAM | |DRAM |Upper MONITOR ROM
|
|
||||||
// OUT 0xE5 = | | | | |Inhibit | | | | | | |Inhibit
|
|
||||||
// OUT 0xE6 = | | | | |<return> | | | | | | |<return>
|
|
||||||
// IN 0xE0 = | |CGROM* | |VRAM* | | |CGROM | |VRAM | | |
|
|
||||||
// IN 0xE1 = | |DRAM | |DRAM | | |<return> | |DRAM | | |
|
|
||||||
//
|
|
||||||
// <return> = Return to the state prior to the complimentary command being invoked.
|
|
||||||
// * = MZ-800 host only.
|
|
||||||
|
|
||||||
// Macros to lookup and test to see if a given memory block or IO byte is of a given type. Also macros to read/write to the memory block and IO byte.
|
|
||||||
#define MEMORY_BLOCK_GRANULARITY 0x800
|
|
||||||
#define MEMORY_BLOCK_SLOTS (0x10000 / MEMORY_BLOCK_GRANULARITY)
|
|
||||||
#define MEMORY_BLOCK_MASK (0x10000 - MEMORY_BLOCK_GRANULARITY)
|
|
||||||
#define MEMORY_BLOCK_SHIFT 11
|
|
||||||
#define getPageData(a) (Z80Ctrl->page[(a & 0xF800) >> MEMORY_BLOCK_SHIFT])
|
|
||||||
#define getIOPageData(a) (Z80Ctrl->iopage[(a & 0xFFFF])
|
|
||||||
#define getPageType(a, mask) (getPageData(a) & mask)
|
|
||||||
#define getPageAddr(a, mask) ((getPageData(a) & mask) + (a & (MEMORY_BLOCK_GRANULARITY-1)))
|
|
||||||
#define getIOPageType(a, mask) (getIOPageData(a) & mask)
|
|
||||||
#define getIOPageAddr(a, mask) (getIOPageData(a) & mask)
|
|
||||||
#define realAddress(a) (Z80Ctrl->page[getPageAddr(a, MEMORY_TYPE_REAL_MASK)])
|
|
||||||
#define realPort(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_MASK)
|
|
||||||
#define isPhysicalRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_RAM))
|
|
||||||
#define isPhysicalVRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_VRAM))
|
|
||||||
#define isPhysicalROM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_ROM))
|
|
||||||
#define isPhysicalMemory(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM))])
|
|
||||||
#define isPhysicalHW(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_HW))
|
|
||||||
#define isPhysical(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM)))
|
|
||||||
#define isPhysicalIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_PHYSICAL_HW)
|
|
||||||
#define isVirtualRAM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_RAM))
|
|
||||||
#define isVirtualROM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_ROM))
|
|
||||||
#define isVirtualMemory(a) (getPageType(a, (MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_RAM)))
|
|
||||||
#define isVirtualHW(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_HW))
|
|
||||||
#define isVirtualIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_VIRTUAL_HW)
|
|
||||||
#define isHW(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_VIRTUAL_HW)))
|
|
||||||
#define readVirtualRAM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ])
|
|
||||||
#define readVirtualROM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) + Z80_VIRTUAL_RAM_SIZE ])
|
|
||||||
#define writeVirtualRAM(a, d) { Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ] = d; }
|
|
||||||
#define setMemoryType(_block_,_type_,_addr_) { Z80Ctrl->page[_block_] = _type_ | _addr_; }
|
|
||||||
#define backupMemoryType(_block_) { Z80Ctrl->shadowPage[_block_] = Z80Ctrl->page[_block_]; }
|
|
||||||
#define restoreMemoryType(_block_) { Z80Ctrl->page[_block_] = Z80Ctrl->shadowPage[_block_]; }
|
|
||||||
|
|
||||||
#define IO_ADDR_E0 0xE0
|
|
||||||
#define IO_ADDR_E1 0xE1
|
|
||||||
#define IO_ADDR_E2 0xE2
|
|
||||||
#define IO_ADDR_E3 0xE3
|
|
||||||
#define IO_ADDR_E4 0xE4
|
|
||||||
#define IO_ADDR_E5 0xE5
|
|
||||||
#define IO_ADDR_E6 0xE6
|
|
||||||
#define IO_ADDR_E7 0xE7
|
|
||||||
|
|
||||||
|
|
||||||
enum Z80_RUN_STATES {
|
|
||||||
Z80_STOP = 0x00,
|
|
||||||
Z80_STOPPED = 0x01,
|
|
||||||
Z80_PAUSE = 0x02,
|
|
||||||
Z80_PAUSED = 0x03,
|
|
||||||
Z80_CONTINUE = 0x04,
|
|
||||||
Z80_RUNNING = 0x05,
|
|
||||||
};
|
|
||||||
enum Z80_MEMORY_PROFILE {
|
|
||||||
USE_PHYSICAL_RAM = 0x00,
|
|
||||||
USE_VIRTUAL_RAM = 0x01
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
// Main memory, linear but indexed as though it were banks in 1K pages.
|
|
||||||
uint8_t memory[Z80_VIRTUAL_MEMORY_SIZE];
|
|
||||||
|
|
||||||
// Page pointer map.
|
|
||||||
//
|
|
||||||
// Each pointer points to a byte or block of bytes in the Z80 Memory frame, 64K Real + Banked.
|
|
||||||
// This is currently set at a block of size 0x800 per memory pointer for the MZ-700.
|
|
||||||
// The LSB of the pointer is a direct memory index to a byte or block of bytes, the upper byte of the pointer indicates type of memory space.
|
|
||||||
// 0x80<FFFFFF> - physical host RAM
|
|
||||||
// 0x40<FFFFFF> - physical host ROM
|
|
||||||
// 0x20<FFFFFF> - physical host VRAM
|
|
||||||
// 0x10<FFFFFF> - physical host hardware
|
|
||||||
// 0x08<FFFFFF> - virtual host RAM
|
|
||||||
// 0x04<FFFFFF> - virtual host ROM
|
|
||||||
// 0x02<FFFFFF> - virtual host hardware
|
|
||||||
// 16bit Input Address -> map -> Pointer to 24bit memory address + type flag.
|
|
||||||
// -> Pointer+<low bits of address> to 24bit memory address + type flag.
|
|
||||||
uint32_t page[MEMORY_BLOCK_SLOTS];
|
|
||||||
uint32_t shadowPage[MEMORY_BLOCK_SLOTS];
|
|
||||||
|
|
||||||
// I/O Page map.
|
|
||||||
//
|
|
||||||
// This is a map to indicate the use of the I/O page and allow any required remapping.
|
|
||||||
// <0x80>FF<I/O Address> - physical host hardware
|
|
||||||
// <0x40>FF<I/O Address> - virtual host hardware
|
|
||||||
// 16bit Input Address -> map -> Actual 16bit address to use + type flag.
|
|
||||||
uint32_t iopage[65536];
|
|
||||||
|
|
||||||
// Default page mode configured. This value reflects the default page and iotable map.
|
|
||||||
uint8_t defaultPageMode;
|
|
||||||
|
|
||||||
// Refresh DRAM mode. 1 = Refresh, 0 = No refresh. Only applicable when running code in virtual Kernel RAM.
|
|
||||||
uint8_t refreshDRAM;
|
|
||||||
|
|
||||||
// Inhibit mode is where certain memory ranges are inhibitted. The memory page is set to inhibit and this flag
|
|
||||||
// blocks actions which arent allowed during inhibit.
|
|
||||||
uint8_t inhibitMode;
|
|
||||||
|
|
||||||
// Address caching. Used to minimise instruction length sent to CPLD.
|
|
||||||
uint16_t z80PrevAddr;
|
|
||||||
uint16_t z80PrevPort;
|
|
||||||
|
|
||||||
// Keyboard strobe and data. Required to detect hotkey press.
|
|
||||||
uint8_t keyportStrobe;
|
|
||||||
uint8_t keyportShiftCtrl;
|
|
||||||
uint8_t keyportHotKey;
|
|
||||||
|
|
||||||
// Governor is the delay in a 32bit loop per Z80 opcode, used to govern execution speed when using virtual memory.
|
|
||||||
// This mechanism will eventually be tied into the M/T-state calculation for a more precise delay, but at the moment,
|
|
||||||
// with the Z80 assigned to an isolated CPU, it allows time sensitive tasks such as the tape recorder to work.
|
|
||||||
// The lower the value the faster the CPU speed.
|
|
||||||
uint32_t cpuGovernorDelay;
|
|
||||||
} t_Z80Ctrl;
|
|
||||||
|
|
||||||
// IOCTL structure for passing data from user space to driver to perform commands.
|
|
||||||
//
|
|
||||||
struct z80_addr {
|
|
||||||
uint32_t start;
|
|
||||||
uint32_t end;
|
|
||||||
uint32_t size;
|
|
||||||
};
|
|
||||||
struct z80_ctrl {
|
|
||||||
uint16_t pc;
|
|
||||||
};
|
|
||||||
struct speed {
|
|
||||||
uint32_t speedMultiplier;
|
|
||||||
};
|
|
||||||
struct cpld_ctrl {
|
|
||||||
uint32_t cmd;
|
|
||||||
};
|
|
||||||
struct ioctlCmd {
|
|
||||||
int32_t cmd;
|
|
||||||
union {
|
|
||||||
struct z80_addr addr;
|
|
||||||
struct z80_ctrl z80;
|
|
||||||
struct speed speed;
|
|
||||||
struct cpld_ctrl cpld;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Prototypes.
|
|
||||||
void setupMemory(enum Z80_MEMORY_PROFILE mode);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,428 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80io.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 IO Interface
|
|
||||||
// This file contains the methods used in interfacing the SOM to the Z80 socket
|
|
||||||
// and host hardware via a CPLD.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
//#include <stdio.h>
|
|
||||||
//#include <stdlib.h>
|
|
||||||
//#include <string.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <asm/uaccess.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/time.h>
|
|
||||||
#include "z80io.h"
|
|
||||||
|
|
||||||
#include <gpio_table.h>
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include <infinity2m/gpio.h>
|
|
||||||
#include <infinity2m/registers.h>
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// User space driver access.
|
|
||||||
//
|
|
||||||
//-------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Initialise the SOM hardware used to communicate with the z80 socket and host hardware.
|
|
||||||
// The SOM interfaces to a CPLD which provides voltage level translation and also encapsulates the Z80 timing cycles as recreating
|
|
||||||
// them within the SOM is much more tricky.
|
|
||||||
//
|
|
||||||
// As this is an embedded device and performance/latency are priorities, minimal structured code is used to keep call stack and
|
|
||||||
// generated code to a mimimum without relying on the optimiser.
|
|
||||||
int z80io_init(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
// Initialise GPIO. We call the HAL api to minimise time but for actual bit set/reset and read we go directly to registers to save time, increase throughput and minimise latency.
|
|
||||||
// Initialise the HAL.
|
|
||||||
MHal_GPIO_Init();
|
|
||||||
|
|
||||||
// Set the pads as GPIO devices. The HAL takes care of allocating and deallocating the padmux resources.
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_0); // Word (16bit) bidirectional bus. Default is read with data set.
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_HIGH_BYTE);
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO8); // SPIO 4wire control lines setup by the spidev driver but controlled directly in this driver.
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO9);
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO10);
|
|
||||||
//MHal_GPIO_Pad_Set(PAD_GPIO11);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_READY);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_LTSTATE);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSRQ);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSACK);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_INT);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_NMI);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WAIT);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RESET);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RSV1);
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_0);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WRITE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set required input pads.
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_0);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_READY);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_LTSTATE);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSRQ);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSACK);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_INT);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_NMI);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_WAIT);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RESET);
|
|
||||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RSV1);
|
|
||||||
|
|
||||||
// Set required output pads.
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_0);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_1);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_2);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_3);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_4);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_5);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_6);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_7);
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_WRITE);
|
|
||||||
MHal_GPIO_Pull_High(PAD_Z80IO_WRITE);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Control signals.
|
|
||||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_HIGH_BYTE);
|
|
||||||
MHal_GPIO_Pull_High(PAD_Z80IO_HIGH_BYTE);
|
|
||||||
|
|
||||||
// Setup the MSPI0 device.
|
|
||||||
//
|
|
||||||
// Setup control, interrupts are not used.
|
|
||||||
MSPI_WRITE(MSPI_CTRL_OFFSET, MSPI_CPU_CLOCK_1_2 | MSPI_CTRL_CPOL_LOW | MSPI_CTRL_CPHA_HIGH | MSPI_CTRL_RESET | MSPI_CTRL_ENABLE_SPI);
|
|
||||||
|
|
||||||
// Setup LSB First mode.
|
|
||||||
MSPI_WRITE(MSPI_LSB_FIRST_OFFSET, 0x0);
|
|
||||||
|
|
||||||
// Setup clock.
|
|
||||||
CLK_WRITE(MSPI0_CLK_CFG, 0x1100)
|
|
||||||
|
|
||||||
// Setup the frame size (all buffers to 8bits).
|
|
||||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET, 0xfff);
|
|
||||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET+1, 0xfff);
|
|
||||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET, 0xfff);
|
|
||||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET+1, 0xfff);
|
|
||||||
|
|
||||||
// Setup Chip Selects to inactive.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Switch Video and Audio to host.
|
|
||||||
z80io_SPI_Send16(0x00f0, NULL);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Parallel bus Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
|
|
||||||
// Methods to read data from the parallel bus.
|
|
||||||
// The CPLD returns status and Z80 data on the 8bit bus as it is marginally quicker than retrieving it over the SPI bus.
|
|
||||||
//
|
|
||||||
inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint8_t result = 0;
|
|
||||||
|
|
||||||
// Byte according to flag.
|
|
||||||
if(dataFlag)
|
|
||||||
SET_CPLD_READ_DATA()
|
|
||||||
else
|
|
||||||
SET_CPLD_READ_STATUS()
|
|
||||||
|
|
||||||
// Read the input registers and set value accordingly.
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
|
|
||||||
// Return 16bit value read from CPLD.
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint16_t z80io_PRL_Read16(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint16_t result = 0;
|
|
||||||
|
|
||||||
// Low byte first.
|
|
||||||
CLEAR_CPLD_HIGH_BYTE();
|
|
||||||
|
|
||||||
// Read the input registers and set value accordingly.
|
|
||||||
result = (uint16_t)READ_CPLD_DATA_IN();
|
|
||||||
|
|
||||||
// High byte next.
|
|
||||||
SET_CPLD_HIGH_BYTE();
|
|
||||||
|
|
||||||
// Read the input registers and set value accordingly.
|
|
||||||
result |= (uint16_t)(READ_CPLD_DATA_IN() << 8);
|
|
||||||
|
|
||||||
// Return 16bit value read from CPLD.
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Parallel Bus methods were tried and tested but due to the GPIO bits being controlled by individual registers per bit, the setup time was longer
|
|
||||||
// than the transmission time of SPI. These methods are thus deprecated and a fusion of SPI and 8bit parallel is now used.
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
inline uint8_t z80io_PRL_Send8(uint8_t txData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Low byte only.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
|
||||||
|
|
||||||
// Setup data.
|
|
||||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
|
||||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
|
||||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
|
||||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
|
||||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
|
||||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
|
||||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
|
||||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
|
||||||
|
|
||||||
// Clock data.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint8_t z80io_PRL_Send16(uint16_t txData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Low byte first.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
|
||||||
|
|
||||||
// Setup data.
|
|
||||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
|
||||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
|
||||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
|
||||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
|
||||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
|
||||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
|
||||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
|
||||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
|
||||||
|
|
||||||
// Clock data.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
|
||||||
|
|
||||||
// High byte next.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
|
||||||
|
|
||||||
// Setup high byte.
|
|
||||||
if(txData & 0x8000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
|
||||||
if(txData & 0x4000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
|
||||||
if(txData & 0x2000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
|
||||||
if(txData & 0x1000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
|
||||||
if(txData & 0x0800) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
|
||||||
if(txData & 0x0400) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
|
||||||
if(txData & 0x0200) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
|
||||||
if(txData & 0x0100) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
|
||||||
|
|
||||||
// Clock data.
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
|
||||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// SPI Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
|
|
||||||
// Methods to send 8,16 or 32 bits. Each method is seperate to minimise logic and execution time, 8bit being most sensitive.
|
|
||||||
// Macros have also been defined for inline inclusion which dont read back the response data.
|
|
||||||
//
|
|
||||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint32_t timeout = MAX_CHECK_CNT;
|
|
||||||
|
|
||||||
// Insert data into write buffers.
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1);
|
|
||||||
|
|
||||||
// Enable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
|
||||||
|
|
||||||
// Send.
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
|
||||||
|
|
||||||
// Wait for completion.
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
|
||||||
{
|
|
||||||
if(--timeout == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Clear flag.
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
|
||||||
|
|
||||||
// Fetch data.
|
|
||||||
if(rxData != NULL) *rxData = (uint8_t)MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
|
||||||
|
|
||||||
// Done.
|
|
||||||
return(timeout == 0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint32_t timeout = MAX_CHECK_CNT;
|
|
||||||
|
|
||||||
// Insert data into write buffers.
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, txData);
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2);
|
|
||||||
|
|
||||||
// Enable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
|
||||||
|
|
||||||
// Send.
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
|
||||||
|
|
||||||
// Wait for completion.
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
|
||||||
{
|
|
||||||
if(--timeout == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Clear flag.
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
|
||||||
|
|
||||||
// Fetch data.
|
|
||||||
if(rxData != NULL) *rxData = MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
|
||||||
|
|
||||||
// Done.
|
|
||||||
return(timeout == 0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint32_t timeout = MAX_CHECK_CNT;
|
|
||||||
|
|
||||||
// Insert data into write buffers.
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)(txData >> 16));
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4);
|
|
||||||
|
|
||||||
// Enable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
|
||||||
|
|
||||||
// Send.
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
|
||||||
|
|
||||||
// Wait for completion.
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
|
||||||
{
|
|
||||||
if(--timeout == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disable SPI select.
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
|
||||||
|
|
||||||
// Clear flag.
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
|
||||||
|
|
||||||
// Fetch data.
|
|
||||||
if(rxData != NULL) *rxData = (uint32_t)(MSPI_READ(MSPI_FULL_DEPLUX_RD00) | (MSPI_READ(MSPI_FULL_DEPLUX_RD02) << 16));
|
|
||||||
|
|
||||||
// Done.
|
|
||||||
return(timeout == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Test Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
#ifdef INCLUDE_TEST_METHODS
|
|
||||||
#include "z80io_test.c"
|
|
||||||
#else
|
|
||||||
uint8_t z80io_Z80_TestMemory(void)
|
|
||||||
{
|
|
||||||
pr_info("Z80 Test Memory functionality not built-in.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_SPI_Test(void)
|
|
||||||
{
|
|
||||||
pr_info("SPI Test functionality not built-in.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
uint8_t z80io_PRL_Test(void)
|
|
||||||
{
|
|
||||||
pr_info("Parallel Bus Test functionality not built-in.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
483
software/FusionX/src/z80drv/MZ700/z80io.h
vendored
483
software/FusionX/src/z80drv/MZ700/z80io.h
vendored
@@ -1,483 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80io.h
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 IO Interface
|
|
||||||
// This file contains the declarations used in interfacing the SOM to the Z80 socket
|
|
||||||
// and host hardware via a CPLD.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifndef Z80IO_H
|
|
||||||
#define Z80IO_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Definitions to control compilation.
|
|
||||||
#define INCLUDE_TEST_METHODS 1
|
|
||||||
|
|
||||||
// CPLD Commands.
|
|
||||||
#define CPLD_CMD_FETCH_ADDR 0x10
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P1 0x11
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P2 0x12
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P3 0x13
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P4 0x14
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P5 0x15
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P6 0x16
|
|
||||||
#define CPLD_CMD_FETCH_ADDR_P7 0x17
|
|
||||||
#define CPLD_CMD_WRITE_ADDR 0x18
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P1 0x19
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P2 0x1A
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P3 0x1B
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P4 0x1C
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P5 0x1D
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P6 0x1E
|
|
||||||
#define CPLD_CMD_WRITE_ADDR_P7 0x1F
|
|
||||||
#define CPLD_CMD_READ_ADDR 0x20
|
|
||||||
#define CPLD_CMD_READ_ADDR_P1 0x21
|
|
||||||
#define CPLD_CMD_READ_ADDR_P2 0x22
|
|
||||||
#define CPLD_CMD_READ_ADDR_P3 0x23
|
|
||||||
#define CPLD_CMD_READ_ADDR_P4 0x24
|
|
||||||
#define CPLD_CMD_READ_ADDR_P5 0x25
|
|
||||||
#define CPLD_CMD_READ_ADDR_P6 0x26
|
|
||||||
#define CPLD_CMD_READ_ADDR_P7 0x27
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR 0x28
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P1 0x29
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P2 0x2A
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P3 0x2B
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P4 0x2C
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P5 0x2D
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P6 0x2E
|
|
||||||
#define CPLD_CMD_WRITEIO_ADDR_P7 0x2F
|
|
||||||
#define CPLD_CMD_READIO_ADDR 0x30
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P1 0x31
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P2 0x32
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P3 0x33
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P4 0x34
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
|
||||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
|
||||||
#define CPLD_CMD_HALT 0x50
|
|
||||||
#define CPLD_CMD_REFRESH 0x51
|
|
||||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
|
||||||
#define CPLD_CMD_SET_AUTO_REFRESH 0xF1
|
|
||||||
#define CPLD_CMD_CLEAR_AUTO_REFRESH 0xF2
|
|
||||||
#define CPLD_CMD_SET_SPI_LOOPBACK 0xFE
|
|
||||||
#define CPLD_CMD_NOP1 0x00
|
|
||||||
#define CPLD_CMD_NOP2 0xFF
|
|
||||||
|
|
||||||
|
|
||||||
// Pad numbers for using the MHal GPIO library.
|
|
||||||
#define PAD_Z80IO_IN_DATA_0 PAD_GPIO0
|
|
||||||
#define PAD_Z80IO_IN_DATA_1 PAD_GPIO1
|
|
||||||
#define PAD_Z80IO_IN_DATA_2 PAD_GPIO2
|
|
||||||
#define PAD_Z80IO_IN_DATA_3 PAD_GPIO3
|
|
||||||
#define PAD_Z80IO_IN_DATA_4 PAD_GPIO4
|
|
||||||
#define PAD_Z80IO_IN_DATA_5 PAD_GPIO5
|
|
||||||
#define PAD_Z80IO_IN_DATA_6 PAD_GPIO6
|
|
||||||
#define PAD_Z80IO_IN_DATA_7 PAD_GPIO7
|
|
||||||
#define PAD_SPIO_0 PAD_GPIO8
|
|
||||||
#define PAD_SPIO_1 PAD_GPIO9
|
|
||||||
#define PAD_SPIO_2 PAD_GPIO10
|
|
||||||
#define PAD_SPIO_3 PAD_GPIO11
|
|
||||||
#define PAD_Z80IO_HIGH_BYTE PAD_SAR_GPIO2 // Byte requiured, 0 = Low Byte, 1 = High Byte.
|
|
||||||
#define PAD_Z80IO_READY PAD_GPIO12
|
|
||||||
#define PAD_Z80IO_LTSTATE PAD_PM_IRIN // IRIN
|
|
||||||
#define PAD_Z80IO_BUSRQ PAD_GPIO13
|
|
||||||
#define PAD_Z80IO_BUSACK PAD_GPIO14
|
|
||||||
#define PAD_Z80IO_INT PAD_UART0_RX // GPIO47
|
|
||||||
#define PAD_Z80IO_NMI PAD_UART0_TX // GPIO48
|
|
||||||
#define PAD_Z80IO_WAIT PAD_HSYNC_OUT // GPIO85
|
|
||||||
#define PAD_Z80IO_RESET PAD_VSYNC_OUT // GPIO86
|
|
||||||
#define PAD_Z80IO_RSV1 PAD_SATA_GPIO // GPIO90
|
|
||||||
|
|
||||||
// Physical register addresses.
|
|
||||||
#define PAD_Z80IO_IN_DATA_0_ADDR 0x103C00
|
|
||||||
#define PAD_Z80IO_IN_DATA_1_ADDR 0x103C02
|
|
||||||
#define PAD_Z80IO_IN_DATA_2_ADDR 0x103C04
|
|
||||||
#define PAD_Z80IO_IN_DATA_3_ADDR 0x103C06
|
|
||||||
#define PAD_Z80IO_IN_DATA_4_ADDR 0x103C08
|
|
||||||
#define PAD_Z80IO_IN_DATA_5_ADDR 0x103C0A
|
|
||||||
#define PAD_Z80IO_IN_DATA_6_ADDR 0x103C0C
|
|
||||||
#define PAD_Z80IO_IN_DATA_7_ADDR 0x103C0E
|
|
||||||
#define PAD_SPIO_0_ADDR 0x103C10
|
|
||||||
#define PAD_SPIO_1_ADDR 0x103C12
|
|
||||||
#define PAD_SPIO_2_ADDR 0x103C14
|
|
||||||
#define PAD_SPIO_3_ADDR 0x103C16
|
|
||||||
#define PAD_Z80IO_HIGH_BYTE_ADDR 0x1425
|
|
||||||
#define PAD_Z80IO_READY_ADDR 0x103C18
|
|
||||||
#define PAD_Z80IO_LTSTATE_ADDR 0xF28 // IRIN
|
|
||||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
|
||||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
|
||||||
#define PAD_Z80IO_INT_ADDR 0x103C30 // GPIO47
|
|
||||||
#define PAD_Z80IO_NMI_ADDR 0x103C32 // GPIO48
|
|
||||||
#define PAD_Z80IO_WAIT_ADDR 0x103C80 // GPIO85
|
|
||||||
#define PAD_Z80IO_RESET_ADDR 0x103C82 // GPIO86
|
|
||||||
#define PAD_Z80IO_RSV1_ADDR 0x103C8A // GPIO90
|
|
||||||
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
#define PAD_Z80IO_OUT_DATA_0 PAD_GPIO12
|
|
||||||
#define PAD_Z80IO_OUT_DATA_1 PAD_GPIO13
|
|
||||||
#define PAD_Z80IO_OUT_DATA_2 PAD_GPIO14
|
|
||||||
#define PAD_Z80IO_OUT_DATA_3 PAD_UART0_RX // GPIO47
|
|
||||||
#define PAD_Z80IO_OUT_DATA_4 PAD_UART0_TX // GPIO48
|
|
||||||
#define PAD_Z80IO_OUT_DATA_5 PAD_HSYNC_OUT // GPIO85
|
|
||||||
#define PAD_Z80IO_OUT_DATA_6 PAD_VSYNC_OUT // GPIO86
|
|
||||||
#define PAD_Z80IO_OUT_DATA_7 PAD_SATA_GPIO // GPIO90
|
|
||||||
#define PAD_Z80IO_WRITE PAD_PM_IRIN // Write data clock.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
// The definitions below come from SigmaStar kernel drivers. No header file exists hence the
|
|
||||||
// duplication.
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
#define SUPPORT_SPI_1 0
|
|
||||||
#define MAX_SUPPORT_BITS 16
|
|
||||||
|
|
||||||
#define BANK_TO_ADDR32(b) (b<<9)
|
|
||||||
#define BANK_SIZE 0x200
|
|
||||||
|
|
||||||
#define MS_BASE_REG_RIU_PA 0x1F000000
|
|
||||||
#define gChipBaseAddr 0xFD203C00
|
|
||||||
#define gPmSleepBaseAddr 0xFD001C00
|
|
||||||
#define gSarBaseAddr 0xFD002800
|
|
||||||
#define gRIUBaseAddr 0xFD000000
|
|
||||||
#define gMOVDMAAddr 0xFD201600
|
|
||||||
#define gClkBaseAddr 0xFD207000
|
|
||||||
#define gMspBaseAddr 0xfd222000
|
|
||||||
|
|
||||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
|
|
||||||
|
|
||||||
#define MSPI0_BANK_ADDR 0x1110
|
|
||||||
#define MSPI1_BANK_ADDR 0x1111
|
|
||||||
#define CLK__BANK_ADDR 0x1038
|
|
||||||
#define CHIPTOP_BANK_ADDR 0x101E
|
|
||||||
#define MOVDMA_BANK_ADDR 0x100B
|
|
||||||
|
|
||||||
#define BASE_REG_MSPI0_ADDR MSPI0_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111000)
|
|
||||||
#define BASE_REG_MSPI1_ADDR MSPI1_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111100)
|
|
||||||
#define BASE_REG_CLK_ADDR CLK__BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x103800)
|
|
||||||
#define BASE_REG_CHIPTOP_ADDR CHIPTOP_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x101E00)
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
// Hardware Register Capability
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
#define MSPI_WRITE_BUF_OFFSET 0x40
|
|
||||||
#define MSPI_READ_BUF_OFFSET 0x44
|
|
||||||
#define MSPI_WBF_SIZE_OFFSET 0x48
|
|
||||||
#define MSPI_RBF_SIZE_OFFSET 0x48
|
|
||||||
// read/ write buffer size
|
|
||||||
#define MSPI_RWSIZE_MASK 0xFF
|
|
||||||
#define MSPI_RSIZE_BIT_OFFSET 0x8
|
|
||||||
#define MAX_READ_BUF_SIZE 0x8
|
|
||||||
#define MAX_WRITE_BUF_SIZE 0x8
|
|
||||||
// CLK config
|
|
||||||
#define MSPI_CTRL_OFFSET 0x49
|
|
||||||
#define MSPI_CLK_CLOCK_OFFSET 0x49
|
|
||||||
#define MSPI_CLK_CLOCK_BIT_OFFSET 0x08
|
|
||||||
#define MSPI_CLK_CLOCK_MASK 0xFF
|
|
||||||
#define MSPI_CLK_PHASE_MASK 0x40
|
|
||||||
#define MSPI_CLK_PHASE_BIT_OFFSET 0x06
|
|
||||||
#define MSPI_CLK_POLARITY_MASK 0x80
|
|
||||||
#define MSPI_CLK_POLARITY_BIT_OFFSET 0x07
|
|
||||||
#define MSPI_CLK_PHASE_MAX 0x1
|
|
||||||
#define MSPI_CLK_POLARITY_MAX 0x1
|
|
||||||
#define MSPI_CLK_CLOCK_MAX 0x7
|
|
||||||
#define MSPI_CTRL_CPOL_LOW 0x00
|
|
||||||
#define MSPI_CTRL_CPOL_HIGH 0x80
|
|
||||||
#define MSPI_CTRL_CPHA_LOW 0x00
|
|
||||||
#define MSPI_CTRL_CPHA_HIGH 0x40
|
|
||||||
#define MSPI_CTRL_3WIRE 0x10
|
|
||||||
#define MSPI_CTRL_INTEN 0x04
|
|
||||||
#define MSPI_CTRL_RESET 0x02
|
|
||||||
#define MSPI_CTRL_ENABLE_SPI 0x01
|
|
||||||
// DC config
|
|
||||||
#define MSPI_DC_MASK 0xFF
|
|
||||||
#define MSPI_DC_BIT_OFFSET 0x08
|
|
||||||
#define MSPI_DC_TR_START_OFFSET 0x4A
|
|
||||||
#define MSPI_DC_TRSTART_MAX 0xFF
|
|
||||||
#define MSPI_DC_TR_END_OFFSET 0x4A
|
|
||||||
#define MSPI_DC_TREND_MAX 0xFF
|
|
||||||
#define MSPI_DC_TB_OFFSET 0x4B
|
|
||||||
#define MSPI_DC_TB_MAX 0xFF
|
|
||||||
#define MSPI_DC_TRW_OFFSET 0x4B
|
|
||||||
#define MSPI_DC_TRW_MAX 0xFF
|
|
||||||
// Frame Config
|
|
||||||
#define MSPI_FRAME_WBIT_OFFSET 0x4C
|
|
||||||
#define MSPI_FRAME_RBIT_OFFSET 0x4E
|
|
||||||
#define MSPI_FRAME_BIT_MAX 0x07
|
|
||||||
#define MSPI_FRAME_BIT_MASK 0x07
|
|
||||||
#define MSPI_FRAME_BIT_FIELD 0x03
|
|
||||||
#define MSPI_LSB_FIRST_OFFSET 0x50
|
|
||||||
#define MSPI_TRIGGER_OFFSET 0x5A
|
|
||||||
#define MSPI_DONE_OFFSET 0x5B
|
|
||||||
#define MSPI_DONE_CLEAR_OFFSET 0x5C
|
|
||||||
#define MSPI_CHIP_SELECT_OFFSET 0x5F
|
|
||||||
#define MSPI_CS1_DISABLE 0x01
|
|
||||||
#define MSPI_CS1_ENABLE 0x00
|
|
||||||
#define MSPI_CS2_DISABLE 0x02
|
|
||||||
#define MSPI_CS2_ENABLE 0x00
|
|
||||||
#define MSPI_CS3_DISABLE 0x04
|
|
||||||
#define MSPI_CS3_ENABLE 0x00
|
|
||||||
#define MSPI_CS4_DISABLE 0x08
|
|
||||||
#define MSPI_CS4_ENABLE 0x00
|
|
||||||
#define MSPI_CS5_DISABLE 0x10
|
|
||||||
#define MSPI_CS5_ENABLE 0x00
|
|
||||||
#define MSPI_CS6_DISABLE 0x20
|
|
||||||
#define MSPI_CS6_ENABLE 0x00
|
|
||||||
#define MSPI_CS7_DISABLE 0x40
|
|
||||||
#define MSPI_CS7_ENABLE 0x00
|
|
||||||
#define MSPI_CS8_DISABLE 0x80
|
|
||||||
#define MSPI_CS8_ENABLE 0x00
|
|
||||||
|
|
||||||
#define MSPI_FULL_DEPLUX_RD_CNT (0x77)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD00 (0x78)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD01 (0x78)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD02 (0x79)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD03 (0x79)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD04 (0x7a)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD05 (0x7a)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD06 (0x7b)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD07 (0x7b)
|
|
||||||
|
|
||||||
#define MSPI_FULL_DEPLUX_RD08 (0x7c)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD09 (0x7c)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD10 (0x7d)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD11 (0x7d)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD12 (0x7e)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD13 (0x7e)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD14 (0x7f)
|
|
||||||
#define MSPI_FULL_DEPLUX_RD15 (0x7f)
|
|
||||||
|
|
||||||
//chip select bit map
|
|
||||||
#define MSPI_CHIP_SELECT_MAX 0x07
|
|
||||||
|
|
||||||
// control bit
|
|
||||||
#define MSPI_DONE_FLAG 0x01
|
|
||||||
#define MSPI_TRIGGER 0x01
|
|
||||||
#define MSPI_CLEAR_DONE 0x01
|
|
||||||
#define MSPI_INT_ENABLE 0x04
|
|
||||||
#define MSPI_RESET 0x02
|
|
||||||
#define MSPI_ENABLE 0x01
|
|
||||||
|
|
||||||
// clk_mspi0
|
|
||||||
#define MSPI0_CLK_CFG 0x33 //bit 2 ~bit 3
|
|
||||||
#define MSPI0_CLK_108M 0x00
|
|
||||||
#define MSPI0_CLK_54M 0x04
|
|
||||||
#define MSPI0_CLK_12M 0x08
|
|
||||||
#define MSPI0_CLK_MASK 0x0F
|
|
||||||
|
|
||||||
// clk_mspi1
|
|
||||||
#define MSPI1_CLK_CFG 0x33 //bit 10 ~bit 11
|
|
||||||
#define MSPI1_CLK_108M 0x0000
|
|
||||||
#define MSPI1_CLK_54M 0x0400
|
|
||||||
#define MSPI1_CLK_12M 0x0800
|
|
||||||
#define MSPI1_CLK_MASK 0x0F00
|
|
||||||
|
|
||||||
// clk_mspi
|
|
||||||
#define MSPI_CLK_CFG 0x33
|
|
||||||
#define MSPI_SELECT_0 0x0000
|
|
||||||
#define MSPI_SELECT_1 0x4000
|
|
||||||
#define MSPI_CLK_MASK 0xF000
|
|
||||||
|
|
||||||
// Clock settings
|
|
||||||
#define MSPI_CPU_CLOCK_1_2 0x0000
|
|
||||||
#define MSPI_CPU_CLOCK_1_4 0x0100
|
|
||||||
#define MSPI_CPU_CLOCK_1_8 0x0200
|
|
||||||
#define MSPI_CPU_CLOCK_1_16 0x0300
|
|
||||||
#define MSPI_CPU_CLOCK_1_32 0x0400
|
|
||||||
#define MSPI_CPU_CLOCK_1_64 0x0500
|
|
||||||
#define MSPI_CPU_CLOCK_1_128 0x0600
|
|
||||||
#define MSPI_CPU_CLOCK_1_256 0x0700
|
|
||||||
|
|
||||||
//CHITOP 101E mspi mode select
|
|
||||||
#define MSPI0_MODE 0x0C //bit0~bit1
|
|
||||||
#define MSPI0_MODE_MASK 0x07
|
|
||||||
#define MSPI1_MODE 0x0C //bit4~bit5
|
|
||||||
#define MSPI1_MODE_MASK 0x70
|
|
||||||
#define EJTAG_MODE 0xF
|
|
||||||
#define EJTAG_MODE_1 0x01
|
|
||||||
#define EJTAG_MODE_2 0x02
|
|
||||||
#define EJTAG_MODE_3 0x03
|
|
||||||
#define EJTAG_MODE_MASK 0x03
|
|
||||||
|
|
||||||
//MOVDMA 100B
|
|
||||||
#define MOV_DMA_SRC_ADDR_L 0x03
|
|
||||||
#define MOV_DMA_SRC_ADDR_H 0x04
|
|
||||||
#define MOV_DMA_DST_ADDR_L 0x05
|
|
||||||
#define MOV_DMA_DST_ADDR_H 0x06
|
|
||||||
#define MOV_DMA_BYTE_CNT_L 0x07
|
|
||||||
#define MOV_DMA_BYTE_CNT_H 0x08
|
|
||||||
#define DMA_MOVE0_IRQ_CLR 0x28
|
|
||||||
#define MOV_DMA_IRQ_FINAL_STATUS 0x2A
|
|
||||||
#define DMA_MOVE0_ENABLE 0x00
|
|
||||||
#define DMA_RW 0x50 //0 for dma write to device, 1 for dma read from device
|
|
||||||
#define DMA_READ 0x01
|
|
||||||
#define DMA_WRITE 0x00
|
|
||||||
#define DMA_DEVICE_MODE 0x51
|
|
||||||
#define DMA_DEVICE_SEL 0x52
|
|
||||||
|
|
||||||
//spi dma
|
|
||||||
#define MSPI_DMA_DATA_LENGTH_L 0x30
|
|
||||||
#define MSPI_DMA_DATA_LENGTH_H 0x31
|
|
||||||
#define MSPI_DMA_ENABLE 0x32
|
|
||||||
#define MSPI_DMA_RW_MODE 0x33
|
|
||||||
#define MSPI_DMA_WRITE 0x00
|
|
||||||
#define MSPI_DMA_READ 0x01
|
|
||||||
|
|
||||||
#define MSTAR_SPI_TIMEOUT_MS 30000
|
|
||||||
#define MSTAR_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA /*| SPI_CS_HIGH | SPI_NO_CS | SPI_LSB_FIRST*/)
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
// Macros
|
|
||||||
//-------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
|
||||||
#define READ_BYTE(_reg) (*(volatile u8*)(_reg))
|
|
||||||
#define READ_WORD(_reg) (*(volatile u16*)(_reg))
|
|
||||||
#define READ_LONG(_reg) (*(volatile u32*)(_reg))
|
|
||||||
#define WRITE_BYTE(_reg, _val) {(*((volatile u8*)(_reg))) = (u8)(_val); }
|
|
||||||
#define WRITE_WORD(_reg, _val) {(*((volatile u16*)(_reg))) = (u16)(_val); }
|
|
||||||
#define WRITE_LONG(_reg, _val) {(*((volatile u32*)(_reg))) = (u32)(_val); }
|
|
||||||
#define WRITE_WORD_MASK(_reg, _val, _mask) {(*((volatile u16*)(_reg))) = ((*((volatile u16*)(_reg))) & ~(_mask)) | ((u16)(_val) & (_mask)); }
|
|
||||||
#define READ_CPLD_DATA_IN() ((MHal_RIU_REG(PAD_Z80IO_IN_DATA_7_ADDR) & 0x1) << 7 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_6_ADDR) & 0x1) << 6 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_5_ADDR) & 0x1) << 5 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_4_ADDR) & 0x1) << 4 |\
|
|
||||||
(MHal_RIU_REG(PAD_Z80IO_IN_DATA_3_ADDR) & 0x1) << 3 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_2_ADDR) & 0x1) << 2 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_1_ADDR) & 0x1) << 1 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_0_ADDR) & 0x1))
|
|
||||||
#define SET_CPLD_READ_DATA() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
|
||||||
#define SET_CPLD_READ_STATUS() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
|
||||||
#define SET_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
|
||||||
#define CLEAR_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
|
||||||
#define CPLD_READY() (MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1)
|
|
||||||
#define CPLD_RESET() (MHal_RIU_REG(PAD_Z80IO_RESET_ADDR) & 0x1)
|
|
||||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
|
||||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
|
||||||
}
|
|
||||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
|
||||||
}
|
|
||||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
|
||||||
}
|
|
||||||
|
|
||||||
// read 2 byte
|
|
||||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
|
||||||
// write 2 byte
|
|
||||||
//#define MSPI_WRITE(_reg_, _val_) {pr_info("PDS: MSPI_WRITE(0x%x, 0x%x, 0x%x)\n", _reg_, _val_, gMspBaseAddr + ((_reg_)<<2)); WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define MSPI_WRITE(_reg_, _val_) WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_));
|
|
||||||
//write 2 byte mask
|
|
||||||
//#define MSPI_WRITE_MASK(_reg_, _val_, mask) {pr_info("PDS: WRITE_LONG(0x%x, 0x%x, mask=0x%x)\n", _reg_, _val_, mask); WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask)); }
|
|
||||||
#define MSPI_WRITE_MASK(_reg_, _val_, mask) WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask));
|
|
||||||
|
|
||||||
#define CLK_READ(_reg_) READ_WORD(gClkBaseAddr + ((_reg_)<<2))
|
|
||||||
//#define CLK_WRITE(_reg_, _val_) {pr_info("PDS: CLK_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define CLK_WRITE(_reg_, _val_) WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_));
|
|
||||||
|
|
||||||
#define CHIPTOP_READ(_reg_) READ_WORD(gChipBaseAddr + ((_reg_)<<2))
|
|
||||||
//#define CHIPTOP_WRITE(_reg_, _val_) {pr_info("PDS: CHIPTOP_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define CHIPTOP_WRITE(_reg_, _val_) WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_));
|
|
||||||
|
|
||||||
#define MOVDMA_READ(_reg_) READ_WORD(gMOVDMAAddr + ((_reg_)<<2))
|
|
||||||
//#define MOVDMA_WRITE(_reg_, _val_) {pr_info("PDS: MOVDMA_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_)); }
|
|
||||||
#define MOVDMA_WRITE(_reg_, _val_) WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_));
|
|
||||||
|
|
||||||
#define _HAL_MSPI_ClearDone() MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET,MSPI_CLEAR_DONE)
|
|
||||||
#define MAX_CHECK_CNT 2000
|
|
||||||
|
|
||||||
#define MSPI_READ_INDEX 0x0
|
|
||||||
#define MSPI_WRITE_INDEX 0x1
|
|
||||||
|
|
||||||
#define SPI_MIU0_BUS_BASE 0x20000000
|
|
||||||
#define SPI_MIU1_BUS_BASE 0xFFFFFFFF
|
|
||||||
|
|
||||||
|
|
||||||
// Function definitions.
|
|
||||||
//
|
|
||||||
int z80io_init(void);
|
|
||||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData);
|
|
||||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData);
|
|
||||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData);
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
uint8_t z80io_PRL_Send8(uint8_t txData);
|
|
||||||
uint8_t z680io_PRL_Send16(uint16_t txData);
|
|
||||||
#endif
|
|
||||||
uint8_t z80io_PRL_Read8(uint8_t dataFlag);
|
|
||||||
uint16_t z80io_PRL_Read16(void);
|
|
||||||
uint8_t z80io_SPI_Test(void);
|
|
||||||
uint8_t z80io_PRL_Test(void);
|
|
||||||
uint8_t z80io_Z80_TestMemory(void);
|
|
||||||
|
|
||||||
extern void MHal_GPIO_Init(void);
|
|
||||||
extern void MHal_GPIO_Pad_Set(uint8_t u8IndexGPIO);
|
|
||||||
extern int MHal_GPIO_PadGroupMode_Set(uint32_t u32PadMode);
|
|
||||||
extern int MHal_GPIO_PadVal_Set(uint8_t u8IndexGPIO, uint32_t u32PadMode);
|
|
||||||
extern void MHal_GPIO_Pad_Oen(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Pad_Odn(uint8_t u8IndexGPIO);
|
|
||||||
extern uint8_t MHal_GPIO_Pad_Level(uint8_t u8IndexGPIO);
|
|
||||||
extern uint8_t MHal_GPIO_Pad_InOut(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Pull_High(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Pull_Low(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Set_High(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Set_Low(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_Enable_GPIO_INT(uint8_t u8IndexGPIO);
|
|
||||||
extern int MHal_GPIO_To_Irq(uint8_t u8IndexGPIO);
|
|
||||||
extern void MHal_GPIO_Set_POLARITY(uint8_t u8IndexGPIO, uint8_t reverse);
|
|
||||||
extern void MHal_GPIO_Set_Driving(uint8_t u8IndexGPIO, uint8_t setHigh);
|
|
||||||
extern void MHal_GPIO_PAD_32K_OUT(uint8_t u8Enable);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif // Z80IO_H
|
|
||||||
@@ -1,541 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80io_test.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 IO Interface Test Methods
|
|
||||||
// This file contains the methods used to test the SOM to CPLD interface and evaluate
|
|
||||||
// it's performance. Production builds wont include these methods.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/semaphore.h>
|
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
|
|
||||||
//--------------------------------------------------------
|
|
||||||
// Test Methods.
|
|
||||||
//--------------------------------------------------------
|
|
||||||
uint8_t z80io_Z80_TestMemory(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t fullCmd;
|
|
||||||
uint8_t cmd;
|
|
||||||
struct timeval start, stop;
|
|
||||||
uint32_t iterations = 100;
|
|
||||||
uint32_t errorCount;
|
|
||||||
uint32_t idx;
|
|
||||||
long totalTime;
|
|
||||||
long bytesMSec;
|
|
||||||
uint8_t result;
|
|
||||||
spinlock_t spinLock;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
SPI_SEND8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
|
||||||
|
|
||||||
SPI_SEND32(0x00E30000 | (0x07 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E80000 | (0x82 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E20000 | (0x58 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E00000 | (0xF7 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00E90000 | (0x0F << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00EB0000 | (0xCF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
SPI_SEND32(0x00EB0000 | (0xFF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
udelay(100);
|
|
||||||
pr_info("Z80 Host Test - IO.\n");
|
|
||||||
for(idx=0; idx < 1000000; idx++)
|
|
||||||
{
|
|
||||||
SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
SPI_SEND32(0xD0000000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
SPI_SEND32(0xD0100000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
SPI_SEND32(0xD0200000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
SPI_SEND32(0xD0300000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
SPI_SEND32(0xD0400000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
SPI_SEND32(0xD0500000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_lock_init(&spinLock);
|
|
||||||
pr_info("Z80 Host Test - Testing IO Write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
for(addr=0x0000; addr < 0x10000; addr++)
|
|
||||||
{
|
|
||||||
fullCmd = 0x00000000| ((uint8_t)addr) << 8 | CPLD_CMD_WRITEIO_ADDR;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
spin_lock_init(&spinLock);
|
|
||||||
pr_info("Z80 Host Test - Testing IO Read performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible IO ports and write to it.
|
|
||||||
for(addr=0x0000; addr < 0x10000; addr++)
|
|
||||||
{
|
|
||||||
fullCmd = 0x00000000 | ((uint8_t)addr) << 8 | CPLD_CMD_READIO_ADDR;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
spin_lock_init(&spinLock);
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write performance (opt).\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
spin_lock_irqsave(&spinLock, flags);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x1000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&spinLock, flags);
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write/Fetch performance (opt).\n");
|
|
||||||
errorCount = 0;
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x8000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x8000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read back the same byte.
|
|
||||||
cmd = 0x10;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
if(result != (uint8_t)addr)
|
|
||||||
{
|
|
||||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Write/Read performance (opt).\n");
|
|
||||||
errorCount = 0;
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and write to it.
|
|
||||||
for(addr=0x8000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x8000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read back the same byte.
|
|
||||||
cmd = 0x20;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
if(result != (uint8_t)addr)
|
|
||||||
{
|
|
||||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Fetch performance.\n");
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and read from it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x1000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x10;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x11;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Z80 Host Test - Testing RAM Read performance (opt).\n");
|
|
||||||
SET_CPLD_READ_DATA();
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible RAM and read from it.
|
|
||||||
for(addr=0x1000; addr < 0xD000; addr++)
|
|
||||||
{
|
|
||||||
if(addr == 0x1000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x20;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x21;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
while(CPLD_READY() == 0);
|
|
||||||
result = READ_CPLD_DATA_IN();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// Go through all the accessible attribute VRAM and initialise it.
|
|
||||||
pr_info("Z80 Host Test - Testing VRAM Write performance.\n");
|
|
||||||
SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
|
||||||
iterations = 256*10;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(addr=0xD800; addr < 0xE000; addr++)
|
|
||||||
{
|
|
||||||
//while(CPLD_READY() == 0);
|
|
||||||
if(addr == 0xD800)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) |(0x71 << 8) | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Go through all the accessible VRAM and write to it.
|
|
||||||
for(addr=0xD000; addr < 0xD800; addr++)
|
|
||||||
{
|
|
||||||
//while(CPLD_READY() == 0);
|
|
||||||
if(addr == 0xD000)
|
|
||||||
{
|
|
||||||
fullCmd = (addr << 16) | ((uint8_t)idx << 8) | 0x18;
|
|
||||||
SPI_SEND32(fullCmd);
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
cmd = 0x19;
|
|
||||||
SPI_SEND8(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)((1*iterations*0x800)+0x800)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// A simple test to verify the SOM to CPLD SPI connectivity and give an estimate of its performance.
|
|
||||||
// The performance is based on the SPI setup and transmit time along with the close and received data processing.
|
|
||||||
// In real use, the driver will just send a command and generally ignore received data so increased throughput can be achieved.
|
|
||||||
//
|
|
||||||
uint8_t z80io_SPI_Test(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
struct timeval start, stop;
|
|
||||||
uint32_t iterations = 10000000;
|
|
||||||
uint32_t idx;
|
|
||||||
uint8_t rxData8;
|
|
||||||
uint16_t rxData16;
|
|
||||||
uint16_t rxData16Last;
|
|
||||||
uint32_t rxData32;
|
|
||||||
uint32_t rxData32Last;
|
|
||||||
uint32_t errorCount;
|
|
||||||
long totalTime;
|
|
||||||
long bytesMSec;
|
|
||||||
|
|
||||||
// Place the CPLD into echo test mode.
|
|
||||||
z80io_SPI_Send8(0xfe, &rxData8);
|
|
||||||
|
|
||||||
// 1st. test, 8bit.
|
|
||||||
pr_info("SPI Test - Testing 8 bit performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
z80io_SPI_Send8((uint8_t)idx, &rxData8);
|
|
||||||
if(idx > 1 && (uint8_t)(idx-1) != rxData8)
|
|
||||||
{
|
|
||||||
if(errorCount < 20)
|
|
||||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint8_t)(idx-1), rxData8 );
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(1*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 2nd. test, 16bit.
|
|
||||||
pr_info("SPI Test - Testing 16 bit performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
|
||||||
z80io_SPI_Send16((uint16_t)idx, &rxData16);
|
|
||||||
if(idx > 0 && (uint16_t)(idx-1) != (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)))
|
|
||||||
{
|
|
||||||
if(errorCount < 20)
|
|
||||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint16_t)(idx-1), (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)));
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
rxData16Last = rxData16;
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 3rd. test, 32bit.
|
|
||||||
pr_info("SPI Test - Testing 32 bit performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
z80io_SPI_Send32((uint32_t)idx, &rxData32);
|
|
||||||
if(idx > 0 && (uint32_t)(idx-1) != (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)))
|
|
||||||
{
|
|
||||||
if(errorCount < 20)
|
|
||||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint32_t)(idx-1), (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)));
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
rxData32Last = rxData32;
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(4*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method to test the parallel bus, verifying integrity and assessing performance.
|
|
||||||
uint8_t z80io_PRL_Test(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
//
|
|
||||||
struct timeval start, stop;
|
|
||||||
uint32_t iterations = 10000000;
|
|
||||||
uint32_t idx;
|
|
||||||
uint8_t rxData8;
|
|
||||||
uint16_t rxData16;
|
|
||||||
long totalTime;
|
|
||||||
long bytesMSec;
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
uint32_t errorCount;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Place the CPLD into echo test mode.
|
|
||||||
|
|
||||||
// 1st. test, 8bit RW.
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
pr_info("Parallel Test - Testing 8 bit r/w performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Write byte and readback to compare.
|
|
||||||
z80io_PRL_Send8((uint8_t)idx);
|
|
||||||
rxData8 = z80io_PRL_Read8();
|
|
||||||
if((uint8_t)idx != rxData8)
|
|
||||||
{
|
|
||||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint8_t)(idx), rxData8);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 2nd. test, 8bit Write.
|
|
||||||
pr_info("Parallel Test - Testing 8 bit write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Write byte.
|
|
||||||
z80io_PRL_Send8((uint8_t)idx);
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 3rd. test, 8bit Read.
|
|
||||||
pr_info("Parallel Test - Testing 8 bit read performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Read byte.
|
|
||||||
rxData8 = z80io_PRL_Read8(0);
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
#ifdef NOTNEEDED
|
|
||||||
// 4th test, 16bit.
|
|
||||||
pr_info("Parallel Test - Testing 16 bit r/w performance.\n");
|
|
||||||
errorCount=0;
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
|
||||||
z80io_PRL_Send16((uint16_t)idx);
|
|
||||||
rxData16 = z80io_PRL_Read16();
|
|
||||||
if((uint16_t)idx != rxData16)
|
|
||||||
{
|
|
||||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint16_t)(idx), rxData16);
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
// 5th test, 16bit Write.
|
|
||||||
pr_info("Parallel Test - Testing 16 bit write performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Write word.
|
|
||||||
z80io_PRL_Send16((uint16_t)idx);
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 6th test, 16bit Read.
|
|
||||||
pr_info("Parallel Test - Testing 16 bit read performance.\n");
|
|
||||||
do_gettimeofday(&start);
|
|
||||||
for(idx=0; idx < iterations; idx++)
|
|
||||||
{
|
|
||||||
// Read word.
|
|
||||||
rxData16 = z80io_PRL_Read16();
|
|
||||||
}
|
|
||||||
do_gettimeofday(&stop);
|
|
||||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
|
||||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
|
||||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
|
||||||
|
|
||||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80menu.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 User Menu
|
|
||||||
// This file contains the methods used to present a menu of options to a user to aid
|
|
||||||
// in configuration and load/save of applications and data.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <asm/uaccess.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/time.h>
|
|
||||||
#include "z80io.h"
|
|
||||||
#include "z80menu.h"
|
|
||||||
|
|
||||||
#include <gpio_table.h>
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include <infinity2m/gpio.h>
|
|
||||||
#include <infinity2m/registers.h>
|
|
||||||
|
|
||||||
void z80menu(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
|
|
||||||
}
|
|
||||||
44
software/FusionX/src/z80drv/MZ700/z80menu.h
vendored
44
software/FusionX/src/z80drv/MZ700/z80menu.h
vendored
@@ -1,44 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80menu.h
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 User Interface Menu
|
|
||||||
// This file contains the declarations required to provide a menu system allowing a
|
|
||||||
// user to configure and load/save applications/data.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifndef Z80MENU_H
|
|
||||||
#define Z80MENU_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Function definitions.
|
|
||||||
//
|
|
||||||
void z80menu(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif // Z80MENU_H
|
|
||||||
403
software/FusionX/src/z80drv/MZ80A/optparse.h
vendored
403
software/FusionX/src/z80drv/MZ80A/optparse.h
vendored
@@ -1,403 +0,0 @@
|
|||||||
/* Optparse --- portable, reentrant, embeddable, getopt-like option parser
|
|
||||||
*
|
|
||||||
* This is free and unencumbered software released into the public domain.
|
|
||||||
*
|
|
||||||
* To get the implementation, define OPTPARSE_IMPLEMENTATION.
|
|
||||||
* Optionally define OPTPARSE_API to control the API's visibility
|
|
||||||
* and/or linkage (static, __attribute__, __declspec).
|
|
||||||
*
|
|
||||||
* The POSIX getopt() option parser has three fatal flaws. These flaws
|
|
||||||
* are solved by Optparse.
|
|
||||||
*
|
|
||||||
* 1) Parser state is stored entirely in global variables, some of
|
|
||||||
* which are static and inaccessible. This means only one thread can
|
|
||||||
* use getopt(). It also means it's not possible to recursively parse
|
|
||||||
* nested sub-arguments while in the middle of argument parsing.
|
|
||||||
* Optparse fixes this by storing all state on a local struct.
|
|
||||||
*
|
|
||||||
* 2) The POSIX standard provides no way to properly reset the parser.
|
|
||||||
* This means for portable code that getopt() is only good for one
|
|
||||||
* run, over one argv with one option string. It also means subcommand
|
|
||||||
* options cannot be processed with getopt(). Most implementations
|
|
||||||
* provide a method to reset the parser, but it's not portable.
|
|
||||||
* Optparse provides an optparse_arg() function for stepping over
|
|
||||||
* subcommands and continuing parsing of options with another option
|
|
||||||
* string. The Optparse struct itself can be passed around to
|
|
||||||
* subcommand handlers for additional subcommand option parsing. A
|
|
||||||
* full reset can be achieved by with an additional optparse_init().
|
|
||||||
*
|
|
||||||
* 3) Error messages are printed to stderr. This can be disabled with
|
|
||||||
* opterr, but the messages themselves are still inaccessible.
|
|
||||||
* Optparse solves this by writing an error message in its errmsg
|
|
||||||
* field. The downside to Optparse is that this error message will
|
|
||||||
* always be in English rather than the current locale.
|
|
||||||
*
|
|
||||||
* Optparse should be familiar with anyone accustomed to getopt(), and
|
|
||||||
* it could be a nearly drop-in replacement. The option string is the
|
|
||||||
* same and the fields have the same names as the getopt() global
|
|
||||||
* variables (optarg, optind, optopt).
|
|
||||||
*
|
|
||||||
* Optparse also supports GNU-style long options with optparse_long().
|
|
||||||
* The interface is slightly different and simpler than getopt_long().
|
|
||||||
*
|
|
||||||
* By default, argv is permuted as it is parsed, moving non-option
|
|
||||||
* arguments to the end. This can be disabled by setting the `permute`
|
|
||||||
* field to 0 after initialization.
|
|
||||||
*/
|
|
||||||
#ifndef OPTPARSE_H
|
|
||||||
#define OPTPARSE_H
|
|
||||||
|
|
||||||
#ifndef OPTPARSE_API
|
|
||||||
# define OPTPARSE_API
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct optparse {
|
|
||||||
char **argv;
|
|
||||||
int permute;
|
|
||||||
int optind;
|
|
||||||
int optopt;
|
|
||||||
char *optarg;
|
|
||||||
char errmsg[64];
|
|
||||||
int subopt;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum optparse_argtype {
|
|
||||||
OPTPARSE_NONE,
|
|
||||||
OPTPARSE_REQUIRED,
|
|
||||||
OPTPARSE_OPTIONAL
|
|
||||||
};
|
|
||||||
|
|
||||||
struct optparse_long {
|
|
||||||
const char *longname;
|
|
||||||
int shortname;
|
|
||||||
enum optparse_argtype argtype;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the parser state.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
void optparse_init(struct optparse *options, char **argv);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the next option in the argv array.
|
|
||||||
* @param optstring a getopt()-formatted option string.
|
|
||||||
* @return the next option character, -1 for done, or '?' for error
|
|
||||||
*
|
|
||||||
* Just like getopt(), a character followed by no colons means no
|
|
||||||
* argument. One colon means the option has a required argument. Two
|
|
||||||
* colons means the option takes an optional argument.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
int optparse(struct optparse *options, const char *optstring);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles GNU-style long options in addition to getopt() options.
|
|
||||||
* This works a lot like GNU's getopt_long(). The last option in
|
|
||||||
* longopts must be all zeros, marking the end of the array. The
|
|
||||||
* longindex argument may be NULL.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
int optparse_long(struct optparse *options,
|
|
||||||
const struct optparse_long *longopts,
|
|
||||||
int *longindex);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used for stepping over non-option arguments.
|
|
||||||
* @return the next non-option argument, or NULL for no more arguments
|
|
||||||
*
|
|
||||||
* Argument parsing can continue with optparse() after using this
|
|
||||||
* function. That would be used to parse the options for the
|
|
||||||
* subcommand returned by optparse_arg(). This function allows you to
|
|
||||||
* ignore the value of optind.
|
|
||||||
*/
|
|
||||||
OPTPARSE_API
|
|
||||||
char *optparse_arg(struct optparse *options);
|
|
||||||
|
|
||||||
/* Implementation */
|
|
||||||
#ifdef OPTPARSE_IMPLEMENTATION
|
|
||||||
|
|
||||||
#define OPTPARSE_MSG_INVALID "invalid option"
|
|
||||||
#define OPTPARSE_MSG_MISSING "option requires an argument"
|
|
||||||
#define OPTPARSE_MSG_TOOMANY "option takes no arguments"
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_error(struct optparse *options, const char *msg, const char *data)
|
|
||||||
{
|
|
||||||
unsigned p = 0;
|
|
||||||
const char *sep = " -- '";
|
|
||||||
while (*msg)
|
|
||||||
options->errmsg[p++] = *msg++;
|
|
||||||
while (*sep)
|
|
||||||
options->errmsg[p++] = *sep++;
|
|
||||||
while (p < sizeof(options->errmsg) - 2 && *data)
|
|
||||||
options->errmsg[p++] = *data++;
|
|
||||||
options->errmsg[p++] = '\'';
|
|
||||||
options->errmsg[p++] = '\0';
|
|
||||||
return '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
void
|
|
||||||
optparse_init(struct optparse *options, char **argv)
|
|
||||||
{
|
|
||||||
options->argv = argv;
|
|
||||||
options->permute = 1;
|
|
||||||
options->optind = 1;
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optarg = 0;
|
|
||||||
options->errmsg[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_is_dashdash(const char *arg)
|
|
||||||
{
|
|
||||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_is_shortopt(const char *arg)
|
|
||||||
{
|
|
||||||
return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_is_longopt(const char *arg)
|
|
||||||
{
|
|
||||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
optparse_permute(struct optparse *options, int index)
|
|
||||||
{
|
|
||||||
char *nonoption = options->argv[index];
|
|
||||||
int i;
|
|
||||||
for (i = index; i < options->optind - 1; i++)
|
|
||||||
options->argv[i] = options->argv[i + 1];
|
|
||||||
options->argv[options->optind - 1] = nonoption;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_argtype(const char *optstring, char c)
|
|
||||||
{
|
|
||||||
int count = OPTPARSE_NONE;
|
|
||||||
if (c == ':')
|
|
||||||
return -1;
|
|
||||||
for (; *optstring && c != *optstring; optstring++);
|
|
||||||
if (!*optstring)
|
|
||||||
return -1;
|
|
||||||
if (optstring[1] == ':')
|
|
||||||
count += optstring[2] == ':' ? 2 : 1;
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
int
|
|
||||||
optparse(struct optparse *options, const char *optstring)
|
|
||||||
{
|
|
||||||
int type;
|
|
||||||
char *next;
|
|
||||||
char *option = options->argv[options->optind];
|
|
||||||
options->errmsg[0] = '\0';
|
|
||||||
options->optopt = 0;
|
|
||||||
options->optarg = 0;
|
|
||||||
if (option == 0) {
|
|
||||||
return -1;
|
|
||||||
} else if (optparse_is_dashdash(option)) {
|
|
||||||
options->optind++; /* consume "--" */
|
|
||||||
return -1;
|
|
||||||
} else if (!optparse_is_shortopt(option)) {
|
|
||||||
if (options->permute) {
|
|
||||||
int index = options->optind++;
|
|
||||||
int r = optparse(options, optstring);
|
|
||||||
optparse_permute(options, index);
|
|
||||||
options->optind--;
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
option += options->subopt + 1;
|
|
||||||
options->optopt = option[0];
|
|
||||||
type = optparse_argtype(optstring, option[0]);
|
|
||||||
next = options->argv[options->optind + 1];
|
|
||||||
switch (type) {
|
|
||||||
case -1: {
|
|
||||||
char str[2] = {0, 0};
|
|
||||||
str[0] = option[0];
|
|
||||||
options->optind++;
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_INVALID, str);
|
|
||||||
}
|
|
||||||
case OPTPARSE_NONE:
|
|
||||||
if (option[1]) {
|
|
||||||
options->subopt++;
|
|
||||||
} else {
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optind++;
|
|
||||||
}
|
|
||||||
return option[0];
|
|
||||||
case OPTPARSE_REQUIRED:
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optind++;
|
|
||||||
if (option[1]) {
|
|
||||||
options->optarg = option + 1;
|
|
||||||
} else if (next != 0) {
|
|
||||||
options->optarg = next;
|
|
||||||
options->optind++;
|
|
||||||
} else {
|
|
||||||
char str[2] = {0, 0};
|
|
||||||
str[0] = option[0];
|
|
||||||
options->optarg = 0;
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_MISSING, str);
|
|
||||||
}
|
|
||||||
return option[0];
|
|
||||||
case OPTPARSE_OPTIONAL:
|
|
||||||
options->subopt = 0;
|
|
||||||
options->optind++;
|
|
||||||
if (option[1])
|
|
||||||
options->optarg = option + 1;
|
|
||||||
else
|
|
||||||
options->optarg = 0;
|
|
||||||
return option[0];
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
char *
|
|
||||||
optparse_arg(struct optparse *options)
|
|
||||||
{
|
|
||||||
char *option = options->argv[options->optind];
|
|
||||||
options->subopt = 0;
|
|
||||||
if (option != 0)
|
|
||||||
options->optind++;
|
|
||||||
return option;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_longopts_end(const struct optparse_long *longopts, int i)
|
|
||||||
{
|
|
||||||
return !longopts[i].longname && !longopts[i].shortname;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
optparse_from_long(const struct optparse_long *longopts, char *optstring)
|
|
||||||
{
|
|
||||||
char *p = optstring;
|
|
||||||
int i;
|
|
||||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
|
||||||
if (longopts[i].shortname && longopts[i].shortname < 127) {
|
|
||||||
int a;
|
|
||||||
*p++ = longopts[i].shortname;
|
|
||||||
for (a = 0; a < (int)longopts[i].argtype; a++)
|
|
||||||
*p++ = ':';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unlike strcmp(), handles options containing "=". */
|
|
||||||
static int
|
|
||||||
optparse_longopts_match(const char *longname, const char *option)
|
|
||||||
{
|
|
||||||
const char *a = option, *n = longname;
|
|
||||||
if (longname == 0)
|
|
||||||
return 0;
|
|
||||||
for (; *a && *n && *a != '='; a++, n++)
|
|
||||||
if (*a != *n)
|
|
||||||
return 0;
|
|
||||||
return *n == '\0' && (*a == '\0' || *a == '=');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the part after "=", or NULL. */
|
|
||||||
static char *
|
|
||||||
optparse_longopts_arg(char *option)
|
|
||||||
{
|
|
||||||
for (; *option && *option != '='; option++);
|
|
||||||
if (*option == '=')
|
|
||||||
return option + 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
optparse_long_fallback(struct optparse *options,
|
|
||||||
const struct optparse_long *longopts,
|
|
||||||
int *longindex)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
|
|
||||||
optparse_from_long(longopts, optstring);
|
|
||||||
result = optparse(options, optstring);
|
|
||||||
if (longindex != 0) {
|
|
||||||
*longindex = -1;
|
|
||||||
if (result != -1) {
|
|
||||||
int i;
|
|
||||||
for (i = 0; !optparse_longopts_end(longopts, i); i++)
|
|
||||||
if (longopts[i].shortname == options->optopt)
|
|
||||||
*longindex = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTPARSE_API
|
|
||||||
int
|
|
||||||
optparse_long(struct optparse *options,
|
|
||||||
const struct optparse_long *longopts,
|
|
||||||
int *longindex)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *option = options->argv[options->optind];
|
|
||||||
if (option == 0) {
|
|
||||||
return -1;
|
|
||||||
} else if (optparse_is_dashdash(option)) {
|
|
||||||
options->optind++; /* consume "--" */
|
|
||||||
return -1;
|
|
||||||
} else if (optparse_is_shortopt(option)) {
|
|
||||||
return optparse_long_fallback(options, longopts, longindex);
|
|
||||||
} else if (!optparse_is_longopt(option)) {
|
|
||||||
if (options->permute) {
|
|
||||||
int index = options->optind++;
|
|
||||||
int r = optparse_long(options, longopts, longindex);
|
|
||||||
optparse_permute(options, index);
|
|
||||||
options->optind--;
|
|
||||||
return r;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse as long option. */
|
|
||||||
options->errmsg[0] = '\0';
|
|
||||||
options->optopt = 0;
|
|
||||||
options->optarg = 0;
|
|
||||||
option += 2; /* skip "--" */
|
|
||||||
options->optind++;
|
|
||||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
|
||||||
const char *name = longopts[i].longname;
|
|
||||||
if (optparse_longopts_match(name, option)) {
|
|
||||||
char *arg;
|
|
||||||
if (longindex)
|
|
||||||
*longindex = i;
|
|
||||||
options->optopt = longopts[i].shortname;
|
|
||||||
arg = optparse_longopts_arg(option);
|
|
||||||
if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
|
|
||||||
} if (arg != 0) {
|
|
||||||
options->optarg = arg;
|
|
||||||
} else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
|
|
||||||
options->optarg = options->argv[options->optind];
|
|
||||||
if (options->optarg == 0)
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_MISSING, name);
|
|
||||||
else
|
|
||||||
options->optind++;
|
|
||||||
}
|
|
||||||
return options->optopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return optparse_error(options, OPTPARSE_MSG_INVALID, option);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* OPTPARSE_IMPLEMENTATION */
|
|
||||||
#endif /* OPTPARSE_H */
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80menu.c
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 User Menu
|
|
||||||
// This file contains the methods used to present a menu of options to a user to aid
|
|
||||||
// in configuration and load/save of applications and data.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/fs.h>
|
|
||||||
#include <linux/mm.h>
|
|
||||||
#include <asm/uaccess.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/string.h>
|
|
||||||
#include <linux/kthread.h>
|
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/time.h>
|
|
||||||
#include "z80io.h"
|
|
||||||
#include "z80menu.h"
|
|
||||||
|
|
||||||
#include <gpio_table.h>
|
|
||||||
#include <asm/io.h>
|
|
||||||
#include <infinity2m/gpio.h>
|
|
||||||
#include <infinity2m/registers.h>
|
|
||||||
|
|
||||||
void z80menu(void)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
|
|
||||||
}
|
|
||||||
44
software/FusionX/src/z80drv/MZ80A/z80menu.h
vendored
44
software/FusionX/src/z80drv/MZ80A/z80menu.h
vendored
@@ -1,44 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Name: z80menu.h
|
|
||||||
// Created: Oct 2022
|
|
||||||
// Author(s): Philip Smart
|
|
||||||
// Description: Z80 User Interface Menu
|
|
||||||
// This file contains the declarations required to provide a menu system allowing a
|
|
||||||
// user to configure and load/save applications/data.
|
|
||||||
// Credits:
|
|
||||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
|
||||||
//
|
|
||||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
|
||||||
//
|
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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/>.
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifndef Z80MENU_H
|
|
||||||
#define Z80MENU_H
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Function definitions.
|
|
||||||
//
|
|
||||||
void z80menu(void);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif // Z80MENU_H
|
|
||||||
59
software/FusionX/src/z80drv/Makefile
vendored
59
software/FusionX/src/z80drv/Makefile
vendored
@@ -1,14 +1,16 @@
|
|||||||
#MODEL := MZ2000
|
#MODEL := MZ2000
|
||||||
#MODEL := MZ700
|
#MODEL := MZ700
|
||||||
MODEL := MZ80A
|
#MODEL := MZ80A
|
||||||
|
#MODEL := PCW8XXX
|
||||||
|
#MODEL := PCW9XXX
|
||||||
KERNEL := $(PWD)/../../../linux/kernel
|
KERNEL := $(PWD)/../../../linux/kernel
|
||||||
FUSIONX := $(PWD)/../..
|
FUSIONX := $(PWD)/../..
|
||||||
CROSS := arm-linux-gnueabihf-
|
CROSS := arm-linux-gnueabihf-
|
||||||
ccflags-y += -O2 -I${src}/Zeta/API -I${src}/Z80/API -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__
|
ccflags-y = -O2 -I${src}/Zeta/API -I${src}/Z80/API -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__ -DTARGET_HOST_$(MODEL)=1
|
||||||
CTRLINC += -IZeta/API -IZ80/API
|
CTRLINC = -IZeta/API -IZ80/API -DTARGET_HOST_$(MODEL)=1
|
||||||
|
|
||||||
obj-m += z80drv.o
|
obj-m += z80drv.o
|
||||||
z80drv-objs += $(MODEL)/z80driver.o Z80.o $(MODEL)/z80io.o $(MODEL)/z80menu.o # emumz.o sharpmz.o osd.o
|
z80drv-objs += src/z80driver.o Z80.o src/z80io.o src/z80menu.o # emumz.o sharpmz.o osd.o
|
||||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/gpio_table.o
|
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/gpio_table.o
|
||||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_gpio.o
|
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_gpio.o
|
||||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
||||||
@@ -16,25 +18,68 @@ z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables
|
|||||||
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
@echo "Specify target host, ie. make <host>"
|
||||||
|
@echo "Supported hosts: MZ80A, MZ700, MZ2000, PCW8XXX, PCW9XXX"
|
||||||
|
|
||||||
|
MZ80A: MODEL_MZ80A
|
||||||
|
MZ700: MODEL_MZ700
|
||||||
|
MZ2000: MODEL_MZ2000
|
||||||
|
PCW8XXX: MODEL_PCW8XXX
|
||||||
|
PCW9XXX: MODEL_PCW9XXX
|
||||||
|
|
||||||
|
MODEL_MZ80A:
|
||||||
|
$(MAKE) MODEL=MZ80A BUILD_MZ80A
|
||||||
|
MODEL_MZ700:
|
||||||
|
$(MAKE) MODEL=MZ700 BUILD_MZ700
|
||||||
|
MODEL_MZ2000:
|
||||||
|
$(MAKE) MODEL=MZ2000 BUILD_MZ2000
|
||||||
|
MODEL_PCW8XXX:
|
||||||
|
$(MAKE) MODEL=PCW8XXX BUILD_PCW8XXX
|
||||||
|
MODEL_PCW9XXX:
|
||||||
|
$(MAKE) MODEL=PCW8XXX BUILD_PCW9XXX
|
||||||
|
|
||||||
|
BUILD_MZ80A: sharpbiter k64fcpu kmod z80ctrl
|
||||||
|
BUILD_MZ700: sharpbiter k64fcpu kmod z80ctrl
|
||||||
|
BUILD_MZ2000: sharpbiter k64fcpu kmod z80ctrl
|
||||||
|
BUILD_PCW8XXX: kmod z80ctrl
|
||||||
|
BUILD_PCW9XXX: kmod z80ctrl
|
||||||
|
|
||||||
|
|
||||||
|
sharpbiter:
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Build Sharp MZ Arbiter for host: $(MODEL)"
|
@echo "Build Sharp MZ Arbiter for host: $(MODEL)"
|
||||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/sharpbiter.c -o sharpbiter
|
$(CROSS)gcc $(CTRLINC) src/sharpbiter.c -o sharpbiter
|
||||||
|
|
||||||
|
k64fcpu:
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Build K64F Daemon for host: $(MODEL)"
|
@echo "Build K64F Daemon for host: $(MODEL)"
|
||||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/k64fcpu.c -o k64fcpu
|
$(CROSS)gcc $(CTRLINC) src/k64fcpu.c -o k64fcpu
|
||||||
|
|
||||||
|
kmod:
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Build driver for host: $(MODEL)"
|
@echo "Build driver for host: $(MODEL)"
|
||||||
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
||||||
|
|
||||||
|
z80ctrl:
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Build z80ctrl tool for host: $(MODEL)"
|
@echo "Build z80ctrl tool for host: $(MODEL)"
|
||||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/z80ctrl.c -o z80ctrl
|
$(CROSS)gcc $(CTRLINC) src/z80ctrl.c -o z80ctrl
|
||||||
|
|
||||||
install:
|
install:
|
||||||
@echo "Copy kernel driver..."
|
@echo "Copy kernel driver..."
|
||||||
@cp z80drv.ko $(FUSIONX)/modules/
|
@cp z80drv.ko $(FUSIONX)/modules/
|
||||||
@echo "Copy z80ctrl app..."
|
@echo "Copy z80ctrl app..."
|
||||||
@cp z80ctrl $(FUSIONX)/bin/
|
@cp z80ctrl $(FUSIONX)/bin/
|
||||||
|
@if [ -f sharpbiter ]; then\
|
||||||
|
echo "Copy sharpbiter app...";\
|
||||||
|
cp sharpbiter $(FUSIONX)/bin/;\
|
||||||
|
fi
|
||||||
|
@if [ -f k64fcpu ]; then\
|
||||||
|
echo "Copy k64fcpu app...";\
|
||||||
|
cp k64fcpu $(FUSIONX)/bin/;\
|
||||||
|
fi
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
make -C $(KERNEL) M=$(PWD) clean
|
make -C $(KERNEL) M=$(PWD) clean
|
||||||
|
@rm -f sharpbiter k64fcpu z80ctrl
|
||||||
|
|
||||||
|
|||||||
2
software/FusionX/src/z80drv/Z80
vendored
2
software/FusionX/src/z80drv/Z80
vendored
Submodule software/FusionX/src/z80drv/Z80 updated: 75d01a9cca...ada1e2921f
6127
software/FusionX/src/z80drv/src/emumz.c
Normal file
6127
software/FusionX/src/z80drv/src/emumz.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -183,16 +183,10 @@ int getch(uint8_t wait)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void delay(int number_of_seconds)
|
// Millisecond delay routine.
|
||||||
|
void delay(int ms_delay)
|
||||||
{
|
{
|
||||||
// Converting time into milli_seconds
|
usleep(1000 * ms_delay);
|
||||||
int milli_seconds = 1000 * number_of_seconds;
|
|
||||||
|
|
||||||
// Storing start time
|
|
||||||
clock_t start_time = clock();
|
|
||||||
|
|
||||||
// looping till required time is not achieved
|
|
||||||
while (clock() < start_time + milli_seconds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to dump out a given section of memory via the UART.
|
// Function to dump out a given section of memory via the UART.
|
||||||
@@ -2799,6 +2793,7 @@ void z80ResetRequest(int signalNo)
|
|||||||
svcCacheDir(TZSVC_DEFAULT_MZF_DIR, MZF, 1);
|
svcCacheDir(TZSVC_DEFAULT_MZF_DIR, MZF, 1);
|
||||||
|
|
||||||
// Start the Z80 after initialisation of the memory.
|
// Start the Z80 after initialisation of the memory.
|
||||||
|
delay(500);
|
||||||
startZ80(TZMM_BOOT);
|
startZ80(TZMM_BOOT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2926,6 +2921,18 @@ int main(int argc, char *argv[])
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup host type, at the moment this is static but as the FusionX progresses and it can be hosted in multiple hosts without firmware change, then we can pull the
|
||||||
|
// host type from the detected hardware.
|
||||||
|
#if (TARGET_HOST_MZ80A == 1)
|
||||||
|
z80Control.hostType = HW_MZ80A;
|
||||||
|
#elif (TARGET_HOST_MZ700 == 1)
|
||||||
|
z80Control.hostType = HW_MZ700;
|
||||||
|
#elif (TARGET_HOST_MZ2000 == 1)
|
||||||
|
z80Control.hostType = HW_MZ2000;
|
||||||
|
#else
|
||||||
|
#error "Unknown host, update code to accommodate."
|
||||||
|
#endif
|
||||||
|
|
||||||
// Register the service request handler.
|
// Register the service request handler.
|
||||||
signal(SIGIO, z80ServiceRequest);
|
signal(SIGIO, z80ServiceRequest);
|
||||||
|
|
||||||
@@ -101,9 +101,15 @@ static t_Z80Ctrl *Z80Ctrl = NULL;
|
|||||||
static uint8_t *Z80RAM = NULL;
|
static uint8_t *Z80RAM = NULL;
|
||||||
static uint8_t *Z80ROM = NULL;
|
static uint8_t *Z80ROM = NULL;
|
||||||
|
|
||||||
|
// Millisecond delay routine.
|
||||||
|
void delay(int ms_delay)
|
||||||
|
{
|
||||||
|
usleep(1000 * ms_delay);
|
||||||
|
}
|
||||||
|
|
||||||
// Method to reset the Z80 CPU.
|
// Method to reset the Z80 CPU.
|
||||||
//
|
//
|
||||||
void reqResetZ80(uint8_t memoryMode)
|
void reqResetZ80(void)
|
||||||
{
|
{
|
||||||
// Locals.
|
// Locals.
|
||||||
//
|
//
|
||||||
@@ -116,7 +122,7 @@ void reqResetZ80(uint8_t memoryMode)
|
|||||||
|
|
||||||
// Method to start the Z80 CPU.
|
// Method to start the Z80 CPU.
|
||||||
//
|
//
|
||||||
void startZ80(uint8_t memoryMode)
|
void startZ80(void)
|
||||||
{
|
{
|
||||||
// Locals.
|
// Locals.
|
||||||
//
|
//
|
||||||
@@ -129,7 +135,7 @@ void startZ80(uint8_t memoryMode)
|
|||||||
|
|
||||||
// Method to stop the Z80 CPU.
|
// Method to stop the Z80 CPU.
|
||||||
//
|
//
|
||||||
void stopZ80(uint8_t memoryMode)
|
void stopZ80(void)
|
||||||
{
|
{
|
||||||
// Locals.
|
// Locals.
|
||||||
//
|
//
|
||||||
@@ -323,12 +329,21 @@ int main(int argc, char *argv[])
|
|||||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||||
|
|
||||||
// Stop the Z80.
|
// Stop the Z80.
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
stopZ80();
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||||
//
|
//
|
||||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||||
|
#if(TARGET_HOST_MZ80A == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ2000 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ700 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#endif
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||||
@@ -336,11 +351,20 @@ int main(int argc, char *argv[])
|
|||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
|
||||||
|
// Add in the required driver.
|
||||||
|
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||||
|
#if(TARGET_HOST_MZ80A == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||||
|
#elif(TARGET_HOST_MZ2000 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||||
|
#elif(TARGET_HOST_MZ700 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||||
|
#endif
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
|
||||||
// Reset and start the Z80.
|
// Reset and start the Z80.
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
delay(500);
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
reqResetZ80();
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOTKEY_RFS80:
|
case HOTKEY_RFS80:
|
||||||
@@ -349,12 +373,21 @@ int main(int argc, char *argv[])
|
|||||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||||
|
|
||||||
// Stop the Z80.
|
// Stop the Z80.
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
stopZ80();
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||||
//
|
//
|
||||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||||
|
#if(TARGET_HOST_MZ80A == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ2000 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ700 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#endif
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||||
@@ -368,10 +401,8 @@ int main(int argc, char *argv[])
|
|||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
|
||||||
// Reset and start the Z80.
|
// Reset and start the Z80.
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
delay(500);
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
reqResetZ80();
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOTKEY_TZFS:
|
case HOTKEY_TZFS:
|
||||||
@@ -379,12 +410,21 @@ int main(int argc, char *argv[])
|
|||||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||||
|
|
||||||
// Stop the Z80.
|
// Stop the Z80.
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
stopZ80();
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
|
|
||||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||||
//
|
//
|
||||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||||
|
#if(TARGET_HOST_MZ80A == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ2000 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ700 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#endif
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||||
@@ -396,12 +436,6 @@ int main(int argc, char *argv[])
|
|||||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
|
||||||
// Reset and start the Z80.
|
|
||||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
// ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
|
||||||
// ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HOTKEY_LINUX:
|
case HOTKEY_LINUX:
|
||||||
@@ -412,6 +446,16 @@ int main(int argc, char *argv[])
|
|||||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||||
//
|
//
|
||||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||||
|
#if(TARGET_HOST_MZ80A == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ2000 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#elif(TARGET_HOST_MZ700 == 1)
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||||
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
|
#endif
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||||
@@ -46,7 +46,13 @@
|
|||||||
#define REFRESH_BYTE_COUNT 8 // This constant controls the number of bytes read/written to the z80 bus before a refresh cycle is needed.
|
#define REFRESH_BYTE_COUNT 8 // This constant controls the number of bytes read/written to the z80 bus before a refresh cycle is needed.
|
||||||
#define RFSH_BYTE_CNT 256 // Number of bytes we can write before needing a full refresh for the DRAM.
|
#define RFSH_BYTE_CNT 256 // Number of bytes we can write before needing a full refresh for the DRAM.
|
||||||
#define HOST_MON_TEST_VECTOR 0x4 // Address in the host monitor to test to identify host type.
|
#define HOST_MON_TEST_VECTOR 0x4 // Address in the host monitor to test to identify host type.
|
||||||
#define OS_BASE_DIR "/apps/FusionX/host/MZ-80A/" // Linux base directory where all the files are stored. On a real tranZPUter this would be the SD card root dir.
|
#if (TARGET_HOST_MZ80A == 1)
|
||||||
|
#define OS_BASE_DIR "/apps/FusionX/host/MZ-80A/" // Linux base directory where all the files are stored. On a real tranZPUter this would be the SD card root dir.
|
||||||
|
#elif (TARGET_HOST_MZ700 == 1)
|
||||||
|
#define OS_BASE_DIR "/apps/FusionX/host/MZ-700/"
|
||||||
|
#elif (TARGET_HOST_MZ2000 == 1)
|
||||||
|
#define OS_BASE_DIR "/apps/FusionX/host/MZ-2000/"
|
||||||
|
#endif
|
||||||
#define TZFS_AUTOBOOT_FLAG OS_BASE_DIR "/TZFSBOOT.FLG" // Filename used as a flag, if this file exists in the base directory then TZFS is booted automatically.
|
#define TZFS_AUTOBOOT_FLAG OS_BASE_DIR "/TZFSBOOT.FLG" // Filename used as a flag, if this file exists in the base directory then TZFS is booted automatically.
|
||||||
#define TZ_MAX_Z80_MEM 0x100000 // Maximum Z80 memory available on the tranZPUter board.
|
#define TZ_MAX_Z80_MEM 0x100000 // Maximum Z80 memory available on the tranZPUter board.
|
||||||
|
|
||||||
@@ -593,6 +593,23 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
|||||||
{
|
{
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||||
}
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "MZ80A") == 0)
|
||||||
|
{
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||||
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "MZ700") == 0)
|
||||||
|
{
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||||
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "MZ2000") == 0)
|
||||||
|
{
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||||
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "PCW") == 0)
|
||||||
|
{
|
||||||
|
printf("Add device:%s\n", (char *)param1);
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_PCW;
|
||||||
|
}
|
||||||
if(ioctlCmd.vdev.device != VIRTUAL_DEVICE_NONE)
|
if(ioctlCmd.vdev.device != VIRTUAL_DEVICE_NONE)
|
||||||
{
|
{
|
||||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||||
@@ -613,6 +630,22 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
|||||||
{
|
{
|
||||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||||
}
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "MZ80A") == 0)
|
||||||
|
{
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||||
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "MZ700") == 0)
|
||||||
|
{
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||||
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "MZ2000") == 0)
|
||||||
|
{
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||||
|
}
|
||||||
|
else if(strcasecmp((char *)param1, "PCW") == 0)
|
||||||
|
{
|
||||||
|
ioctlCmd.vdev.device = VIRTUAL_DEVICE_PCW;
|
||||||
|
}
|
||||||
if(ioctlCmd.vdev.device != VIRTUAL_DEVICE_NONE)
|
if(ioctlCmd.vdev.device != VIRTUAL_DEVICE_NONE)
|
||||||
{
|
{
|
||||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||||
@@ -749,7 +782,7 @@ void showArgs(char *progName, struct optparse *options)
|
|||||||
printf(" # Load contents of binary file into memory at address. default = 0x000000.\n");
|
printf(" # Load contents of binary file into memory at address. default = 0x000000.\n");
|
||||||
printf(" = LOADMEM --file <binary filename> --addr <24 bit addr> --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM> [--offset <offset> --len <length>]\n");
|
printf(" = LOADMEM --file <binary filename> --addr <24 bit addr> --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM> [--offset <offset> --len <length>]\n");
|
||||||
printf(" = SAVE --file <filename> --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = PageTable, 4 = IOPageTable>\n");
|
printf(" = SAVE --file <filename> --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = PageTable, 4 = IOPageTable>\n");
|
||||||
printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = MemoryPageTable, 4 = IOPageTable> [--memorypage <0..31>]\n");
|
printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = MemoryPageTable, 4 = IOPageTable> [--memorypage <0..41>]\n");
|
||||||
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
||||||
#if(DEBUG_ENABLED != 0)
|
#if(DEBUG_ENABLED != 0)
|
||||||
printf(" = DEBUG --level <level> # 0 = off, 1..15 debug level, 15 is very verbose.\n");
|
printf(" = DEBUG --level <level> # 0 = off, 1..15 debug level, 15 is very verbose.\n");
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -35,16 +35,41 @@
|
|||||||
#ifndef Z80DRIVER_H
|
#ifndef Z80DRIVER_H
|
||||||
#define Z80DRIVER_H
|
#define Z80DRIVER_H
|
||||||
|
|
||||||
|
// Build time target. Overrides if compile time definition given.
|
||||||
|
#if defined(TARGET_HOST_MZ700)
|
||||||
|
#define TARGET_HOST_MZ700 1
|
||||||
|
#define TARGET_HOST_MZ2000 0
|
||||||
|
#define TARGET_HOST_MZ80A 0
|
||||||
|
#define TARGET_HOST_PCW 0
|
||||||
|
#elif defined(TARGET_HOST_MZ2000)
|
||||||
|
#define TARGET_HOST_MZ2000 1
|
||||||
|
#define TARGET_HOST_MZ700 0
|
||||||
|
#define TARGET_HOST_MZ80A 0
|
||||||
|
#define TARGET_HOST_PCW 0
|
||||||
|
#elif defined(TARGET_HOST_MZ80A)
|
||||||
|
#define TARGET_HOST_MZ80A 1
|
||||||
|
#define TARGET_HOST_MZ2000 0
|
||||||
|
#define TARGET_HOST_MZ700 0
|
||||||
|
#define TARGET_HOST_PCW 0
|
||||||
|
#elif defined(TARGET_HOST_PCW8XXX) || defined(TARGET_HOST_PCW9XXX)
|
||||||
|
#define TARGET_HOST_PCW 1
|
||||||
|
#define TARGET_HOST_MZ2000 0
|
||||||
|
#define TARGET_HOST_MZ700 0
|
||||||
|
#define TARGET_HOST_MZ80A 0
|
||||||
|
#else
|
||||||
|
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
||||||
|
#define TARGET_HOST_MZ2000 0 // MZ2000
|
||||||
|
#define TARGET_HOST_MZ80A 0 // MZ80A
|
||||||
|
#define TARGET_HOST_PCW 0 // Amstrad PCW8XXX/9XXX
|
||||||
|
#endif
|
||||||
|
|
||||||
// Constants.
|
// Constants.
|
||||||
#define DRIVER_LICENSE "GPL"
|
#define DRIVER_LICENSE "GPL"
|
||||||
#define DRIVER_AUTHOR "Philip D Smart"
|
#define DRIVER_AUTHOR "Philip D Smart"
|
||||||
#define DRIVER_DESCRIPTION "Z80 CPU Emulator and Hardware Interface Driver"
|
#define DRIVER_DESCRIPTION "Z80 CPU Emulator and Hardware Interface Driver"
|
||||||
#define DRIVER_VERSION "v1.3"
|
#define DRIVER_VERSION "v1.4"
|
||||||
#define DRIVER_VERSION_DATE "Feb 2023"
|
#define DRIVER_VERSION_DATE "Apr 2023"
|
||||||
#define DRIVER_COPYRIGHT "(C) 2018-2023"
|
#define DRIVER_COPYRIGHT "(C) 2018-2023"
|
||||||
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
|
||||||
#define TARGET_HOST_MZ2000 0 // MZ2000
|
|
||||||
#define TARGET_HOST_MZ80A 1 // MZ80A
|
|
||||||
#define Z80_VIRTUAL_ROM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M which is 4x512K ROMS.
|
#define Z80_VIRTUAL_ROM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M which is 4x512K ROMS.
|
||||||
#define Z80_VIRTUAL_RAM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M.
|
#define Z80_VIRTUAL_RAM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M.
|
||||||
#define Z80_MEMORY_PAGE_SIZE 16
|
#define Z80_MEMORY_PAGE_SIZE 16
|
||||||
@@ -69,13 +94,14 @@
|
|||||||
#define MEMORY_TYPE_VIRTUAL_ROM 0x04000000
|
#define MEMORY_TYPE_VIRTUAL_ROM 0x04000000
|
||||||
#define MEMORY_TYPE_VIRTUAL_RAM_RO 0x02000000
|
#define MEMORY_TYPE_VIRTUAL_RAM_RO 0x02000000
|
||||||
#define MEMORY_TYPE_VIRTUAL_HW 0x01000000
|
#define MEMORY_TYPE_VIRTUAL_HW 0x01000000
|
||||||
|
#define MEMORY_TYPE_PHYSICAL_RAM_WT MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_VIRTUAL_RAM
|
||||||
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
||||||
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
||||||
|
|
||||||
// Hotkeys handled.
|
// Hotkeys handled.
|
||||||
#define HOTKEY_ORIGINAL 0xE8
|
#define HOTKEY_ORIGINAL 0xE8
|
||||||
#define HOTKEY_RFS80 0xE9
|
#define HOTKEY_RFS40 0xE9
|
||||||
#define HOTKEY_RFS40 0xEA
|
#define HOTKEY_RFS80 0xEA
|
||||||
#define HOTKEY_TZFS 0xEB
|
#define HOTKEY_TZFS 0xEB
|
||||||
#define HOTKEY_LINUX 0xEC
|
#define HOTKEY_LINUX 0xEC
|
||||||
|
|
||||||
@@ -100,22 +126,42 @@
|
|||||||
// Approximate governor delays to regulate emulated CPU speed.
|
// Approximate governor delays to regulate emulated CPU speed.
|
||||||
// MZ-700
|
// MZ-700
|
||||||
#if(TARGET_HOST_MZ700 == 1)
|
#if(TARGET_HOST_MZ700 == 1)
|
||||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
#if(DEBUG_ENABLED > 0)
|
||||||
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
||||||
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
||||||
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
||||||
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
||||||
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
||||||
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
||||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
||||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
||||||
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
||||||
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
||||||
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
||||||
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
||||||
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
||||||
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
||||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
||||||
|
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
||||||
|
#endif
|
||||||
|
#if(DEBUG_ENABLED == 0)
|
||||||
|
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
||||||
|
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
||||||
|
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
||||||
|
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
||||||
|
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
||||||
|
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
||||||
|
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
||||||
|
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
||||||
|
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
||||||
|
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
||||||
|
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
||||||
|
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
||||||
|
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
||||||
|
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
||||||
|
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
||||||
|
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
||||||
|
#endif
|
||||||
#define INSTRUCTION_EQUIV_FREQ_3_54MHZ 3540000
|
#define INSTRUCTION_EQUIV_FREQ_3_54MHZ 3540000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_7MHZ 7000000
|
#define INSTRUCTION_EQUIV_FREQ_7MHZ 7000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_14MHZ 14000000
|
#define INSTRUCTION_EQUIV_FREQ_14MHZ 14000000
|
||||||
@@ -124,6 +170,7 @@
|
|||||||
#define INSTRUCTION_EQUIV_FREQ_112MHZ 112000000
|
#define INSTRUCTION_EQUIV_FREQ_112MHZ 112000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_224MHZ 224000000
|
#define INSTRUCTION_EQUIV_FREQ_224MHZ 224000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_448MHZ 448000000
|
#define INSTRUCTION_EQUIV_FREQ_448MHZ 448000000
|
||||||
|
#define INSTRUCTION_GOVERNOR_IO_SKIP 10
|
||||||
|
|
||||||
enum Z80_INSTRUCTION_DELAY {
|
enum Z80_INSTRUCTION_DELAY {
|
||||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_3_54MHZ,
|
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_3_54MHZ,
|
||||||
@@ -141,7 +188,7 @@ enum Z80_INSTRUCTION_DELAY {
|
|||||||
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_56MHZ,
|
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_56MHZ,
|
||||||
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_112MHZ,
|
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_112MHZ,
|
||||||
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_224MHZ,
|
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_224MHZ,
|
||||||
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_448MHZ
|
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_448MHZ,
|
||||||
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_3_54MHZ,
|
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_3_54MHZ,
|
||||||
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_7MHZ,
|
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_7MHZ,
|
||||||
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_14MHZ,
|
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_14MHZ,
|
||||||
@@ -155,22 +202,43 @@ enum Z80_INSTRUCTION_DELAY {
|
|||||||
|
|
||||||
// MZ-2000
|
// MZ-2000
|
||||||
#if(TARGET_HOST_MZ2000 == 1)
|
#if(TARGET_HOST_MZ2000 == 1)
|
||||||
#define INSTRUCTION_DELAY_ROM_4MHZ 243
|
|
||||||
#define INSTRUCTION_DELAY_ROM_8MHZ 122
|
#if(DEBUG_ENABLED > 0)
|
||||||
#define INSTRUCTION_DELAY_ROM_16MHZ 61
|
#define INSTRUCTION_DELAY_ROM_4MHZ 213
|
||||||
#define INSTRUCTION_DELAY_ROM_32MHZ 30
|
#define INSTRUCTION_DELAY_ROM_8MHZ 109
|
||||||
#define INSTRUCTION_DELAY_ROM_64MHZ 15
|
#define INSTRUCTION_DELAY_ROM_16MHZ 54
|
||||||
#define INSTRUCTION_DELAY_ROM_128MHZ 7
|
#define INSTRUCTION_DELAY_ROM_32MHZ 27
|
||||||
#define INSTRUCTION_DELAY_ROM_256MHZ 3
|
#define INSTRUCTION_DELAY_ROM_64MHZ 14
|
||||||
#define INSTRUCTION_DELAY_ROM_512MHZ 1
|
#define INSTRUCTION_DELAY_ROM_128MHZ 7
|
||||||
#define INSTRUCTION_DELAY_RAM_4MHZ 218
|
#define INSTRUCTION_DELAY_ROM_256MHZ 3
|
||||||
#define INSTRUCTION_DELAY_RAM_8MHZ 112
|
#define INSTRUCTION_DELAY_ROM_512MHZ 1
|
||||||
#define INSTRUCTION_DELAY_RAM_16MHZ 56
|
#define INSTRUCTION_DELAY_RAM_4MHZ 212
|
||||||
#define INSTRUCTION_DELAY_RAM_32MHZ 28
|
#define INSTRUCTION_DELAY_RAM_8MHZ 106
|
||||||
#define INSTRUCTION_DELAY_RAM_64MHZ 14
|
#define INSTRUCTION_DELAY_RAM_16MHZ 53
|
||||||
#define INSTRUCTION_DELAY_RAM_128MHZ 7
|
#define INSTRUCTION_DELAY_RAM_32MHZ 26
|
||||||
#define INSTRUCTION_DELAY_RAM_256MHZ 3
|
#define INSTRUCTION_DELAY_RAM_64MHZ 13
|
||||||
#define INSTRUCTION_DELAY_RAM_512MHZ 1
|
#define INSTRUCTION_DELAY_RAM_128MHZ 7
|
||||||
|
#define INSTRUCTION_DELAY_RAM_256MHZ 3
|
||||||
|
#define INSTRUCTION_DELAY_RAM_512MHZ 1
|
||||||
|
#endif
|
||||||
|
#if(DEBUG_ENABLED == 0)
|
||||||
|
#define INSTRUCTION_DELAY_ROM_4MHZ 295
|
||||||
|
#define INSTRUCTION_DELAY_ROM_8MHZ 148
|
||||||
|
#define INSTRUCTION_DELAY_ROM_16MHZ 74
|
||||||
|
#define INSTRUCTION_DELAY_ROM_32MHZ 37
|
||||||
|
#define INSTRUCTION_DELAY_ROM_64MHZ 19
|
||||||
|
#define INSTRUCTION_DELAY_ROM_128MHZ 10
|
||||||
|
#define INSTRUCTION_DELAY_ROM_256MHZ 5
|
||||||
|
#define INSTRUCTION_DELAY_ROM_512MHZ 3
|
||||||
|
#define INSTRUCTION_DELAY_RAM_4MHZ 240 // These values are smaller than the ROM as Rom has 1 wait state added per cycle.
|
||||||
|
#define INSTRUCTION_DELAY_RAM_8MHZ 148
|
||||||
|
#define INSTRUCTION_DELAY_RAM_16MHZ 74
|
||||||
|
#define INSTRUCTION_DELAY_RAM_32MHZ 37
|
||||||
|
#define INSTRUCTION_DELAY_RAM_64MHZ 19
|
||||||
|
#define INSTRUCTION_DELAY_RAM_128MHZ 10
|
||||||
|
#define INSTRUCTION_DELAY_RAM_256MHZ 5
|
||||||
|
#define INSTRUCTION_DELAY_RAM_512MHZ 3
|
||||||
|
#endif
|
||||||
#define INSTRUCTION_EQUIV_FREQ_4MHZ 4000000
|
#define INSTRUCTION_EQUIV_FREQ_4MHZ 4000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_8MHZ 8000000
|
#define INSTRUCTION_EQUIV_FREQ_8MHZ 8000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_16MHZ 16000000
|
#define INSTRUCTION_EQUIV_FREQ_16MHZ 16000000
|
||||||
@@ -179,6 +247,7 @@ enum Z80_INSTRUCTION_DELAY {
|
|||||||
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_512MHZ 512000000
|
#define INSTRUCTION_EQUIV_FREQ_512MHZ 512000000
|
||||||
|
#define INSTRUCTION_GOVERNOR_IO_SKIP 4
|
||||||
|
|
||||||
enum Z80_INSTRUCTION_DELAY {
|
enum Z80_INSTRUCTION_DELAY {
|
||||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_4MHZ,
|
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_4MHZ,
|
||||||
@@ -258,6 +327,7 @@ enum Z80_INSTRUCTION_DELAY {
|
|||||||
#define INSTRUCTION_EQUIV_FREQ_64MHZ 64000000
|
#define INSTRUCTION_EQUIV_FREQ_64MHZ 64000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
||||||
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
||||||
|
#define INSTRUCTION_GOVERNOR_IO_SKIP 2
|
||||||
|
|
||||||
// Table of governor delays to be used to control run frequency,
|
// Table of governor delays to be used to control run frequency,
|
||||||
enum Z80_INSTRUCTION_DELAY {
|
enum Z80_INSTRUCTION_DELAY {
|
||||||
@@ -288,6 +358,82 @@ enum Z80_INSTRUCTION_DELAY {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Amstrad PCW-8256
|
||||||
|
#if(TARGET_HOST_PCW == 1)
|
||||||
|
#if(DEBUG_ENABLED > 0)
|
||||||
|
#define INSTRUCTION_DELAY_ROM_4MHZ 295
|
||||||
|
#define INSTRUCTION_DELAY_ROM_8MHZ 148
|
||||||
|
#define INSTRUCTION_DELAY_ROM_16MHZ 74
|
||||||
|
#define INSTRUCTION_DELAY_ROM_32MHZ 37
|
||||||
|
#define INSTRUCTION_DELAY_ROM_64MHZ 19
|
||||||
|
#define INSTRUCTION_DELAY_ROM_128MHZ 10
|
||||||
|
#define INSTRUCTION_DELAY_ROM_256MHZ 5
|
||||||
|
#define INSTRUCTION_DELAY_ROM_512MHZ 3
|
||||||
|
#define INSTRUCTION_DELAY_RAM_4MHZ 240
|
||||||
|
#define INSTRUCTION_DELAY_RAM_8MHZ 148
|
||||||
|
#define INSTRUCTION_DELAY_RAM_16MHZ 74
|
||||||
|
#define INSTRUCTION_DELAY_RAM_32MHZ 37
|
||||||
|
#define INSTRUCTION_DELAY_RAM_64MHZ 19
|
||||||
|
#define INSTRUCTION_DELAY_RAM_128MHZ 10
|
||||||
|
#define INSTRUCTION_DELAY_RAM_256MHZ 5
|
||||||
|
#define INSTRUCTION_DELAY_RAM_512MHZ 3
|
||||||
|
#endif
|
||||||
|
#if(DEBUG_ENABLED == 0)
|
||||||
|
#define INSTRUCTION_DELAY_ROM_4MHZ 295
|
||||||
|
#define INSTRUCTION_DELAY_ROM_8MHZ 148
|
||||||
|
#define INSTRUCTION_DELAY_ROM_16MHZ 74
|
||||||
|
#define INSTRUCTION_DELAY_ROM_32MHZ 37
|
||||||
|
#define INSTRUCTION_DELAY_ROM_64MHZ 19
|
||||||
|
#define INSTRUCTION_DELAY_ROM_128MHZ 10
|
||||||
|
#define INSTRUCTION_DELAY_ROM_256MHZ 5
|
||||||
|
#define INSTRUCTION_DELAY_ROM_512MHZ 3
|
||||||
|
#define INSTRUCTION_DELAY_RAM_4MHZ 240
|
||||||
|
#define INSTRUCTION_DELAY_RAM_8MHZ 148
|
||||||
|
#define INSTRUCTION_DELAY_RAM_16MHZ 74
|
||||||
|
#define INSTRUCTION_DELAY_RAM_32MHZ 37
|
||||||
|
#define INSTRUCTION_DELAY_RAM_64MHZ 19
|
||||||
|
#define INSTRUCTION_DELAY_RAM_128MHZ 10
|
||||||
|
#define INSTRUCTION_DELAY_RAM_256MHZ 5
|
||||||
|
#define INSTRUCTION_DELAY_RAM_512MHZ 3
|
||||||
|
#endif
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_4MHZ 4000000
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_8MHZ 8000000
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_16MHZ 16000000
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_32MHZ 32000000
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_64MHZ 64000000
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
||||||
|
#define INSTRUCTION_EQUIV_FREQ_512MHZ 512000000
|
||||||
|
#define INSTRUCTION_GOVERNOR_IO_SKIP 5
|
||||||
|
|
||||||
|
enum Z80_INSTRUCTION_DELAY {
|
||||||
|
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_4MHZ,
|
||||||
|
ROM_DELAY_X2 = INSTRUCTION_DELAY_ROM_8MHZ,
|
||||||
|
ROM_DELAY_X4 = INSTRUCTION_DELAY_ROM_16MHZ,
|
||||||
|
ROM_DELAY_X8 = INSTRUCTION_DELAY_ROM_32MHZ,
|
||||||
|
ROM_DELAY_X16 = INSTRUCTION_DELAY_ROM_64MHZ,
|
||||||
|
ROM_DELAY_X32 = INSTRUCTION_DELAY_ROM_128MHZ,
|
||||||
|
ROM_DELAY_X64 = INSTRUCTION_DELAY_ROM_256MHZ,
|
||||||
|
ROM_DELAY_X128 = INSTRUCTION_DELAY_ROM_512MHZ,
|
||||||
|
RAM_DELAY_NORMAL = INSTRUCTION_DELAY_RAM_4MHZ,
|
||||||
|
RAM_DELAY_X2 = INSTRUCTION_DELAY_RAM_8MHZ,
|
||||||
|
RAM_DELAY_X4 = INSTRUCTION_DELAY_RAM_16MHZ,
|
||||||
|
RAM_DELAY_X8 = INSTRUCTION_DELAY_RAM_32MHZ,
|
||||||
|
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_64MHZ,
|
||||||
|
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_128MHZ,
|
||||||
|
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_256MHZ,
|
||||||
|
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_512MHZ,
|
||||||
|
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_4MHZ,
|
||||||
|
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_8MHZ,
|
||||||
|
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_16MHZ,
|
||||||
|
CPU_FREQUENCY_X8 = INSTRUCTION_EQUIV_FREQ_32MHZ,
|
||||||
|
CPU_FREQUENCY_X16 = INSTRUCTION_EQUIV_FREQ_64MHZ,
|
||||||
|
CPU_FREQUENCY_X32 = INSTRUCTION_EQUIV_FREQ_128MHZ,
|
||||||
|
CPU_FREQUENCY_X64 = INSTRUCTION_EQUIV_FREQ_256MHZ,
|
||||||
|
CPU_FREQUENCY_X128 = INSTRUCTION_EQUIV_FREQ_512MHZ,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
||||||
#define IOCTL_CMD_Z80_STOP 's'
|
#define IOCTL_CMD_Z80_STOP 's'
|
||||||
#define IOCTL_CMD_Z80_START 'S'
|
#define IOCTL_CMD_Z80_START 'S'
|
||||||
@@ -426,9 +572,12 @@ enum Z80_INSTRUCTION_DELAY {
|
|||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
#define resetZ80() {\
|
#define resetZ80() {\
|
||||||
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_TZPU)\
|
|
||||||
sendSignal(Z80Ctrl->ioTask, SIGUSR1); \
|
|
||||||
setupMemory(Z80Ctrl->defaultPageMode);\
|
setupMemory(Z80Ctrl->defaultPageMode);\
|
||||||
|
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_TZPU)\
|
||||||
|
{\
|
||||||
|
sendSignal(Z80Ctrl->ioTask, SIGUSR1); \
|
||||||
|
udelay(2000);\
|
||||||
|
}\
|
||||||
z80_instant_reset(&Z80CPU);\
|
z80_instant_reset(&Z80CPU);\
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,10 +609,14 @@ enum Z80_MEMORY_PROFILE {
|
|||||||
};
|
};
|
||||||
enum VIRTUAL_DEVICE {
|
enum VIRTUAL_DEVICE {
|
||||||
VIRTUAL_DEVICE_NONE = 0x00000000,
|
VIRTUAL_DEVICE_NONE = 0x00000000,
|
||||||
|
VIRTUAL_DEVICE_MZ80A = 0x00000001,
|
||||||
|
VIRTUAL_DEVICE_MZ700 = 0x00000002,
|
||||||
|
VIRTUAL_DEVICE_MZ2000 = 0x00000004,
|
||||||
|
VIRTUAL_DEVICE_PCW = 0x00000008,
|
||||||
VIRTUAL_DEVICE_RFS40 = 0x01000000,
|
VIRTUAL_DEVICE_RFS40 = 0x01000000,
|
||||||
VIRTUAL_DEVICE_RFS80 = 0x02000000,
|
VIRTUAL_DEVICE_RFS80 = 0x02000000,
|
||||||
VIRTUAL_DEVICE_RFS = 0x03000000,
|
VIRTUAL_DEVICE_RFS = 0x03000000,
|
||||||
VIRTUAL_DEVICE_TZPU = 0x04000000
|
VIRTUAL_DEVICE_TZPU = 0x04000000,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -524,14 +677,6 @@ typedef struct {
|
|||||||
uint8_t ioReadAhead;
|
uint8_t ioReadAhead;
|
||||||
uint8_t ioWriteAhead;
|
uint8_t ioWriteAhead;
|
||||||
|
|
||||||
#if(TARGET_HOST_MZ2000 == 1)
|
|
||||||
uint8_t lowMemorySwap;
|
|
||||||
#endif
|
|
||||||
#if(TARGET_HOST_MZ80A == 1)
|
|
||||||
// MZ-80A can relocate the lower 4K ROM by swapping RAM at 0xC000.
|
|
||||||
uint8_t memSwitch;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Keyboard strobe and data. Required to detect hotkey press.
|
// Keyboard strobe and data. Required to detect hotkey press.
|
||||||
uint8_t keyportStrobe;
|
uint8_t keyportStrobe;
|
||||||
uint8_t keyportShiftCtrl;
|
uint8_t keyportShiftCtrl;
|
||||||
@@ -546,6 +691,7 @@ typedef struct {
|
|||||||
// is quicker than RAM (both are in the same kernel memory) as a pointer calculation needs to be made.
|
// is quicker than RAM (both are in the same kernel memory) as a pointer calculation needs to be made.
|
||||||
uint32_t cpuGovernorDelayROM;
|
uint32_t cpuGovernorDelayROM;
|
||||||
uint32_t cpuGovernorDelayRAM;
|
uint32_t cpuGovernorDelayRAM;
|
||||||
|
uint8_t governorSkip;
|
||||||
|
|
||||||
// An I/O processor, running as a User Space daemon, can register to receive signals and events.
|
// An I/O processor, running as a User Space daemon, can register to receive signals and events.
|
||||||
struct task_struct *ioTask;
|
struct task_struct *ioTask;
|
||||||
@@ -82,6 +82,14 @@
|
|||||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR 0x38
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P1 0x39
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P2 0x3A
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P3 0x3B
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P4 0x3C
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P5 0x3D
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P6 0x3E
|
||||||
|
#define CPLD_CMD_READIO_WRITE_ADDR_P7 0x3F
|
||||||
#define CPLD_CMD_HALT 0x50
|
#define CPLD_CMD_HALT 0x50
|
||||||
#define CPLD_CMD_REFRESH 0x51
|
#define CPLD_CMD_REFRESH 0x51
|
||||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||||
@@ -130,7 +138,7 @@
|
|||||||
#define PAD_SPIO_2_ADDR 0x103C14
|
#define PAD_SPIO_2_ADDR 0x103C14
|
||||||
#define PAD_SPIO_3_ADDR 0x103C16
|
#define PAD_SPIO_3_ADDR 0x103C16
|
||||||
#define PAD_Z80IO_HIGH_BYTE_ADDR 0x1425
|
#define PAD_Z80IO_HIGH_BYTE_ADDR 0x1425
|
||||||
#define PAD_Z80IO_READY_ADDR 0x103C18
|
#define PAD_Z80IO_READY_ADDR 0x103C18 // GPIO12
|
||||||
#define PAD_Z80IO_LTSTATE_ADDR 0x103C30 // GPIO47
|
#define PAD_Z80IO_LTSTATE_ADDR 0x103C30 // GPIO47
|
||||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
||||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
||||||
@@ -386,8 +394,8 @@
|
|||||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
||||||
#define CPLD_Z80_INT() (MHal_RIU_REG(PAD_Z80IO_INT_ADDR) & 0x4)
|
#define CPLD_Z80_INT() (MHal_RIU_REG(PAD_Z80IO_INT_ADDR) & 0x4)
|
||||||
#define CPLD_Z80_NMI() (MHal_RIU_REG(PAD_Z80IO_NMI_ADDR) & 0x4)
|
#define CPLD_Z80_NMI() (MHal_RIU_REG(PAD_Z80IO_NMI_ADDR) & 0x4)
|
||||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
@@ -396,9 +404,18 @@
|
|||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||||
}
|
}
|
||||||
|
#define SPI_SEND_I_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||||
|
}
|
||||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
@@ -406,10 +423,9 @@
|
|||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
}
|
}
|
||||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
@@ -417,24 +433,63 @@
|
|||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
}
|
}
|
||||||
#define SPI_SEND32i(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
#define SPI_SEND_P_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) != 0);\
|
||||||
pr_info("Stage 0");\
|
|
||||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
|
||||||
pr_info("Stage 1");\
|
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
pr_info("Stage 2");\
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
timeout = MAX_CHECK_CNT; \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; }; \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
pr_info("Stage 3");\
|
}
|
||||||
|
#define SPI_SET_FRAME_SIZE() { MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND_I_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
|
}
|
||||||
|
#define SPI_SEND_48(_d1_, _d2_, _d3_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||||
|
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 6); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d3_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d2_); \
|
||||||
|
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+2, (uint16_t)_d1_); \
|
||||||
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||||
|
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||||
|
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||||
|
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };
|
|
||||||
// read 2 byte
|
// read 2 byte
|
||||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||||
// write 2 byte
|
// write 2 byte
|
||||||
@@ -54,7 +54,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
|||||||
spinlock_t spinLock;
|
spinlock_t spinLock;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
SPI_SEND8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
SPI_SEND_8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
||||||
|
|
||||||
SPI_SEND32(0x00E30000 | (0x07 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
SPI_SEND32(0x00E30000 | (0x07 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||||
udelay(100);
|
udelay(100);
|
||||||
@@ -185,7 +185,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
|||||||
|
|
||||||
// Read back the same byte.
|
// Read back the same byte.
|
||||||
cmd = 0x10;
|
cmd = 0x10;
|
||||||
SPI_SEND8(cmd);
|
SPI_SEND_8(cmd);
|
||||||
while(CPLD_READY() == 0);
|
while(CPLD_READY() == 0);
|
||||||
|
|
||||||
result = READ_CPLD_DATA_IN();
|
result = READ_CPLD_DATA_IN();
|
||||||
@@ -223,7 +223,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
|||||||
|
|
||||||
// Read back the same byte.
|
// Read back the same byte.
|
||||||
cmd = 0x20;
|
cmd = 0x20;
|
||||||
SPI_SEND8(cmd);
|
SPI_SEND_8(cmd);
|
||||||
while(CPLD_READY() == 0);
|
while(CPLD_READY() == 0);
|
||||||
|
|
||||||
result = READ_CPLD_DATA_IN();
|
result = READ_CPLD_DATA_IN();
|
||||||
@@ -254,7 +254,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
|||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
cmd = 0x11;
|
cmd = 0x11;
|
||||||
SPI_SEND8(cmd);
|
SPI_SEND_8(cmd);
|
||||||
}
|
}
|
||||||
while(CPLD_READY() == 0);
|
while(CPLD_READY() == 0);
|
||||||
result = READ_CPLD_DATA_IN();
|
result = READ_CPLD_DATA_IN();
|
||||||
@@ -280,7 +280,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
|||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
cmd = 0x21;
|
cmd = 0x21;
|
||||||
SPI_SEND8(cmd);
|
SPI_SEND_8(cmd);
|
||||||
}
|
}
|
||||||
while(CPLD_READY() == 0);
|
while(CPLD_READY() == 0);
|
||||||
result = READ_CPLD_DATA_IN();
|
result = READ_CPLD_DATA_IN();
|
||||||
@@ -306,7 +306,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
|||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
cmd = 0x19;
|
cmd = 0x19;
|
||||||
SPI_SEND8(cmd);
|
SPI_SEND_8(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(idx=0; idx < iterations; idx++)
|
for(idx=0; idx < iterations; idx++)
|
||||||
@@ -322,7 +322,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
|||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
cmd = 0x19;
|
cmd = 0x19;
|
||||||
SPI_SEND8(cmd);
|
SPI_SEND_8(cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
436
software/FusionX/src/z80drv/src/z80vhw_mz2000.c
Normal file
436
software/FusionX/src/z80drv/src/z80vhw_mz2000.c
Normal file
@@ -0,0 +1,436 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Name: z80vhw_mz2000.c
|
||||||
|
// Created: Oct 2022
|
||||||
|
// Author(s): Philip Smart
|
||||||
|
// Description: Z80 Virtual Hardware Driver - MZ-2000
|
||||||
|
// This file contains the methods used to emulate the original Sharp MZ-2000 without
|
||||||
|
// any additions, such as the RFS or TZFS boards.
|
||||||
|
//
|
||||||
|
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||||
|
// and as such, they are included like header files rather than C linked object files.
|
||||||
|
// Credits:
|
||||||
|
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||||
|
//
|
||||||
|
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||||
|
//
|
||||||
|
// Notes: See Makefile to enable/disable conditional components
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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/>.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include "z80io.h"
|
||||||
|
|
||||||
|
#include <gpio_table.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <infinity2m/gpio.h>
|
||||||
|
#include <infinity2m/registers.h>
|
||||||
|
|
||||||
|
// Device constants.
|
||||||
|
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||||
|
|
||||||
|
// System ROM's, either use the host machine ROM or preload a ROM image.
|
||||||
|
#define ROM_DIR "/apps/FusionX/host/MZ-2000/ROMS/"
|
||||||
|
#define ROM_IPL_ORIG_FILENAME ROM_DIR "mz2000_ipl.orig"
|
||||||
|
|
||||||
|
// Boot ROM rom load and size definitions.
|
||||||
|
#define ROM_BOOT_LOAD_ADDR 0x000000
|
||||||
|
#define ROM_BOOT_SIZE 0x800
|
||||||
|
|
||||||
|
// PCW control.
|
||||||
|
typedef struct {
|
||||||
|
uint8_t lowMemorySwap; // Boot mode lower memory is swapped to 0x8000:0xFFFF
|
||||||
|
uint8_t highMemoryVRAM; // Flag to indicate high memory range 0xD000:0xFFFF is assigned to VRAM.
|
||||||
|
uint8_t graphicsVRAM; // Flag to indicate graphics VRAM selected, default is character VRAM (0).
|
||||||
|
uint8_t regCtrl; // Control register.
|
||||||
|
} t_MZ2000Ctrl;
|
||||||
|
|
||||||
|
// RFS Board control.
|
||||||
|
static t_MZ2000Ctrl MZ2000Ctrl;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Method to setup the memory page config to reflect the PCW configuration.
|
||||||
|
void mz2000SetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// The PCW contains upto 512KB of standard RAM which can be expnded to a physical max of 2MB. The kernel malloc limit is 2MB so the whole virtual
|
||||||
|
// memory can be mapped into the PCW memory address range.
|
||||||
|
|
||||||
|
// Setup defaults.
|
||||||
|
MZ2000Ctrl.lowMemorySwap = 0x01; // Set memory swap flag to swapped, ie. IPL mode sees DRAM 0x0000:0x7FFF swapped to 0x8000:0xFFFF and ROM pages into 0x0000.
|
||||||
|
MZ2000Ctrl.highMemoryVRAM = 0x00;
|
||||||
|
MZ2000Ctrl.graphicsVRAM = 0x00;
|
||||||
|
MZ2000Ctrl.regCtrl = 0x00;
|
||||||
|
|
||||||
|
// Setup default mode according to run mode, ie. Physical run or Virtual run.
|
||||||
|
//
|
||||||
|
if(mode == USE_PHYSICAL_RAM)
|
||||||
|
{
|
||||||
|
// Initialise the page pointers and memory to use physical RAM.
|
||||||
|
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx >= 0 && idx < 0x8000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||||
|
}
|
||||||
|
else //if(idx >= 0x8000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Video RAM labelled as HW as we dont want to cache it.
|
||||||
|
//else if(idx >= 0xD000 && idx < 0xE000)
|
||||||
|
// {
|
||||||
|
// setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
//} else
|
||||||
|
// {
|
||||||
|
// setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
// Cancel refresh as using physical RAM for program automatically refreshes DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 0;
|
||||||
|
}
|
||||||
|
else if(mode == USE_VIRTUAL_RAM)
|
||||||
|
{
|
||||||
|
// Initialise the page pointers and memory to use virtual RAM.
|
||||||
|
// MZ-2000 comes up in IPL mode where lower 32K is ROM and upper 32K is RAM remapped from 0x0000.
|
||||||
|
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx >= 0 && idx < 0x8000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (MZ2000Ctrl.lowMemorySwap ? idx - 0x8000 : idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("MZ-2000 Memory Setup complete.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to load a ROM image into the RAM memory.
|
||||||
|
//
|
||||||
|
uint8_t mz2000LoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t result = 0;
|
||||||
|
long noBytes;
|
||||||
|
struct file *fp;
|
||||||
|
|
||||||
|
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||||
|
if(IS_ERR(fp))
|
||||||
|
{
|
||||||
|
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||||
|
result = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
vfs_llseek(fp, 0, SEEK_SET);
|
||||||
|
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||||
|
if(noBytes < loadSize)
|
||||||
|
{
|
||||||
|
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||||
|
}
|
||||||
|
filp_close(fp,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||||
|
void mz2000Init(uint8_t mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have
|
||||||
|
// bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating
|
||||||
|
// when first powered on.
|
||||||
|
pr_info("Sync Host RAM to virtual RAM.\n");
|
||||||
|
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||||
|
{
|
||||||
|
// Lower memory is actually upper on startup, but ROM paged in, so set to zero.
|
||||||
|
if(idx >= 0x0000 && idx < 0x8000)
|
||||||
|
{
|
||||||
|
Z80Ctrl->ram[idx+0x8000] = 0x00;
|
||||||
|
} else
|
||||||
|
// Lower memory is paged in at 0x8000:0xFFFF
|
||||||
|
if(idx >= 0x8000 && idx < 0x10000)
|
||||||
|
{
|
||||||
|
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||||
|
while(CPLD_READY() == 0);
|
||||||
|
Z80Ctrl->ram[idx-0x8000] = z80io_PRL_Read8(1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Z80Ctrl->ram[idx] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Original mode, ie. no virtual devices active, copy the host BIOS into the Virtual ROM and initialise remainder of ROM memory
|
||||||
|
// such that the host behaves as per original spec.
|
||||||
|
pr_info("Sync Host BIOS to virtual ROM.\n");
|
||||||
|
for(idx=0; idx < Z80_VIRTUAL_ROM_SIZE; idx++)
|
||||||
|
{
|
||||||
|
if(idx >= 0x0000 && idx < 0x8000)
|
||||||
|
{
|
||||||
|
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||||
|
while(CPLD_READY() == 0);
|
||||||
|
Z80Ctrl->rom[idx] = z80io_PRL_Read8(1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Z80Ctrl->rom[idx] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial memory config.
|
||||||
|
mz2000SetupMemory(Z80Ctrl->defaultPageMode);
|
||||||
|
|
||||||
|
// mz2000LoadROM(ROM_IPL_ORIG_FILENAME, ROM_BOOT_LOAD_ADDR, ROM_BOOT_SIZE);
|
||||||
|
|
||||||
|
pr_info("Enabling MZ-2000 driver.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any de-initialisation when the driver is removed.
|
||||||
|
void mz2000Remove(void)
|
||||||
|
{
|
||||||
|
pr_info("Removing MZ-2000 driver.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to decode an address and make any system memory map changes as required.
|
||||||
|
//
|
||||||
|
static inline void mz2000DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Decoding memory address or I/O address?
|
||||||
|
if(ioFlag == 0)
|
||||||
|
{
|
||||||
|
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||||
|
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||||
|
//
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// Determine if this is a memory management port and update the memory page if required.
|
||||||
|
switch(address & 0x00FF)
|
||||||
|
{
|
||||||
|
// 8255 - Port A
|
||||||
|
case IO_ADDR_E0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 8255 - Port B
|
||||||
|
case IO_ADDR_E1:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 8255 - Port C
|
||||||
|
// Bit 3 - L = Reset and enter IPL mode.
|
||||||
|
// Bit 1 - H = Set memory to normal state and reset cpu, RAM 0x0000:0xFFFF, L = no change.
|
||||||
|
case IO_ADDR_E2:
|
||||||
|
if(data & 0x01)
|
||||||
|
data = 0x03;
|
||||||
|
else if((data & 0x08) == 0)
|
||||||
|
data = 0x06;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 8255 - Control Port
|
||||||
|
// Bit 7 - H = Control word, L 3:1 define port C bit, bit 0 defines its state.
|
||||||
|
case IO_ADDR_E3:
|
||||||
|
//pr_info("E3:%02x\n", data);
|
||||||
|
// Program control register.
|
||||||
|
if(data & 0x80)
|
||||||
|
{
|
||||||
|
// Do nothing, this is the register which sets the 8255 mode.
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch((data >> 1) & 0x07)
|
||||||
|
{
|
||||||
|
// NST toggle.
|
||||||
|
case 1:
|
||||||
|
// NST pages in all RAM and resets cpu.
|
||||||
|
if(data & 0x01)
|
||||||
|
{
|
||||||
|
MZ2000Ctrl.lowMemorySwap = 0;
|
||||||
|
for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(Z80Ctrl->defaultPageMode == USE_PHYSICAL_RAM)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//resetZ80();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// IPL start.
|
||||||
|
case 3:
|
||||||
|
// If IPL is active (L), reconfigure memory for power on state.
|
||||||
|
if((data & 0x01) == 0)
|
||||||
|
{
|
||||||
|
mz2000SetupMemory(Z80Ctrl->defaultPageMode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Port A - Z80 PIO, contains control bits affecting memory mapping.
|
||||||
|
// Bit
|
||||||
|
// 7 - Assign address range 0xD000:0xFFFF to V-RAM when H, when L assign RAM
|
||||||
|
// 6 - Character VRAM (H), Graphics VRAM (L)
|
||||||
|
// 4 - Change screen to 80 Char (H), 40 Char (L)
|
||||||
|
// NB. When the VRAM is paged in, if Character VRAM is selected, range 0xD000:0xD7FF is VRAM, 0xC000:0xCFFF, 0xE000:0xFFFF is RAM.
|
||||||
|
case IO_ADDR_E8:
|
||||||
|
// High memory being assigned to VRAM or reverting?
|
||||||
|
if(MZ2000Ctrl.highMemoryVRAM && (data & 0x80) == 0)
|
||||||
|
{
|
||||||
|
for(idx=0xC000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(Z80Ctrl->defaultPageMode == USE_PHYSICAL_RAM)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (MZ2000Ctrl.lowMemorySwap ? idx - 0x8000 : idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MZ2000Ctrl.highMemoryVRAM = 0;
|
||||||
|
} else
|
||||||
|
// If this is the first activation of the VRAM or the state of it changes, ie. character <-> graphics, then update the memory mapping.
|
||||||
|
if( (!MZ2000Ctrl.highMemoryVRAM && (data & 0x80) != 0) || (MZ2000Ctrl.highMemoryVRAM && (MZ2000Ctrl.graphicsVRAM >> 6) != (data & 0x40)) )
|
||||||
|
{
|
||||||
|
for(idx=0xC000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
// Graphics RAM see's the entire range set to PHYSICAL, Character RAM only see's 0xD000:0xD7FF set to PHYSICAL.
|
||||||
|
if( ((data & 0x40) && (idx >= 0xD000 && idx < 0xD800)) || ((data & 0x40) == 0) )
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MZ2000Ctrl.highMemoryVRAM = 1;
|
||||||
|
}
|
||||||
|
MZ2000Ctrl.graphicsVRAM = (data & 0x040) ? 1 : 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Port is not a memory management port.
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||||
|
static inline uint8_t mz2000Read(zuint16 address, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t data = 0xFF;
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if(isVirtualMemory(address))
|
||||||
|
{
|
||||||
|
// Retrieve data from virtual memory.
|
||||||
|
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to handle writes.
|
||||||
|
static inline void mz2000Write(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
// uint32_t idx;
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if(isVirtualRAM(address))
|
||||||
|
{
|
||||||
|
// Update virtual memory.
|
||||||
|
writeVirtualRAM(address, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
481
software/FusionX/src/z80drv/src/z80vhw_mz700.c
Normal file
481
software/FusionX/src/z80drv/src/z80vhw_mz700.c
Normal file
@@ -0,0 +1,481 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Name: z80vhw_mz700.c
|
||||||
|
// Created: Oct 2022
|
||||||
|
// Author(s): Philip Smart
|
||||||
|
// Description: Z80 Virtual Hardware Driver - MZ-700
|
||||||
|
// This file contains the methods used to emulate the original Sharp MZ-700 without
|
||||||
|
// any additions, such as the RFS or TZFS boards.
|
||||||
|
//
|
||||||
|
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||||
|
// and as such, they are included like header files rather than C linked object files.
|
||||||
|
// Credits:
|
||||||
|
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||||
|
//
|
||||||
|
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||||
|
// Apr 2023 v1.1 - Updates from the PCW/MZ2000 changes.
|
||||||
|
//
|
||||||
|
// Notes: See Makefile to enable/disable conditional components
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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/>.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include "z80io.h"
|
||||||
|
|
||||||
|
#include <gpio_table.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <infinity2m/gpio.h>
|
||||||
|
#include <infinity2m/registers.h>
|
||||||
|
|
||||||
|
// Device constants.
|
||||||
|
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||||
|
|
||||||
|
// PCW control.
|
||||||
|
typedef struct {
|
||||||
|
uint8_t regCtrl; // Control register.
|
||||||
|
} t_MZ700Ctrl;
|
||||||
|
|
||||||
|
// RFS Board control.
|
||||||
|
static t_MZ700Ctrl MZ700Ctrl;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Method to setup the memory page config to reflect the PCW configuration.
|
||||||
|
void mz700SetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// The PCW contains upto 512KB of standard RAM which can be expnded to a physical max of 2MB. The kernel malloc limit is 2MB so the whole virtual
|
||||||
|
// memory can be mapped into the PCW memory address range.
|
||||||
|
|
||||||
|
// Setup defaults.
|
||||||
|
MZ700Ctrl.regCtrl = 0x00;
|
||||||
|
|
||||||
|
// Setup default mode according to run mode, ie. Physical run or Virtual run.
|
||||||
|
//
|
||||||
|
if(mode == USE_PHYSICAL_RAM)
|
||||||
|
{
|
||||||
|
// Initialise the page pointers and memory to use physical RAM.
|
||||||
|
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx >= 0 && idx < 0x1000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0x1000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xD000 && idx < 0xE000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE000 && idx < 0xE800)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE800 && idx < 0x10000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
// Cancel refresh as using physical RAM for program automatically refreshes DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 0;
|
||||||
|
}
|
||||||
|
else if(mode == USE_VIRTUAL_RAM)
|
||||||
|
{
|
||||||
|
// Initialise the page pointers and memory to use virtual RAM.
|
||||||
|
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx >= 0 && idx < 0x1000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0x1000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xD000 && idx < 0xE000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE000 && idx < 0xE800)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE800 && idx < 0xF000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xF000 && idx < 0x10000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset memory paging to default.
|
||||||
|
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
|
||||||
|
pr_info("MZ-700 Memory Setup complete.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to load a ROM image into the RAM memory.
|
||||||
|
//
|
||||||
|
uint8_t mz700LoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t result = 0;
|
||||||
|
long noBytes;
|
||||||
|
struct file *fp;
|
||||||
|
|
||||||
|
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||||
|
if(IS_ERR(fp))
|
||||||
|
{
|
||||||
|
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||||
|
result = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
vfs_llseek(fp, 0, SEEK_SET);
|
||||||
|
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||||
|
if(noBytes < loadSize)
|
||||||
|
{
|
||||||
|
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||||
|
}
|
||||||
|
filp_close(fp,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||||
|
void mz700Init(uint8_t mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have
|
||||||
|
// bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating
|
||||||
|
// when first powered on.
|
||||||
|
pr_info("Sync Host RAM to virtual RAM.\n");
|
||||||
|
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||||
|
{
|
||||||
|
if(idx >= 0x1000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||||
|
while(CPLD_READY() == 0);
|
||||||
|
Z80Ctrl->ram[idx] = z80io_PRL_Read8(1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Z80Ctrl->ram[idx] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Original mode, ie. no virtual devices active, copy the host BIOS into the Virtual ROM and initialise remainder of ROM memory
|
||||||
|
// such that the host behaves as per original spec.
|
||||||
|
pr_info("Sync Host BIOS to virtual ROM.\n");
|
||||||
|
for(idx=0; idx < Z80_VIRTUAL_ROM_SIZE; idx++)
|
||||||
|
{
|
||||||
|
// Copy BIOS and any add-on ROMS.
|
||||||
|
if((idx >= 0x0000 && idx < 0x1000) || (idx >= 0xE800 && idx < 0x10000))
|
||||||
|
{
|
||||||
|
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||||
|
while(CPLD_READY() == 0);
|
||||||
|
Z80Ctrl->rom[idx] = z80io_PRL_Read8(1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Z80Ctrl->rom[idx] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add in a test program to guage execution speed.
|
||||||
|
#if(TARGET_HOST_MZ700 == 1)
|
||||||
|
Z80Ctrl->ram[0x1200] = 0x01;
|
||||||
|
Z80Ctrl->ram[0x1201] = 0x86;
|
||||||
|
Z80Ctrl->ram[0x1202] = 0xf2;
|
||||||
|
Z80Ctrl->ram[0x1203] = 0x3e;
|
||||||
|
Z80Ctrl->ram[0x1204] = 0x15;
|
||||||
|
Z80Ctrl->ram[0x1205] = 0x3d;
|
||||||
|
Z80Ctrl->ram[0x1206] = 0x20;
|
||||||
|
Z80Ctrl->ram[0x1207] = 0xfd;
|
||||||
|
Z80Ctrl->ram[0x1208] = 0x0b;
|
||||||
|
Z80Ctrl->ram[0x1209] = 0x78;
|
||||||
|
Z80Ctrl->ram[0x120a] = 0xb1;
|
||||||
|
Z80Ctrl->ram[0x120b] = 0x20;
|
||||||
|
Z80Ctrl->ram[0x120c] = 0xf6;
|
||||||
|
Z80Ctrl->ram[0x120d] = 0xc3;
|
||||||
|
Z80Ctrl->ram[0x120e] = 0x00;
|
||||||
|
Z80Ctrl->ram[0x120f] = 0x00;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Reset memory paging to default.
|
||||||
|
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
|
||||||
|
pr_info("Enabling MZ-700 driver.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any de-initialisation when the driver is removed.
|
||||||
|
void mz700Remove(void)
|
||||||
|
{
|
||||||
|
pr_info("Removing MZ-700 driver.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to decode an address and make any system memory map changes as required.
|
||||||
|
//
|
||||||
|
static inline void mz700DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Decoding memory address or I/O address?
|
||||||
|
if(ioFlag == 0)
|
||||||
|
{
|
||||||
|
// #if(DEBUG_ENABLED & 1)
|
||||||
|
// if(Z80Ctrl->debug >= 2)
|
||||||
|
// {
|
||||||
|
// pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||||
|
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||||
|
//
|
||||||
|
// 0000 - 0FFF : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||||
|
// 1000 - CFFF : MZ80K/A/700 = RAM
|
||||||
|
// C000 - CFFF : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||||
|
// D000 - D7FF : MZ80K/A/700 = VRAM
|
||||||
|
// D800 - DFFF : MZ700 = Colour VRAM (MZ700)
|
||||||
|
// E000 - E003 : MZ80K/A/700 = 8255
|
||||||
|
// E004 - E007 : MZ80K/A/700 = 8254
|
||||||
|
// E008 - E00B : MZ80K/A/700 = LS367
|
||||||
|
// E00C - E00F : MZ80A = Memory Swap (MZ80A)
|
||||||
|
// E010 - E013 : MZ80A = Reset Memory Swap (MZ80A)
|
||||||
|
// E014 : MZ80A/700 = Normat CRT display
|
||||||
|
// E015 : MZ80A/700 = Reverse CRT display
|
||||||
|
// E200 - E2FF : MZ80A/700 = VRAM roll up/roll down.
|
||||||
|
// E800 - EFFF : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||||
|
// F000 - F7FF : MZ80K/A/700 = Floppy Disk interface.
|
||||||
|
// F800 - FFFF : MZ80K/A/700 = Floppy Disk interface.
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// #if(DEBUG_ENABLED & 1)
|
||||||
|
// if(Z80Ctrl->debug >= 2)
|
||||||
|
// {
|
||||||
|
// pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// Determine if this is a memory management port and update the memory page if required.
|
||||||
|
switch(address & 0x00FF)
|
||||||
|
{
|
||||||
|
// MZ700 memory mode switch.
|
||||||
|
//
|
||||||
|
// MZ-700
|
||||||
|
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||||
|
// ------------------------------
|
||||||
|
// OUT 0xE0 = |DRAM | |
|
||||||
|
// OUT 0xE1 = | | |DRAM
|
||||||
|
// OUT 0xE2 = |MONITOR | |
|
||||||
|
// OUT 0xE3 = | | |Memory Mapped I/O
|
||||||
|
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||||
|
// OUT 0xE5 = | | |Inhibit
|
||||||
|
// OUT 0xE6 = | | |<return>
|
||||||
|
//
|
||||||
|
// <return> = Return to the state prior to the complimentary command being invoked.
|
||||||
|
// Enable lower 4K block as DRAM
|
||||||
|
case IO_ADDR_E0:
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM.
|
||||||
|
case IO_ADDR_E1:
|
||||||
|
if(!Z80Ctrl->inhibitMode)
|
||||||
|
{
|
||||||
|
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
// MZ-700 mode we only work in first 64K block.
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Enable MOnitor ROM in lower 4K block
|
||||||
|
case IO_ADDR_E2:
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Enable Video RAM and Memory mapped peripherals in upper 12K block.
|
||||||
|
case IO_ADDR_E3:
|
||||||
|
if(!Z80Ctrl->inhibitMode)
|
||||||
|
{
|
||||||
|
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Reset to power on condition memory map.
|
||||||
|
case IO_ADDR_E4:
|
||||||
|
// Lower 4K set to Monitor ROM.
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
if(!Z80Ctrl->inhibitMode)
|
||||||
|
{
|
||||||
|
// Upper 12K to hardware.
|
||||||
|
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it.
|
||||||
|
case IO_ADDR_E5:
|
||||||
|
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
backupMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx);
|
||||||
|
}
|
||||||
|
Z80Ctrl->inhibitMode = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Restore D000-FFFF to its original state.
|
||||||
|
case IO_ADDR_E6:
|
||||||
|
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
restoreMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||||
|
}
|
||||||
|
Z80Ctrl->inhibitMode = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Port is not a memory management port.
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||||
|
static inline uint8_t mz700Read(zuint16 address, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t data = 0xFF;
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if(isVirtualMemory(address))
|
||||||
|
{
|
||||||
|
// Retrieve data from virtual memory.
|
||||||
|
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to handle writes.
|
||||||
|
static inline void mz700Write(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
// uint32_t idx;
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if(isVirtualRAM(address))
|
||||||
|
{
|
||||||
|
// Update virtual memory.
|
||||||
|
writeVirtualRAM(address, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
382
software/FusionX/src/z80drv/src/z80vhw_mz80a.c
Normal file
382
software/FusionX/src/z80drv/src/z80vhw_mz80a.c
Normal file
@@ -0,0 +1,382 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Name: z80vhw_mz80a.c
|
||||||
|
// Created: Oct 2022
|
||||||
|
// Author(s): Philip Smart
|
||||||
|
// Description: Z80 Virtual Hardware Driver - MZ-80A
|
||||||
|
// This file contains the methods used to emulate the original Sharp MZ-80A without
|
||||||
|
// any additions, such as the RFS or TZFS boards.
|
||||||
|
//
|
||||||
|
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||||
|
// and as such, they are included like header files rather than C linked object files.
|
||||||
|
// Credits:
|
||||||
|
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||||
|
//
|
||||||
|
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||||
|
//
|
||||||
|
// Notes: See Makefile to enable/disable conditional components
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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/>.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include "z80io.h"
|
||||||
|
|
||||||
|
#include <gpio_table.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <infinity2m/gpio.h>
|
||||||
|
#include <infinity2m/registers.h>
|
||||||
|
|
||||||
|
// Device constants.
|
||||||
|
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||||
|
|
||||||
|
// 40/80 Video Module control registers.
|
||||||
|
//
|
||||||
|
#define DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||||
|
|
||||||
|
// PCW control.
|
||||||
|
typedef struct {
|
||||||
|
// MZ-80A can relocate the lower 4K ROM by swapping RAM at 0xC000.
|
||||||
|
uint8_t memSwitch;
|
||||||
|
|
||||||
|
uint8_t regCtrl; // Control register.
|
||||||
|
} t_MZ80ACtrl;
|
||||||
|
|
||||||
|
// RFS Board control.
|
||||||
|
static t_MZ80ACtrl MZ80ACtrl;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Method to setup the memory page config to reflect the PCW configuration.
|
||||||
|
void mz80aSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Setup defaults.
|
||||||
|
MZ80ACtrl.memSwitch = 0x00;
|
||||||
|
MZ80ACtrl.regCtrl = 0x00;
|
||||||
|
|
||||||
|
// Setup default mode according to run mode, ie. Physical run or Virtual run.
|
||||||
|
//
|
||||||
|
if(mode == USE_PHYSICAL_RAM)
|
||||||
|
{
|
||||||
|
// Initialise the page pointers and memory to use physical RAM.
|
||||||
|
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx >= 0 && idx < 0x1000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0x1000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xD000 && idx < 0xE000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE000 && idx < 0xE800)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE800 && idx < 0x10000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel refresh as using physical RAM for program automatically refreshes DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 0;
|
||||||
|
}
|
||||||
|
else if(mode == USE_VIRTUAL_RAM)
|
||||||
|
{
|
||||||
|
// Initialise the page pointers and memory to use virtual RAM.
|
||||||
|
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx >= 0 && idx < 0x1000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0x1000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xD000 && idx < 0xE000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE000 && idx < 0xE800)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE800 && idx < 0xF000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_HW, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xF000 && idx < 0x10000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Original mode, ie. no virtual devices active, copy the host BIOS into the Virtual ROM and initialise remainder of ROM memory
|
||||||
|
// such that the host behaves as per original spec.
|
||||||
|
pr_info("Sync Host BIOS to virtual ROM.\n");
|
||||||
|
for(idx=0; idx < Z80_VIRTUAL_ROM_SIZE; idx++)
|
||||||
|
{
|
||||||
|
if((idx >= 0x0000 && idx < 0x1000) || (idx >= 0xF000 && idx < 0x10000))
|
||||||
|
{
|
||||||
|
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||||
|
while(CPLD_READY() == 0);
|
||||||
|
Z80Ctrl->rom[idx] = z80io_PRL_Read8(1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Z80Ctrl->rom[idx] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_info("MZ-80A Memory Setup complete.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to load a ROM image into the RAM memory.
|
||||||
|
//
|
||||||
|
uint8_t mz80aLoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t result = 0;
|
||||||
|
long noBytes;
|
||||||
|
struct file *fp;
|
||||||
|
|
||||||
|
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||||
|
if(IS_ERR(fp))
|
||||||
|
{
|
||||||
|
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||||
|
result = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
vfs_llseek(fp, 0, SEEK_SET);
|
||||||
|
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||||
|
if(noBytes < loadSize)
|
||||||
|
{
|
||||||
|
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||||
|
}
|
||||||
|
filp_close(fp,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||||
|
void mz80aInit(uint8_t mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have
|
||||||
|
// bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating
|
||||||
|
// when first powered on.
|
||||||
|
pr_info("Sync Host RAM to virtual RAM.\n");
|
||||||
|
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||||
|
{
|
||||||
|
if(idx >= 0x1000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||||
|
while(CPLD_READY() == 0);
|
||||||
|
Z80Ctrl->ram[idx] = z80io_PRL_Read8(1);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
Z80Ctrl->ram[idx] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MZ80ACtrl.memSwitch = 0;
|
||||||
|
|
||||||
|
// If the 40/80 Video Module board is installed, ensure 40 character mode is selected.
|
||||||
|
SPI_SEND_32(DSPCTL, CPLD_CMD_READ_ADDR);
|
||||||
|
while(CPLD_READY() == 0);
|
||||||
|
SPI_SEND_32(DSPCTL, CPLD_CMD_WRITE_ADDR);
|
||||||
|
|
||||||
|
pr_info("Enabling MZ-80A driver.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any de-initialisation when the driver is removed.
|
||||||
|
void mz80aRemove(void)
|
||||||
|
{
|
||||||
|
pr_info("Removing MZ-80A driver.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to decode an address and make any system memory map changes as required.
|
||||||
|
//
|
||||||
|
static inline void mz80aDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Decoding memory address or I/O address?
|
||||||
|
if(ioFlag == 0)
|
||||||
|
{
|
||||||
|
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||||
|
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||||
|
//
|
||||||
|
// 0000 - 0FFF : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||||
|
// 1000 - CFFF : MZ80K/A/700 = RAM
|
||||||
|
// C000 - CFFF : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||||
|
// D000 - D7FF : MZ80K/A/700 = VRAM
|
||||||
|
// D800 - DFFF : MZ700 = Colour VRAM (MZ700)
|
||||||
|
// E000 - E003 : MZ80K/A/700 = 8255
|
||||||
|
// E004 - E007 : MZ80K/A/700 = 8254
|
||||||
|
// E008 - E00B : MZ80K/A/700 = LS367
|
||||||
|
// E00C - E00F : MZ80A = Memory Swap (MZ80A)
|
||||||
|
// E010 - E013 : MZ80A = Reset Memory Swap (MZ80A)
|
||||||
|
// E014 : MZ80A/700 = Normat CRT display
|
||||||
|
// E015 : MZ80A/700 = Reverse CRT display
|
||||||
|
// E200 - E2FF : MZ80A/700 = VRAM roll up/roll down.
|
||||||
|
// E800 - EFFF : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||||
|
// F000 - F7FF : MZ80K/A/700 = Floppy Disk interface.
|
||||||
|
// F800 - FFFF : MZ80K/A/700 = Floppy Disk interface.
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
// Memory map switch.
|
||||||
|
case 0xE00C: case 0xE00D: case 0xE00E: case 0xE00F:
|
||||||
|
if(readFlag)
|
||||||
|
{
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
||||||
|
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MZ80ACtrl.memSwitch = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Reset memory map switch.
|
||||||
|
case 0xE010: case 0xE011: case 0xE012: case 0xE013:
|
||||||
|
if(readFlag)
|
||||||
|
{
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (idx+0xC000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MZ80ACtrl.memSwitch = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// Determine if this is a memory management port and update the memory page if required.
|
||||||
|
switch(address & 0x00FF)
|
||||||
|
{
|
||||||
|
// Port is not a memory management port.
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||||
|
static inline uint8_t mz80aRead(zuint16 address, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t data = 0xFF;
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if(isVirtualMemory(address))
|
||||||
|
{
|
||||||
|
// Retrieve data from virtual memory.
|
||||||
|
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to handle writes.
|
||||||
|
static inline void mz80aWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
// uint32_t idx;
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
if(isVirtualRAM(address))
|
||||||
|
{
|
||||||
|
// Update virtual memory.
|
||||||
|
writeVirtualRAM(address, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
379
software/FusionX/src/z80drv/src/z80vhw_pcw.c
Normal file
379
software/FusionX/src/z80drv/src/z80vhw_pcw.c
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Name: z80vhw_pcw.c
|
||||||
|
// Created: Oct 2022
|
||||||
|
// Author(s): Philip Smart
|
||||||
|
// Description: Z80 Virtual Hardware Driver - Amstrad PCW-8xxx/PCW-9xxx
|
||||||
|
// This file contains the methods used to emulate the Amstrad PCW specific
|
||||||
|
// hardware.
|
||||||
|
//
|
||||||
|
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||||
|
// and as such, they are included like header files rather than C linked object files.
|
||||||
|
// Credits:
|
||||||
|
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||||
|
//
|
||||||
|
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||||
|
//
|
||||||
|
// Notes: See Makefile to enable/disable conditional components
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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/>.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/kthread.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include "z80io.h"
|
||||||
|
|
||||||
|
#include <gpio_table.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
#include <infinity2m/gpio.h>
|
||||||
|
#include <infinity2m/registers.h>
|
||||||
|
|
||||||
|
// Device constants.
|
||||||
|
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||||
|
|
||||||
|
// IO Ports.
|
||||||
|
#define IO_FDC_STATUS 0x00 // NEC765 FDC Status Register.
|
||||||
|
#define IO_FDC_DATA 0x01 // NEC765 FDC Data Register.
|
||||||
|
#define IO_MEMBNK0 0xF0 // Memory bank 0000:3FFF register.
|
||||||
|
#define IO_MEMBNK1 0xF1 // Memory bank 4000:7FFF register.
|
||||||
|
#define IO_MEMBNK2 0xF2 // Memory bank 8000:BFFF register.
|
||||||
|
#define IO_MEMBNK3 0xF3 // Memory bank C000:FFFF register.
|
||||||
|
#define IO_MEMLOCK 0xF4 // CPC mode memory lock range.
|
||||||
|
#define IO_ROLLERRAM 0xF5 // Set the Roller RAM address.
|
||||||
|
#define IO_VORIGIN 0xF6 // Set screen vertical origin.
|
||||||
|
#define IO_SCREENATTR 0xF7 // Set screen attributes.
|
||||||
|
#define IO_GACMD 0xF8 // Gatearray command register.
|
||||||
|
#define IO_GASTATUS 0xF8 // Gatearray status register.
|
||||||
|
|
||||||
|
// The boot code for the PCW-8256 is located within the printer controller. To avoid special hardware within the CPLD, this code is incorporated
|
||||||
|
// into this module for rapid loading into RAM.
|
||||||
|
#define ROM_DIR "/apps/FusionX/host/PCW/roms/"
|
||||||
|
#define ROM_PCW8_BOOT_FILENAME ROM_DIR "PCW8256_boot.bin"
|
||||||
|
#define ROM_PCW9_BOOT_FILENAME ROM_DIR "PCW9256_boot.bin"
|
||||||
|
|
||||||
|
// Boot ROM rom load and size definitions.
|
||||||
|
#define ROM_BOOT_LOAD_ADDR 0x000000
|
||||||
|
#define ROM_BOOT_SIZE 275
|
||||||
|
|
||||||
|
// PCW control.
|
||||||
|
typedef struct {
|
||||||
|
uint8_t regMemBank0; // Mirror of register F0, memory block select 0x0000-0x3FFF.
|
||||||
|
uint8_t regMemBank1; // Mirror of register F1, memory block select 0x4000-0x7FFF.
|
||||||
|
uint8_t regMemBank2; // Mirror of register F2, memory block select 0x8000-0xBFFF.
|
||||||
|
uint8_t regMemBank3; // Mirror of register F3, memory block select 0xC000-0xFFFF.
|
||||||
|
uint8_t regCPCPageMode; // Mirror of the CPC paging lock register F4.
|
||||||
|
uint8_t regRollerRAM; // Mirror of Roller-RAM address register.
|
||||||
|
uint8_t regCtrl; // Control register.
|
||||||
|
} t_PCWCtrl;
|
||||||
|
|
||||||
|
// RFS Board control.
|
||||||
|
static t_PCWCtrl PCWCtrl;
|
||||||
|
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Method to setup the memory page config to reflect the PCW configuration.
|
||||||
|
void pcwSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// The PCW contains upto 512KB of standard RAM which can be expnded to a physical max of 2MB. The kernel malloc limit is 2MB so the whole virtual
|
||||||
|
// memory can be mapped into the PCW memory address range.
|
||||||
|
|
||||||
|
// Setup defaults.
|
||||||
|
PCWCtrl.regMemBank0 = 0x00;
|
||||||
|
PCWCtrl.regMemBank1 = 0x01;
|
||||||
|
PCWCtrl.regMemBank2 = 0x02;
|
||||||
|
PCWCtrl.regMemBank3 = 0x03; // Keyboard is in locations 0x3FF0 - 0x3FFF of this memory block.
|
||||||
|
PCWCtrl.regCPCPageMode = 0x00;
|
||||||
|
PCWCtrl.regRollerRAM = 0x00;
|
||||||
|
PCWCtrl.regCtrl = 0x00;
|
||||||
|
|
||||||
|
// Initialise the page pointers and memory to reflect a PCW, lower 128K is used by video logic so must always be accessed in hardware.
|
||||||
|
for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx >= 0x0000 && idx < 0xFFF0)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+idx));
|
||||||
|
}
|
||||||
|
if(idx >= 0xFFF0 && idx < 0x10000)
|
||||||
|
{
|
||||||
|
// The keyboard is memory mapped into upper bytes of block 3.
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, (RAM_BASE_ADDR+idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 2;
|
||||||
|
|
||||||
|
// No I/O Ports on the RFS board.
|
||||||
|
pr_info("PCW Memory Setup complete.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to load a ROM image into the RAM memory.
|
||||||
|
//
|
||||||
|
uint8_t loadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t result = 0;
|
||||||
|
long noBytes;
|
||||||
|
struct file *fp;
|
||||||
|
|
||||||
|
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||||
|
if(IS_ERR(fp))
|
||||||
|
{
|
||||||
|
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||||
|
result = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
vfs_llseek(fp, 0, SEEK_SET);
|
||||||
|
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||||
|
if(noBytes < loadSize)
|
||||||
|
{
|
||||||
|
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||||
|
}
|
||||||
|
filp_close(fp,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||||
|
void pcwInit(uint8_t mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
//
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Clear memory as previous use or malloc can leave it randomly set.
|
||||||
|
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->ram[idx] = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable boot mode, we dont need to fetch the boot rom as we preload it.
|
||||||
|
SPI_SEND32( (0x00F8 << 16) | (0x00 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
|
||||||
|
// Load boot ROM.
|
||||||
|
loadROM(mode == 0 ? ROM_PCW8_BOOT_FILENAME : ROM_PCW9_BOOT_FILENAME, ROM_BOOT_LOAD_ADDR, ROM_BOOT_SIZE);
|
||||||
|
|
||||||
|
// Reset.
|
||||||
|
//SPI_SEND32( (0x00F8 << 16) | (0x01 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
|
||||||
|
// First two bytes to NULL as were not using the bootstrap and normal operations after bootstrap would disable the mode.
|
||||||
|
Z80Ctrl->ram[0] = 0x00;
|
||||||
|
Z80Ctrl->ram[1] = 0x00;
|
||||||
|
|
||||||
|
pr_info("Enabling PCW-%s driver.\n", mode == 0 ? "8256" : "9256");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform any de-initialisation when the driver is removed.
|
||||||
|
void pcwRemove(void)
|
||||||
|
{
|
||||||
|
pr_info("Removing PCW driver.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to decode an address and make any system memory map changes as required.
|
||||||
|
//
|
||||||
|
static inline void pcwDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// IO Switch.
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address&0xff)
|
||||||
|
{
|
||||||
|
case IO_FDC_STATUS:
|
||||||
|
//pr_info("FDC_STATUS:%02x\n", data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_FDC_DATA:
|
||||||
|
//pr_info("FDC_DATA:%02x\n", data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_MEMBNK0:
|
||||||
|
if(!readFlag)
|
||||||
|
{
|
||||||
|
PCWCtrl.regMemBank0 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank0;
|
||||||
|
pr_info("Setting Bank 0:%02x\n", PCWCtrl.regMemBank0);
|
||||||
|
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType((idx+0x0000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank0 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank0*16384)+idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_MEMBNK1:
|
||||||
|
if(!readFlag)
|
||||||
|
{
|
||||||
|
PCWCtrl.regMemBank1 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank1;
|
||||||
|
pr_info("Setting Bank 1:%02x\n", PCWCtrl.regMemBank1);
|
||||||
|
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType((idx+0x4000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank1 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank1*16384)+idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_MEMBNK2:
|
||||||
|
if(!readFlag)
|
||||||
|
{
|
||||||
|
PCWCtrl.regMemBank2 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank2;
|
||||||
|
pr_info("Setting Bank 2:%02x\n", PCWCtrl.regMemBank2);
|
||||||
|
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType((idx+0x8000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank2 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank2*16384)+idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_MEMBNK3:
|
||||||
|
if(!readFlag)
|
||||||
|
{
|
||||||
|
PCWCtrl.regMemBank3 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank3;
|
||||||
|
pr_info("Setting Bank 3:%02x\n", PCWCtrl.regMemBank3);
|
||||||
|
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
if(idx < 0x3FF0)
|
||||||
|
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank3 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank3*16384)+idx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_MEMLOCK:
|
||||||
|
if(!readFlag)
|
||||||
|
{
|
||||||
|
pr_info("MEMLOCK:%02x\n", data);
|
||||||
|
PCWCtrl.regCPCPageMode = data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_ROLLERRAM:
|
||||||
|
if(!readFlag)
|
||||||
|
{
|
||||||
|
pr_info("********RollerRAM********:%02x => %04x\n", data, (((data >> 5)&0x7) * 16384)+((data&0x1f)*512));
|
||||||
|
PCWCtrl.regRollerRAM = data;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IO_VORIGIN:
|
||||||
|
pr_info("VORIGIN:%02x\n", data);
|
||||||
|
break;
|
||||||
|
case IO_SCREENATTR:
|
||||||
|
pr_info("SCREENATTR:%02x\n", data);
|
||||||
|
break;
|
||||||
|
case IO_GACMD:
|
||||||
|
pr_info("GACMD:%02x\n", data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
pr_info("Unknown:ADDR:%02x,%02x\n", address&0xff, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
// Memory map switch.
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||||
|
static inline uint8_t pcwRead(zuint16 address, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t data = 0xFF;
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
// Return the contents of the ROM at given address.
|
||||||
|
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if(DEBUG_ENABLED & 1)
|
||||||
|
if(Z80Ctrl->debug >= 3) pr_info("PCW-Read:%04x, BK0:%02x, BK1:%02x, BK2:%02x, BK3:%02x, CTRL:%02x\n", address, PCWCtrl.regMemBank0, PCWCtrl.regMemBank1, PCWCtrl.regMemBank2, PCWCtrl.regMemBank3, PCWCtrl.regCtrl);
|
||||||
|
#endif
|
||||||
|
return(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to handle writes.
|
||||||
|
static inline void pcwWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
// uint32_t idx;
|
||||||
|
|
||||||
|
|
||||||
|
// I/O Operation?
|
||||||
|
if(ioFlag)
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
switch(address)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
// Any unprocessed write is commited to RAM.
|
||||||
|
writeVirtualRAM(address, data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if(DEBUG_ENABLED & 1)
|
||||||
|
if(Z80Ctrl->debug >= 3) pr_info("PCW-Write:%04x, BK0:%02x, BK1:%02x, BK2:%02x, BK3:%02x, CTRL:%02x\n", address, PCWCtrl.regMemBank0, PCWCtrl.regMemBank1, PCWCtrl.regMemBank2, PCWCtrl.regMemBank3, PCWCtrl.regCtrl);
|
||||||
|
#endif
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -67,6 +67,10 @@
|
|||||||
#define BNKSELUSER 0xEFFE // Select RFS Bank2 (User ROM)
|
#define BNKSELUSER 0xEFFE // Select RFS Bank2 (User ROM)
|
||||||
#define BNKCTRL 0xEFFF // Bank Control register (read/write).
|
#define BNKCTRL 0xEFFF // Bank Control register (read/write).
|
||||||
|
|
||||||
|
// 40/80 Video Module control registers.
|
||||||
|
//
|
||||||
|
#define DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||||
|
|
||||||
//
|
//
|
||||||
// RFS v2 Control Register constants.
|
// RFS v2 Control Register constants.
|
||||||
//
|
//
|
||||||
@@ -87,7 +91,13 @@
|
|||||||
#define BNKCTRLDEF BBMOSI+SDCS+BBCLK // Default on startup for the Bank Control register.
|
#define BNKCTRLDEF BBMOSI+SDCS+BBCLK // Default on startup for the Bank Control register.
|
||||||
|
|
||||||
// RFS Board ROM rom filename definitions.
|
// RFS Board ROM rom filename definitions.
|
||||||
#define ROM_DIR "/apps/FusionX/host/MZ-80A/RFS/"
|
#if(TARGET_HOST_MZ80A == 1)
|
||||||
|
#define ROM_DIR "/apps/FusionX/host/MZ-80A/RFS/"
|
||||||
|
#elif(TARGET_HOST_MZ700 == 1)
|
||||||
|
#define ROM_DIR "/apps/FusionX/host/MZ-700/RFS/"
|
||||||
|
#else
|
||||||
|
#error "Unknown host configured."
|
||||||
|
#endif
|
||||||
#define ROM_MROM_40C_FILENAME ROM_DIR "MROM_256_40c.bin"
|
#define ROM_MROM_40C_FILENAME ROM_DIR "MROM_256_40c.bin"
|
||||||
#define ROM_USER_I_40C_FILENAME ROM_DIR "USER_ROM_256_40c.bin"
|
#define ROM_USER_I_40C_FILENAME ROM_DIR "USER_ROM_256_40c.bin"
|
||||||
#define ROM_USER_II_40C_FILENAME ROM_DIR "USER_ROM_II_256_40c.bin"
|
#define ROM_USER_II_40C_FILENAME ROM_DIR "USER_ROM_II_256_40c.bin"
|
||||||
@@ -167,6 +177,7 @@ typedef struct {
|
|||||||
uint8_t upCntr; // Register enable up counter.
|
uint8_t upCntr; // Register enable up counter.
|
||||||
uint32_t mromAddr; // Actual address in MROM of active bank.
|
uint32_t mromAddr; // Actual address in MROM of active bank.
|
||||||
uint32_t uromAddr; // Actual address in UROM of active bank.
|
uint32_t uromAddr; // Actual address in UROM of active bank.
|
||||||
|
uint8_t memSwitch; // MZ-80A can relocate the lower 4K ROM by swapping RAM at 0xC000.
|
||||||
t_SDCtrl sd; // SD Control.
|
t_SDCtrl sd; // SD Control.
|
||||||
} t_RFSCtrl;
|
} t_RFSCtrl;
|
||||||
|
|
||||||
@@ -194,7 +205,7 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
|||||||
RFSCtrl.regCtrl = 0x00;
|
RFSCtrl.regCtrl = 0x00;
|
||||||
RFSCtrl.mromAddr = MROM_ADDR;
|
RFSCtrl.mromAddr = MROM_ADDR;
|
||||||
RFSCtrl.uromAddr = USER_ROM_I_ADDR;
|
RFSCtrl.uromAddr = USER_ROM_I_ADDR;
|
||||||
Z80Ctrl->memSwitch = 0;
|
RFSCtrl.memSwitch = 0;
|
||||||
RFSCtrl.sd.trainingCnt = 0;
|
RFSCtrl.sd.trainingCnt = 0;
|
||||||
RFSCtrl.sd.initialised = 0;
|
RFSCtrl.sd.initialised = 0;
|
||||||
RFSCtrl.sd.dataOutFlag = 0;
|
RFSCtrl.sd.dataOutFlag = 0;
|
||||||
@@ -214,7 +225,19 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
|||||||
{
|
{
|
||||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||||
}
|
}
|
||||||
if(idx >= 0xE800 && idx < 0xF000)
|
else if(idx >= 0x1000 && idx < 0xD000)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xD000 && idx < 0xE000)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE000 && idx < 0xE800)
|
||||||
|
{
|
||||||
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
else if(idx >= 0xE800 && idx < 0xF000)
|
||||||
{
|
{
|
||||||
// Memory is both ROM and hardware, the registers share the same address space.
|
// Memory is both ROM and hardware, the registers share the same address space.
|
||||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_HW, (RFSCtrl.uromAddr+(idx-0xE800)));
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_HW, (RFSCtrl.uromAddr+(idx-0xE800)));
|
||||||
@@ -224,6 +247,18 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
|||||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, (idx+(Z80_VIRTUAL_ROM_SIZE - 0x10000)));
|
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, (idx+(Z80_VIRTUAL_ROM_SIZE - 0x10000)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||||
|
Z80Ctrl->refreshDRAM = 2;
|
||||||
|
|
||||||
|
#if (TARGET_HOST_MZ700 == 1)
|
||||||
|
// Reset memory paging to default.
|
||||||
|
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
#endif
|
||||||
|
|
||||||
// No I/O Ports on the RFS board.
|
// No I/O Ports on the RFS board.
|
||||||
pr_info("RFS Memory Setup complete.\n");
|
pr_info("RFS Memory Setup complete.\n");
|
||||||
@@ -231,7 +266,7 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
|||||||
|
|
||||||
// Method to load a ROM image into the ROM memory.
|
// Method to load a ROM image into the ROM memory.
|
||||||
//
|
//
|
||||||
uint8_t loadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
uint8_t rfsLoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||||
{
|
{
|
||||||
// Locals.
|
// Locals.
|
||||||
uint8_t result = 0;
|
uint8_t result = 0;
|
||||||
@@ -264,10 +299,10 @@ void rfsInit(uint8_t mode80c)
|
|||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
|
|
||||||
// Load ROMS according to the display configuration, 40 char = standard, 80 char = 40/80 board installed.
|
// Load ROMS according to the display configuration, 40 char = standard, 80 char = 40/80 board installed.
|
||||||
loadROM(mode80c == 0 ? ROM_MROM_40C_FILENAME : ROM_MROM_80C_FILENAME, ROM_MROM_LOAD_ADDR, ROM_MROM_SIZE);
|
rfsLoadROM(mode80c == 0 ? ROM_MROM_40C_FILENAME : ROM_MROM_80C_FILENAME, ROM_MROM_LOAD_ADDR, ROM_MROM_SIZE);
|
||||||
loadROM(mode80c == 0 ? ROM_USER_I_40C_FILENAME : ROM_USER_I_80C_FILENAME, ROM_USER_I_LOAD_ADDR, ROM_MROM_SIZE);
|
rfsLoadROM(mode80c == 0 ? ROM_USER_I_40C_FILENAME : ROM_USER_I_80C_FILENAME, ROM_USER_I_LOAD_ADDR, ROM_MROM_SIZE);
|
||||||
loadROM(mode80c == 0 ? ROM_USER_II_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_II_LOAD_ADDR, ROM_MROM_SIZE);
|
rfsLoadROM(mode80c == 0 ? ROM_USER_II_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_II_LOAD_ADDR, ROM_MROM_SIZE);
|
||||||
loadROM(mode80c == 0 ? ROM_USER_III_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_III_LOAD_ADDR, ROM_MROM_SIZE);
|
rfsLoadROM(mode80c == 0 ? ROM_USER_III_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_III_LOAD_ADDR, ROM_MROM_SIZE);
|
||||||
|
|
||||||
// Copy the Floppy ROM to the top portion of ROM. USER III isnt normally used and if it is, 4K will be free.
|
// Copy the Floppy ROM to the top portion of ROM. USER III isnt normally used and if it is, 4K will be free.
|
||||||
for(idx=0xF000; idx < 0x10000; idx++)
|
for(idx=0xF000; idx < 0x10000; idx++)
|
||||||
@@ -276,7 +311,13 @@ void rfsInit(uint8_t mode80c)
|
|||||||
while(CPLD_READY() == 0);
|
while(CPLD_READY() == 0);
|
||||||
Z80Ctrl->rom[idx+(Z80_VIRTUAL_ROM_SIZE-0x10000)] = z80io_PRL_Read8(1);
|
Z80Ctrl->rom[idx+(Z80_VIRTUAL_ROM_SIZE-0x10000)] = z80io_PRL_Read8(1);
|
||||||
}
|
}
|
||||||
pr_info("Enabling RFS driver.\n");
|
|
||||||
|
#if (TARGET_HOST_MZ700 == 1)
|
||||||
|
// Reset memory paging to default.
|
||||||
|
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pr_info("Enabling RFS(%d) driver.\n", mode80c == 1 ? 80 : 40);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +345,7 @@ static inline void rfsDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t
|
|||||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
||||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||||
}
|
}
|
||||||
Z80Ctrl->memSwitch = 0x01;
|
RFSCtrl.memSwitch = 0x01;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset memory map switch.
|
// Reset memory map switch.
|
||||||
@@ -318,7 +359,7 @@ static inline void rfsDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t
|
|||||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Z80Ctrl->memSwitch = 0x00;
|
RFSCtrl.memSwitch = 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -755,7 +796,7 @@ static inline void rfsWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
|||||||
// Update memory map to reflect register change.
|
// Update memory map to reflect register change.
|
||||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
{
|
{
|
||||||
if(Z80Ctrl->memSwitch)
|
if(RFSCtrl.memSwitch)
|
||||||
{
|
{
|
||||||
// Monitor ROM is located at 0xC000.
|
// Monitor ROM is located at 0xC000.
|
||||||
setMemoryType((0xC000+idx)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
setMemoryType((0xC000+idx)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||||
//
|
//
|
||||||
// History: Feb 2023 v1.0 - Initial write based on the tranZPUter SW hardware.
|
// History: Feb 2023 v1.0 - Initial write based on the tranZPUter SW hardware.
|
||||||
|
// Apr 2023 v1.1 - Updates & bug fixes.
|
||||||
//
|
//
|
||||||
// Notes: See Makefile to enable/disable conditional components
|
// Notes: See Makefile to enable/disable conditional components
|
||||||
//
|
//
|
||||||
@@ -72,6 +73,9 @@ typedef struct {
|
|||||||
// TZPU Board control.
|
// TZPU Board control.
|
||||||
static t_TZPUCtrl TZPUCtrl;
|
static t_TZPUCtrl TZPUCtrl;
|
||||||
|
|
||||||
|
// Forward prototypes.
|
||||||
|
static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag);
|
||||||
|
|
||||||
//-------------------------------------------------------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
@@ -115,15 +119,145 @@ static t_TZPUCtrl TZPUCtrl;
|
|||||||
// 30 - All memory and IO are on the tranZPUter board, 64K block 6 selected.
|
// 30 - All memory and IO are on the tranZPUter board, 64K block 6 selected.
|
||||||
// 31 - All memory and IO are on the tranZPUter board, 64K block 7 selected.
|
// 31 - All memory and IO are on the tranZPUter board, 64K block 7 selected.
|
||||||
|
|
||||||
|
// Method to setup the memory page config to reflect installation of a tranZPUter SW Board. This sets up the default
|
||||||
|
// as the memory map changes according to selection and handled in-situ.
|
||||||
|
void tzpuSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// The tranZPUter SW uses a CPLD to set a 4K Z80 memory range window into a 512K-1MB linear RAM block. The actual map required
|
||||||
|
// at any one time is governed by the Memory Config register at I/O port 0x60.
|
||||||
|
// This method sets the initial state, which is a normal Sharp operating mode, all memory and IO (except tranZPUter
|
||||||
|
// control IO block) are on the mainboard.
|
||||||
|
|
||||||
|
// Setup defaults.
|
||||||
|
TZPUCtrl.clkSrc = 0x00; // Clock defaults to host.
|
||||||
|
TZPUCtrl.regCmd = 0x00; // Default for the CPLD Command.
|
||||||
|
TZPUCtrl.regCmdStatus = 0x00; // Default for the CPLD Command Status.
|
||||||
|
TZPUCtrl.regCpuCfg = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
||||||
|
TZPUCtrl.regCpuInfo = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
||||||
|
// Setup the CPLD status value, this is used by the host for configuration of tzfs.
|
||||||
|
#if(TARGET_HOST_MZ80A == 1)
|
||||||
|
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ80A;
|
||||||
|
#endif
|
||||||
|
#if(TARGET_HOST_MZ700 == 1)
|
||||||
|
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ700;
|
||||||
|
#endif
|
||||||
|
#if(TARGET_HOST_MZ2000 == 1)
|
||||||
|
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ2000;
|
||||||
|
#endif
|
||||||
|
TZPUCtrl.regCpldCfg = 0x00; // Not used, as no CPLD available, but need to store/return value if addressed.
|
||||||
|
|
||||||
|
// Default memory mode, TZFS.
|
||||||
|
Z80Ctrl->memoryMode = TZMM_ORIG;
|
||||||
|
|
||||||
|
// Reset IO mapping.
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||||
|
}
|
||||||
|
|
||||||
|
// I/O Ports on the tranZPUter SW board. All hosts have the same ports for the tzpu board.
|
||||||
|
for(idx=0x0000; idx < IO_PAGE_SIZE; idx+=0x0100)
|
||||||
|
{
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CTRLLATCH] = IO_TZ_CTRLLATCH | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_SETXMHZ] = IO_TZ_SETXMHZ | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_SET2MHZ] = IO_TZ_SET2MHZ | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CLKSELRD] = IO_TZ_CLKSELRD | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_SVCREQ] = IO_TZ_SVCREQ | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_SYSREQ] = IO_TZ_SYSREQ | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CPLDCMD] = IO_TZ_CPLDCMD | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CPLDSTATUS] = IO_TZ_CPLDSTATUS | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CPUCFG] = IO_TZ_CPUCFG | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CPUSTATUS] = IO_TZ_CPUSTATUS | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CPUINFO] = IO_TZ_CPUINFO | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CPLDCFG] = IO_TZ_CPLDCFG | IO_TYPE_VIRTUAL_HW;
|
||||||
|
Z80Ctrl->iopage[idx+IO_TZ_CPLDINFO] = IO_TZ_CPLDINFO | IO_TYPE_VIRTUAL_HW;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (TARGET_HOST_MZ700 == 1)
|
||||||
|
// Reset memory paging to default.
|
||||||
|
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pr_info("TZPU Memory Setup complete.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to load a ROM image into the ROM memory.
|
||||||
|
//
|
||||||
|
uint8_t tzpuLoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||||
|
{
|
||||||
|
// Locals.
|
||||||
|
uint8_t result = 0;
|
||||||
|
long noBytes;
|
||||||
|
struct file *fp;
|
||||||
|
|
||||||
|
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||||
|
if(IS_ERR(fp))
|
||||||
|
{
|
||||||
|
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||||
|
result = 1;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
vfs_llseek(fp, 0, SEEK_SET);
|
||||||
|
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->rom[loadAddr], loadSize);
|
||||||
|
if(noBytes < loadSize)
|
||||||
|
{
|
||||||
|
// pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||||
|
}
|
||||||
|
filp_close(fp,NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(result);
|
||||||
|
}
|
||||||
|
|
||||||
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||||
void tzpuInit(void)
|
void tzpuInit(void)
|
||||||
{
|
{
|
||||||
|
// Setup all initial TZFS memory modes
|
||||||
|
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_ORIG, 1);
|
||||||
|
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS, 1);
|
||||||
|
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS2, 1);
|
||||||
|
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS3, 1);
|
||||||
|
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS4, 1);
|
||||||
|
|
||||||
|
// Ensure memory configuration is correct before requesting K64F to load Bios.
|
||||||
|
tzpuSetupMemory(USE_VIRTUAL_RAM);
|
||||||
|
|
||||||
|
// Default memory mode, TZFS.
|
||||||
|
Z80Ctrl->memoryMode = TZMM_TZFS;
|
||||||
|
|
||||||
|
#if (TARGET_HOST_MZ700 == 1)
|
||||||
|
// Reset memory paging to default.
|
||||||
|
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// New memory maps setup, perform a reset so that the K64F CPU loads the required ROMS.
|
||||||
|
sendSignal(Z80Ctrl->ioTask, SIGUSR1);
|
||||||
|
|
||||||
pr_info("Enabling TZPU driver.\n");
|
pr_info("Enabling TZPU driver.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform any de-initialisation when the driver is removed.
|
// Perform any de-initialisation when the driver is removed.
|
||||||
void tzpuRemove(void)
|
void tzpuRemove(void)
|
||||||
{
|
{
|
||||||
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
// Go through and clear all memory maps, leave the original page in slot 0.
|
||||||
|
for(idx=1; idx < MEMORY_MODES; idx++)
|
||||||
|
{
|
||||||
|
if(Z80Ctrl->page[idx] != NULL)
|
||||||
|
{
|
||||||
|
kfree(Z80Ctrl->page[idx]);
|
||||||
|
Z80Ctrl->page[idx] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default memory mode, ORIG.
|
||||||
|
Z80Ctrl->memoryMode = TZMM_ORIG;
|
||||||
|
|
||||||
pr_info("Removing TZPU driver.\n");
|
pr_info("Removing TZPU driver.\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -133,27 +267,154 @@ void tzpuRemove(void)
|
|||||||
static inline void tzpuDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
static inline void tzpuDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||||
{
|
{
|
||||||
// Locals.
|
// Locals.
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
// I/O or Memory?
|
// I/O or Memory?
|
||||||
if(ioFlag == 0)
|
if(ioFlag == 0)
|
||||||
{
|
{
|
||||||
// Memory map switch.
|
// #if(DEBUG_ENABLED & 1)
|
||||||
if(readFlag == 0)
|
// if(Z80Ctrl->debug >= 2)
|
||||||
|
// {
|
||||||
|
// pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||||
|
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||||
|
//
|
||||||
|
// 0000 - 0FFF : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||||
|
// 1000 - CFFF : MZ80K/A/700 = RAM
|
||||||
|
// C000 - CFFF : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||||
|
// D000 - D7FF : MZ80K/A/700 = VRAM
|
||||||
|
// D800 - DFFF : MZ700 = Colour VRAM (MZ700)
|
||||||
|
// E000 - E003 : MZ80K/A/700 = 8255
|
||||||
|
// E004 - E007 : MZ80K/A/700 = 8254
|
||||||
|
// E008 - E00B : MZ80K/A/700 = LS367
|
||||||
|
// E00C - E00F : MZ80A = Memory Swap (MZ80A)
|
||||||
|
// E010 - E013 : MZ80A = Reset Memory Swap (MZ80A)
|
||||||
|
// E014 : MZ80A/700 = Normat CRT display
|
||||||
|
// E015 : MZ80A/700 = Reverse CRT display
|
||||||
|
// E200 - E2FF : MZ80A/700 = VRAM roll up/roll down.
|
||||||
|
// E800 - EFFF : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||||
|
// F000 - F7FF : MZ80K/A/700 = Floppy Disk interface.
|
||||||
|
// F800 - FFFF : MZ80K/A/700 = Floppy Disk interface.
|
||||||
|
switch(address)
|
||||||
{
|
{
|
||||||
|
default:
|
||||||
} else
|
break;
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
// I/O Decoding.
|
// I/O Decoding.
|
||||||
{
|
{
|
||||||
// Only lower 8 bits recognised in the tzpu.
|
// #if(DEBUG_ENABLED & 1)
|
||||||
switch(address & 0xFF)
|
// if(Z80Ctrl->debug >= 2)
|
||||||
|
// {
|
||||||
|
// pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// Determine if this is a memory management port and update the memory page if required.
|
||||||
|
switch(address & 0x00FF)
|
||||||
{
|
{
|
||||||
default:
|
// MZ700 memory mode switch.
|
||||||
|
//
|
||||||
|
// MZ-700
|
||||||
|
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||||
|
// ------------------------------
|
||||||
|
// OUT 0xE0 = |DRAM | |
|
||||||
|
// OUT 0xE1 = | | |DRAM
|
||||||
|
// OUT 0xE2 = |MONITOR | |
|
||||||
|
// OUT 0xE3 = | | |Memory Mapped I/O
|
||||||
|
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||||
|
// OUT 0xE5 = | | |Inhibit
|
||||||
|
// OUT 0xE6 = | | |<return>
|
||||||
|
//
|
||||||
|
// <return> = Return to the state prior to the complimentary command being invoked.
|
||||||
|
// Enable lower 4K block as DRAM
|
||||||
|
case IO_ADDR_E0:
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM.
|
||||||
|
case IO_ADDR_E1:
|
||||||
|
if(!Z80Ctrl->inhibitMode)
|
||||||
|
{
|
||||||
|
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
// MZ-700 mode we only work in first 64K block.
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Enable MOnitor ROM in lower 4K block
|
||||||
|
case IO_ADDR_E2:
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Enable Video RAM and Memory mapped peripherals in upper 12K block.
|
||||||
|
case IO_ADDR_E3:
|
||||||
|
if(!Z80Ctrl->inhibitMode)
|
||||||
|
{
|
||||||
|
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Reset to power on condition memory map.
|
||||||
|
case IO_ADDR_E4:
|
||||||
|
// Lower 4K set to Monitor ROM.
|
||||||
|
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||||
|
}
|
||||||
|
if(!Z80Ctrl->inhibitMode)
|
||||||
|
{
|
||||||
|
// Upper 12K to hardware.
|
||||||
|
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||||
|
}
|
||||||
|
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it.
|
||||||
|
case IO_ADDR_E5:
|
||||||
|
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
backupMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||||
|
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx);
|
||||||
|
}
|
||||||
|
Z80Ctrl->inhibitMode = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Restore D000-FFFF to its original state.
|
||||||
|
case IO_ADDR_E6:
|
||||||
|
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
|
{
|
||||||
|
restoreMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||||
|
}
|
||||||
|
Z80Ctrl->inhibitMode = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Port is not a memory management port.
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +513,9 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
|||||||
switch(address & 0x00FF)
|
switch(address & 0x00FF)
|
||||||
{
|
{
|
||||||
case IO_TZ_CTRLLATCH:
|
case IO_TZ_CTRLLATCH:
|
||||||
//pr_info("CTRLLATCH:%02x\n", data);
|
#if(DEBUG_ENABLED & 0x01)
|
||||||
|
if(Z80Ctrl->debug >=3) pr_info("CTRLLATCH:%02x\n", data);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Check to see if the memory mode page has been allocated for requested mode, if it hasnt, we need to allocate and then define.
|
// Check to see if the memory mode page has been allocated for requested mode, if it hasnt, we need to allocate and then define.
|
||||||
Z80Ctrl->memoryMode = (data & (MEMORY_MODES - 1));
|
Z80Ctrl->memoryMode = (data & (MEMORY_MODES - 1));
|
||||||
@@ -264,13 +527,13 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
|||||||
(Z80Ctrl->page[Z80Ctrl->memoryMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL);
|
(Z80Ctrl->page[Z80Ctrl->memoryMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL);
|
||||||
if ((Z80Ctrl->page[Z80Ctrl->memoryMode]) == NULL)
|
if ((Z80Ctrl->page[Z80Ctrl->memoryMode]) == NULL)
|
||||||
{
|
{
|
||||||
pr_info("z80drv: failed to allocate memory mapping page:%d memory!", Z80Ctrl->memoryMode);
|
pr_info("z80drv: failed to allocate memory mapping page:%d memory!", Z80Ctrl->memoryMode);
|
||||||
Z80Ctrl->page[Z80Ctrl->memoryMode] = Z80Ctrl->page[0];
|
Z80Ctrl->page[Z80Ctrl->memoryMode] = Z80Ctrl->page[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// A lot of the memory maps below are identical, minor changes such as RAM bank. This is a direct conversion of the VHDL code from the CPLD.
|
// A lot of the memory maps below are identical, minor changes such as RAM bank. This is a direct conversion of the VHDL code from the CPLD.
|
||||||
//
|
//
|
||||||
for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||||
{
|
{
|
||||||
switch(Z80Ctrl->memoryMode)
|
switch(Z80Ctrl->memoryMode)
|
||||||
{
|
{
|
||||||
@@ -744,71 +1007,3 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to setup the memory page config to reflect installation of a tranZPUter SW Board. This sets up the default
|
|
||||||
// as the memory map changes according to selection and handled in-situ.
|
|
||||||
void tzpuSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
|
||||||
{
|
|
||||||
// Locals.
|
|
||||||
uint32_t idx;
|
|
||||||
|
|
||||||
// The tranZPUter SW uses a CPLD to set a 4K Z80 memory range window into a 512K-1MB linear RAM block. The actual map required
|
|
||||||
// at any one time is governed by the Memory Config register at I/O port 0x60.
|
|
||||||
// This method sets the initial state, which is a normal Sharp operating mode, all memory and IO (except tranZPUter
|
|
||||||
// control IO block) are on the mainboard.
|
|
||||||
|
|
||||||
// Setup defaults.
|
|
||||||
TZPUCtrl.clkSrc = 0x00; // Clock defaults to host.
|
|
||||||
TZPUCtrl.regCmd = 0x00; // Default for the CPLD Command.
|
|
||||||
TZPUCtrl.regCmdStatus = 0x00; // Default for the CPLD Command Status.
|
|
||||||
TZPUCtrl.regCpuCfg = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
|
||||||
TZPUCtrl.regCpuInfo = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
|
||||||
// Setup the CPLD status value, this is used by the host for configuration of tzfs.
|
|
||||||
#if(TARGET_HOST_MZ80A == 1)
|
|
||||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ80A;
|
|
||||||
#endif
|
|
||||||
#if(TARGET_HOST_MZ700 == 1)
|
|
||||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ700;
|
|
||||||
#endif
|
|
||||||
#if(TARGET_HOST_MZ2000 == 1)
|
|
||||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ2000;
|
|
||||||
#endif
|
|
||||||
TZPUCtrl.regCpldCfg = 0x00; // Not used, as no CPLD available, but need to store/return value if addressed.
|
|
||||||
|
|
||||||
// Go through and clear all memory maps, valid for startup and reset.
|
|
||||||
for(idx=0; idx < MEMORY_MODES; idx++)
|
|
||||||
{
|
|
||||||
if(Z80Ctrl->page[idx] != NULL)
|
|
||||||
{
|
|
||||||
kfree(Z80Ctrl->page[idx]);
|
|
||||||
Z80Ctrl->page[idx] = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup all initial TZFS memory modes
|
|
||||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_ORIG, 1);
|
|
||||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS, 1);
|
|
||||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS2, 1);
|
|
||||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS3, 1);
|
|
||||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS4, 1);
|
|
||||||
Z80Ctrl->memoryMode = 0x02; // Default memory mode, MZ-80A.
|
|
||||||
|
|
||||||
// I/O Ports on the tranZPUter SW board. All hosts have the same ports for the tzpu board.
|
|
||||||
for(idx=0x0000; idx < 0x10000; idx+=0x0100)
|
|
||||||
{
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CTRLLATCH] = IO_TZ_CTRLLATCH | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_SETXMHZ] = IO_TZ_SETXMHZ | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_SET2MHZ] = IO_TZ_SET2MHZ | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CLKSELRD] = IO_TZ_CLKSELRD | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_SVCREQ] = IO_TZ_SVCREQ | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_SYSREQ] = IO_TZ_SYSREQ | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDCMD] = IO_TZ_CPLDCMD | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDSTATUS] = IO_TZ_CPLDSTATUS | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CPUCFG] = IO_TZ_CPUCFG | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CPUSTATUS] = IO_TZ_CPUSTATUS | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CPUINFO] = IO_TZ_CPUINFO | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDCFG] = IO_TZ_CPLDCFG | IO_TYPE_VIRTUAL_HW;
|
|
||||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDINFO] = IO_TZ_CPLDINFO | IO_TYPE_VIRTUAL_HW;
|
|
||||||
}
|
|
||||||
|
|
||||||
pr_info("TZPU Memory Setup complete.\n");
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user