Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78fddfb2eb | ||
|
|
066e049538 | ||
|
|
e3771cdf9c | ||
|
|
0a0ed14c6c | ||
| 9baeec811b | |||
|
|
75fb464b4d | ||
|
|
dcb308f0df | ||
|
|
5fa8d1fada | ||
|
|
462052140e | ||
|
|
5d0daa838e | ||
|
|
1ff4b558a5 | ||
|
|
b0ad5db6c6 | ||
|
|
2200e233e2 | ||
|
|
bd8cc2e964 | ||
|
|
fe53a4c871 | ||
|
|
09c9f0dadc | ||
|
|
e88777b04b | ||
|
|
582a50dd80 | ||
|
|
a3cfebc7f9 | ||
|
|
652bdd81eb | ||
|
|
db177d2240 | ||
|
|
dfa3dd5a57 | ||
|
|
826783ab79 |
7
.gitattributes
vendored
Normal file
7
.gitattributes
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
* linguist-vendored
|
||||
*.asm linguist-vendored=false
|
||||
*.c linguist-vendored=false
|
||||
*.cpp linguist-vendored=false
|
||||
*.pl linguist-vendored=false
|
||||
*.sh linguist-vendored=false
|
||||
*.vhd linguist-vendored=false
|
||||
113
.gitignore
vendored
113
.gitignore
vendored
@@ -3,18 +3,14 @@
|
||||
**/build/**
|
||||
c5_pin_model_dump.txt
|
||||
_config.yml
|
||||
CPLD
|
||||
CPLD/build/db/
|
||||
CPLD/build/incremental_db/
|
||||
CPLD/build/output_files/
|
||||
CPLD/build/simulation/
|
||||
CPLD/build/tranZPUterSW_constraints.sdc.clk
|
||||
CPLD/mz80b/
|
||||
CPLD/v1.0
|
||||
CPLD/v1.0.bak/
|
||||
CPLD/v1.0/build/greybox_tmp/
|
||||
CPLD/v1.0/MZ2000
|
||||
CPLD/v1.0/MZ2000/build
|
||||
CPLD/v1.0/MZ2000/build/db/
|
||||
CPLD/v1.0/MZ2000/build/greybox_tmp
|
||||
CPLD/v1.0/MZ2000/build/greybox_tmp/
|
||||
@@ -35,8 +31,6 @@ CPLD/v1.0/MZ2000/tranZPUterSW700.vhd.sav3
|
||||
CPLD/v1.0/MZ2000/tranZPUterSW.sav2
|
||||
CPLD/v1.0/MZ2000/tranZPUterSW.vhd.clk
|
||||
CPLD/v1.0/MZ2000/tranZPUterSW.vhd.presweep
|
||||
CPLD/v1.0/MZ700
|
||||
CPLD/v1.0/MZ700/build
|
||||
CPLD/v1.0/MZ700/build/db
|
||||
CPLD/v1.0/MZ700/build/db/
|
||||
CPLD/v1.0/MZ700/build/greybox_tmp
|
||||
@@ -58,8 +52,6 @@ CPLD/v1.0/MZ700/tranZPUterSW.vhd.clk
|
||||
CPLD/v1.0/MZ700/tranZPUterSW.vhd.presweep
|
||||
CPLD/v1.0/MZ700/working
|
||||
CPLD/v1.0/MZ700/working2
|
||||
CPLD/v1.0/MZ80A
|
||||
CPLD/v1.0/MZ80A/build
|
||||
CPLD/v1.0/MZ80A/build/db/
|
||||
CPLD/v1.0/MZ80A/build/emuMZ_ClockII.qip
|
||||
CPLD/v1.0/MZ80A/build/greybox_tmp
|
||||
@@ -341,7 +333,6 @@ software/FusionX/src/driver/Makefile3
|
||||
software/FusionX/src/driver/MZ2000/old/
|
||||
software/FusionX/src/driver/MZ700/old/
|
||||
software/FusionX/src/driver/mz700.rom
|
||||
software/FusionX/src/driver/MZ80A/
|
||||
software/FusionX/src/driver/MZ80A/old/
|
||||
software/FusionX/src/driver/test
|
||||
software/FusionX/src/driver/.tmp_versions
|
||||
@@ -350,6 +341,7 @@ software/FusionX/src/driver/Z80
|
||||
software/FusionX/src/driver/Z80/
|
||||
software/FusionX/src/driver/Z80.c.old
|
||||
software/FusionX/src/driver/z80ctrl
|
||||
software/FusionX/src/driver/k64fcpu
|
||||
software/FusionX/src/driver/Z80.rc.in
|
||||
software/FusionX/src/hello
|
||||
software/FusionX/src/spitools
|
||||
@@ -1668,4 +1660,107 @@ software/linux/kernel/drivers/sstar/emac/modules.order
|
||||
software/linux/kernel/drivers/sstar/netphy/modules.builtin
|
||||
software/linux/kernel/drivers/sstar/netphy/modules.order
|
||||
software/linux/project/release/nvr/i2m/011A/glibc/8.2.1/bin/kernel/spinand/
|
||||
README.md.last
|
||||
software/CPM
|
||||
software/FusionX/history
|
||||
software/FusionX/src/driver.ng/
|
||||
software/FusionX/src/driver/Makefile.old
|
||||
software/FusionX/src/driver/Z80.c.old2
|
||||
software/FusionX/src/driver/Zeta.test/
|
||||
software/FusionX/src/driver/sa1510.orig
|
||||
software/linux/kernel/arch/arm/boot/dts/hold/
|
||||
software/linux/kernel/arch/arm/configs/infinity2m_spinand_fusionx_defconfig.hld2
|
||||
CPLD/v1.0/MZ80A.ng/
|
||||
software/FusionX/src/driver/MZ80A/emumz.c
|
||||
software/FusionX/src/driver/MZ80A/sharpmz.c
|
||||
software/FusionX/src/driver/MZ700/emumz.c
|
||||
software/FusionX/src/driver/MZ700/sharpmz.c
|
||||
software/FusionX/src/driver/MZ2000/emumz.c
|
||||
software/FusionX/src/driver/MZ2000/sharpmz.c
|
||||
software/FusionX/src/driver/MZ80A/z80driver.c.bad
|
||||
software/FusionX/src/driver/MZ80A/z80vhw_rfs.c.bad
|
||||
software/FusionX/disk
|
||||
software/FusionX/roms
|
||||
software/linux/project/FusionX/
|
||||
software/FusionX/src/driver/MZ80A/k64fcpu.c.hld
|
||||
software/linux/buildroot/.config.old
|
||||
software/linux/kernel/scripts/kconfig/.mconf.cmd
|
||||
software/FusionX/src/ttymz/.tmp_versions/
|
||||
software/FusionX/src/ttymz/.ttymzdrv.ko.cmd
|
||||
software/FusionX/src/ttymz/Makefile.orig
|
||||
software/FusionX/src/ttymz/Module.symvers
|
||||
software/FusionX/src/ttymz/modules.order
|
||||
software/FusionX/src/ttymz/ttymzdrv.ko
|
||||
software/FusionX/src/ttymz/ttymzdrv.mod.c
|
||||
software/FusionX/src/z80drv/.tmp_versions/
|
||||
software/FusionX/src/z80drv/.z80drv.ko.cmd
|
||||
software/FusionX/src/z80drv/Kbuild.in
|
||||
software/FusionX/src/z80drv/MZ80A/emumz.c
|
||||
software/FusionX/src/z80drv/MZ80A/k64fcpu.c.hld
|
||||
software/FusionX/src/z80drv/MZ80A/z80driver.c.bad
|
||||
software/FusionX/src/z80drv/MZ80A/z80vhw_rfs.c.bad
|
||||
software/FusionX/src/z80drv/Makefile.old
|
||||
software/FusionX/src/z80drv/Makefile1
|
||||
software/FusionX/src/z80drv/Makefile3
|
||||
software/FusionX/src/z80drv/Module.symvers
|
||||
software/FusionX/src/z80drv/Z80.c.old
|
||||
software/FusionX/src/z80drv/Z80.c.old2
|
||||
software/FusionX/src/z80drv/Z80.rc.in
|
||||
software/FusionX/src/z80drv/Z80.x/
|
||||
software/FusionX/src/z80drv/Zeta.test/
|
||||
software/FusionX/src/z80drv/k64fcpu
|
||||
software/FusionX/src/z80drv/modules.order
|
||||
software/FusionX/src/z80drv/mz700.rom
|
||||
software/FusionX/src/z80drv/sa1510.orig
|
||||
software/FusionX/src/z80drv/test
|
||||
software/FusionX/src/z80drv/x.mzf
|
||||
software/FusionX/src/z80drv/z80ctrl
|
||||
software/FusionX/src/z80drv/z80drv.ko
|
||||
software/FusionX/src/z80drv/z80drv.mod.c
|
||||
software/FusionX/host/
|
||||
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/
|
||||
|
||||
# Un-ignore files needed for CI/CD builds
|
||||
!software/asm/
|
||||
!software/asm/*.asm
|
||||
!software/asm/include/
|
||||
!software/asm/include/*.asm
|
||||
!software/tools/
|
||||
!software/tools/assemble_*.sh
|
||||
!software/tools/copytosd.sh
|
||||
!software/tools/make_cpmdisks.sh
|
||||
!software/tools/glass*.jar
|
||||
!software/tools/dz80
|
||||
!software/tools/dz80_v20
|
||||
!software/tools/nasconv
|
||||
!software/tools/mzftool.pl
|
||||
!software/tools/flashmmcfg
|
||||
!software/tmp/
|
||||
!software/roms/
|
||||
!software/roms/*.rom
|
||||
!software/roms/*.bin
|
||||
!software/roms/*.BIN
|
||||
!software/roms/*.ori
|
||||
|
||||
10
.gitmodules
vendored
10
.gitmodules
vendored
@@ -1,6 +1,12 @@
|
||||
[submodule "software/FusionX/src/driver/Z80"]
|
||||
path = software/FusionX/src/driver/Z80
|
||||
path = software/FusionX/src/z80drv/Z80
|
||||
url = https://github.com/redcode/Z80.git
|
||||
[submodule "software/FusionX/src/driver/Zeta"]
|
||||
path = software/FusionX/src/driver/Zeta
|
||||
path = software/FusionX/src/z80drv/Zeta
|
||||
url = https://github.com/redcode/Zeta.git
|
||||
[submodule "software/FusionX/src/driver/6502"]
|
||||
path = software/FusionX/src/z80drv/6502
|
||||
url = https://github.com/redcode/6502.git
|
||||
[submodule "software/FusionX/src/driver/software/FusionX/src/driver/6502"]
|
||||
path = software/FusionX/src/z80drv/software/FusionX/src/driver/6502
|
||||
url = https://github.com/redcode/6502.git
|
||||
|
||||
@@ -127,10 +127,10 @@ set_location_assignment PIN_21 -to VSOM_RSV[1]
|
||||
# SOM Control Signals
|
||||
# ===================
|
||||
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_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_25 -to VSOM_WAIT
|
||||
set_location_assignment PIN_23 -to VSOM_RESET
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
--
|
||||
-- Name: tzpuFusionX.vhd
|
||||
-- Version: MZ-2000
|
||||
-- Created: June 2020
|
||||
-- Created: Jan 2023
|
||||
-- Author(s): Philip Smart
|
||||
-- Description: tzpuFusionX CPLD logic definition file.
|
||||
-- This module contains the definition of the tzpuFusionX project plus enhancements
|
||||
-- for the MZ-2000.
|
||||
--
|
||||
-- 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
|
||||
@@ -128,7 +129,7 @@ end entity;
|
||||
|
||||
architecture rtl of cpld512 is
|
||||
|
||||
-- Finite State Machine states.
|
||||
-- Z80 Finite State Machine states.
|
||||
type SOMFSMState is
|
||||
(
|
||||
IdleCycle,
|
||||
@@ -174,6 +175,14 @@ architecture rtl of cpld512 is
|
||||
BusReqCycle
|
||||
);
|
||||
|
||||
-- Controller FSM states.
|
||||
type CTRLFSMState is
|
||||
(
|
||||
CTRLCMD_Idle,
|
||||
CTRLCMD_ReadIOWrite,
|
||||
CTRLCMD_ReadIOWrite_1
|
||||
);
|
||||
|
||||
-- CPU Interface internal signals.
|
||||
signal Z80_BUSRQni : std_logic;
|
||||
signal Z80_INTni : std_logic;
|
||||
@@ -185,7 +194,6 @@ architecture rtl of cpld512 is
|
||||
signal Z80_HALTni : std_logic;
|
||||
signal Z80_M1ni : std_logic;
|
||||
signal Z80_RFSHni : std_logic;
|
||||
signal Z80_DATAi : std_logic_vector(7 downto 0);
|
||||
signal Z80_BUSRQ_ACKni : std_logic;
|
||||
|
||||
-- Internal CPU state control.
|
||||
@@ -203,9 +211,10 @@ architecture rtl of cpld512 is
|
||||
|
||||
-- Refresh control.
|
||||
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 AUTOREFRESH_CNT : integer range 0 to 7;
|
||||
signal AUTOREFRESH_CNT : integer range 0 to 63;
|
||||
signal FSM_STATUS : std_logic := '0';
|
||||
signal FSM_CHECK_WAIT : 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_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_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).
|
||||
|
||||
-- SPI Command interface.
|
||||
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_PROCESSING : std_logic;
|
||||
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,
|
||||
-- forcing the SOM to reboot.
|
||||
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 timerPMReset : integer range 0 to 10 := 0;
|
||||
variable resetCount : integer range 0 to 3 := 0;
|
||||
@@ -311,7 +321,7 @@ begin
|
||||
end if;
|
||||
|
||||
-- 100ms interval.
|
||||
if(timer1 = 354000) then
|
||||
if(timer1 = 400000) then
|
||||
timer100 := timer100 + 1;
|
||||
|
||||
if(timer100 >= 10) then
|
||||
@@ -340,8 +350,11 @@ begin
|
||||
-- SPI Slave input. Receive command and data from the SOM.
|
||||
SPI_INPUT : process(VSOM_SPI_CLK)
|
||||
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
|
||||
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
|
||||
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
|
||||
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;
|
||||
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_OUTPUT : process(VSOM_SPI_CLK,VSOM_SPI_CSn,SPI_TX_DATA)
|
||||
begin
|
||||
-- Chip Select inactive, disable process and reset control flags.
|
||||
if(VSOM_SPI_CSn = '1') then
|
||||
SPI_SHIFT_EN <= '0';
|
||||
SPI_BIT_CNT <= 15;
|
||||
SPI_BIT_CNT <= 7;
|
||||
|
||||
-- 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
|
||||
-- Each clock reset the shift enable and done flag in preparation for the next cycle.
|
||||
SPI_SHIFT_EN <= '1';
|
||||
|
||||
-- Bit count decrements to detect when last bit of byte is sent.
|
||||
if(SPI_BIT_CNT > 0) then
|
||||
SPI_BIT_CNT <= SPI_BIT_CNT - 1;
|
||||
end if;
|
||||
|
||||
-- Shift out the next bit.
|
||||
VSOM_SPI_MISO <= SPI_TX_SREG(6);
|
||||
SPI_TX_SREG <= SPI_TX_SREG(5 downto 0) & '0';
|
||||
|
||||
@@ -392,6 +409,7 @@ begin
|
||||
SPI_FRAME_CNT<= 1;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(7);
|
||||
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
|
||||
SPI_FRAME_CNT<= 2;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(15);
|
||||
@@ -400,13 +418,14 @@ begin
|
||||
SPI_FRAME_CNT<= 3;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(23);
|
||||
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.
|
||||
SPI_FRAME_CNT<= 4;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(31);
|
||||
SPI_TX_SREG <= SPI_TX_DATA(30 downto 24);
|
||||
else
|
||||
SPI_FRAME_CNT<= 0;
|
||||
end if;
|
||||
|
||||
SPI_BIT_CNT <= 7;
|
||||
end if;
|
||||
end if;
|
||||
@@ -424,6 +443,7 @@ begin
|
||||
AUTOREFRESH <= '0';
|
||||
SPI_LOOPBACK_TEST <= '0';
|
||||
SOM_CMD <= (others => '0');
|
||||
SOM_PARAM_CNT <= 0;
|
||||
SPI_CPU_ADDR <= (others => '0');
|
||||
SPI_NEW_DATA <= '0';
|
||||
|
||||
@@ -432,6 +452,7 @@ begin
|
||||
-- for 8bit, 16bit and 32bit transmissions.
|
||||
-- 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>
|
||||
-- < 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
|
||||
@@ -441,66 +462,110 @@ begin
|
||||
--
|
||||
elsif(VSOM_SPI_CSn'event and VSOM_SPI_CSn = '1') then
|
||||
|
||||
-- Command is always located in the upper byte of frame 1.
|
||||
SOM_CMD <= SPI_RX_DATA(7 downto 0);
|
||||
-- If active, decrement parameter count. Parameters sent after a command are not considered as commands.
|
||||
if(SOM_PARAM_CNT > 0) then
|
||||
SOM_PARAM_CNT <= SOM_PARAM_CNT - 1;
|
||||
end if;
|
||||
|
||||
-- Toggle flag to indicate new data arrived.
|
||||
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
||||
-- Process if command, store parameters.
|
||||
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.
|
||||
case SPI_RX_DATA(7 downto 0) is
|
||||
-- Toggle flag to indicate new data arrived.
|
||||
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
||||
|
||||
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
||||
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" =>
|
||||
-- Process the command. Some commands require the FSM, others can be serviced immediately.
|
||||
case SPI_RX_DATA(7 downto 0) is
|
||||
|
||||
-- Direct address set.
|
||||
if(SPI_FRAME_CNT = 4) then
|
||||
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||
else
|
||||
-- if(SPI_CPU_ADDR >= X"D010" and SPI_CPU_ADDR < X"D020") then
|
||||
-- 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;
|
||||
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
||||
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"48" | X"49" | X"4A" | X"4B" | X"4C" | X"4D" | X"4E" | X"4F" =>
|
||||
|
||||
if(SPI_FRAME_CNT > 1) then
|
||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||
end if;
|
||||
-- Direct address set.
|
||||
if(SPI_FRAME_CNT = 4) then
|
||||
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.
|
||||
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);
|
||||
if(SPI_FRAME_CNT > 1) then
|
||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||
end if;
|
||||
|
||||
-- Enable auto refresh DRAM cycle.
|
||||
when X"F1" =>
|
||||
AUTOREFRESH <= '1';
|
||||
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" => -- WriteIO
|
||||
|
||||
-- Disable auto refresh DRAM cycle.
|
||||
when X"F2" =>
|
||||
AUTOREFRESH <= '0';
|
||||
-- Direct address set.
|
||||
if(SPI_FRAME_CNT = 4) then
|
||||
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.
|
||||
when X"FE" =>
|
||||
SPI_LOOPBACK_TEST<= '1';
|
||||
if(SPI_FRAME_CNT > 1) then
|
||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||
end if;
|
||||
|
||||
-- No action, called to retrieve status.
|
||||
when X"00" | X"FF" =>
|
||||
when 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" => -- ReadIO-Write
|
||||
|
||||
when others =>
|
||||
end case;
|
||||
-- Direct address set.
|
||||
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 process;
|
||||
|
||||
@@ -561,9 +626,9 @@ begin
|
||||
CPU_DATA_EN <= '0';
|
||||
CPU_DATA_IN <= (others => '0');
|
||||
REFRESH_ADDR <= (others => '0');
|
||||
AUTOREFRESH_CNT <= 7;
|
||||
AUTOREFRESH_CNT <= 63;
|
||||
IPAR <= (others => '0');
|
||||
NEW_SPI_CMD <= '0';
|
||||
NEW_SPI_DATA <= '0';
|
||||
VCPU_CS_EDGE <= "11";
|
||||
SPI_PROCESSING <= '0';
|
||||
|
||||
@@ -580,98 +645,12 @@ begin
|
||||
|
||||
-- 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
|
||||
NEW_SPI_CMD <= '1';
|
||||
NEW_SPI_DATA <= '1';
|
||||
end if;
|
||||
|
||||
-- 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) 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 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';
|
||||
-- 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(AUTOREFRESH = '1' and AUTOREFRESH_CNT /= 0 and Z80_CLK_RE = '1') then
|
||||
AUTOREFRESH_CNT <= AUTOREFRESH_CNT - 1;
|
||||
end if;
|
||||
|
||||
-- Refresh status bit. Indicates a Refresh cycle is under way.
|
||||
@@ -686,7 +665,143 @@ begin
|
||||
FSM_WAIT_ACTIVE <= '1';
|
||||
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
|
||||
|
||||
-- The FSM advances to the next stage on each Z80 edge unless in Idle state.
|
||||
@@ -704,7 +819,7 @@ begin
|
||||
|
||||
when IdleCycle =>
|
||||
CPU_LAST_T_STATE <= '1';
|
||||
-- FSM_STATE <= IdleCycle;
|
||||
FSM_STATUS <= '0';
|
||||
|
||||
-----------------------------
|
||||
-- Z80 Fetch Cycle.
|
||||
@@ -727,7 +842,7 @@ begin
|
||||
|
||||
when FetchCycle_30 =>
|
||||
-- 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;
|
||||
|
||||
-----------------------------
|
||||
@@ -736,18 +851,18 @@ begin
|
||||
when RefreshCycle =>
|
||||
-- Latch data from mainboard.
|
||||
CPU_DATA_IN <= Z80_DATA;
|
||||
FSM_STATUS <= '0';
|
||||
Z80_RFSHni <= '0';
|
||||
|
||||
when RefreshCycle_11 =>
|
||||
-- Falling edge of T3 activates the MREQ line.
|
||||
Z80_MREQni <= '0';
|
||||
FSM_STATUS <= '0';
|
||||
|
||||
when RefreshCycle_20 =>
|
||||
|
||||
when RefreshCycle_21 =>
|
||||
Z80_MREQni <= '1';
|
||||
REFRESH_ADDR(6 downto 0) <= REFRESH_ADDR(6 downto 0) + 1;
|
||||
REFRESH_ADDR <= REFRESH_ADDR + 1;
|
||||
FSM_STATE <= IdleCycle;
|
||||
|
||||
when RefreshCycle_3 =>
|
||||
@@ -769,7 +884,7 @@ begin
|
||||
when WriteCycle_21 =>
|
||||
Z80_WRni <= '0';
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= WriteCycle_20;
|
||||
FSM_STATE <= WriteCycle_20;
|
||||
end if;
|
||||
|
||||
when WriteCycle_30 =>
|
||||
@@ -794,7 +909,7 @@ begin
|
||||
|
||||
when ReadCycle_21 =>
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= ReadCycle_20;
|
||||
FSM_STATE <= ReadCycle_20;
|
||||
end if;
|
||||
|
||||
when ReadCycle_30 =>
|
||||
@@ -805,7 +920,6 @@ begin
|
||||
FSM_STATUS <= '0';
|
||||
FSM_STATE <= IdleCycle;
|
||||
|
||||
|
||||
-----------------------------
|
||||
-- Z80 IO Write Cycle.
|
||||
-----------------------------
|
||||
@@ -825,7 +939,7 @@ begin
|
||||
|
||||
when WriteIOCycle_31 =>
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= WriteIOCycle_20;
|
||||
FSM_STATE <= WriteIOCycle_30;
|
||||
end if;
|
||||
|
||||
when WriteIOCycle_40 =>
|
||||
@@ -854,7 +968,7 @@ begin
|
||||
|
||||
when ReadIOCycle_31 =>
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= ReadIOCycle_20;
|
||||
FSM_STATE <= ReadIOCycle_30;
|
||||
end if;
|
||||
|
||||
when ReadIOCycle_40 =>
|
||||
@@ -902,8 +1016,6 @@ begin
|
||||
Z80_DATA <= CPU_DATA_OUT when Z80_BUSRQ_ACKni = '1' and CPU_DATA_EN = '1'
|
||||
else
|
||||
(others => 'Z');
|
||||
-- Z80_DATAi <= Z80_DATA when Z80_RDn = '0'
|
||||
-- else (others => '1');
|
||||
Z80_RDn <= Z80_RDni when Z80_BUSRQ_ACKni = '1'
|
||||
else 'Z';
|
||||
Z80_WRn <= Z80_WRni when Z80_BUSRQ_ACKni = '1'
|
||||
@@ -944,7 +1056,7 @@ begin
|
||||
|
||||
-- Signal mirrors.
|
||||
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.
|
||||
else '0';
|
||||
VSOM_BUSRQ <= not Z80_BUSRQn; -- Host device requesting Z80 Bus.
|
||||
@@ -981,5 +1093,9 @@ begin
|
||||
-- DAC clocks.
|
||||
--VGA_PXL_CLK <= CLK_50M;
|
||||
MONO_PXL_CLK <= VGA_PXL_CLK;
|
||||
|
||||
-- Currently unassigned.
|
||||
VGA_COLR <= '0';
|
||||
MONO_RSV <= '0';
|
||||
|
||||
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
|
||||
# ===================
|
||||
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_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_25 -to VSOM_WAIT
|
||||
set_location_assignment PIN_23 -to VSOM_RESET
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
4
CPLD/v1.0/MZ80A/build/tzpuFusionX_MZ80A.qsf
vendored
4
CPLD/v1.0/MZ80A/build/tzpuFusionX_MZ80A.qsf
vendored
@@ -127,10 +127,10 @@ set_location_assignment PIN_21 -to VSOM_RSV[1]
|
||||
# SOM Control Signals
|
||||
# ===================
|
||||
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_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_25 -to VSOM_WAIT
|
||||
set_location_assignment PIN_23 -to VSOM_RESET
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
-- for the MZ-80A.
|
||||
--
|
||||
-- Credits:
|
||||
-- Copyright: (c) 2018-22 Philip Smart <philip.smart@net2net.org>
|
||||
-- Copyright: (c) 2018-23 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: Nov 2022 - Initial write for the MZ-2000, adaption to MZ-80A underway.
|
||||
-- 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.
|
||||
-- Apr 2023 v1.2 - Updated from the PCW8256 development.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- This source file is free software: you can redistribute it and-or modify
|
||||
@@ -128,7 +132,7 @@ end entity;
|
||||
|
||||
architecture rtl of cpld512 is
|
||||
|
||||
-- Finite State Machine states.
|
||||
-- Z80 Finite State Machine states.
|
||||
type SOMFSMState is
|
||||
(
|
||||
IdleCycle,
|
||||
@@ -174,6 +178,14 @@ architecture rtl of cpld512 is
|
||||
BusReqCycle
|
||||
);
|
||||
|
||||
-- Controller FSM states.
|
||||
type CTRLFSMState is
|
||||
(
|
||||
CTRLCMD_Idle,
|
||||
CTRLCMD_ReadIOWrite,
|
||||
CTRLCMD_ReadIOWrite_1
|
||||
);
|
||||
|
||||
-- CPU Interface internal signals.
|
||||
signal Z80_BUSRQni : std_logic;
|
||||
signal Z80_INTni : std_logic;
|
||||
@@ -185,7 +197,6 @@ architecture rtl of cpld512 is
|
||||
signal Z80_HALTni : std_logic;
|
||||
signal Z80_M1ni : std_logic;
|
||||
signal Z80_RFSHni : std_logic;
|
||||
signal Z80_DATAi : std_logic_vector(7 downto 0);
|
||||
signal Z80_BUSRQ_ACKni : std_logic;
|
||||
|
||||
-- Internal CPU state control.
|
||||
@@ -203,14 +214,15 @@ architecture rtl of cpld512 is
|
||||
|
||||
-- Refresh control.
|
||||
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 AUTOREFRESH_CNT : integer range 0 to 7;
|
||||
signal AUTOREFRESH_CNT : integer range 0 to 31;
|
||||
signal FSM_STATUS : std_logic := '0';
|
||||
signal FSM_CHECK_WAIT : std_logic := '0';
|
||||
signal FSM_WAIT_ACTIVE : 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 AUTOREFRESH : std_logic;
|
||||
|
||||
@@ -229,11 +241,12 @@ architecture rtl of cpld512 is
|
||||
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_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).
|
||||
|
||||
-- SPI Command interface.
|
||||
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_PROCESSING : std_logic;
|
||||
signal SPI_CPU_ADDR : std_logic_vector(15 downto 0) := (others => '0');
|
||||
@@ -272,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,
|
||||
-- forcing the SOM to reboot.
|
||||
SYSRESET: process( Z80_CLKi, Z80_RESETn )
|
||||
variable timer1 : integer range 0 to 354000 := 0;
|
||||
variable timer1 : integer range 0 to 200000 := 0;
|
||||
variable timer100 : integer range 0 to 10 := 0;
|
||||
variable timerPMReset : integer range 0 to 10 := 0;
|
||||
variable resetCount : integer range 0 to 3 := 0;
|
||||
@@ -308,7 +321,7 @@ begin
|
||||
end if;
|
||||
|
||||
-- 100ms interval.
|
||||
if(timer1 = 354000) then
|
||||
if(timer1 = 200000) then
|
||||
timer100 := timer100 + 1;
|
||||
|
||||
if(timer100 >= 10) then
|
||||
@@ -337,8 +350,11 @@ begin
|
||||
-- SPI Slave input. Receive command and data from the SOM.
|
||||
SPI_INPUT : process(VSOM_SPI_CLK)
|
||||
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
|
||||
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
|
||||
SPI_RX_SREG <= SPI_RX_SREG(6 downto 0) & VSOM_SPI_MOSI;
|
||||
|
||||
@@ -353,7 +369,7 @@ begin
|
||||
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;
|
||||
|
||||
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;
|
||||
end if;
|
||||
end if;
|
||||
@@ -363,18 +379,22 @@ begin
|
||||
-- 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)
|
||||
begin
|
||||
-- Chip Select inactive, disable process and reset control flags.
|
||||
if(VSOM_SPI_CSn = '1') then
|
||||
SPI_SHIFT_EN <= '0';
|
||||
SPI_BIT_CNT <= 15;
|
||||
SPI_BIT_CNT <= 7;
|
||||
|
||||
-- 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
|
||||
-- Each clock reset the shift enable and done flag in preparation for the next cycle.
|
||||
SPI_SHIFT_EN <= '1';
|
||||
|
||||
-- Bit count decrements to detect when last bit of byte is sent.
|
||||
if(SPI_BIT_CNT > 0) then
|
||||
SPI_BIT_CNT <= SPI_BIT_CNT - 1;
|
||||
end if;
|
||||
|
||||
-- Shift out the next bit.
|
||||
VSOM_SPI_MISO <= SPI_TX_SREG(6);
|
||||
SPI_TX_SREG <= SPI_TX_SREG(5 downto 0) & '0';
|
||||
|
||||
@@ -389,6 +409,7 @@ begin
|
||||
SPI_FRAME_CNT<= 1;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(7);
|
||||
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
|
||||
SPI_FRAME_CNT<= 2;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(15);
|
||||
@@ -397,13 +418,14 @@ begin
|
||||
SPI_FRAME_CNT<= 3;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(23);
|
||||
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.
|
||||
SPI_FRAME_CNT<= 4;
|
||||
VSOM_SPI_MISO<= SPI_TX_DATA(31);
|
||||
SPI_TX_SREG <= SPI_TX_DATA(30 downto 24);
|
||||
else
|
||||
SPI_FRAME_CNT<= 0;
|
||||
end if;
|
||||
|
||||
SPI_BIT_CNT <= 7;
|
||||
end if;
|
||||
end if;
|
||||
@@ -421,6 +443,7 @@ begin
|
||||
AUTOREFRESH <= '0';
|
||||
SPI_LOOPBACK_TEST <= '0';
|
||||
SOM_CMD <= (others => '0');
|
||||
SOM_PARAM_CNT <= 0;
|
||||
SPI_CPU_ADDR <= (others => '0');
|
||||
SPI_NEW_DATA <= '0';
|
||||
|
||||
@@ -429,6 +452,7 @@ begin
|
||||
-- for 8bit, 16bit and 32bit transmissions.
|
||||
-- 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>
|
||||
-- < 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
|
||||
@@ -438,66 +462,110 @@ begin
|
||||
--
|
||||
elsif(VSOM_SPI_CSn'event and VSOM_SPI_CSn = '1') then
|
||||
|
||||
-- Command is always located in the upper byte of frame 1.
|
||||
SOM_CMD <= SPI_RX_DATA(7 downto 0);
|
||||
-- If active, decrement parameter count. Parameters sent after a command are not considered as commands.
|
||||
if(SOM_PARAM_CNT > 0) then
|
||||
SOM_PARAM_CNT <= SOM_PARAM_CNT - 1;
|
||||
end if;
|
||||
|
||||
-- Toggle flag to indicate new data arrived.
|
||||
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
||||
-- Process if command, store parameters.
|
||||
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.
|
||||
case SPI_RX_DATA(7 downto 0) is
|
||||
-- Toggle flag to indicate new data arrived.
|
||||
SPI_NEW_DATA <= not SPI_NEW_DATA;
|
||||
|
||||
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
||||
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" =>
|
||||
-- Process the command. Some commands require the FSM, others can be serviced immediately.
|
||||
case SPI_RX_DATA(7 downto 0) is
|
||||
|
||||
-- Direct address set.
|
||||
if(SPI_FRAME_CNT = 4) then
|
||||
SPI_CPU_ADDR <= SPI_RX_DATA(31 downto 16);
|
||||
else
|
||||
-- if(SPI_CPU_ADDR >= X"D010" and SPI_CPU_ADDR < X"D020") then
|
||||
-- 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;
|
||||
-- Z80XACT(0..15): Setup data and address as provided then execute FSM.
|
||||
when X"10" | X"11" | X"12" | X"13" | X"14" | X"15" | X"16" | X"17" | -- Fetch
|
||||
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"48" | X"49" | X"4A" | X"4B" | X"4C" | X"4D" | X"4E" | X"4F" =>
|
||||
|
||||
if(SPI_FRAME_CNT > 1) then
|
||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||
end if;
|
||||
-- Direct address set.
|
||||
if(SPI_FRAME_CNT = 4) then
|
||||
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.
|
||||
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);
|
||||
if(SPI_FRAME_CNT > 1) then
|
||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||
end if;
|
||||
|
||||
-- Enable auto refresh DRAM cycle.
|
||||
when X"F1" =>
|
||||
AUTOREFRESH <= '1';
|
||||
when X"28" | X"29" | X"2A" | X"2B" | X"2C" | X"2D" | X"2E" | X"2F" => -- WriteIO
|
||||
|
||||
-- Disable auto refresh DRAM cycle.
|
||||
when X"F2" =>
|
||||
AUTOREFRESH <= '0';
|
||||
-- Direct address set.
|
||||
if(SPI_FRAME_CNT = 4) then
|
||||
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.
|
||||
when X"FE" =>
|
||||
SPI_LOOPBACK_TEST<= '1';
|
||||
if(SPI_FRAME_CNT > 1) then
|
||||
SPI_CPU_DATA <= SPI_RX_DATA(15 downto 8);
|
||||
end if;
|
||||
|
||||
-- No action, called to retrieve status.
|
||||
when X"00" | X"FF" =>
|
||||
when 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" => -- ReadIO-Write
|
||||
|
||||
when others =>
|
||||
end case;
|
||||
-- Direct address set.
|
||||
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 process;
|
||||
|
||||
@@ -558,9 +626,9 @@ begin
|
||||
CPU_DATA_EN <= '0';
|
||||
CPU_DATA_IN <= (others => '0');
|
||||
REFRESH_ADDR <= (others => '0');
|
||||
AUTOREFRESH_CNT <= 7;
|
||||
AUTOREFRESH_CNT <= 31;
|
||||
IPAR <= (others => '0');
|
||||
NEW_SPI_CMD <= '0';
|
||||
NEW_SPI_DATA <= '0';
|
||||
VCPU_CS_EDGE <= "11";
|
||||
SPI_PROCESSING <= '0';
|
||||
|
||||
@@ -577,98 +645,12 @@ begin
|
||||
|
||||
-- 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
|
||||
NEW_SPI_CMD <= '1';
|
||||
NEW_SPI_DATA <= '1';
|
||||
end if;
|
||||
|
||||
-- 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) 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 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';
|
||||
-- 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(AUTOREFRESH = '1' and AUTOREFRESH_CNT /= 0 and Z80_CLK_RE = '1') then
|
||||
AUTOREFRESH_CNT <= AUTOREFRESH_CNT - 1;
|
||||
end if;
|
||||
|
||||
-- Refresh status bit. Indicates a Refresh cycle is under way.
|
||||
@@ -683,7 +665,143 @@ begin
|
||||
FSM_WAIT_ACTIVE <= '1';
|
||||
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
|
||||
|
||||
-- The FSM advances to the next stage on each Z80 edge unless in Idle state.
|
||||
@@ -701,7 +819,7 @@ begin
|
||||
|
||||
when IdleCycle =>
|
||||
CPU_LAST_T_STATE <= '1';
|
||||
-- FSM_STATE <= IdleCycle;
|
||||
FSM_STATUS <= '0';
|
||||
|
||||
-----------------------------
|
||||
-- Z80 Fetch Cycle.
|
||||
@@ -724,7 +842,7 @@ begin
|
||||
|
||||
when FetchCycle_30 =>
|
||||
-- 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;
|
||||
|
||||
-----------------------------
|
||||
@@ -733,18 +851,18 @@ begin
|
||||
when RefreshCycle =>
|
||||
-- Latch data from mainboard.
|
||||
CPU_DATA_IN <= Z80_DATA;
|
||||
FSM_STATUS <= '0';
|
||||
Z80_RFSHni <= '0';
|
||||
|
||||
when RefreshCycle_11 =>
|
||||
-- Falling edge of T3 activates the MREQ line.
|
||||
Z80_MREQni <= '0';
|
||||
FSM_STATUS <= '0';
|
||||
|
||||
when RefreshCycle_20 =>
|
||||
|
||||
when RefreshCycle_21 =>
|
||||
Z80_MREQni <= '1';
|
||||
REFRESH_ADDR(6 downto 0) <= REFRESH_ADDR(6 downto 0) + 1;
|
||||
REFRESH_ADDR <= REFRESH_ADDR + 1;
|
||||
FSM_STATE <= IdleCycle;
|
||||
|
||||
when RefreshCycle_3 =>
|
||||
@@ -766,7 +884,7 @@ begin
|
||||
when WriteCycle_21 =>
|
||||
Z80_WRni <= '0';
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= WriteCycle_20;
|
||||
FSM_STATE <= WriteCycle_20;
|
||||
end if;
|
||||
|
||||
when WriteCycle_30 =>
|
||||
@@ -791,7 +909,7 @@ begin
|
||||
|
||||
when ReadCycle_21 =>
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= ReadCycle_20;
|
||||
FSM_STATE <= ReadCycle_20;
|
||||
end if;
|
||||
|
||||
when ReadCycle_30 =>
|
||||
@@ -802,7 +920,6 @@ begin
|
||||
FSM_STATUS <= '0';
|
||||
FSM_STATE <= IdleCycle;
|
||||
|
||||
|
||||
-----------------------------
|
||||
-- Z80 IO Write Cycle.
|
||||
-----------------------------
|
||||
@@ -822,7 +939,7 @@ begin
|
||||
|
||||
when WriteIOCycle_31 =>
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= WriteIOCycle_20;
|
||||
FSM_STATE <= WriteIOCycle_30;
|
||||
end if;
|
||||
|
||||
when WriteIOCycle_40 =>
|
||||
@@ -851,7 +968,7 @@ begin
|
||||
|
||||
when ReadIOCycle_31 =>
|
||||
if(Z80_WAITn = '0' or FSM_WAIT_ACTIVE = '1') then
|
||||
FSM_STATE <= ReadIOCycle_20;
|
||||
FSM_STATE <= ReadIOCycle_30;
|
||||
end if;
|
||||
|
||||
when ReadIOCycle_40 =>
|
||||
@@ -891,7 +1008,7 @@ begin
|
||||
Z80_CLKi <= not Z80_CLK;
|
||||
|
||||
-- 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
|
||||
CPU_ADDR when Z80_BUSRQ_ACKni = '1'
|
||||
else
|
||||
@@ -899,8 +1016,6 @@ begin
|
||||
Z80_DATA <= CPU_DATA_OUT when Z80_BUSRQ_ACKni = '1' and CPU_DATA_EN = '1'
|
||||
else
|
||||
(others => 'Z');
|
||||
-- Z80_DATAi <= Z80_DATA when Z80_RDn = '0'
|
||||
-- else (others => '1');
|
||||
Z80_RDn <= Z80_RDni when Z80_BUSRQ_ACKni = '1'
|
||||
else 'Z';
|
||||
Z80_WRn <= Z80_WRni when Z80_BUSRQ_ACKni = '1'
|
||||
@@ -941,7 +1056,7 @@ begin
|
||||
|
||||
-- Signal mirrors.
|
||||
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.
|
||||
else '0';
|
||||
VSOM_BUSRQ <= not Z80_BUSRQn; -- Host device requesting Z80 Bus.
|
||||
@@ -978,5 +1093,9 @@ begin
|
||||
-- DAC clocks.
|
||||
--VGA_PXL_CLK <= CLK_50M;
|
||||
MONO_PXL_CLK <= VGA_PXL_CLK;
|
||||
|
||||
-- Currently unassigned.
|
||||
VGA_COLR <= '0';
|
||||
MONO_RSV <= '0';
|
||||
|
||||
end architecture;
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
-- project which targets the MZ-80A host.
|
||||
--
|
||||
-- Credits:
|
||||
-- Copyright: (c) 2018-22 Philip Smart <philip.smart@net2net.org>
|
||||
-- Copyright: (c) 2018-23 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: Nov 2022 - Snapshot taken from the MZ-2000 version of the tzpuFusionX source.
|
||||
-- History: Nov 2022 v1.0 - Snapshot taken from the MZ-2000 version of the tzpuFusionX source.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- This source file is free software: you can redistribute it and-or modify
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
-- which targets the MZ-80A host.
|
||||
--
|
||||
-- Credits:
|
||||
-- Copyright: (c) 2018-22 Philip Smart <philip.smart@net2net.org>
|
||||
-- Copyright: (c) 2018-23 Philip Smart <philip.smart@net2net.org>
|
||||
--
|
||||
-- History: Nov 2022 - Snapshot taken from the MZ-2000 version of the tzpuFusionX source.
|
||||
-- History: Nov 2022 v1.0 - Snapshot taken from the MZ-2000 version of the tzpuFusionX source.
|
||||
--
|
||||
---------------------------------------------------------------------------------------------------------
|
||||
-- This source file is free software: you can redistribute it and-or modify
|
||||
|
||||
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;
|
||||
572
README.md
vendored
572
README.md
vendored
@@ -1,4 +1,10 @@
|
||||
<img src='http://eaw.app/images/FusionX_Wired.png' height='70%' width='70%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
# tzpuFusionX
|
||||
|
||||
**Website:** [engineers@work](https://eaw.app) | **Repository:** [git.eaw.app/eaw/tzpuFusionX](https://git.eaw.app/eaw/tzpuFusionX)
|
||||
|
||||
---
|
||||
|
||||
<img src='../images/FusionX_Wired.png' height='70%' width='70%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
|
||||
## <font style="color: yellow;" size="6">Overview</font>
|
||||
|
||||
@@ -7,7 +13,7 @@ The tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> is a spinoff concept from the tra
|
||||
rapid application loading from SD card and by using a daughter board, better graphics and sound.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The <i>FusionX</i> board can also be used to power alternative CPU's on the host for testing, development and to provide a completely different software platform and applications. It can use the underlying hosts keyboard, monitor, I/O and additionally better graphics and sound provided by the <i>FusionX</i>.
|
||||
The <i>FusionX</i> board can also be used to power alternative CPUs on the host for testing, development and to provide a completely different software platform and applications. It can use the underlying hosts keyboard, monitor, I/O and additionally better graphics and sound provided by the <i>FusionX</i>.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
It shares similarities with the tran<i>ZPU</i>ter<sup><i>Fusion</i></sup> but instead of realising it in hardware via an FPGA it realises
|
||||
@@ -18,7 +24,7 @@ Using the same base design as the tran<i>ZPU</i>ter<sup><i>Fusion</i></sup> it i
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
In Z80 configuration, a Linux Kernel driver instantiates a Z80 emulation which realises a Z80 CPU in software which in turn can command and control the host system. The kernel driver along with a controlling application
|
||||
can provide a wealth of features to the host through this mechanism. The SOM is also connected to an SD Drive and USB 2.0 port so there is no limit to features which can be proivded.
|
||||
can provide a wealth of features to the host through this mechanism. The SOM is also connected to an SD Drive and USB 2.0 port so there is no limit to features which can be provided.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
Like the tran<i>ZPU</i>ter<sup><i>Fusion</i></sup>, the tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> can provide enhanced video and sound to the host. The SOM incorporates dual DAC audio and a 2D GPU with configurable resolutions switched onto the hosts video and audio outputs under software control.
|
||||
@@ -27,8 +33,8 @@ Like the tran<i>ZPU</i>ter<sup><i>Fusion</i></sup>, the tran<i>ZPU</i>ter<sup><i
|
||||
The <i>FusionX</i> board is ideal for any developer wanting to physically program and interact with retro hardware using a Linux platform with Wifi and USB/Serial port connectivity.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
To most retro users, in the early stages of <i>FusionX</i> development, the board wont have much use. As the project matures, a board can be obtained and installed into the Z80 socket of their Sharp or simlar Z80 based system (providing there is sufficient room to accommodate this board) and utilise the upgraded featues, such as:
|
||||
<ul style="line-height: 0.9em;"><font size="3">
|
||||
To most retro users, in the early stages of <i>FusionX</i> development, the board won't have much use. As the project matures, a board can be obtained and installed into the Z80 socket of their Sharp or similar Z80 based system (providing there is sufficient room to accommodate this board) and utilise the upgraded features, such as:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">Original host specifications</font><br>- the machine behaves just as though it had a physical Z80 within. There might be slight differences in the Z80 functionality as it is implemented in software but the Z80 hardware timing is accurate.</li>
|
||||
<li><font style="color: orange;" size="3">Accelerator</font><br>- the Z80 can run at much higher speeds due to the abundance of memory and 1.2GHz dual-core processor, which would typically see performance upto that of a 500MHz Z80.</li>
|
||||
<li><font style="color: orange;" size="3">Emulation</font><br>- emulation of all the Sharp MZ series machines, experiencing it through the host system keyboard, monitor and I/O.</li>
|
||||
@@ -82,13 +88,13 @@ thus the CPLD is able to drive 5V circuitry and with sufficient drive current, 2
|
||||
The CPLD internal state machines are clocked by an external 50MHz oscillator, this allows for adequate sampling and state change for a typical 1MHz - 6MHz Z80 host.
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">Schematic 2 - I/O (Audio, UART, USB)</font>
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The SOM is rich in peripherals and this circuit interfaces some of them for use in the FusionX, these include:
|
||||
|
||||
<ul style="line-height: 0.9em;"><font size="3">
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">Stereo Audio Microphone input</font><br>- a digital microphone input is also available but the pins are used in the CPLD interface.</li>
|
||||
<li><font style="color: orange;" size="3">Stereo Audio DAC output</font><br>- dual digital to analogue converters for sound output which can be clocked at 48KHz.</li>
|
||||
<li><font style="color: orange;" size="3">WiFi Antenna</font><br>- a SSW101B 20/40MHz IEEE 802.11 b/g/n/e/l/n/w WiFi transceiver operating in the 2.4GHz band with a 500M range. The SOM also includes a 100MHz ETH PHY but this is not used in this design as hard wired ethernet is not practical for a board which is
|
||||
@@ -97,12 +103,12 @@ sited inside a retro machine.</li>
|
||||
<li><font style="color: orange;" size="3">USB</font><br>- a Linux connected USB port allowing for device expansion, such as additional storage, mice etc.</li>
|
||||
<li><font style="color: orange;" size="3">Fast UART</font><br>- high speed full duplex with hardware handshake UART.</li>
|
||||
<li><font style="color: orange;" size="3">UART</font><br>- standard 2 pin UART operating upto 500KHz.</li>
|
||||
<li><font style="color: orange;" size="3">SD Card</font><br>- the SOM has inbuilt FlashNAND so can accomodate a simple Linux filesystem, addition of an SD card allows for greater storage of Host applications and Linux utilities. An SD card also makes for ease of upgrades as the SOM will auto upgrade when a suitably prepared SD card is present on boot.</li>
|
||||
<li><font style="color: orange;" size="3">SD Card</font><br>- the SOM has inbuilt FlashNAND so can accommodate a simple Linux filesystem, addition of an SD card allows for greater storage of Host applications and Linux utilities. An SD card also makes for ease of upgrades as the SOM will auto upgrade when a suitably prepared SD card is present on boot.</li>
|
||||
</font></ul>
|
||||
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">Schematic 3 - Video (VideoDAC, Contrast DAC)</font>
|
||||
|
||||
@@ -117,7 +123,7 @@ DAC, as it is sending the video signal with colour information as a voltage cont
|
||||
In order to get true black, the CPLD creates a blanking signal, MONO.BLANK, which is paired with a MUX 0V clamp on the daughter board which drives the monochrome monitor, this sees the RGB332 as 0V when 00000000 is present, then varying between 4.01V-5V when non-zero.
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">Schematic 4 - Power Supply (3.3V, USB)</font>
|
||||
|
||||
@@ -128,7 +134,7 @@ The power supply, for the SOM and CPLD, converts the 5V present on the Z80 socke
|
||||
Additionally, a software controlled USB power switch is installed to enable (and reset if required) +5V power to the USB expansion port.
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">Schematic 5 - CPLD Interface</font>
|
||||
|
||||
@@ -136,70 +142,490 @@ Additionally, a software controlled USB power switch is installed to enable (and
|
||||
The final schematic is the interface between the SOM and the CPLD. Originally this was going to be a bi-directional 16bit bus with Read/Write and Strobe signals but after testing, the setup time for a 16bit signal with tri-state switching was much slower than an SPI connection
|
||||
due to the GPIO register layout and operation within the SOM and the speed of the I/O operations within the SOM.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
The solution used is to have a bidirectional 72MHz SPI bus between the SOM and CPLD for transmitting Z80 transaction requests and an 8bit read only parallel bus for more rapid reading of Z80 Data and seperate Z80 state information.
|
||||
The solution used is to have a bidirectional 72MHz SPI bus between the SOM and CPLD for transmitting Z80 transaction requests and an 8bit read only parallel bus for more rapid reading of Z80 Data and separate Z80 state information.
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
#### <font style="color: yellow;" size="5">PCB
|
||||
#### <font style="color: yellow;" size="5">PCB</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The PCB was designed with minimum size as a primary requirement for the various machines in which it would be installed. It also had to be compatible with the tran<i>ZPU</i>ter<sup><i>Fusion</i></sup> for interchangeability.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
A major concern was heat dissipation as the PCB, when installed within an MZ-700 is very close to existing motherboard components which give off a lot of heat with no air circulation in a sealed compact housing. This meant active components couldnt be sited on the PCB underside
|
||||
A major concern was heat dissipation as the PCB, when installed within an MZ-700 is very close to existing motherboard components which give off a lot of heat with no air circulation in a sealed compact housing. This meant active components couldn't be sited on the PCB underside
|
||||
as heat generation would lead to instability and failure, which in turn led to an increase in the final PCB size.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The smallest components which could be manually assembled where used, ie. 0402/0603 passive devices and 0.5mm IC pitch spacing to reduce overall size and a 4 layer stackup selected to fit all required components.
|
||||
The smallest components which could be manually assembled were used, ie. 0402/0603 passive devices and 0.5mm IC pitch spacing to reduce overall size and a 4 layer stackup selected to fit all required components.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
</div>
|
||||
|
||||
<font style="color: cyan;" size="4">PCB Top Overview</font>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">PCB Bottom Overview</font>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">PCB 4 Layer Routing Overview</font>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">PCB Assembled</font>
|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
<font style="color: cyan;" size="4">PCB Component Placement and Bill of Materials</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
Click <a href="http://eaw.app/_pages/FusionX_v1_0_BOM.html">here</a> to view an interactive PCB component placement diagram and Bill of Materials.
|
||||
Click <a href="../_pages/FusionX_v1_0_BOM.html">here</a> to view an interactive PCB component placement diagram and Bill of Materials.
|
||||
</div>
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
|
||||
<a name="cpld" id="cpld"></a>
|
||||
###### <font style="color: yellow;" size="5">CPLD</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> uses an Altera MAX7000AE CPLD — specifically the <b>EPM7512AETC144-10</b> — as the central interface between the SOM and the host Z80 socket. This is a 512-macrocell, 144-pin TQFP device operating at 3.3V LVTTL on its outputs while accepting 5V TTL levels on its inputs, making it directly compatible with vintage Sharp MZ and other Z80-based hardware without any additional level shifting.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The CPLD design is written in VHDL and built with <b>Altera Quartus II 13.0.1 SP1 (Web Edition)</b>. Because each host machine has slightly different bus timing requirements and memory map constraints, a separate VHDL implementation is maintained for each supported host:
|
||||
</div>
|
||||
<div style="padding-top: 0.4em;"></div>
|
||||
|
||||
| VHDL Variant | Host Machine | Directory |
|
||||
|---|---|---|
|
||||
| `tzpuFusionX.vhd` (MZ80A) | Sharp MZ-80A | `CPLD/v1.0/MZ80A/` |
|
||||
| `tzpuFusionX.vhd` (MZ700) | Sharp MZ-700 | `CPLD/v1.0/MZ700/` |
|
||||
| `tzpuFusionX.vhd` (MZ2000) | Sharp MZ-2000 | `CPLD/v1.0/MZ2000/` |
|
||||
| `tzpuFusionX.vhd` (PCW8256) | Amstrad PCW-8256 | `CPLD/v1.0/PCW8256/` |
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="cpld-purpose" id="cpld-purpose"></a>
|
||||
<font style="color: cyan;" size="4">Purpose and Role</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The CPLD performs several functions that would be impractical or impossible to implement directly in software on the SOM:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">Voltage level translation</font><br>— Bridges the 5V TTL Z80 host bus to the 3.3V LVTTL signals used by the SOM. The MAX7000AE is 5V tolerant on inputs and drives outputs at 3.3V, which exceeds the 2.4V switching threshold of 5V TTL receivers, giving up to 25mA drive per pin.</li>
|
||||
<li><font style="color: orange;" size="3">Cycle-accurate Z80 bus timing</font><br>— The CPLD implements a hardware FSM clocked by a 50MHz external oscillator that samples the host Z80 clock and reproduces the precise T-state sequence for every bus cycle type. This offloads all critical timing from the SOM, which only needs to respond with data within the window defined by the CPLD FSM.</li>
|
||||
<li><font style="color: orange;" size="3">SOM interface bridging</font><br>— Converts between the Z80 parallel bus protocol and the SPI + 8-bit GPIO interface used by the SOM kernel module, translating bus events into a format that the SSD202 can service efficiently from a Linux kernel thread.</li>
|
||||
<li><font style="color: orange;" size="3">Video and audio switching</font><br>— Controls multiplexers that select between the host machine's native video/audio output and the SOM video/audio for routing to the monitor and speakers via daughter board connectors. Switching is commanded by the SOM over SPI.</li>
|
||||
<li><font style="color: orange;" size="3">Video sync and clock generation</font><br>— Generates composite sync (<code>VGA_CSYNCn</code>) from the SOM VSync and HSync signals, detects blanking intervals, generates a 25MHz pixel clock for the monochrome DAC (by dividing the 50MHz oscillator), and produces a colour carrier frequency signal (<code>VGA_COLR</code>) for composite colour output.</li>
|
||||
<li><font style="color: orange;" size="3">Reset management</font><br>— Monitors the host Z80 RESET line and implements a dual-press reset protocol: a single reset press asserts a soft reset to the SOM (allowing the Z80 application to reinitialise), while a second press within one second drives the SOM <code>PM_RESET</code> line to force a full SOM power-cycle reboot.</li>
|
||||
<li><font style="color: orange;" size="3">USB power control</font><br>— Controls the USB VBUS power enable signal under SOM command.</li>
|
||||
</font></ul>
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="cpld-fsm" id="cpld-fsm"></a>
|
||||
<font style="color: cyan;" size="4">Z80 Bus FSM</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The heart of the CPLD design is a finite state machine (<code>SOMFSMState</code>) that tracks and reproduces the Z80 bus cycle state at 50MHz resolution. The FSM monitors the host Z80 clock edges and the bus control signals (MREQ, IORQ, RD, WR, M1, RFSH, BUSRQ, HALT, WAIT) to classify each bus cycle and step through the correct T-state sequence:
|
||||
</div>
|
||||
<div style="padding-top: 0.4em;"></div>
|
||||
|
||||
| FSM State | Z80 Bus Cycle | Description |
|
||||
|---|---|---|
|
||||
| `IdleCycle` | — | Bus is idle; waiting for MREQ or IORQ assertion. |
|
||||
| `FetchCycle` | Opcode Fetch (M1) | M1 + MREQ + RD active; address and data phases timed across T1–T3. |
|
||||
| `RefreshCycle` | DRAM Refresh | RFSH + MREQ active; lower 7 bits of address presented for DRAM row refresh. |
|
||||
| `ReadCycle` | Memory Read | MREQ + RD active; address presented T1, data sampled T3. |
|
||||
| `WriteCycle` | Memory Write | MREQ + WR active; address and data presented T1–T2, write strobed T3. |
|
||||
| `ReadIOCycle` | I/O Read | IORQ + RD active; I/O address and data phases with WAIT support. |
|
||||
| `WriteIOCycle` | I/O Write | IORQ + WR active; I/O address and data presented with WAIT support. |
|
||||
| `HaltCycle` | HALT | Z80 HALT assertion detected; repeated NOP fetch cycles suppressed. |
|
||||
| `BusReqCycle` | Bus Request | BUSRQ asserted; BUSACK driven, bus lines tri-stated, SOM notified. |
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
Each state has numbered sub-states (e.g. <code>FetchCycle_11</code>, <code>FetchCycle_20</code>) corresponding to individual half-cycles within the T-state, allowing the CPLD to assert or deassert control signals with sub-clock-cycle precision relative to the host CLK edges.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
A secondary <code>CTRLFSMState</code> FSM handles SPI command processing (<code>CTRLCMD_Idle</code> → <code>CTRLCMD_ReadIOWrite</code>) independently of the main bus cycle FSM, so that SPI transactions from the SOM do not block Z80 bus cycle servicing.
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="cpld-som-interface" id="cpld-som-interface"></a>
|
||||
<font style="color: cyan;" size="4">SOM Interface</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The CPLD presents two distinct interfaces to the SOM:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">SPI slave (write path)</font><br>— A 4-wire SPI slave (<code>VSOM_SPI_CLK</code>, <code>VSOM_SPI_MOSI</code>, <code>VSOM_SPI_MISO</code>, <code>VSOM_SPI_CSn</code>) receives commands and data from the SOM. Up to 4 bytes per frame are shifted in via a serial shift register and decoded into bus control commands (memory write data, I/O write data, video/audio source selection, USB power control). The SPI clock polarity is parameterised (<code>SPI_CLK_POLARITY</code>) to accommodate different SOM SPI configurations.</li>
|
||||
<li><font style="color: orange;" size="3">8-bit parallel bus (read path)</font><br>— An 8-bit output bus (<code>VSOM_DATA_OUT[7:0]</code>) with a <code>VSOM_HBYTE</code> select line presents either the low or high byte of the current Z80 address/data word to the SOM GPIO inputs. Additional single-bit status lines report: <code>VSOM_READY</code> (FSM idle), <code>VSOM_LTSTATE</code> (last T-state of current cycle), <code>VSOM_BUSRQ</code>, <code>VSOM_BUSACK</code>, <code>VSOM_INT</code>, <code>VSOM_NMI</code>, <code>VSOM_WAIT</code>, and <code>VSOM_RESET</code>.</li>
|
||||
</font></ul>
|
||||
|
||||
This split architecture — SPI for writes, GPIO parallel bus for reads — matches the relative performance characteristics of the SSD202: SPI is clocked and reliable for multi-byte writes, while GPIO direct register access gives the lowest possible read latency for sampling bus state within a Z80 T-state window.
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="cpld-build" id="cpld-build"></a>
|
||||
<font style="color: cyan;" size="4">Building the CPLD Image</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The CPLD bitstream is produced using <b>Altera Quartus II 13.0.1 SP1 Web Edition</b>, which is available as a free download from the Intel FPGA (formerly Altera) website. The Web Edition supports all MAX7000AE devices and is sufficient for this project.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
<font style="color: cyan;" size="3">Opening the Project</font><br>
|
||||
|
||||
Each host machine variant has its own Quartus project in the corresponding subdirectory. To build the MZ-80A variant, for example:
|
||||
|
||||
<pre style="font-size: 0.70em; line-height: 1.3em; background: #1a1a1a; padding: 1em; border-radius: 4px; overflow-x: auto;"># Open in Quartus II GUI:
|
||||
File -> Open Project -> CPLD/v1.0/MZ80A/build/tzpuFusionX_MZ80A.qpf
|
||||
|
||||
# Or launch from the command line using the Quartus shell:
|
||||
quartus_sh --flow compile tzpuFusionX_MZ80A
|
||||
</pre>
|
||||
|
||||
The project references three VHDL source files (paths relative to the project <code>build/</code> directory):
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><code>../tzpuFusionX_Toplevel.vhd</code> — top-level entity instantiation and I/O pin definitions</li>
|
||||
<li><code>../tzpuFusionX_pkg.vhd</code> — shared package (types, constants)</li>
|
||||
<li><code>../tzpuFusionX.vhd</code> — main RTL architecture (FSMs, SPI, bus interface, video/audio control)</li>
|
||||
</font></ul>
|
||||
|
||||
<font style="color: cyan;" size="3">Compilation</font><br>
|
||||
|
||||
In the Quartus GUI select <b>Processing → Start Compilation</b> (or press Ctrl+L). The tool runs Analysis & Synthesis, Fitter, Assembler and Timing Analysis in sequence. A successful build produces:
|
||||
|
||||
<pre style="font-size: 0.70em; line-height: 1.3em; background: #1a1a1a; padding: 1em; border-radius: 4px; overflow-x: auto;">build/output_files/tzpuFusionX_MZ80A.pof # Programmer Object File (JTAG programming)
|
||||
build/output_files/tzpuFusionX_MZ80A.fit.rpt # Fitter report (resource usage)
|
||||
build/output_files/tzpuFusionX_MZ80A.sta.rpt # Timing analysis report
|
||||
</pre>
|
||||
|
||||
The <code>.pof</code> file is the binary image used to program the physical CPLD device.
|
||||
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
<font style="color: cyan;" size="3">Programming the CPLD</font><br>
|
||||
|
||||
Programming is performed via JTAG using an Altera USB-Blaster or compatible JTAG adapter connected to the 10-pin JTAG header on the <i>FusionX</i> board:
|
||||
<ol style="line-height: 1.6em;"><font size="3">
|
||||
<li>Connect the USB-Blaster to the <i>FusionX</i> JTAG header and the host PC.</li>
|
||||
<li>Power the <i>FusionX</i> board (the CPLD must be powered during programming).</li>
|
||||
<li>In Quartus II, open <b>Tools → Programmer</b>.</li>
|
||||
<li>Load the chain description file: <code>build/output_files/tzpuFusionX_MZ80A.cdf</code>.</li>
|
||||
<li>Verify the USB-Blaster is detected in the hardware list, then click <b>Start</b>.</li>
|
||||
<li>Programming completes in a few seconds; the CPLD becomes active immediately on completion.</li>
|
||||
</font></ol>
|
||||
|
||||
The CPLD retains its programmed logic indefinitely without power (MAX7000AE uses EEPROM-based configuration cells) so the device only needs to be programmed once per build or when updating to a new bitstream.
|
||||
</div>
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
|
||||
## <font style="color: yellow;" size="6">Software</font>
|
||||
|
||||
<font size="2">Under construction.</font>
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The <i>FusionX</i> software stack spans from the Linux operating system through to dedicated kernel modules and user-space utilities. The complete software set is built using a customised SigmaStar build environment and loaded onto the SOM's SPI NAND flash. On boot, U-boot initialises the SOM and hands off to the Linux kernel, which loads the Buildroot root filesystem. The <i>FusionX</i> startup script then configures the system and brings the Z80 emulator online.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The software components are:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">Linux OS</font><br>— Kernel 4.9-rt (PREEMPT_RT) with Buildroot root filesystem running on the SigmaStar SSD202 dual-core Cortex-A7.</li>
|
||||
<li><font style="color: orange;" size="3">z80drv.ko</font><br>— Linux kernel module implementing the Z80 CPU emulator and host hardware interface. Runs the Z80 emulation loop on a dedicated CPU core.</li>
|
||||
<li><font style="color: orange;" size="3">ttymzdrv.ko</font><br>— Linux TTY kernel module that presents the Sharp MZ keyboard and display as a standard Linux terminal device (<code>/dev/ttymz0</code>).</li>
|
||||
<li><font style="color: orange;" size="3">z80ctrl</font><br>— User-space command-line utility for controlling the z80drv kernel module: load ROM images, add virtual hardware devices, start/stop emulation and inspect emulated memory.</li>
|
||||
<li><font style="color: orange;" size="3">k64fcpu</font><br>— User-space daemon emulating a K64F virtual CPU. Used in TZFS mode to manage ROM loading and inter-processor communication with the Z80 emulator.</li>
|
||||
<li><font style="color: orange;" size="3">sharpbiter</font><br>— Sharp MZ arbiter daemon, coordinating access to the shared Sharp MZ hardware resources between the Z80 emulator and the Linux TTY driver.</li>
|
||||
</font></ul>
|
||||
|
||||
Startup is handled by <code>start_FusionX.sh</code>, which loads <code>ttymzdrv.ko</code>, starts a getty login session on <code>/dev/ttymz0</code>, pins all Linux processes and IRQs to CPU0, loads <code>z80drv.ko</code> onto the isolated CPU1, then launches the <code>k64fcpu</code> and <code>sharpbiter</code> daemons. Two pre-built startup modes are provided:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">RFS mode</font><br>(<code>startZ80_RFS.sh</code>) — loads the ROM Filing System virtual hardware device and starts the MZ-80A emulator with 40- or 80-column ROM images.</li>
|
||||
<li><font style="color: orange;" size="3">TZFS mode</font><br>(<code>startZ80_TZFS.sh</code>) — loads the tranZPUter SW virtual hardware device and starts the <code>k64fcpu</code> K64F daemon which manages Monitor and TZFS ROM image loading.</li>
|
||||
</font></ul>
|
||||
</div>
|
||||
|
||||
|
||||
<a name="architecture" id="architecture"></a>
|
||||
###### <font style="color: yellow;" size="5">Architecture</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The <i>FusionX</i> software architecture is layered, with each layer handling a distinct responsibility. From the host machine's perspective the flow is entirely transparent — the Z80 socket behaves as a normal Z80 CPU while the SOM is silently intercepting and emulating every bus cycle.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
<pre style="font-size: 0.70em; line-height: 1.3em; background: #1a1a1a; padding: 1em; border-radius: 4px; overflow-x: auto;">
|
||||
Sharp MZ Host
|
||||
+------------------------------------------+
|
||||
| Z80 DIP-40 Socket |
|
||||
+--------------+---------------------------+
|
||||
| Z80 bus (address, data, control)
|
||||
+--------------v---------------------------+
|
||||
| CPLD (Altera MAX 7000A) |
|
||||
| . 5V <-> 3.3V level translation |
|
||||
| . Cycle-accurate Z80 bus timing |
|
||||
| . 50 MHz internal clock |
|
||||
+--------------+---------------------------+
|
||||
| SPI (50 MHz) + 8-bit GPIO bus
|
||||
+--------------v---------------------------+
|
||||
| SSD202 SOM -- CPU1 (dedicated) |
|
||||
| +--------------------------------------+|
|
||||
| | z80drv.ko kernel module ||
|
||||
| | +----------------------------------+||
|
||||
| | | z80io.c (GPIO/SPI HAL) |||
|
||||
| | +----------------------------------+||
|
||||
| | | Zeta Z80 CPU emulator core |||
|
||||
| | +----------------------------------+||
|
||||
| | | Virtual hardware modules |||
|
||||
| | | (z80vhw_*.c, inline) |||
|
||||
| | +----------------------------------+||
|
||||
| +--------------------------------------+|
|
||||
| |
|
||||
| SSD202 SOM -- CPU0 (Linux) |
|
||||
| +--------------------------------------+|
|
||||
| | Linux 4.9-rt / Buildroot rootfs ||
|
||||
| | ttymzdrv.ko --> /dev/ttymz0 ||
|
||||
| | z80ctrl (control utility) ||
|
||||
| | k64fcpu (K64F daemon) ||
|
||||
| | sharpbiter (MZ arbiter) ||
|
||||
| +--------------------------------------+|
|
||||
+------------------------------------------+
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="dual-core-design" id="dual-core-design"></a>
|
||||
<font style="color: cyan;" size="4">Dual-Core Design</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The SSD202's two Cortex-A7 cores operate under a strict separation of responsibility. At startup every Linux process and every hardware IRQ affinity is migrated to CPU0, leaving CPU1 exclusively available to the Z80 emulation kernel thread. The CPU frequency governor is set to performance mode (1.2GHz fixed) after the emulator starts to prevent frequency-scaling transitions from introducing timing variation in the emulation loop.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
<b>CPU0 — Linux and User-Space Services</b><br>
|
||||
Runs the complete Linux 4.9-rt operating system, all user-space daemons and handles all hardware interrupts. Key responsibilities on CPU0 include:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">ttymzdrv.ko</font><br>— Linux TTY kernel module that maps the Sharp MZ keyboard and display to <code>/dev/ttymz0</code>. Supports suspend and resume, enabling the user to switch seamlessly between a Z80 session and a Linux console at the host machine without losing state in either.</li>
|
||||
<li><font style="color: orange;" size="3">z80ctrl utility</font><br>— Command-line tool for runtime control of the Z80 emulator: loading ROM images, registering virtual hardware devices, starting and stopping the emulation loop, and inspecting emulated memory. Communicates with <code>z80drv.ko</code> via a kernel character device.</li>
|
||||
<li><font style="color: orange;" size="3">k64fcpu daemon</font><br>— User-space daemon that emulates a K64F virtual CPU. Active in TZFS mode; it manages Monitor and TZFS ROM image loading into the emulator's memory space and relays inter-processor commands to <code>z80drv.ko</code>.</li>
|
||||
<li><font style="color: orange;" size="3">sharpbiter daemon</font><br>— Sharp MZ arbiter; coordinates access to the shared Sharp MZ keyboard and display hardware between the TTY driver and the Z80 emulator so that both can operate without conflicting on the underlying I/O registers.</li>
|
||||
<li><font style="color: orange;" size="3">WiFi and web server</font><br>— The SOM's integrated 802.11 b/g/n transceiver (SSW101B) provides network connectivity. A lightweight web server on CPU0 can serve configuration and status pages, and the WiFi stack handles OTA firmware delivery via SD card auto-upgrade on boot.</li>
|
||||
</font></ul>
|
||||
|
||||
<b>CPU1 — Z80 Emulator (dedicated)</b><br>
|
||||
Exclusively runs the <code>kthread_z80</code> kernel thread spawned by <code>z80drv.ko</code>. No other process or interrupt is ever scheduled on CPU1 after initialisation. The emulation loop on CPU1:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li>Calls the Zeta Z80 CPU core for each instruction execution step</li>
|
||||
<li>Dispatches each resulting memory or I/O access to the correct handler — physical host hardware, kernel-resident RAM image, or a virtual hardware module function</li>
|
||||
<li>Drives the GPIO and SPI hardware via <code>z80io.c</code> to assert or sample the Z80 bus signals through the CPLD</li>
|
||||
<li>Runs at 1.2GHz with the PREEMPT_RT kernel ensuring minimal interrupt jitter even from CPU0 activity</li>
|
||||
</font></ul>
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="cpld-bus-interface" id="cpld-bus-interface"></a>
|
||||
<font style="color: cyan;" size="4">CPLD Bus Interface</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The hardware path from the SOM to the Z80 host socket passes through an Altera MAX 7000A CPLD. This device serves two essential roles:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">Voltage level translation</font><br>— The CPLD is 5V tolerant on its inputs and drives outputs at 3.3V Low Voltage TTL levels. Since the 5V TTL switching threshold is approximately 2.4V the CPLD can drive 5V host logic directly with up to 25mA per pin, making the board compatible with unmodified vintage Z80 hardware.</li>
|
||||
<li><font style="color: orange;" size="3">Cycle-accurate Z80 bus timing</font><br>— The CPLD embeds state machines clocked by an external 50MHz oscillator. These state machines sample the Z80 host clock and reproduce the precise T-state sequence for each bus cycle (fetch, memory read/write, I/O read/write) as defined in the Z80 state diagrams. This means the SOM kernel module does not need to replicate sub-microsecond Z80 timing in software — the CPLD handles it in hardware.</li>
|
||||
</font></ul>
|
||||
|
||||
The SOM communicates with the CPLD through two parallel channels:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">SPI channel (50MHz)</font><br>— used for writing data and commands to the CPLD. SPI write is used in preference to GPIO for host bus writes because it is clocked and therefore more reliable for multi-byte transfers at speed.</li>
|
||||
<li><font style="color: orange;" size="3">8-bit GPIO bus</font><br>— used by <code>z80io.c</code> for reading bus status and address/data values from the CPLD. Direct register access is used (bypassing the SigmaStar HAL API after initialisation) to minimise read latency. The maximum read throughput achievable via the SSD202 GPIO structure is approximately 2MB/s for an 8-bit byte — fast enough to service Z80 bus cycles at typical host clock rates (1MHz–6MHz) when combined with the CPLD buffering.</li>
|
||||
</font></ul>
|
||||
|
||||
Because the GPIO read throughput sets an upper bound on bus transaction rate, Z80 programs execute from kernel-resident memory images rather than being read from the physical host memory bus on every access. ROM images are loaded into kernel memory at startup, and all memory accesses by the emulated Z80 are serviced from there — the physical host bus is only engaged when a <code>PHYSICAL</code>-type block is encountered (e.g. for host video RAM or hardware registers that must be accessed on the real hardware).
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="memory-architecture" id="memory-architecture"></a>
|
||||
<font style="color: cyan;" size="4">Memory Architecture</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The 128MB DRAM on the SSD202 SOM is shared between the Linux operating system and the Z80 kernel module. The kernel module allocates a contiguous region of physically-addressed kernel memory to hold ROM and RAM images for the emulated Z80. This region is accessed directly by the <code>kthread_z80</code> running on CPU1, with no virtual memory translation overhead in the inner emulation loop.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The emulated Z80 sees a configurable memory map across the standard 64KB (0x0000–0xFFFF) address space. Each region is assigned one of the following access types:
|
||||
</div>
|
||||
<div style="padding-top: 0.4em;"></div>
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `kernel RAM` | Read/write region backed by a kernel-allocated DRAM buffer. Standard RAM for the emulated machine. |
|
||||
| `kernel ROM` | Read-only region in kernel DRAM. Write cycles are silently discarded. Used for Monitor ROMs, BASIC ROMs, User ROMs, TZFS ROM pages. |
|
||||
| `PHYSICAL` | Pass-through to real host hardware — the SOM releases the CPLD bus and the host hardware responds to the cycle directly. Used for host video RAM and I/O registers that must interact with real hardware. |
|
||||
| `VIRTUAL` | Each access triggers a C handler function within the kernel module. Used to emulate peripheral devices (floppy controller, QuickDisk, RFS banking logic) without any real hardware. |
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
ROM images are loaded into kernel memory at startup by <code>z80ctrl --loadrom</code> (or automatically by the active virtual hardware module or the <code>k64fcpu</code> daemon in TZFS mode). Multiple ROM page sets can be resident simultaneously — the RFS virtual hardware module, for example, maintains up to four switchable ROM pages (MROM, User ROM I/II/III) for 40-column and 80-column configurations.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
Machine timing constants for each supported host (MZ-80A, MZ-700, MZ-2000, PCW-8256) are defined in <code>z80driver.h</code> and used by the emulation loop to pace bus cycles at the correct rate relative to the host clock, ensuring that time-sensitive software (tape motor control, serial I/O, delay loops) behaves as it would on original hardware.
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="virtual-hardware-modules" id="virtual-hardware-modules"></a>
|
||||
<font style="color: cyan;" size="4">Virtual Hardware Modules</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
Virtual hardware modules are C source files (<code>z80vhw_*.c</code>) that define the behaviour of a specific host machine or peripheral set. Rather than being compiled as separately-linked objects they are <code>#include</code>d directly into <code>z80driver.c</code>, so their handler functions are inlined into the emulation dispatch path with no function-call overhead.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
Up to five virtual hardware devices can be active simultaneously (<code>MAX_VIRTUAL_DEVICES 5</code>). Devices are registered at runtime before the emulator starts using <code>z80ctrl --adddev --device <name></code>. Each registered device receives memory read, memory write, I/O read and I/O write callbacks for the address ranges it claims, and can optionally install its own ROM images and configure the memory map during initialisation.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The available modules and the host machines they support are:
|
||||
</div>
|
||||
<div style="padding-top: 0.4em;"></div>
|
||||
|
||||
| Module | Host | Role |
|
||||
|--------|------|------|
|
||||
| `z80vhw_mz80a.c` | Sharp MZ-80A | Original MZ-80A memory map, keyboard matrix and display I/O — no extensions. |
|
||||
| `z80vhw_mz700.c` | Sharp MZ-700 | MZ-700 bank-switching, video and keyboard I/O emulation. |
|
||||
| `z80vhw_mz2000.c` | Sharp MZ-2000 | MZ-2000 memory map, extended video modes and I/O. |
|
||||
| `z80vhw_pcw.c` | Amstrad PCW-8256 | PCW-8256 memory/bank paging and peripheral I/O. |
|
||||
| `z80vhw_rfs.c` | MZ-80A + RFS board | ROM Filing System: manages four switchable ROM pages (40-col and 80-col sets), SD-based MZF program loading, bank switching. |
|
||||
| `z80vhw_tzpu.c` | MZ-80A + tranZPUter SW | tranZPUter SW virtual hardware; the kernel-side driver works with the userspace <code>k64fcpu</code> daemon to provide K64F virtual CPU behaviour, TZFS ROM page management and CP/M support. |
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The TZPU module (<code>z80vhw_tzpu.c</code>) is architecturally distinct from the others. Because the K64F co-processor behaviour is complex and stateful, it is split across two components: the <code>z80vhw_tzpu.c</code> kernel-side stub handles fast bus-cycle dispatch while the <code>k64fcpu</code> user-space daemon on CPU0 manages ROM loading, memory bank selection and higher-level K64F command processing. The two halves communicate via a shared memory region in the kernel module.
|
||||
</div>
|
||||
|
||||
|
||||
<a name="build" id="build"></a>
|
||||
###### <font style="color: yellow;" size="5">Build</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The complete <i>FusionX</i> OS and application set is built using the <code>Build_FusionX.sh</code> script, which wraps the SigmaStar SDK build system and produces a ready-to-flash NAND image. Building requires a Linux host with the ARM cross-compiler toolchain installed.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
<font style="color: cyan;" size="4">Prerequisites</font>
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li>ARM cross-compiler: <code>arm-linux-gnueabihf-gcc</code> (e.g. from <code>gcc-arm-linux-gnueabihf</code> package)</li>
|
||||
<li>SigmaStar SDK source tree (kernel, U-boot, Buildroot) in the parent directory structure expected by <code>Build_FusionX.sh</code></li>
|
||||
<li>FusionX application source in the <code>../FusionX</code> directory relative to the linux build directory</li>
|
||||
<li>Standard build tools: <code>make</code>, <code>cmake</code>, <code>bc</code>, <code>libssl-dev</code></li>
|
||||
</font></ul>
|
||||
|
||||
<font style="color: cyan;" size="4">Building the Full OS Image</font>
|
||||
|
||||
The build is launched from the <code>software/linux/</code> directory:
|
||||
|
||||
<pre style="font-size: 0.70em; line-height: 1.3em; background: #1a1a1a; padding: 1em; border-radius: 4px; overflow-x: auto;"># Build full image for FusionX (project 2D06, SPI NAND, SSD202, 256MB flash)
|
||||
./Build_FusionX.sh -f nand -p ssd202 -o 2D06 -m 256
|
||||
</pre>
|
||||
|
||||
This builds in sequence: U-boot bootloader, Linux kernel (using the FusionX custom defconfig <code>infinity2m_spinand_fusionx_defconfig</code>), Buildroot root filesystem and the FusionX application set. Output images are written to <code>project/image/output/images/</code>.
|
||||
|
||||
For the standard SigmaStar reference configuration use project <code>2D07</code> instead.
|
||||
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
<font style="color: cyan;" size="4">Building Kernel Modules Only</font>
|
||||
|
||||
The kernel modules can be rebuilt independently against an already-built kernel tree, which is useful during development:
|
||||
|
||||
<pre style="font-size: 0.70em; line-height: 1.3em; background: #1a1a1a; padding: 1em; border-radius: 4px; overflow-x: auto;"># Build z80drv kernel module
|
||||
cd software/FusionX/src/z80drv/src.mz80a
|
||||
make
|
||||
|
||||
# Build ttymzdrv kernel module
|
||||
cd software/FusionX/src/ttymz
|
||||
make
|
||||
</pre>
|
||||
|
||||
The resulting <code>z80drv.ko</code> and <code>ttymzdrv.ko</code> files can be copied directly to the <code>/apps/FusionX/modules/</code> directory on the running SOM (via SSH or SD card) and loaded with <code>insmod</code>.
|
||||
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
<font style="color: cyan;" size="4">Flashing and Updates</font>
|
||||
|
||||
The flash image produced by the build script is programmed to the SOM SPI NAND via the SigmaStar ISP tool over USB. Once the initial image is installed, subsequent updates can be delivered via SD card — when the SOM boots with a suitably prepared SD card present it will auto-upgrade the NAND image without requiring a USB connection.
|
||||
</div>
|
||||
|
||||
|
||||
###### <font style="color: yellow;" size="5">Linux</font>
|
||||
|
||||
<font size="2">Under construction.</font>
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The Linux platform runs on the SigmaStar SSD202 (Infinity2M) SOM — a 29mm × 29mm stamp module containing a dual-core ARM Cortex-A7 at 1.2GHz, 128MB DRAM, 256MB SPI NAND flash and an integrated 802.11 b/g/n WiFi transceiver. The kernel is Linux 4.9 with the PREEMPT_RT real-time patch applied to minimise scheduling latency, which is essential for responsive Z80 emulation.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The complete OS image — U-boot bootloader, Linux kernel, Buildroot root filesystem and FusionX application set — is assembled using the <code>Build_FusionX.sh</code> script, a customised version of the SigmaStar SDK build system. Two project targets are defined:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><font style="color: orange;" size="3">2D06</font><br>— FusionX custom configuration using the <code>infinity2m_spinand_fusionx_defconfig</code> kernel defconfig.</li>
|
||||
<li><font style="color: orange;" size="3">2D07</font><br>— Standard SigmaStar reference configuration using <code>infinity2m_spinand_ssc011a_s01a_minigui_defconfig</code>.</li>
|
||||
</font></ul>
|
||||
|
||||
The build script is invoked as: <code>Build_FusionX.sh -f nand -p ssd202 -o 2D06 -m 256</code> and produces a full flash image ready for programming to the SOM NAND.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
A key aspect of the Linux configuration is CPU isolation. At startup all Linux processes and hardware IRQs are migrated to CPU0. CPU1 is then dedicated exclusively to the <code>kthread_z80</code> kernel thread which runs the Z80 emulation loop. This CPU affinity separation, combined with the PREEMPT_RT kernel, gives the Z80 emulator the most consistent and lowest-latency access to the host hardware interface. The CPU performance governor is also set to maximum frequency (1.2GHz) after the Z80 emulator is running to avoid frequency scaling causing timing variation in the emulation loop.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The root filesystem is a Buildroot-based minimal Linux environment stored in the SOM NAND flash. An optional SD card can extend storage for Sharp MZ application software, ROM images and additional Linux utilities. When a suitably prepared SD card is present at boot the SOM will auto-upgrade from it, simplifying firmware updates.
|
||||
</div>
|
||||
|
||||
|
||||
###### <font style="color: yellow;" size="5">Z80 Emulator</font>
|
||||
|
||||
<font size="2">Under construction.</font>
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The Z80 emulator is implemented as a Linux kernel module, <code>z80drv.ko</code> (v1.4, April 2023). It uses the <a href="https://github.com/redcode/Z80">Zeta Z80 CPU emulator library</a> by Manuel Sainz de Baranda y Goñi as its Z80 instruction-set core, wrapped in a kernel-space driver that interfaces with the SSD202 GPIO hardware and the CPLD Z80 host interface.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The hardware path from the SOM to the Z80 host socket runs: SSD202 GPIO / SPI → CPLD → Z80 DIP-40 socket. The CPLD handles accurate Z80 bus timing using a 50MHz clock, so the kernel module does not need to reproduce precise T-state timing itself. The GPIO interface is managed by <code>z80io.c</code>, which calls the SigmaStar HAL for initialisation but accesses registers directly for bit-level read/write operations to minimise latency. The practical read throughput of the SSD202 GPIO structure is approximately 2MB/s for an 8-bit byte, which means programs execute from emulated (kernel) memory rather than from the physical host memory over the bus.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The emulator supports the following host machines, each with its own virtual hardware module:
|
||||
<table style="font-size: 0.85em; width: 100%; border-collapse: collapse; margin-top: 0.5em;">
|
||||
<thead>
|
||||
<tr style="background: #2a2a2a;">
|
||||
<th style="padding: 0.4em 0.8em; text-align: left; border: 1px solid #444;">Virtual Hardware Module</th>
|
||||
<th style="padding: 0.4em 0.8em; text-align: left; border: 1px solid #444;">Host Machine</th>
|
||||
<th style="padding: 0.4em 0.8em; text-align: left; border: 1px solid #444;">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td style="padding: 0.4em 0.8em; border: 1px solid #444;"><code>z80vhw_mz80a.c</code></td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">Sharp MZ-80A</td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">Original MZ-80A behaviour, no additions</td></tr>
|
||||
<tr><td style="padding: 0.4em 0.8em; border: 1px solid #444;"><code>z80vhw_mz700.c</code></td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">Sharp MZ-700</td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">Original MZ-700 behaviour, no additions</td></tr>
|
||||
<tr><td style="padding: 0.4em 0.8em; border: 1px solid #444;"><code>z80vhw_mz2000.c</code></td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">Sharp MZ-2000</td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">MZ-2000 emulation</td></tr>
|
||||
<tr><td style="padding: 0.4em 0.8em; border: 1px solid #444;"><code>z80vhw_pcw.c</code></td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">Amstrad PCW-8256</td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">PCW-8256 emulation</td></tr>
|
||||
<tr><td style="padding: 0.4em 0.8em; border: 1px solid #444;"><code>z80vhw_rfs.c</code></td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">MZ-80A + RFS</td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">ROM Filing System virtual hardware for MZ-80A</td></tr>
|
||||
<tr><td style="padding: 0.4em 0.8em; border: 1px solid #444;"><code>z80vhw_tzpu.c</code></td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">MZ-80A + tranZPUter SW</td><td style="padding: 0.4em 0.8em; border: 1px solid #444;">tranZPUter SW virtual hardware; combines kernel driver with userspace <code>k64fcpu</code> daemon</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The virtual hardware modules are compiled inline into <code>z80drv.ko</code> rather than linked as separate objects, which eliminates function call overhead in the emulation hot path. Up to five virtual hardware devices can be active simultaneously (<code>MAX_VIRTUAL_DEVICES 5</code>). Devices are added at runtime using <code>z80ctrl --adddev --device <name></code> before starting the emulator.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The <code>z80ctrl</code> utility provides full runtime control of the emulator from the Linux command line:
|
||||
<ul style="line-height: 1.6em;"><font size="3">
|
||||
<li><code>--adddev --device <name></code> — add a virtual hardware device (rfs, tzpu, mz700, mz80a, mz2000, pcw)</li>
|
||||
<li><code>--start</code> / <code>--stop</code> — start or stop the Z80 emulation loop</li>
|
||||
<li><code>--loadrom --file <path> --addr <hex> --type <n></code> — load a ROM binary into emulated memory</li>
|
||||
<li><code>--mem --addr <hex> --len <n></code> — inspect emulated memory contents</li>
|
||||
<li><code>--cmd <hex></code> — send a command byte directly to the CPLD/Z80 gateway</li>
|
||||
</font></ul>
|
||||
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The <code>ttymzdrv.ko</code> module (<code>ttymz.c</code>, v1.2, July 2023) provides a standard Linux TTY interface on <code>/dev/ttymz0</code> backed by the Sharp MZ keyboard and display hardware. This allows the host machine's console to be used as a Linux terminal — running a getty login session — while also supporting suspend and resume to switch the display between Linux and the Z80 emulation session without losing state. Supported hosts are MZ-80A, MZ-700 and MZ-2000.
|
||||
</div>
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
|
||||
## <font style="color: yellow;" size="6">Daughter Boards</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The tranZPUter series was initially developed in the Sharp MZ-80A and was primarily a Z80 replacement. As the concept evolved and the tranZPUter SW-700 was developed for the MZ-700 it became more of an integral component of the machine, offering original and upgraded Video and Audio capabilites by intercepting and routing existing signals.
|
||||
The tranZPUter series was initially developed in the Sharp MZ-80A and was primarily a Z80 replacement. As the concept evolved and the tranZPUter SW-700 was developed for the MZ-700 it became more of an integral component of the machine, offering original and upgraded Video and Audio capabilities by intercepting and routing existing signals.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
After significant developments on the tranZPUter SW-700 it became desirable to port it back to the MZ-80A and MZ-2000 but these machines had different CPU orientation and signal requirements, ie. driving an internal and external monitor. This requirement led to the concept of daughter boards, where a specific board would be designed and developed for
|
||||
@@ -207,7 +633,7 @@ the target host and would plug into the tranZPUter SW-700 card. Ideally I wanted
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
During the design of the tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> one of the main requirements was to make the board small, the Z80 orientation changeable and also compatible with the tran<i>ZPU</i>ter<sup><i>Fusion</i></sup> so that it could fit many machines and be interchangeable. As the SW-700 also interfaced to the Video and Audio of the machines
|
||||
and each was quite different, it became apparent that the tran<i>ZPU</i>ter<sup>FusionX</sup> needed to include a concept to allow different video/audio interfaces according to the targetted host. This concept was realised via daughter boards. Two connectors would link the tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> to a daughter board which would be
|
||||
and each was quite different, it became apparent that the tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> needed to include a concept to allow different video/audio interfaces according to the targeted host. This concept was realised via daughter boards. Two connectors would link the tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> to a daughter board which would be
|
||||
specifically designed for the intended host.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
@@ -226,7 +652,7 @@ The purpose of the MZ-700 daughter board is to interface the video/audio circuit
|
||||
is switched between the MZ-700 and <i>FusionX</i> under control of the <i>FusionX</i>.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The original sound circuity of the MZ-700 drives a speaker directly and in order to inject <i>FusionX</i> audio into the MZ-700 speaker, the mainboard speaker output is routed to the daughter board, level converted and switched under control of the <i>FusionX</I>. The <i>FusionX</i> offers stereo sound so this is selectively switched/mixed with the
|
||||
The original sound circuitry of the MZ-700 drives a speaker directly and in order to inject <i>FusionX</i> audio into the MZ-700 speaker, the mainboard speaker output is routed to the daughter board, level converted and switched under control of the <i>FusionX</I>. The <i>FusionX</i> offers stereo sound so this is selectively switched/mixed with the
|
||||
original MZ-700 sound and fed to a Class D amplifier which then drives the internal speaker. Line level stereo output is achieved via an additional 4pin connector and used as required.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
@@ -241,7 +667,7 @@ This setup allows for Linux or emulated machines, whilst running as an applicati
|
||||
The MZ-700 daughter board consists of three 4way SPDT analogue switches to route video and audio signals under <i>FusionX</i> control and a Class D power amplifier.
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">MZ-700 Video Interface PCB</font>
|
||||
|
||||
@@ -251,16 +677,16 @@ The MZ-700 daughter board PCB is small and compact due to the space restrictions
|
||||
|
||||
<div style='content: ""; clear: both; display: table;'>
|
||||
<div style='width: 35%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/VideoInterface_MZ700_v1_0_3D_Top.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/VideoInterface_MZ700_v1_0_3D_Top.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
<div style='width: 39%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/VideoInterface_MZ700_v1_0_3D_Bottom.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/VideoInterface_MZ700_v1_0_3D_Bottom.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style='content: ""; clear: both; display: table;'>
|
||||
<div style='width: 80%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/FusionX_MZ700.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/FusionX_MZ700.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -284,7 +710,7 @@ The video signals from the mainboard are switched with the <i>FusionX</i> video
|
||||
The <i>FusionX</i> RGB output is routed to the MZ-2000 external RGB video socket allowing for upto full HD external colour video display.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The sound circuity of the MZ-2000 is sent to an audio amplifier on the CRT monitor. This signal is intercepted and switched with the <i>FusionX</i> audio which then drives the CRT monitor amplifier. Line level stereo output is achieved via an additional 4pin connector and used as required.
|
||||
The sound circuitry of the MZ-2000 is sent to an audio amplifier on the CRT monitor. This signal is intercepted and switched with the <i>FusionX</i> audio which then drives the CRT monitor amplifier. Line level stereo output is achieved via an additional 4pin connector and used as required.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
</div>
|
||||
@@ -295,26 +721,26 @@ The sound circuity of the MZ-2000 is sent to an audio amplifier on the CRT monit
|
||||
The MZ-2000 daughter board consists of two 4way SPDT analogue switches to route video and audio signals under <i>FusionX</i> control. One SPDT switch is used for creating pure black in the modified video signal generated on the <i>FusionX</i> board.
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">MZ-2000 Video Interface PCB</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The MZ-2000 daughter board PCB is small and compact due to the space restrictions and the number of connectors it must carry. It plugs into the mainboard monitor/IPL male connectors and then presents new CRT monitor, external Video and IPL/RESET switch connectors for all the exising internal cabling.
|
||||
The MZ-2000 daughter board PCB is small and compact due to the space restrictions and the number of connectors it must carry. It plugs into the mainboard monitor/IPL male connectors and then presents new CRT monitor, external Video and IPL/RESET switch connectors for all the existing internal cabling.
|
||||
</div>
|
||||
|
||||
<div style='content: ""; clear: both; display: table;'>
|
||||
<div style='width: 50%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/VideoInterface_MZ2000_v1_0_3D_Top.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/VideoInterface_MZ2000_v1_0_3D_Top.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
<div style='width: 50%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/VideoInterface_MZ2000_v1_0_3D_Bottom.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/VideoInterface_MZ2000_v1_0_3D_Bottom.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style='content: ""; clear: both; display: table;'>
|
||||
<div style='width: 60%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/FusionX_MZ2000.png' height='80%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/FusionX_MZ2000.png' height='80%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -323,7 +749,7 @@ The MZ-2000 daughter board PCB is small and compact due to the space restriction
|
||||
###### <font style="color: yellow;" size="5">MZ-80A Daughter Board</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The purpose of the MZ-80A daughter board is to interface the video/audio/reset circuits of the <i>FusionX</I> board with those of the MZ-80A. The MZ-80A has an internal monochrome CRT, cutouts for and external RGB video socket and internal Audio with an amplifier on the monochrome CRT control board.
|
||||
The purpose of the MZ-80A daughter board is to interface the video/audio/reset circuits of the <i>FusionX</I> board with those of the MZ-80A. The MZ-80A has an internal monochrome CRT, cutouts for an external RGB video socket and internal Audio with an amplifier on the monochrome CRT control board.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The daughter board is designed to plug into the vertical mainboard CRT video connector with a gap so that the data cassette connector can be simultaneously connected. The gap is necessary as the CRT video connector sits close to the rear sidewall so the daughter board must extend forwards towards the keyboard.
|
||||
@@ -332,7 +758,7 @@ The daughter board is designed to plug into the vertical mainboard CRT video con
|
||||
It presents all the required connectors to connect the RESET switch (both in and out), internal monitor and external monitor on the same board.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The RESET input is intercepted on the daughter board and sent to the <i>FusionX</i>. Technically it isnt needed as the <i>FusionX</i> samples the Z80 Reset which is based on this input, but it can be useful, for example, detecting requests to reboot the SOM (double press) rather than the MZ-80A circuitry.
|
||||
The RESET input is intercepted on the daughter board and sent to the <i>FusionX</i>. Technically it isn't needed as the <i>FusionX</i> samples the Z80 Reset which is based on this input, but it can be useful, for example, detecting requests to reboot the SOM (double press) rather than the MZ-80A circuitry.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The video signals from the mainboard are switched with the <i>FusionX</i> video monochrome signals and sent to the internal CRT monitor. This allows for original video output on the CRT monitor or advanced <i>FusionX</i> text and graphics, resolution subject to the timing constraints of the monitor.
|
||||
@@ -341,7 +767,7 @@ The video signals from the mainboard are switched with the <i>FusionX</i> video
|
||||
The <i>FusionX</i> RGB output is routed to the MZ-80A external RGB video socket (if installed) allowing for upto full HD external colour video display.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The sound circuity of the MZ-80A is sent to an audio amplifier on the CRT monitor. This signal is intercepted and switched with the <i>FusionX</i> audio which then drives the CRT monitor amplifier. Line level stereo output is achieved via an additional 4pin connector and used as required.
|
||||
The sound circuitry of the MZ-80A is sent to an audio amplifier on the CRT monitor. This signal is intercepted and switched with the <i>FusionX</i> audio which then drives the CRT monitor amplifier. Line level stereo output is achieved via an additional 4pin connector and used as required.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
</div>
|
||||
@@ -352,20 +778,20 @@ The sound circuity of the MZ-80A is sent to an audio amplifier on the CRT monito
|
||||
The MZ-80A daughter board consists of two 4way SPDT analogue switches to route video and audio signals under <i>FusionX</i> control. One SPDT switch is used for creating pure black in the modified video signal generated on the <i>FusionX</i> board.
|
||||
</div>
|
||||
|
||||

|
||||

|
||||
|
||||
<font style="color: cyan;" size="4">MZ-80A Video Interface PCB</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The MZ-80A daughter board PCB is small and compact with a large punchout to enable connection with the mainboard CRT connector and thru connection of the data cassette signal connector. It plugs into the mainboard CRT monitor connector and then presents new CRT monitor, external Video and RESET In/Out switch connectors to be used with all the exising internal cabling.
|
||||
The MZ-80A daughter board PCB is small and compact with a large punchout to enable connection with the mainboard CRT connector and thru connection of the data cassette signal connector. It plugs into the mainboard CRT monitor connector and then presents new CRT monitor, external Video and RESET In/Out switch connectors to be used with all the existing internal cabling.
|
||||
</div>
|
||||
|
||||
<div style='content: ""; clear: both; display: table;'>
|
||||
<div style='width: 47%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/VideoInterface_MZ80A_V1_0_3D_Top.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/VideoInterface_MZ80A_V1_0_3D_Top.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
<div style='width: 50%; padding: 5px; padding-left: 1em; float: left'>
|
||||
<img src='http://eaw.app/images/VideoInterface_MZ80A_V1_0_3D_Bottom.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
<img src='../images/VideoInterface_MZ80A_V1_0_3D_Bottom.png' height='100%' width='100%' style="margin-left: auto; margin-right: auto; display: block;"/>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
@@ -384,6 +810,17 @@ The table below contains all the sites referenced in the design and programming
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
<div style="padding-left: 10%;">
|
||||
<font size="4">
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
tr td {
|
||||
padding-top: 0em;
|
||||
}
|
||||
tr:nth-child(4) td {
|
||||
padding-top: 0;
|
||||
}
|
||||
</style>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -438,6 +875,17 @@ The table below contains all the datasheets and manuals referenced in the design
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
<div style="padding-left: 10%;">
|
||||
<font size="4">
|
||||
<style>
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
tr td {
|
||||
padding-top: 0em;
|
||||
}
|
||||
tr:nth-child(4) td {
|
||||
padding-top: 0;
|
||||
}
|
||||
</style>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -548,19 +996,43 @@ The table below contains all the datasheets and manuals referenced in the design
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
|
||||
## <font style="color: yellow;" size="5">Demonstration Videos</font>
|
||||
<a name="project-preview" id="project-preview"></a>
|
||||
## <font style="color: yellow;" size="6">Project Preview</font>
|
||||
|
||||
<a href="https://t.co/ZP4T3oisrg">MZ-2000 Demo</a>
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
Development progress on the tran<i>ZPU</i>ter<sup><i>FusionX</i></sup> was shared on X (formerly Twitter) as each milestone was reached. The posts below document key stages from the first hardware bring-up through to running RFS, MZ-700 and MZ-2000 emulation:
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
<a href="https://t.co/6lJoGkNuiP">MZ-700 Demo</a>
|
||||
<a href="https://x.com/engineerswork1/status/1579209688495054849" target="_blank">https://x.com/engineerswork1/status/1579209688495054849</a><br>
|
||||
<a href="https://x.com/engineerswork1/status/1583918702415577089" target="_blank">https://x.com/engineerswork1/status/1583918702415577089</a><br>
|
||||
<a href="https://x.com/engineerswork1/status/1596925535787286528" target="_blank">https://x.com/engineerswork1/status/1596925535787286528</a><br>
|
||||
<a href="https://x.com/engineerswork1/status/1616571495957909510" target="_blank">https://x.com/engineerswork1/status/1616571495957909510</a><br>
|
||||
<a href="https://x.com/engineerswork1/status/1630985022604804109" target="_blank">https://x.com/engineerswork1/status/1630985022604804109</a>
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 1.2em;"></div>
|
||||
<a name="demonstration-videos" id="demonstration-videos"></a>
|
||||
<font style="color: yellow;" size="5">Demonstration Videos</font>
|
||||
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
<font style="color: cyan;" size="4">MZ-80A Demo (includes virtual RFS Board)</font>
|
||||
|
||||
<blockquote class="twitter-tweet" data-dnt="true" data-theme="dark"><p lang="en" dir="ltr"> <a href="https://t.co/3gbEHVzS6X">pic.twitter.com/3gbEHVzS6X</a></p>— engineers@work (@engineerswork1) <a href="https://twitter.com/engineerswork1/status/1625281950897303553?ref_src=twsrc%5Etfw">February 13, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
<font style="color: cyan;" size="4">MZ-2000 Demo</font>
|
||||
|
||||
<blockquote class="twitter-tweet" data-dnt="true" data-theme="dark"><p lang="zxx" dir="ltr"><a href="https://t.co/ZP4T3oisrg">pic.twitter.com/ZP4T3oisrg</a></p>— engineers@work (@engineerswork1) <a href="https://twitter.com/engineerswork1/status/1596925985592864768?ref_src=twsrc%5Etfw">November 27, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
<font style="color: cyan;" size="4">MZ-700 Demo</font>
|
||||
|
||||
<blockquote class="twitter-tweet" data-dnt="true" data-theme="dark"><p lang="en" dir="ltr"> <a href="https://t.co/6lJoGkNuiP">pic.twitter.com/6lJoGkNuiP</a></p>— engineers@work (@engineerswork1) <a href="https://twitter.com/engineerswork1/status/1586864092601630721?ref_src=twsrc%5Etfw">October 30, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
|
||||
--------------------------------------------------------------------------------------------------------
|
||||
|
||||
## <font style="color: yellow;" size="5">Credits</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
The Z80 Emulation used in the <i>FusionX</i> is (c) 1999-2022 Manuel Sainz de Baranda y Goñi, which is licensed under the LGPL v3 license, source can be found in <a href="https://github.com/redcode/Z80">github</a>.
|
||||
The Z80 Emulation used in the <i>FusionX</i> is (c) 1999-2022 Manuel Sainz de Baranda y Goñi, which is licensed under the LGPL v3 license, source can be found in <a href="https://github.com/redcode/Z80">Gitea</a>.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
The SSD202/SOM2D0X build system is based on Linux with extensions by SigmaStar and Industio, licensing can be found in their updated source files.
|
||||
@@ -571,7 +1043,7 @@ The SSD202/SOM2D0X build system is based on Linux with extensions by SigmaStar a
|
||||
## <font style="color: yellow;" size="5">Licenses</font>
|
||||
|
||||
<div style="text-align: justify; line-height: 1.4em; font-size: 0.8em; font-family:sans-serif;">
|
||||
This design, hardware and software (attributable components excluding seperately licensed software) is licensed under the GNU Public Licence v3 and free to use, adapt and modify by individuals, groups and educational institutes.
|
||||
This design, hardware and software (attributable components excluding separately licensed software) is licensed under the GNU Public Licence v3 and free to use, adapt and modify by individuals, groups and educational institutes.
|
||||
<div style="padding-top: 0.8em;"></div>
|
||||
|
||||
No commercial use to be made of this design or any hardware/firmware component without express permission from the author.
|
||||
|
||||
438
build.sh
Executable file
438
build.sh
Executable file
@@ -0,0 +1,438 @@
|
||||
#!/bin/bash
|
||||
#########################################################################################################
|
||||
##
|
||||
## Name: build.sh
|
||||
## Created: March 2026
|
||||
## Author(s): Philip Smart
|
||||
## Description: FusionX global build script
|
||||
## Builds all software components for the FusionX tranZPUter board:
|
||||
## - Z80 assembly ROMs (monitor, MS BASIC, CP/M, TZFS)
|
||||
## - Linux kernel modules (z80drv, ttymzdrv) for each target machine
|
||||
## - User-space applications (sharpbiter, k64fcpu, z80ctrl)
|
||||
## - SPI tools (mspi_main)
|
||||
## - CPLD bitstreams for each target machine (requires Quartus Docker)
|
||||
##
|
||||
## Credits:
|
||||
## Copyright: (c) 2019-2026 Philip Smart <philip.smart@net2net.org>
|
||||
##
|
||||
## History: March 2026 - Initial global build script.
|
||||
##
|
||||
#########################################################################################################
|
||||
## 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/>.
|
||||
#########################################################################################################
|
||||
|
||||
# Root directory of the FusionX project.
|
||||
ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# Directories.
|
||||
SOFTDIR="${ROOT_DIR}/software"
|
||||
ASMDIR="${SOFTDIR}/asm"
|
||||
INCDIR="${ASMDIR}/include"
|
||||
TMPDIR="${SOFTDIR}/tmp"
|
||||
ROMDIR="${SOFTDIR}/roms"
|
||||
TOOLDIR="${SOFTDIR}/tools"
|
||||
CPLDDIR="${ROOT_DIR}/CPLD/v1.0"
|
||||
DRVDIR="${SOFTDIR}/FusionX/src/z80drv"
|
||||
TTYDIR="${SOFTDIR}/FusionX/src/ttymz"
|
||||
SPIDIR="${SOFTDIR}/FusionX/src/spitools"
|
||||
BINDIR="${SOFTDIR}/FusionX/bin"
|
||||
MODDIR="${SOFTDIR}/FusionX/modules"
|
||||
|
||||
# Tools.
|
||||
ASM_JAR="${TOOLDIR}/glass-0.5.1.jar"
|
||||
CROSS_PREFIX="arm-linux-gnueabihf-"
|
||||
|
||||
# Build targets.
|
||||
SOFTWARE_TARGETS="MZ80A MZ700 MZ2000"
|
||||
CPLD_TARGETS="MZ80A MZ700 MZ2000 PCW8256"
|
||||
|
||||
# Assembly build lists.
|
||||
BUILDROMLIST="mz2000_ipl_original mz2000_ipl_tzpu mz2000_ipl_fusionx mz800_1z_013b mz800_9z_504m mz800_iocs mz80afi monitor_sa1510 monitor_80c_sa1510 monitor_1z-013a monitor_80c_1z-013a monitor_1z-013a-km monitor_80c_1z-013a-km mz80b_ipl"
|
||||
BUILDMZFLIST="5z009-1b sa-5510_tzfs msbasic_mz80a msbasic_mz700 msbasic_tz40 msbasic_tz80 sharpmz-test"
|
||||
BUILDTZFSROMLIST="tzfs"
|
||||
BUILDTZFSMZFLIST="testtz"
|
||||
CPMVERSIONS="mz700_80c:0 mz80a_80c:1 mz80a_std:2"
|
||||
|
||||
# Counters for summary.
|
||||
PASS=0
|
||||
FAIL=0
|
||||
SKIP=0
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Helper functions.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
log_info() { echo "==> $*"; }
|
||||
log_ok() { echo " [OK] $*"; PASS=$((PASS + 1)); }
|
||||
log_fail() { echo " [FAIL] $*"; FAIL=$((FAIL + 1)); }
|
||||
log_skip() { echo " [SKIP] $*"; SKIP=$((SKIP + 1)); }
|
||||
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Build all or selected FusionX components."
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --all Build everything (default)"
|
||||
echo " --asm Build Z80 assembly ROMs only"
|
||||
echo " --tzfs Build TZFS ROM only"
|
||||
echo " --cpm Build CP/M only"
|
||||
echo " --drivers Build kernel modules and user-space apps only"
|
||||
echo " --spi Build SPI tools only"
|
||||
echo " --cpld Build CPLD bitstreams only (requires Quartus Docker)"
|
||||
echo " --clean Clean all build artifacts"
|
||||
echo " --help Show this help"
|
||||
echo ""
|
||||
echo "Software targets: ${SOFTWARE_TARGETS}"
|
||||
echo "CPLD targets: ${CPLD_TARGETS}"
|
||||
exit 0
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Build Z80 Assembly ROMs and MZF files.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
build_asm_roms() {
|
||||
log_info "Building Z80 Assembly ROMs and MZF files..."
|
||||
|
||||
if ! command -v java &>/dev/null; then
|
||||
log_skip "Java not found - cannot assemble Z80 ROMs"
|
||||
return
|
||||
fi
|
||||
if [ ! -f "${ASM_JAR}" ]; then
|
||||
log_skip "GLASS assembler not found at ${ASM_JAR}"
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "${TMPDIR}" "${ROMDIR}"
|
||||
|
||||
for f in ${BUILDROMLIST} ${BUILDMZFLIST}; do
|
||||
SRCNAME="${f}"
|
||||
ASMNAME="${f}.asm"
|
||||
OBJNAME="${f}.obj"
|
||||
SYMNAME="${f}.sym"
|
||||
ROMNAME="${f}.rom"
|
||||
MZFNAME="${f}.mzf"
|
||||
|
||||
# MS BASIC variant handling.
|
||||
case "${SRCNAME}" in
|
||||
msbasic_mz80a)
|
||||
ASMNAME="msbasic.asm"
|
||||
echo "BUILD_VERSION EQU 0" > "${INCDIR}/MSBASIC_BuildVersion.asm"
|
||||
;;
|
||||
msbasic_mz700)
|
||||
ASMNAME="msbasic.asm"
|
||||
echo "BUILD_VERSION EQU 1" > "${INCDIR}/MSBASIC_BuildVersion.asm"
|
||||
;;
|
||||
msbasic_tz40)
|
||||
ASMNAME="msbasic.asm"
|
||||
echo "BUILD_VERSION EQU 2" > "${INCDIR}/MSBASIC_BuildVersion.asm"
|
||||
;;
|
||||
msbasic_tz80)
|
||||
ASMNAME="msbasic.asm"
|
||||
echo "BUILD_VERSION EQU 3" > "${INCDIR}/MSBASIC_BuildVersion.asm"
|
||||
;;
|
||||
esac
|
||||
|
||||
if java -jar "${ASM_JAR}" "${ASMDIR}/${ASMNAME}" "${TMPDIR}/${OBJNAME}" "${TMPDIR}/${SYMNAME}" -I "${INCDIR}" -I "${ASMDIR}" 2>&1; then
|
||||
if echo "${BUILDROMLIST}" | grep -qw "${SRCNAME}"; then
|
||||
cp "${TMPDIR}/${OBJNAME}" "${ROMDIR}/${ROMNAME}"
|
||||
log_ok "ROM: ${ROMNAME}"
|
||||
else
|
||||
cp "${TMPDIR}/${OBJNAME}" "${ROMDIR}/${MZFNAME}"
|
||||
log_ok "MZF: ${MZFNAME}"
|
||||
fi
|
||||
else
|
||||
log_fail "${SRCNAME}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Composite MZ-800 ROM.
|
||||
if [ -f "${ROMDIR}/mz800_1z_013b.rom" ] && [ -f "${ROMDIR}/mz800_cgrom.ori" ] && \
|
||||
[ -f "${ROMDIR}/mz800_9z_504m.rom" ] && [ -f "${ROMDIR}/mz800_iocs.rom" ]; then
|
||||
cat "${ROMDIR}/mz800_1z_013b.rom" "${ROMDIR}/mz800_cgrom.ori" \
|
||||
"${ROMDIR}/mz800_9z_504m.rom" "${ROMDIR}/mz800_iocs.rom" > "${ROMDIR}/mz800_ipl.rom"
|
||||
log_ok "ROM: mz800_ipl.rom (composite)"
|
||||
fi
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Build TZFS ROM for each machine+board combination.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
build_tzfs() {
|
||||
log_info "Building TZFS ROMs..."
|
||||
|
||||
if ! command -v java &>/dev/null; then
|
||||
log_skip "Java not found - cannot assemble TZFS"
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "${TMPDIR}" "${ROMDIR}"
|
||||
|
||||
local DEFSFILE="${INCDIR}/tzfs_definitions.asm"
|
||||
local MACHINES="MZ80A MZ700 MZ2000"
|
||||
|
||||
for machine in ${MACHINES}; do
|
||||
# Set machine target in definitions.
|
||||
for m in MZ80A MZ700 MZ1500 MZ2000; do
|
||||
local val=0
|
||||
[ "${m}" = "${machine}" ] && val=1
|
||||
sed -i "s/^BUILD_${m}\s\+EQU\s\+[01]/BUILD_${m} EQU ${val}/" "${DEFSFILE}"
|
||||
done
|
||||
|
||||
# Set board to FusionX.
|
||||
sed -i "s/^BUILD_FUSIONX\s\+EQU\s\+[01]/BUILD_FUSIONX EQU 1/" "${DEFSFILE}"
|
||||
sed -i "s/^BUILD_PICOZ80\s\+EQU\s\+[01]/BUILD_PICOZ80 EQU 0/" "${DEFSFILE}"
|
||||
|
||||
for f in ${BUILDTZFSROMLIST} ${BUILDTZFSMZFLIST}; do
|
||||
if java -jar "${ASM_JAR}" "${ASMDIR}/${f}.asm" "${TMPDIR}/${f}.obj" "${TMPDIR}/${f}.sym" -I "${INCDIR}" -I "${ASMDIR}" 2>&1; then
|
||||
local lower_machine=$(echo "${machine}" | tr '[:upper:]' '[:lower:]')
|
||||
if echo "${BUILDTZFSROMLIST}" | grep -qw "${f}"; then
|
||||
cp "${TMPDIR}/${f}.obj" "${ROMDIR}/${f}_${lower_machine}_fusionx.rom"
|
||||
log_ok "TZFS ROM: ${f}_${lower_machine}_fusionx.rom"
|
||||
else
|
||||
cp "${TMPDIR}/${f}.obj" "${ROMDIR}/${f}_${lower_machine}_fusionx.mzf"
|
||||
log_ok "TZFS MZF: ${f}_${lower_machine}_fusionx.mzf"
|
||||
fi
|
||||
else
|
||||
log_fail "TZFS: ${f} (${machine})"
|
||||
fi
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Build CP/M for each version.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
build_cpm() {
|
||||
log_info "Building CP/M variants..."
|
||||
|
||||
if ! command -v java &>/dev/null; then
|
||||
log_skip "Java not found - cannot assemble CP/M"
|
||||
return
|
||||
fi
|
||||
|
||||
mkdir -p "${TMPDIR}" "${ROMDIR}"
|
||||
|
||||
for ver in ${CPMVERSIONS}; do
|
||||
local FILEEXT=$(echo "${ver}" | cut -d: -f1)
|
||||
local BUILDVER=$(echo "${ver}" | cut -d: -f2)
|
||||
echo "BUILD_VERSION EQU ${BUILDVER}" > "${INCDIR}/cpm_buildversion.asm"
|
||||
|
||||
local all_ok=true
|
||||
for f in cbios cpm22; do
|
||||
if java -jar "${ASM_JAR}" "${ASMDIR}/${f}.asm" "${TMPDIR}/${f}.obj" "${TMPDIR}/${f}.sym" -I "${INCDIR}" -I "${ASMDIR}" 2>&1; then
|
||||
cp "${TMPDIR}/${f}.obj" "${ROMDIR}/${f}.bin"
|
||||
else
|
||||
log_fail "CP/M: ${f} (${FILEEXT})"
|
||||
all_ok=false
|
||||
fi
|
||||
done
|
||||
|
||||
if ${all_ok}; then
|
||||
cat "${ROMDIR}/cpm22.bin" "${ROMDIR}/cbios.bin" > "${ROMDIR}/cpm223_${FILEEXT}.bin"
|
||||
log_ok "CP/M: cpm223_${FILEEXT}.bin"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Build kernel modules and user-space applications for each target machine.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
build_drivers() {
|
||||
log_info "Building kernel modules and user-space applications..."
|
||||
|
||||
if ! command -v ${CROSS_PREFIX}gcc &>/dev/null; then
|
||||
log_skip "ARM cross-compiler (${CROSS_PREFIX}gcc) not found"
|
||||
return
|
||||
fi
|
||||
|
||||
local KERNEL_DIR="${SOFTDIR}/linux/kernel"
|
||||
if [ ! -f "${KERNEL_DIR}/Makefile" ]; then
|
||||
log_skip "Kernel source tree not found at ${KERNEL_DIR}"
|
||||
return
|
||||
fi
|
||||
|
||||
for target in ${SOFTWARE_TARGETS}; do
|
||||
log_info " Target: ${target}"
|
||||
|
||||
# Build z80drv kernel module + user-space tools.
|
||||
# Must cd into directory because Makefile uses $(PWD) for kernel path.
|
||||
if [ -f "${DRVDIR}/Makefile" ]; then
|
||||
if (cd "${DRVDIR}" && make "${target}" 2>&1); then
|
||||
(cd "${DRVDIR}" && make install 2>&1) || true
|
||||
log_ok "z80drv + apps (${target})"
|
||||
else
|
||||
log_fail "z80drv (${target})"
|
||||
fi
|
||||
(cd "${DRVDIR}" && make clean 2>&1) || true
|
||||
fi
|
||||
|
||||
# Build ttymzdrv kernel module.
|
||||
if [ -f "${TTYDIR}/Makefile" ]; then
|
||||
if (cd "${TTYDIR}" && make "${target}" 2>&1); then
|
||||
(cd "${TTYDIR}" && make install 2>&1) || true
|
||||
log_ok "ttymzdrv (${target})"
|
||||
else
|
||||
log_fail "ttymzdrv (${target})"
|
||||
fi
|
||||
(cd "${TTYDIR}" && make clean 2>&1) || true
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Build SPI tools.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
build_spi() {
|
||||
log_info "Building SPI tools..."
|
||||
|
||||
if ! command -v ${CROSS_PREFIX}gcc &>/dev/null; then
|
||||
log_skip "ARM cross-compiler (${CROSS_PREFIX}gcc) not found"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -f "${SPIDIR}/Makefile" ]; then
|
||||
if (cd "${SPIDIR}" && make all 2>&1); then
|
||||
log_ok "SPI tools (mspi_main)"
|
||||
else
|
||||
log_fail "SPI tools"
|
||||
fi
|
||||
else
|
||||
log_skip "SPI tools Makefile not found"
|
||||
fi
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Build CPLD bitstreams for each target machine.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
build_cpld() {
|
||||
log_info "Building CPLD bitstreams..."
|
||||
|
||||
if ! command -v quartus_sh &>/dev/null; then
|
||||
log_skip "Quartus not found in PATH (use Quartus Docker: qp130)"
|
||||
return
|
||||
fi
|
||||
|
||||
for target in ${CPLD_TARGETS}; do
|
||||
local BUILDDIR="${CPLDDIR}/${target}/build"
|
||||
local PROJECT="tzpuFusionX_${target}"
|
||||
|
||||
if [ ! -f "${BUILDDIR}/${PROJECT}.qpf" ]; then
|
||||
log_skip "CPLD: No Quartus project for ${target}"
|
||||
continue
|
||||
fi
|
||||
|
||||
log_info " Compiling CPLD: ${target}"
|
||||
if (cd "${BUILDDIR}" && quartus_sh --flow compile "${PROJECT}" 2>&1); then
|
||||
if [ -f "${BUILDDIR}/output_files/${PROJECT}.pof" ]; then
|
||||
log_ok "CPLD: ${PROJECT}.pof"
|
||||
else
|
||||
log_fail "CPLD: ${target} (no .pof output)"
|
||||
fi
|
||||
else
|
||||
log_fail "CPLD: ${target}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Clean all build artifacts.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
do_clean() {
|
||||
log_info "Cleaning build artifacts..."
|
||||
|
||||
# Assembly temporaries.
|
||||
rm -f "${TMPDIR}"/*.obj "${TMPDIR}"/*.sym 2>/dev/null
|
||||
|
||||
# Driver build artifacts.
|
||||
if [ -f "${DRVDIR}/Makefile" ]; then
|
||||
(cd "${DRVDIR}" && make clean 2>/dev/null) || true
|
||||
fi
|
||||
if [ -f "${TTYDIR}/Makefile" ]; then
|
||||
(cd "${TTYDIR}" && make clean 2>/dev/null) || true
|
||||
fi
|
||||
if [ -f "${SPIDIR}/Makefile" ]; then
|
||||
(cd "${SPIDIR}" && make clean 2>/dev/null) || true
|
||||
fi
|
||||
|
||||
log_ok "Clean complete"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
# Main.
|
||||
#-------------------------------------------------------------------------------------------------------
|
||||
|
||||
BUILD_ASM=false
|
||||
BUILD_TZFS=false
|
||||
BUILD_CPM=false
|
||||
BUILD_DRIVERS=false
|
||||
BUILD_SPI=false
|
||||
BUILD_CPLD=false
|
||||
BUILD_ALL=false
|
||||
DO_CLEAN=false
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
BUILD_ALL=true
|
||||
fi
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--all) BUILD_ALL=true ;;
|
||||
--asm) BUILD_ASM=true ;;
|
||||
--tzfs) BUILD_TZFS=true ;;
|
||||
--cpm) BUILD_CPM=true ;;
|
||||
--drivers) BUILD_DRIVERS=true ;;
|
||||
--spi) BUILD_SPI=true ;;
|
||||
--cpld) BUILD_CPLD=true ;;
|
||||
--clean) DO_CLEAN=true ;;
|
||||
--help|-h) usage ;;
|
||||
*) echo "Unknown option: $1"; usage ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
echo "========================================"
|
||||
echo " FusionX Build System"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
if ${DO_CLEAN}; then
|
||||
do_clean
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ${BUILD_ALL} || ${BUILD_ASM}; then build_asm_roms; fi
|
||||
if ${BUILD_ALL} || ${BUILD_TZFS}; then build_tzfs; fi
|
||||
if ${BUILD_ALL} || ${BUILD_CPM}; then build_cpm; fi
|
||||
if ${BUILD_ALL} || ${BUILD_DRIVERS}; then build_drivers; fi
|
||||
if ${BUILD_ALL} || ${BUILD_SPI}; then build_spi; fi
|
||||
if ${BUILD_ALL} || ${BUILD_CPLD}; then build_cpld; fi
|
||||
|
||||
echo ""
|
||||
echo "========================================"
|
||||
echo " Build Summary"
|
||||
echo " Passed: ${PASS} Failed: ${FAIL} Skipped: ${SKIP}"
|
||||
echo "========================================"
|
||||
|
||||
if [ ${FAIL} -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
exit 0
|
||||
BIN
software/FusionX/bin/k64fcpu
vendored
Executable file
BIN
software/FusionX/bin/k64fcpu
vendored
Executable file
Binary file not shown.
BIN
software/FusionX/bin/sharpbiter
vendored
Executable file
BIN
software/FusionX/bin/sharpbiter
vendored
Executable file
Binary file not shown.
BIN
software/FusionX/bin/z80ctrl
vendored
BIN
software/FusionX/bin/z80ctrl
vendored
Binary file not shown.
54
software/FusionX/etc/startZ80_RFS.sh
Executable file
54
software/FusionX/etc/startZ80_RFS.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
|
||||
FUSIONXDIR=/apps/FusionX
|
||||
|
||||
# Setup screen width, used to load correct RFS ROM images.
|
||||
SCREENWIDTH=40
|
||||
if [[ "$#" -ne 0 ]]; then
|
||||
if [[ "$1" -eq 80 ]]; then
|
||||
SCREENWIDTH=80
|
||||
fi
|
||||
fi
|
||||
echo "Screen width set to: ${SCREENWIDTH}"
|
||||
|
||||
# Detach CPU 1 from scheduler and IRQ's as it will be dedicated to the z80drv.
|
||||
for f in `ps -eaf |grep -v kthread_z80 | awk '{print $1}'`
|
||||
do
|
||||
taskset -pc 0 $f >/dev/null 2>/dev/null
|
||||
done
|
||||
|
||||
# Detach IRQ's
|
||||
for I in $(ls /proc/irq)
|
||||
do
|
||||
if [[ -d "/proc/irq/$I" ]]
|
||||
then
|
||||
echo 0 > /proc/irq/$I/smp_affinity_list 2>/dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
# Load the Z80 driver. Small pause to ensure the driver is fully loaded and initialsed prior to loading ROM images.
|
||||
cd ${FUSIONXDIR}/modules
|
||||
rmmod z80drv 2>/dev/null
|
||||
insmod z80drv.ko
|
||||
sleep 1
|
||||
|
||||
# Add the RFS Virtual Hardware to the driver.
|
||||
${FUSIONXDIR}/bin/z80ctrl --adddev --device rfs
|
||||
|
||||
# Load the original RFS ROM images. These are loaded by the RFS driver but here for reference or to load alternate. If
|
||||
# alternate roms are loaded then ensure they are loaded prior to the start command below.
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/MROM_256_${SCREENWIDTH}c.bin --addr 0x000000 --type 1
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_256_${SCREENWIDTH}c.bin --addr 0x80000 --type 1
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_II_256_${SCREENWIDTH}c.bin --addr 0x100000 --type 1
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/rom/USER_ROM_III_256_${SCREENWIDTH}c.bin --addr 0x180000 --type 1
|
||||
|
||||
# Start the Z80 (ie. MZ-80A virtual processor).
|
||||
${FUSIONXDIR/bin/z80ctrl --start
|
||||
|
||||
# Ensure the system is set for performance mode with max frequency.
|
||||
# NB: Enabling this prior to starting the Z80 results in a kernel error.
|
||||
echo performance > /sys/devices//system/cpu/cpufreq/policy0/scaling_governor
|
||||
echo 1200000 > /sys/devices//system/cpu/cpufreq/policy0/scaling_min_freq
|
||||
|
||||
# Done.
|
||||
echo "FusionX loaded and configured in RFS mode."
|
||||
54
software/FusionX/etc/startZ80_TZFS.sh
Executable file
54
software/FusionX/etc/startZ80_TZFS.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/sh
|
||||
|
||||
FUSIONXDIR=/apps/FusionX
|
||||
|
||||
# Setup screen width, used to load correct Monitor ROM image.
|
||||
SCREENWIDTH=40
|
||||
if [[ "$#" -ne 0 ]]; then
|
||||
if [[ "$1" -eq 80 ]]; then
|
||||
SCREENWIDTH=80
|
||||
fi
|
||||
fi
|
||||
echo "Screen width set to: ${SCREENWIDTH}"
|
||||
|
||||
# Detach CPU 1 from scheduler and IRQ's as it will be dedicated to the z80drv.
|
||||
for f in `ps -eaf |grep -v kthread_z80 | awk '{print $1}'`
|
||||
do
|
||||
taskset -pc 0 $f >/dev/null 2>/dev/null
|
||||
done
|
||||
|
||||
# Detach IRQ's
|
||||
for I in $(ls /proc/irq)
|
||||
do
|
||||
if [[ -d "/proc/irq/$I" ]]
|
||||
then
|
||||
echo 0 > /proc/irq/$I/smp_affinity_list 2>/dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
# Load the Z80 driver. Small pause to ensure the driver is fully loaded and initialsed prior to loading ROM images.
|
||||
cd ${FUSIONXDIR}/modules
|
||||
rmmod z80drv 2>/dev/null
|
||||
insmod z80drv.ko
|
||||
sleep 1
|
||||
|
||||
# Add the TZPU Virtual Hardware to the driver.
|
||||
${FUSIONXDIR}/bin/z80ctrl --adddev --device tzpu
|
||||
|
||||
# Start the K64F Virtual CPU Emulation.
|
||||
${FUSIONXDIR}/bin/k64fcpu &
|
||||
|
||||
# Load the original Monitor and TZFS ROM images. This is done in the K64F daemon but can be manually enabled.
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/monitor_${SCREENWIDTH}c_sa1510.rom --addr 0x000000 --type 1
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/tzfs.rom --offset 0x000000 --len 0x001800 --addr 0x00E800 --type 1
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/tzfs.rom --offset 0x001800 --len 0x001000 --addr 0x01F000 --type 1
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/tzfs.rom --offset 0x002800 --len 0x001000 --addr 0x02F000 --type 1
|
||||
#${FUSIONXDIR}/bin/z80ctrl --loadrom --file ${FUSIONXDIR}/roms/tzfs.rom --offset 0x003800 --len 0x001000 --addr 0x03F000 --type 1
|
||||
|
||||
# Ensure the system is set for performance mode with max frequency.
|
||||
# NB: Enabling this prior to starting the Z80 results in a kernel error.
|
||||
echo performance > /sys/devices//system/cpu/cpufreq/policy0/scaling_governor
|
||||
echo 1200000 > /sys/devices//system/cpu/cpufreq/policy0/scaling_min_freq
|
||||
|
||||
# Done.
|
||||
echo "FusionX loaded and configured in TZFS mode."
|
||||
@@ -1,8 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd /customer
|
||||
./cpuset.sh
|
||||
FUSIONXDIR=/apps/FusionX
|
||||
|
||||
cd ${FUSIONXDIR}/modules
|
||||
${FUSIONXDIR/etc/cpuset.sh
|
||||
rmmod z80drv 2>/dev/null
|
||||
insmod z80drv.ko
|
||||
#echo performance > /sys/devices//system/cpu/cpufreq/policy0/scaling_governor
|
||||
#drvid=`ps -eaf | grep kthread_z80 | grep -v grep | awk '{print $1}'`
|
||||
#taskset -pc 1 $drvid
|
||||
|
||||
BIN
software/FusionX/modules/ttymzdrv.ko
vendored
Normal file
BIN
software/FusionX/modules/ttymzdrv.ko
vendored
Normal file
Binary file not shown.
BIN
software/FusionX/modules/z80drv.ko
vendored
BIN
software/FusionX/modules/z80drv.ko
vendored
Binary file not shown.
File diff suppressed because it is too large
Load Diff
326
software/FusionX/src/driver/MZ2000/z80driver.h
vendored
326
software/FusionX/src/driver/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
|
||||
403
software/FusionX/src/driver/MZ700/optparse.h
vendored
403
software/FusionX/src/driver/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/driver/MZ700/z80driver.h
vendored
284
software/FusionX/src/driver/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,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/driver/MZ700/z80menu.h
vendored
44
software/FusionX/src/driver/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
|
||||
32
software/FusionX/src/driver/Makefile
vendored
32
software/FusionX/src/driver/Makefile
vendored
@@ -1,32 +0,0 @@
|
||||
MODEL := MZ2000
|
||||
#MODEL := MZ700
|
||||
#MODEL := MZ80A
|
||||
KERNEL := $(PWD)/../../../linux/kernel
|
||||
FUSIONX := $(PWD)/../..
|
||||
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
|
||||
CTRLINC += -IZeta/API -IZ80/API
|
||||
|
||||
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 += ../../../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_pinmux.o
|
||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables.o
|
||||
|
||||
|
||||
all:
|
||||
@echo "Build driver for host: $(MODEL)"
|
||||
@echo ""
|
||||
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/z80ctrl.c -o z80ctrl
|
||||
|
||||
install:
|
||||
@echo "Copy kernel driver..."
|
||||
@cp z80drv.ko $(FUSIONX)/modules/
|
||||
@echo "Copy z80ctrl app..."
|
||||
@cp z80ctrl $(FUSIONX)/bin/
|
||||
|
||||
clean:
|
||||
make -C $(KERNEL) M=$(PWD) clean
|
||||
|
||||
1
software/FusionX/src/driver/Z80
vendored
1
software/FusionX/src/driver/Z80
vendored
Submodule software/FusionX/src/driver/Z80 deleted from 75d01a9cca
66
software/FusionX/src/ttymz/Makefile
vendored
Normal file
66
software/FusionX/src/ttymz/Makefile
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
# Select the target host.
|
||||
#MODEL := MZ2000
|
||||
#MODEL := MZ1500
|
||||
#MODEL := MZ700
|
||||
#MODEL := MZ80A
|
||||
#MODEL := PCW8XXX
|
||||
#MODEL := PCW9XXX
|
||||
KERNEL := $(PWD)/../../../linux/kernel
|
||||
FUSIONX := $(PWD)/../..
|
||||
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)
|
||||
ccflags-y += -DTTYMZ_DEBUG
|
||||
endif
|
||||
obj-m += ttymzdrv.o
|
||||
ttymzdrv-objs += ttymz.o z80io.o sharpmz.o
|
||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/gpio_table.o
|
||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_gpio.o
|
||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables.o
|
||||
|
||||
all:
|
||||
@echo "Specify target host, ie. make <host>"
|
||||
@echo "Supported hosts: MZ80A, MZ700, MZ2000, PCW8XXX, PCW9XXX"
|
||||
|
||||
MZ80A: MODEL_MZ80A
|
||||
MZ700: MODEL_MZ700
|
||||
MZ1500: MODEL_MZ1500
|
||||
MZ2000: MODEL_MZ2000
|
||||
PCW8XXX: MODEL_PCW8XXX
|
||||
PCW9XXX: MODEL_PCW9XXX
|
||||
|
||||
MODEL_MZ80A:
|
||||
$(MAKE) MODEL=MZ80A BUILD_MZ80A
|
||||
MODEL_MZ700:
|
||||
$(MAKE) MODEL=MZ700 BUILD_MZ700
|
||||
MODEL_MZ1500:
|
||||
$(MAKE) MODEL=MZ1500 BUILD_MZ1500
|
||||
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_MZ1500: kmod
|
||||
BUILD_MZ2000: kmod
|
||||
BUILD_PCW8XXX: kmod
|
||||
BUILD_PCW9XXX: kmod
|
||||
|
||||
kmod:
|
||||
@echo ""
|
||||
@echo "Build TTYMZ driver for host: $(MODEL)"
|
||||
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
||||
|
||||
install:
|
||||
@echo "Copy kernel driver..."
|
||||
@cp ttymzdrv.ko $(FUSIONX)/modules/
|
||||
|
||||
clean:
|
||||
make -C $(KERNEL) M=$(PWD) clean
|
||||
@rm -f ttymz
|
||||
4670
software/FusionX/src/ttymz/sharpmz.c
Normal file
4670
software/FusionX/src/ttymz/sharpmz.c
Normal file
File diff suppressed because it is too large
Load Diff
592
software/FusionX/src/ttymz/sharpmz.h
vendored
Executable file
592
software/FusionX/src/ttymz/sharpmz.h
vendored
Executable file
@@ -0,0 +1,592 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: sharpmz.c
|
||||
// Created: February 2023
|
||||
// Version: v1.0
|
||||
// Author(s): Philip Smart
|
||||
// Description: Sharp MZ Interface Library.
|
||||
// This file contains methods which allow the Linux TTY driver to access and control the
|
||||
// Sharp MZ series computer hardware.
|
||||
//
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: v1.0 Feb 2023 - Initial write of the Sharp MZ series hardware interface software.
|
||||
// v1.01 Mar 2023 - Bug fixes and additional ESC sequence processing.
|
||||
// v1.02 May 2023 - Updates to accommodate MZ-1500 host.
|
||||
// v1.2 Jul 2023 - Fixed MZ-1500 ATB Display of lower case characters.
|
||||
//
|
||||
// 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 SHARPMZ_H
|
||||
#define SHARPMZ_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Build time target. Overrides if compile time definition given.
|
||||
#if defined(TARGET_HOST_MZ80A)
|
||||
#define TARGET_HOST_MZ80A 1
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ1500 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ700)
|
||||
#define TARGET_HOST_MZ700 1
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_MZ1500 0
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ1500)
|
||||
#define TARGET_HOST_MZ1500 1
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ2000)
|
||||
#define TARGET_HOST_MZ2000 1
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ1500 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_PCW8XXX) || defined(TARGET_HOST_PCW9XXX)
|
||||
#define TARGET_HOST_PCW 1
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ1500 0
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#else
|
||||
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
||||
#define TARGET_HOST_MZ80A 0 // MZ80A
|
||||
#define TARGET_HOST_MZ1500 0 // MZ1500
|
||||
#define TARGET_HOST_MZ2000 0 // MZ2000
|
||||
#define TARGET_HOST_PCW 0 // Amstrad PCW8XXX/9XXX
|
||||
#endif
|
||||
|
||||
// Video display constants.
|
||||
#define VC_MAX_ROWS 25 // Maximum number of rows on display.
|
||||
#if (TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
|
||||
#define VC_MAX_COLUMNS 40 // Maximum number of columns on display.
|
||||
#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.
|
||||
#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_FLASH_TIME 350 // Time in milliseconds for the cursor flash change.
|
||||
#define MAX_KEYB_BUFFER_SIZE 32 // Maximum size of the keyboard buffer.
|
||||
#if (TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
|
||||
#define KEY_SCAN_ROWS 10 // Number of rows on keyboard to scan.
|
||||
#define CURSOR_CHR_THICK_BLOCK 0x43 // Thick block cursor for Shift Lock.
|
||||
#define CURSOR_CHR_BLOCK 0xD0 // Block cursor for CAPS Lock.
|
||||
#define CURSOR_CHR_GRAPH 0xFF // Graphic cursor for GRAPH mode.
|
||||
#define CURSOR_CHR_UNDERLINE 0x3C // Underline for lower case CAPS OFF.
|
||||
#elif (TARGET_HOST_MZ2000 == 1)
|
||||
#define KEY_SCAN_ROWS 12
|
||||
#define CURSOR_CHR_THICK_BLOCK 0x1E // Thick block cursor for Shift Lock.
|
||||
#define CURSOR_CHR_BLOCK 0x82 // Block cursor for CAPS Lock.
|
||||
#define CURSOR_CHR_GRAPH 0x93 // Graphic cursor for GRAPH mode.
|
||||
#define CURSOR_CHR_UNDERLINE 0x1F // Underline for lower case CAPS OFF.
|
||||
#endif
|
||||
|
||||
// Audio constants.
|
||||
#define TIMER_8253_MZ80A_FREQ 2000000 // 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.
|
||||
#define TIMER_8253_MZ1500_FREQ 768000 // Base input frequency of Timer 0 for square wave generation.
|
||||
|
||||
// Base addresses and sizes within 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_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_SIZE 0x800 // Size of the attribute RAM.
|
||||
|
||||
// Video Module control bits.
|
||||
#define VMMODE_MASK 0xF8 // Mask to mask out video mode.
|
||||
#define VMMODE_MZ80K 0x00 // Video mode = MZ80K
|
||||
#define VMMODE_MZ80C 0x01 // Video mode = MZ80C
|
||||
#define VMMODE_MZ1200 0x02 // Video mode = MZ1200
|
||||
#define VMMODE_MZ80A 0x03 // Video mode = MZ80A
|
||||
#define VMMODE_MZ700 0x04 // Video mode = MZ700
|
||||
#define VMMODE_MZ800 0x05 // Video mode = MZ800
|
||||
#define VMMODE_MZ1500 0x06 // Video mode = MZ1500
|
||||
#define VMMODE_MZ80B 0x07 // Video mode = MZ80B
|
||||
#define VMMODE_MZ2000 0x08 // Video mode = MZ2000
|
||||
#define VMMODE_MZ2200 0x09 // Video mode = MZ2200
|
||||
#define VMMODE_MZ2500 0x0A // Video mode = MZ2500
|
||||
#define VMMODE_80CHAR 0x80 // Enable 80 character display.
|
||||
#define VMMODE_80CHAR_MASK 0x7F // Mask to filter out display width control bit.
|
||||
#define VMMODE_COLOUR 0x20 // Enable colour display.
|
||||
#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit.
|
||||
|
||||
// Sharp MZ colour attributes.
|
||||
#define VMATTR_FG_BLACK 0x00 // Foreground black character attribute.
|
||||
#define VMATTR_FG_BLUE 0x10 // Foreground blue character attribute.
|
||||
#define VMATTR_FG_RED 0x20 // Foreground red character attribute.
|
||||
#define VMATTR_FG_PURPLE 0x30 // Foreground purple character attribute.
|
||||
#define VMATTR_FG_GREEN 0x40 // Foreground green character attribute.
|
||||
#define VMATTR_FG_CYAN 0x50 // Foreground cyan character attribute.
|
||||
#define VMATTR_FG_YELLOW 0x60 // Foreground yellow 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_MASKIN 0x70 // Mask to filter out foreground attribute.
|
||||
#define VMATTR_BG_BLACK 0x00 // Background black character attribute.
|
||||
#define VMATTR_BG_BLUE 0x01 // Background blue character attribute.
|
||||
#define VMATTR_BG_RED 0x02 // Background red character attribute.
|
||||
#define VMATTR_BG_PURPLE 0x03 // Background purple character attribute.
|
||||
#define VMATTR_BG_GREEN 0x04 // Background green character attribute.
|
||||
#define VMATTR_BG_CYAN 0x05 // Background cyan character attribute.
|
||||
#define VMATTR_BG_YELLOW 0x06 // Background yellow 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_MASKIN 0x07 // Mask to filter out background attribute.
|
||||
|
||||
// Sharp MZ-80A/700 constants.
|
||||
//
|
||||
#define MBADDR_KEYPA 0xE000 // Mainboard 8255 Port A
|
||||
#define MBADDR_KEYPB 0xE001 // Mainboard 8255 Port B
|
||||
#define MBADDR_KEYPC 0xE002 // Mainboard 8255 Port C
|
||||
#define MBADDR_KEYPF 0xE003 // Mainboard 8255 Mode Control
|
||||
#define MBADDR_CSTR 0xE002 // Mainboard 8255 Port C
|
||||
#define MBADDR_CSTPT 0xE003 // Mainboard 8255 Mode Control
|
||||
#define MBADDR_CONT0 0xE004 // Mainboard 8253 Counter 0
|
||||
#define MBADDR_CONT1 0xE005 // Mainboard 8253 Counter 1
|
||||
#define MBADDR_CONT2 0xE006 // Mainboard 8253 Counter 1
|
||||
#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_TEMP 0xE008 // As above, different name used in original source when writing.
|
||||
#define MBADDR_MEMSW 0xE00C // Memory swap, 0000->C000, C000->0000
|
||||
#define MBADDR_MEMSWR 0xE010 // Reset memory swap.
|
||||
#define MBADDR_NRMDSP 0xE014 // Return display to normal.
|
||||
#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_SCLBASE 0xE2 // High byte scroll base.
|
||||
#define MBADDR_DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||
#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_PSG_BOTH 0xE9
|
||||
#define IO_ADDR_EA 0xEA
|
||||
#define IO_ADDR_EB 0xEB
|
||||
#define IO_PCG_PRIO 0xF0
|
||||
#define IO_PALETTE 0xF1
|
||||
|
||||
// Sharp MZ-2000 constants.
|
||||
#define MBADDR_FDC 0x0D8 // MB8866 IO Region 0D8h - 0DBh
|
||||
#define MBADDR_FDC_CR MBADDR_FDC + 0x00 // Command Register
|
||||
#define MBADDR_FDC_STR MBADDR_FDC + 0x00 // Status Register
|
||||
#define MBADDR_FDC_TR MBADDR_FDC + 0x01 // Track Register
|
||||
#define MBADDR_FDC_SCR MBADDR_FDC + 0x02 // Sector Register
|
||||
#define MBADDR_FDC_DR MBADDR_FDC + 0x03 // Data Register
|
||||
#define MBADDR_FDC_MOTOR MBADDR_FDC + 0x04 // DS[0-3] and Motor control. 4 drives DS= BIT 0 -> Bit 2 = Drive number, 2=1,1=0,0=0 DS0, 2=1,1=0,0=1 DS1 etc
|
||||
// bit 7 = 1 MOTOR ON LOW (Active)
|
||||
#define MBADDR_FDC_SIDE MBADDR_FDC + 0x05 // Side select, Bit 0 when set = SIDE SELECT LOW,
|
||||
#define MBADDR_FDC_DDEN MBADDR_FDC + 0x06 // Double density enable, 0 = double density, 1 = single density disks.
|
||||
#define MBADDR_PPIA 0x0E0 // 8255 Port A
|
||||
#define MBADDR_PPIB 0x0E1 // 8255 Port B
|
||||
#define MBADDR_PPIC 0x0E2 // 8255 Port C
|
||||
#define MBADDR_PPICTL 0x0E3 // 8255 Control Port
|
||||
#define MBADDR_PIOA 0x0E8 // Z80 PIO Port A
|
||||
#define MBADDR_PIOCTLA 0x0E9 // Z80 PIO Port A Control Port
|
||||
#define MBADDR_PIOB 0x0EA // Z80 PIO Port B
|
||||
#define MBADDR_PIOCTLB 0x0EB // Z80 PIO Port B Control Port
|
||||
#define MBADDR_CRTBKCOLR 0x0F4 // Configure external CRT background colour.
|
||||
#define MBADDR_CRTGRPHPRIO 0x0F5 // Graphics priority register, character or a graphics colour has front display priority.
|
||||
#define MBADDR_CRTGRPHSEL 0x0F6 // Graphics output select on CRT or external CRT
|
||||
#define MBADDR_GRAMCOLRSEL 0x0F7 // Graphics RAM colour bank select.
|
||||
#define MBADDR_GRAMADDRL 0x0C000 // Graphics RAM base address.
|
||||
|
||||
//Common character definitions.
|
||||
#define SCROLL 0x01 // Set scroll direction UP.
|
||||
#define BELL 0x07
|
||||
#define ENQ 0x05
|
||||
#define SPACE 0x20
|
||||
#define TAB 0x09 // TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||
#define CR 0x0D
|
||||
#define LF 0x0A
|
||||
#define FF 0x0C
|
||||
#define DELETE 0x7F
|
||||
#define BACKS 0x08
|
||||
#define SOH 0x01 // For XModem etc.
|
||||
#define EOT 0x04
|
||||
#define ACK 0x06
|
||||
#define NAK 0x15
|
||||
#define NUL 0x00
|
||||
//#define NULL 0x00
|
||||
#define CTRL_A 0x01
|
||||
#define CTRL_B 0x02
|
||||
#define CTRL_C 0x03
|
||||
#define CTRL_D 0x04
|
||||
#define CTRL_E 0x05
|
||||
#define CTRL_F 0x06
|
||||
#define CTRL_G 0x07
|
||||
#define CTRL_H 0x08
|
||||
#define CTRL_I 0x09
|
||||
#define CTRL_J 0x0A
|
||||
#define CTRL_K 0x0B
|
||||
#define CTRL_L 0x0C
|
||||
#define CTRL_M 0x0D
|
||||
#define CTRL_N 0x0E
|
||||
#define CTRL_O 0x0F
|
||||
#define CTRL_P 0x10
|
||||
#define CTRL_Q 0x11
|
||||
#define CTRL_R 0x12
|
||||
#define CTRL_S 0x13
|
||||
#define CTRL_T 0x14
|
||||
#define CTRL_U 0x15
|
||||
#define CTRL_V 0x16
|
||||
#define CTRL_W 0x17
|
||||
#define CTRL_X 0x18
|
||||
#define CTRL_Y 0x19
|
||||
#define CTRL_Z 0x1A
|
||||
#define ESC 0x1B
|
||||
#define CTRL_SLASH 0x1C
|
||||
#define CTRL_LB 0x1
|
||||
#define CTRL_RB 0x1D
|
||||
#define CTRL_CAPPA 0x1E
|
||||
#define CTRL_UNDSCR 0x1F
|
||||
#define CTRL_AT 0x00
|
||||
#define FUNC1 0x80
|
||||
#define FUNC2 0x81
|
||||
#define FUNC3 0x82
|
||||
#define FUNC4 0x83
|
||||
#define FUNC5 0x84
|
||||
#define FUNC6 0x85
|
||||
#define FUNC7 0x86
|
||||
#define FUNC8 0x87
|
||||
#define FUNC9 0x88
|
||||
#define FUNC10 0x89
|
||||
#define HOTKEY_ORIGINAL 0xE0
|
||||
#define HOTKEY_RFS80 0xE1
|
||||
#define HOTKEY_RFS40 0xE2
|
||||
#define HOTKEY_TZFS 0xE3
|
||||
#define HOTKEY_LINUX 0xE4
|
||||
#define PAGEUP 0xE8
|
||||
#define PAGEDOWN 0xE9
|
||||
#define CURHOMEKEY 0xEA
|
||||
#define ALPHAGRAPHKEY 0xEB
|
||||
#define SHIFTLOCKKEY 0xEC
|
||||
#define NOKEY 0xF0
|
||||
#define CURSRIGHT 0xF1
|
||||
#define CURSLEFT 0xF2
|
||||
#define CURSUP 0xF3
|
||||
#define CURSDOWN 0xF4
|
||||
#define DBLZERO 0xF5
|
||||
#define INSERT 0xF6
|
||||
#define CLRKEY 0xF7
|
||||
#define HOMEKEY 0xF8
|
||||
#define ENDKEY 0xF9
|
||||
#define ANSITGLKEY 0xFA
|
||||
#define BREAKKEY 0xFB
|
||||
#define GRAPHKEY 0xFC
|
||||
#define ALPHAKEY 0xFD
|
||||
#define DEBUGKEY 0xFE // Special key to enable debug features such as the ANSI emulation.
|
||||
|
||||
// Macros.
|
||||
//
|
||||
// The read/write hardware macros are created in order to allow this module to be used with the zSoft/zOS platform
|
||||
// as well as the FusionX platform. The ZPU writes direct to memory, the FusionX sends via SPI.
|
||||
#define WRITE_HARDWARE(__force__,__addr__,__data__)\
|
||||
{\
|
||||
if(!ctrl.suspendIO || __force__ == 1)\
|
||||
{\
|
||||
SPI_SEND32((uint32_t)__addr__ << 16 | __data__ << 8 | CPLD_CMD_WRITE_ADDR);\
|
||||
}\
|
||||
}
|
||||
#define READ_HARDWARE_INIT(__force__,__addr__)\
|
||||
{\
|
||||
if(!ctrl.suspendIO || __force__ == 1)\
|
||||
{\
|
||||
SPI_SEND32((uint32_t)__addr__ << 16 | 0x00 << 8 | CPLD_CMD_READ_ADDR);\
|
||||
while(CPLD_READY() == 0);\
|
||||
}\
|
||||
}
|
||||
#define READ_HARDWARE() (\
|
||||
z80io_PRL_Read8(1)\
|
||||
)
|
||||
#define WRITE_HARDWARE_IO(__force__,__addr__,__data__)\
|
||||
{\
|
||||
if(!ctrl.suspendIO || __force__ == 1)\
|
||||
{\
|
||||
SPI_SEND32((uint32_t)__addr__ << 16 | __data__ << 8 | CPLD_CMD_WRITEIO_ADDR);\
|
||||
}\
|
||||
}
|
||||
#define READ_HARDWARE_IO_INIT(__force__,__addr__)\
|
||||
{\
|
||||
if(!ctrl.suspendIO || __force__ == 1)\
|
||||
{\
|
||||
SPI_SEND32((uint32_t)__addr__ << 16 | 0x00 << 8 | CPLD_CMD_READIO_ADDR);\
|
||||
while(CPLD_READY() == 0);\
|
||||
}\
|
||||
}
|
||||
#define READ_HARDWARE_IO() (\
|
||||
z80io_PRL_Read8(1)\
|
||||
)
|
||||
// Video memory macros, allows for options based on host hardware - All Sharp MZ series are very similar.
|
||||
#if (TARGET_HOST_MZ2000 == 1)
|
||||
// A7 : H 0xD000:0xD7FF or 0xC000:0xFFFF VRAM paged in.
|
||||
// A6 : H Select Character VRAM (H) or Graphics VRAM (L)
|
||||
// A5 : H Select 80 char mode, 40 char mode = L
|
||||
// A4 : L Select all key strobe lines active, for detection of any key press.
|
||||
// A3-A0: Keyboard strobe lines
|
||||
#define ENABLE_VIDEO() {\
|
||||
display.hwVideoMode = (display.hwVideoMode & 0x3F) | 0xC0;\
|
||||
WRITE_HARDWARE_IO(0, MBADDR_PIOA, display.hwVideoMode);\
|
||||
}
|
||||
#define DISABLE_VIDEO() {\
|
||||
display.hwVideoMode = (display.hwVideoMode & 0x3F);\
|
||||
WRITE_HARDWARE_IO(0, MBADDR_PIOA, display.hwVideoMode);\
|
||||
}
|
||||
#define WRITE_VRAM_CHAR(__addr__,__data__,__xlat__) WRITE_HARDWARE(0,__addr__,__data__)
|
||||
#define WRITE_VRAM_ATTRIBUTE(__addr__,__data__) {}
|
||||
#define WRITE_KEYB_STROBE(__data__)\
|
||||
{\
|
||||
display.hwVideoMode = (display.hwVideoMode & 0xF0) | 0x10 | (__data__ & 0x0F);\
|
||||
WRITE_HARDWARE_IO(0, MBADDR_PIOA, display.hwVideoMode );\
|
||||
}
|
||||
#define READ_KEYB_INIT() READ_HARDWARE_IO_INIT(0, MBADDR_PIOB)
|
||||
#define READ_KEYB() READ_HARDWARE_IO()
|
||||
#elif (TARGET_HOST_MZ1500 ==1)
|
||||
#define ENABLE_VIDEO() {}
|
||||
#define DISABLE_VIDEO() {}
|
||||
#define WRITE_VRAM_CHAR(__addr__,__data__,__xlat__) if(__xlat__ == 1)\
|
||||
{\
|
||||
if(islower(__data__))\
|
||||
{\
|
||||
WRITE_HARDWARE(0,__addr__,(dispCodeMap[(int)(__data__)].dispCode & 0x7F));\
|
||||
READ_HARDWARE_INIT(0,(__addr__+0x800));\
|
||||
WRITE_HARDWARE(0,(__addr__+0x800),(READ_HARDWARE() | 0x80));\
|
||||
} else\
|
||||
{\
|
||||
WRITE_HARDWARE(0,__addr__,dispCodeMap[(int)(__data__)].dispCode);\
|
||||
READ_HARDWARE_INIT(0,(__addr__+0x800));\
|
||||
WRITE_HARDWARE(0,(__addr__+0x800),(READ_HARDWARE() & 0x7F));\
|
||||
}\
|
||||
} else\
|
||||
{\
|
||||
WRITE_HARDWARE(0,__addr__, __data__);\
|
||||
}
|
||||
#define WRITE_VRAM_ATTRIBUTE(__addr__,__data__) {\
|
||||
READ_HARDWARE_INIT(0,(__addr__));\
|
||||
WRITE_HARDWARE(0,__addr__,((READ_HARDWARE() & 0x80) | (__data__ & 0x7F)));\
|
||||
}
|
||||
#define WRITE_KEYB_STROBE(__data__) WRITE_HARDWARE(0, MBADDR_KEYPA, __data__)
|
||||
#define READ_KEYB_INIT() READ_HARDWARE_INIT(0, MBADDR_KEYPB)
|
||||
#define READ_KEYB() READ_HARDWARE()
|
||||
#else
|
||||
#define ENABLE_VIDEO() {}
|
||||
#define DISABLE_VIDEO() {}
|
||||
#define WRITE_VRAM_CHAR(__addr__,__data__,__xlat__) WRITE_HARDWARE(0,__addr__,(__xlat__ == 1 ? dispCodeMap[(int)__data__].dispCode : __data__))
|
||||
#define WRITE_VRAM_ATTRIBUTE(__addr__,__data__) WRITE_HARDWARE(0,__addr__,__data__)
|
||||
#define WRITE_KEYB_STROBE(__data__) WRITE_HARDWARE(0, MBADDR_KEYPA, __data__)
|
||||
#define READ_KEYB_INIT() READ_HARDWARE_INIT(0, MBADDR_KEYPB)
|
||||
#define READ_KEYB() READ_HARDWARE()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Cursor flash mechanism control states.
|
||||
//
|
||||
enum CURSOR_STATES {
|
||||
CURSOR_OFF = 0x00, // Turn the cursor off.
|
||||
CURSOR_ON = 0x01, // Turn the cursor on.
|
||||
CURSOR_RESTORE = 0x02, // Restore the saved cursor character.
|
||||
CURSOR_FLASH = 0x03 // If enabled, flash the cursor.
|
||||
};
|
||||
|
||||
// Cursor positioning states.
|
||||
enum CURSOR_POSITION {
|
||||
CURSOR_UP = 0x00, // Move the cursor up.
|
||||
CURSOR_DOWN = 0x01, // Move the cursor down.
|
||||
CURSOR_LEFT = 0x02, // Move the cursor left.
|
||||
CURSOR_RIGHT = 0x03, // Move the cursor right.
|
||||
CURSOR_COLUMN = 0x04, // Set cursor column to absolute value.
|
||||
CURSOR_NEXT_LINE = 0x05, // Move the cursor to the beginning of the next line.
|
||||
CURSOR_PREV_LINE = 0x06, // Move the cursor to the beginning of the previous line.
|
||||
};
|
||||
|
||||
// Keyboard operating states according to buttons pressed.
|
||||
//
|
||||
enum KEYBOARD_MODES {
|
||||
KEYB_LOWERCASE = 0x00, // Keyboard in lower case mode.
|
||||
KEYB_CAPSLOCK = 0x01, // Keyboard in CAPS lock mode.
|
||||
KEYB_SHIFTLOCK = 0x02, // Keyboard in SHIFT lock mode.
|
||||
KEYB_CTRL = 0x03, // Keyboard in Control mode.
|
||||
KEYB_GRAPHMODE = 0x04, // Keyboard in Graphics mode.
|
||||
};
|
||||
|
||||
// Keyboard dual key modes. This is for hosts whose keyboards dont support the basic key set or when a key needs to have dual functionality.
|
||||
enum KEYBOARD_DUALMODES {
|
||||
KEYB_DUAL_NONE = 0x00, // No dual key modes active.
|
||||
KEYB_DUAL_GRAPH = 0x01, // MZ-80A, no Alpha key, only Graph, so double function required.
|
||||
};
|
||||
|
||||
// Mapping table from Sharp MZ80A Ascii to real Ascii.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t asciiCode;
|
||||
} t_asciiMap;
|
||||
|
||||
// Mapping table from Ascii to Sharp MZ display code.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t dispCode;
|
||||
} t_dispCodeMap;
|
||||
|
||||
// Mapping table from keyboard scan codes to Sharp MZ keys.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t scanCode[KEY_SCAN_ROWS*8];
|
||||
} t_scanCodeMap;
|
||||
|
||||
// Mapping table of a sharp keycode to an ANSI escape sequence string.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t key;
|
||||
const char* ansiKeySequence;
|
||||
} t_ansiKeyMap;
|
||||
|
||||
// Structure to maintain the Sharp MZ display output parameters and data.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t displayAttr; // Attributes for each character in the display.
|
||||
uint16_t backingRow; // Maximum backing RAM row, allows for a larger virtual backing display with the physical display acting as a window.
|
||||
|
||||
// Location on the physical display to output data. displayCol is also used in the backing store.
|
||||
uint8_t displayRow;
|
||||
uint8_t displayCol;
|
||||
|
||||
// History and backing display store. The physical display outputs a portion of this backing store.
|
||||
uint8_t displayCharBuf[VC_DISPLAY_BUFFER_SIZE];
|
||||
uint8_t displayAttrBuf[VC_DISPLAY_BUFFER_SIZE];
|
||||
|
||||
// Maxims, dynamic to allow for future changes.
|
||||
uint8_t maxBackingRow;
|
||||
uint8_t maxDisplayRow;
|
||||
uint8_t maxBackingCol;
|
||||
|
||||
// Features.
|
||||
uint8_t lineWrap; // Wrap line at display edge (1) else stop printing at display edge.
|
||||
uint8_t useAnsiTerm; // Enable (1) Ansi Terminal Emulator, (0) disable.
|
||||
uint8_t inDebug; // Prevent recursion when outputting debug information.
|
||||
|
||||
// Working variables.
|
||||
uint8_t hwVideoMode; // Physical configuration of the video control register.
|
||||
} t_displayBuffer;
|
||||
|
||||
// Structure for maintaining the Sharp MZ keyboard parameters and data. Used to retrieve and map a key along with associated
|
||||
// attributes such as cursor flashing.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t scanbuf[2][KEY_SCAN_ROWS];
|
||||
uint8_t keydown[KEY_SCAN_ROWS];
|
||||
uint8_t keyup[KEY_SCAN_ROWS];
|
||||
uint8_t keyhold[KEY_SCAN_ROWS];
|
||||
uint32_t holdTimer;
|
||||
uint8_t breakKey; // Break key pressed.
|
||||
uint8_t ctrlKey; // Ctrl key pressed.
|
||||
uint8_t shiftKey; // Shift key pressed.
|
||||
uint8_t repeatKey;
|
||||
uint8_t autorepeat;
|
||||
enum KEYBOARD_MODES mode; // Keyboard mode and index into mapping table for a specific map set.
|
||||
enum KEYBOARD_DUALMODES dualmode; // Keyboard dual key override modes.
|
||||
uint8_t keyBuf[MAX_KEYB_BUFFER_SIZE]; // Keyboard buffer.
|
||||
uint8_t keyBufPtr; // Pointer into the keyboard buffer for stored key,
|
||||
uint8_t cursorOn; // Flag to indicate Cursor is switched on.
|
||||
uint8_t displayCursor; // Cursor being displayed = 1
|
||||
uint32_t flashTimer; // Timer to indicate next flash time for cursor.
|
||||
} t_keyboard;
|
||||
|
||||
// Structure for maintaining the Sharp MZ Audio parameters and data.
|
||||
typedef struct {
|
||||
uint32_t audioStopTimer; // Timer to disable audio once elapsed period has expired. Time in ms.
|
||||
} t_audio;
|
||||
|
||||
// Structure for module control parameters.
|
||||
typedef struct {
|
||||
uint8_t suspendIO; // Suspend physical I/O.
|
||||
uint8_t debug; // Enable debugging features.
|
||||
} t_control;
|
||||
|
||||
// Structure to maintain the Ansi Terminal Emulator state and parameters.
|
||||
//
|
||||
typedef struct {
|
||||
enum {
|
||||
ANSITERM_ESC,
|
||||
ANSITERM_BRACKET,
|
||||
ANSITERM_PARSE,
|
||||
} state; // States and current state of the FSM parser.
|
||||
uint8_t charcnt; // Number of characters read into the buffer.
|
||||
uint8_t paramcnt; // Number of parameters parsed and stored.
|
||||
uint8_t setDisplayMode; // Display mode command detected.
|
||||
uint8_t setExtendedMode; // Extended mode command detected.
|
||||
uint8_t charbuf[80]; // Storage for the parameter characters as they are received.
|
||||
uint16_t param[10]; // Parsed parameters.
|
||||
uint8_t saveRow; // Store the current row when requested.
|
||||
uint8_t saveCol; // Store the current column when requested.
|
||||
uint8_t saveDisplayRow; // Store the current display buffer row when requested.
|
||||
} t_AnsiTerm;
|
||||
|
||||
// Application execution constants.
|
||||
//
|
||||
|
||||
// Prototypes.
|
||||
//
|
||||
uint8_t mzInitMBHardware(void);
|
||||
uint8_t mzInit(void);
|
||||
void mzBeep(uint32_t, uint32_t);
|
||||
uint8_t mzMoveCursor(enum CURSOR_POSITION, uint8_t);
|
||||
uint8_t mzSetCursor(uint8_t, uint8_t);
|
||||
int mzPutChar(char);
|
||||
int mzPutRaw(char);
|
||||
uint8_t mzSetAnsiAttribute(uint8_t);
|
||||
int mzAnsiTerm(char);
|
||||
int mzPrintChar(char);
|
||||
uint8_t mzFlashCursor(enum CURSOR_STATES);
|
||||
uint8_t mzPushKey(char *);
|
||||
int mzGetKey(uint8_t);
|
||||
int mzGetChar(void);
|
||||
void mzClearDisplay(uint8_t, uint8_t);
|
||||
void mzClearLine(int, int, int, uint8_t);
|
||||
uint8_t mzGetDisplayWidth(void);
|
||||
uint8_t mzSetDisplayWidth(uint8_t);
|
||||
uint8_t mzSetMachineVideoMode(uint8_t);
|
||||
void mzRefreshDisplay(void);
|
||||
uint8_t mzScrollUp(uint8_t, uint8_t, uint8_t);
|
||||
uint8_t mzScrollDown(uint8_t);
|
||||
void mzDebugOut(uint8_t, uint8_t);
|
||||
void mzSuspendIO(void);
|
||||
void mzResumeIO(void);
|
||||
void mzWriteString(uint8_t, uint8_t, char *, int);
|
||||
void mzService(void);
|
||||
|
||||
// Getter/Setter methods!
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // SHARPMZ_H
|
||||
916
software/FusionX/src/ttymz/ttymz.c
Normal file
916
software/FusionX/src/ttymz/ttymz.c
Normal file
@@ -0,0 +1,916 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: ttymz.c
|
||||
// Created: Feb 2023
|
||||
// Author(s): Philip Smart
|
||||
// Description: Sharp MZ TTY
|
||||
// This file contains the methods used to create a linux tty device driver using the
|
||||
// host Sharp keyboard and screen as input/output.
|
||||
// This driver forms part of the FusionX developments and allows a user sitting at the
|
||||
// Sharp MZ Console to access the underlying FusionX Linux SOM.
|
||||
// Credits: Credits to tiny_tty Greg Kroah-Hartman (greg@kroah.com) and Linux pty which were
|
||||
// used as base and reference in creating this driver.
|
||||
//
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Feb 2023 - v1.0 Initial write of the Sharp MZ tty driver software.
|
||||
// Added suspend I/O logic. This is necessary as I want to enable
|
||||
// switching between a Linux session and a Z80 session, the idea
|
||||
// being the TTY will continue to run within the mirrored framebuffer
|
||||
// and when reselected, refresh the hardware screen.
|
||||
// Apr 2023 - v1.1 Updated to include MZ-2000 mode.
|
||||
// Jul 2023 - v1.2 Updates and bug fixes.
|
||||
//
|
||||
// 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/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/kprobes.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/major.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/devpts_fs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/version.h>
|
||||
#include "z80io.h"
|
||||
#include "sharpmz.h"
|
||||
#include "ttymz.h"
|
||||
|
||||
// Meta Information.
|
||||
MODULE_LICENSE(DRIVER_LICENSE);
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_INFO(versiondate, DRIVER_VERSION_DATE);
|
||||
MODULE_INFO(copyright, DRIVER_COPYRIGHT);
|
||||
|
||||
// Device control variables.
|
||||
static t_TTYMZ *ttymzConnections[SHARPMZ_TTY_MINORS]; // Initially all NULL, no devices connected.
|
||||
static t_TTYMZCtrl ttymzCtrl;
|
||||
|
||||
// Read method. Keys entered on the host keyboard are sent to the user process via this method.
|
||||
//
|
||||
static void ttymz_read(struct tty_struct *tty, char data)
|
||||
{
|
||||
// Locals.
|
||||
struct tty_port *port;
|
||||
|
||||
// Sanity check.
|
||||
if (!tty)
|
||||
return;
|
||||
|
||||
// Get the port, needed to push data onto the ringbuffer for delivery to the user.
|
||||
port = tty->port;
|
||||
|
||||
// If there is no room, push the characters to the user. Add the new character and push again.
|
||||
if (!tty_buffer_request_room(port, 1))
|
||||
tty_flip_buffer_push(port);
|
||||
tty_insert_flip_char(port, data, TTY_NORMAL);
|
||||
tty_flip_buffer_push(port);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to receive data from the user application to be written onto the Sharp or SSD202 framebuffer.
|
||||
//
|
||||
static int ttymz_write(struct tty_struct *tty, const unsigned char *buffer, int count)
|
||||
{
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
int idx;
|
||||
int retval = count;
|
||||
|
||||
if (!ttymz)
|
||||
return -ENODEV;
|
||||
|
||||
// Lock out other processes.
|
||||
mutex_lock(&ttymz->mutex);
|
||||
|
||||
// Sanity check, ensure port is open.
|
||||
if (!ttymz->open_count)
|
||||
goto exit;
|
||||
|
||||
// Send the characters to the Sharp MZ interface for display.
|
||||
for (idx = 0; idx < count; ++idx)
|
||||
{
|
||||
mzPrintChar(buffer[idx]);
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ttymz->mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Method to indicate to the kernel how much buffer space is left in the device.
|
||||
//
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0))
|
||||
static int ttymz_write_room(struct tty_struct *tty)
|
||||
#else
|
||||
static unsigned int ttymz_write_room(struct tty_struct *tty)
|
||||
#endif
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
int room = -EINVAL;
|
||||
|
||||
// Sanity check.
|
||||
if(!ttymz)
|
||||
return -ENODEV;
|
||||
|
||||
if(tty->stopped)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&ttymz->mutex);
|
||||
|
||||
if(!ttymz->open_count)
|
||||
{
|
||||
// Port was not opened
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Calculate how much room is left in the device
|
||||
room = 255;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ttymz->mutex);
|
||||
return room;
|
||||
}
|
||||
|
||||
|
||||
// Timer methods
|
||||
//
|
||||
// Timer to scan the Sharp MZ host keyboard and detect key presses. Any key press detected results
|
||||
// in a character being pushed into the kernel ringbuffer for delivery to the user application.
|
||||
//
|
||||
static void ttymz_keyboardTimer(unsigned long timerAddr)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz = (t_TTYMZ *)timerAddr;
|
||||
struct tty_struct *tty;
|
||||
int key;
|
||||
|
||||
// Sanity check.
|
||||
if (!ttymz)
|
||||
return;
|
||||
|
||||
// Once sanitised, get the tty struct from the given physical address, needed to reset the timer and to
|
||||
// push data to the client.
|
||||
tty = ttymz->tty;
|
||||
|
||||
// Scan the Sharp MZ host keyboard, push any character received. Mode 2 = Ansi scan without wait.
|
||||
if((key = mzGetKey(2)) != -1)
|
||||
{
|
||||
switch(key)
|
||||
{
|
||||
// Hotkeys, send to the Arbiter, not the user process.
|
||||
case HOTKEY_ORIGINAL:
|
||||
case HOTKEY_RFS80:
|
||||
case HOTKEY_RFS40:
|
||||
case HOTKEY_TZFS:
|
||||
case HOTKEY_LINUX:
|
||||
//pr_info("Hotkey detected:%02x\n", key);
|
||||
ttymzCtrl.hotkey = (uint32_t)key;
|
||||
sendSignal(ttymzCtrl.arbTask, SIGUSR2);
|
||||
break;
|
||||
|
||||
default:
|
||||
//pr_info("%d, %08x ", key, (size_t)tty->port);
|
||||
ttymz_read(tty, (char)key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Resubmit the timer again.
|
||||
ttymz->timerKeyboard.expires = jiffies + 1;
|
||||
add_timer(&ttymz->timerKeyboard);
|
||||
}
|
||||
//
|
||||
// Display service timer, used for scheduling tasks within the display driver.
|
||||
//
|
||||
static void ttymz_displayTimer(unsigned long timerAddr)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz = (t_TTYMZ *)timerAddr;
|
||||
struct tty_struct *tty;
|
||||
|
||||
// Sanity check.
|
||||
if (!ttymz)
|
||||
return;
|
||||
|
||||
// Once sanitised, get the tty struct from the given physical address, needed to reset the timer and to
|
||||
// push data to the client.
|
||||
tty = ttymz->tty;
|
||||
|
||||
// Call the display service routine.
|
||||
mzService();
|
||||
|
||||
// Resubmit the timer again.
|
||||
ttymz->timerDisplay.expires = jiffies + 1;
|
||||
add_timer(&ttymz->timerDisplay);
|
||||
}
|
||||
|
||||
|
||||
// Device open.
|
||||
//
|
||||
// When a user space application open's the tty device driver, this function is called
|
||||
// to initialise and allocate any required memory or hardware prior to servicing requests from the
|
||||
// user space application.
|
||||
static int ttymz_open(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz;
|
||||
int index;
|
||||
int ret = 0;
|
||||
struct winsize ws;
|
||||
struct task_struct *task = get_current();
|
||||
|
||||
// Initialize the pointer in case something fails
|
||||
tty->driver_data = NULL;
|
||||
|
||||
// Get the serial object associated with this tty pointer
|
||||
index = tty->index;
|
||||
ttymz = ttymzConnections[index];
|
||||
|
||||
if(ttymz == NULL)
|
||||
{
|
||||
// First time accessing this device, let's create it
|
||||
ttymz = kmalloc(sizeof(*ttymz), GFP_KERNEL);
|
||||
if (!ttymz)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ttymz->mutex);
|
||||
ttymz->open_count = 0;
|
||||
|
||||
ttymzConnections[index] = ttymz;
|
||||
}
|
||||
|
||||
mutex_lock(&ttymz->mutex);
|
||||
|
||||
// Save our structure within the tty structure
|
||||
tty->driver_data = ttymz;
|
||||
ttymz->tty = tty;
|
||||
ttymz->tty->port = tty->port;
|
||||
|
||||
// Setup the default terminal size based on compilation (ie. 40/80 cols).
|
||||
ws.ws_row = VC_MAX_ROWS;
|
||||
ws.ws_col = VC_MAX_COLUMNS;
|
||||
tty->winsize = ws;
|
||||
|
||||
// Port opened, perform initialisation.
|
||||
//
|
||||
++ttymz->open_count;
|
||||
if(ttymz->open_count == 1 && tty->index == 0)
|
||||
{
|
||||
// Create the keyboard sweep timer and submit it
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
|
||||
init_timer(&ttymz->timerKeyboard);
|
||||
ttymz->timerKeyboard.data = (unsigned long)ttymz;
|
||||
ttymz->timerKeyboard.function = ttymz_keyboardTimer;
|
||||
#else
|
||||
timer_setup(timer, (void *)ttymz_keyboardTimer, (unsigned long)ttymz);
|
||||
timer->function = (void *)ttymz_keyboardTimer;
|
||||
#endif
|
||||
// 10 ms sweep timer.
|
||||
ttymz->timerKeyboard.expires = jiffies + 1;
|
||||
add_timer(&ttymz->timerKeyboard);
|
||||
|
||||
// Create the display periodic timer and submit it.
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
|
||||
init_timer(&ttymz->timerDisplay);
|
||||
ttymz->timerDisplay.data = (unsigned long)ttymz;
|
||||
ttymz->timerDisplay.function = ttymz_displayTimer;
|
||||
#else
|
||||
timer_setup(timer, (void *)ttymz_keyboardTimer, (unsigned long)ttymz);
|
||||
timer->function = (void *)ttymz_displayTimer;
|
||||
#endif
|
||||
// 10 ms service interval.
|
||||
ttymz->timerDisplay.expires = jiffies + 1;
|
||||
add_timer(&ttymz->timerDisplay);
|
||||
} else
|
||||
// SSD202 Framebuffer?
|
||||
if(ttymz->open_count == 1 && tty->index == 1)
|
||||
{
|
||||
pr_info("SSD202 Framebuffer not yet implemented.\n");
|
||||
ret = -EBUSY;
|
||||
} else
|
||||
// Control port is just opened, no associated hardware.
|
||||
if(tty->index == 2)
|
||||
{
|
||||
// Arbiter connection?
|
||||
if(ttymzCtrl.arbTask == NULL && strcmp(task->comm, ARBITER_NAME) == 0)
|
||||
{
|
||||
ttymzCtrl.arbTask = task;
|
||||
pr_info("Sharpbiter: Registering Arbiter:%s\n", ttymzCtrl.arbTask->comm);
|
||||
} else
|
||||
if(ttymzCtrl.arbTask != NULL && strcmp(task->comm, ARBITER_NAME) == 0)
|
||||
{
|
||||
pr_info("Arbiter already registered, PID:%d\n", ttymzCtrl.arbTask->pid);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ttymz->mutex);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
// Close helper method, performs the actual deallocation of resources for the open port.
|
||||
//
|
||||
static void do_close(t_TTYMZ *ttymz)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
struct task_struct *task = get_current();
|
||||
|
||||
mutex_lock(&ttymz->mutex);
|
||||
|
||||
if(!ttymz->open_count)
|
||||
{
|
||||
// Port was never opened
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Go through all the connections to find active connection.
|
||||
for(idx = 0; idx < SHARPMZ_TTY_MINORS; idx++)
|
||||
{
|
||||
// Match the handle to find the index.
|
||||
if(ttymz == ttymzConnections[idx])
|
||||
{
|
||||
// Active consoles, ie. host and framebuffer, close hardware and free up timers etc.
|
||||
if(idx < 2)
|
||||
{
|
||||
// Shutdown hardware tasks to exit.
|
||||
// Shut down our timers.
|
||||
del_timer(&ttymz->timerKeyboard);
|
||||
del_timer(&ttymz->timerDisplay);
|
||||
} else
|
||||
if(idx == 2)
|
||||
{
|
||||
// Is this the Arbiter de-registering?
|
||||
if(ttymzCtrl.arbTask == task)
|
||||
{
|
||||
ttymzCtrl.arbTask = NULL;
|
||||
pr_info("Arbiter stopped.\n");
|
||||
}
|
||||
|
||||
// Free up the connection resources.
|
||||
kfree(ttymzConnections[idx]);
|
||||
ttymzConnections[idx] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ttymz->mutex);
|
||||
}
|
||||
|
||||
// Device close.
|
||||
//
|
||||
// When a user space application terminates or closes the tty device driver, this function is called
|
||||
// to close any open connections, memory and variables required to handle the user space application
|
||||
// requests.
|
||||
static void ttymz_close(struct tty_struct *tty, struct file *file)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
|
||||
if (ttymz)
|
||||
do_close(ttymz);
|
||||
}
|
||||
|
||||
#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
|
||||
static void ttymz_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
||||
{
|
||||
// Locals.
|
||||
unsigned int cflag;
|
||||
|
||||
//PRINT_PROC_START();
|
||||
|
||||
cflag = tty->termios.c_cflag;
|
||||
|
||||
// Check that they really want us to change something
|
||||
if (old_termios)
|
||||
{
|
||||
if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios.c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// As this is not a serial based TTY, most of the settings are ignored, they are here for reference
|
||||
// and in-place if something is needed in future.
|
||||
|
||||
// Get the byte size
|
||||
switch(cflag & CSIZE)
|
||||
{
|
||||
case CS5:
|
||||
break;
|
||||
case CS6:
|
||||
break;
|
||||
case CS7:
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
break;
|
||||
}
|
||||
|
||||
// Determine the parity
|
||||
if (cflag & PARENB)
|
||||
if (cflag & PARODD)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// Figure out the stop bits requested
|
||||
if (cflag & CSTOPB)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// Figure out the hardware flow control settings
|
||||
if (cflag & CRTSCTS)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// Determine software flow control
|
||||
// if we are implementing XON/XOFF, set the start and
|
||||
// stop character in the device
|
||||
if (I_IXOFF(tty) || I_IXON(tty))
|
||||
{
|
||||
//unsigned char stop_char = STOP_CHAR(tty);
|
||||
//unsigned char start_char = START_CHAR(tty);
|
||||
|
||||
// If we are implementing INBOUND XON/XOFF
|
||||
if(I_IXOFF(tty))
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// if we are implementing OUTBOUND XON/XOFF
|
||||
if(I_IXON(tty))
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the baud rate wanted
|
||||
// baud = tty_get_baud_rate(tty));
|
||||
return;
|
||||
}
|
||||
|
||||
static int ttymz_tiocmget(struct tty_struct *tty)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
unsigned int result = 0;
|
||||
unsigned int msr = ttymz->msr;
|
||||
unsigned int mcr = ttymz->mcr;
|
||||
|
||||
//PRINT_PROC_START();
|
||||
|
||||
result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | // DTR is set
|
||||
((mcr & MCR_RTS) ? TIOCM_RTS : 0) | // RTS is set
|
||||
((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) | // LOOP is set
|
||||
((msr & MSR_CTS) ? TIOCM_CTS : 0) | // CTS is set
|
||||
((msr & MSR_CD) ? TIOCM_CAR : 0) | // Carrier detect is set
|
||||
((msr & MSR_RI) ? TIOCM_RI : 0) | // Ring Indicator is set
|
||||
((msr & MSR_DSR) ? TIOCM_DSR : 0); // DSR is set
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ttymz_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
unsigned int mcr = ttymz->mcr;
|
||||
|
||||
//PRINT_PROC_START();
|
||||
|
||||
if (set & TIOCM_RTS)
|
||||
mcr |= MCR_RTS;
|
||||
if (set & TIOCM_DTR)
|
||||
mcr |= MCR_RTS;
|
||||
|
||||
if (clear & TIOCM_RTS)
|
||||
mcr &= ~MCR_RTS;
|
||||
if (clear & TIOCM_DTR)
|
||||
mcr &= ~MCR_RTS;
|
||||
|
||||
// Set the new MCR value in the device
|
||||
ttymz->mcr = mcr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ttymz_ioctl ttymz_ioctl_tiocgserial
|
||||
static int ttymz_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
// Locals.
|
||||
struct serial_struct tmp;
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
|
||||
//PRINT_PROC_START();
|
||||
|
||||
if(cmd == TIOCGSERIAL)
|
||||
{
|
||||
if (!arg)
|
||||
return -EFAULT;
|
||||
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
tmp.type = ttymz->serial.type;
|
||||
tmp.line = ttymz->serial.line;
|
||||
tmp.port = ttymz->serial.port;
|
||||
tmp.irq = ttymz->serial.irq;
|
||||
tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
|
||||
tmp.xmit_fifo_size = ttymz->serial.xmit_fifo_size;
|
||||
tmp.baud_base = ttymz->serial.baud_base;
|
||||
tmp.close_delay = 5*HZ;
|
||||
tmp.closing_wait = 30*HZ;
|
||||
tmp.custom_divisor = ttymz->serial.custom_divisor;
|
||||
tmp.hub6 = ttymz->serial.hub6;
|
||||
tmp.io_type = ttymz->serial.io_type;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &tmp, sizeof(struct serial_struct)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
#undef ttymz_ioctl
|
||||
|
||||
#define ttymz_ioctl ttymz_ioctl_tiocmiwait
|
||||
static int ttymz_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
// Locals.
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
struct async_icount cnow;
|
||||
struct async_icount cprev;
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
|
||||
//PRINT_PROC_START();
|
||||
|
||||
if (cmd == TIOCMIWAIT)
|
||||
{
|
||||
cprev = ttymz->icount;
|
||||
while (1)
|
||||
{
|
||||
add_wait_queue(&ttymz->wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
remove_wait_queue(&ttymz->wait, &wait);
|
||||
|
||||
// See if a signal woke us up
|
||||
if (signal_pending(current))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
cnow = ttymz->icount;
|
||||
if(cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
|
||||
return -EIO; // no change => error
|
||||
if(((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
|
||||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
|
||||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
|
||||
((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
cprev = cnow;
|
||||
}
|
||||
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
#undef ttymz_ioctl
|
||||
|
||||
#define ttymz_ioctl ttymz_ioctl_tiocgicount
|
||||
static int ttymz_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz = tty->driver_data;
|
||||
struct async_icount cnow = ttymz->icount;
|
||||
struct serial_icounter_struct icount;
|
||||
|
||||
//PRINT_PROC_START();
|
||||
|
||||
if(cmd == TIOCGICOUNT)
|
||||
{
|
||||
icount.cts = cnow.cts;
|
||||
icount.dsr = cnow.dsr;
|
||||
icount.rng = cnow.rng;
|
||||
icount.dcd = cnow.dcd;
|
||||
icount.rx = cnow.rx;
|
||||
icount.tx = cnow.tx;
|
||||
icount.frame = cnow.frame;
|
||||
icount.overrun = cnow.overrun;
|
||||
icount.parity = cnow.parity;
|
||||
icount.brk = cnow.brk;
|
||||
icount.buf_overrun = cnow.buf_overrun;
|
||||
|
||||
if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
#undef ttymz_ioctl
|
||||
|
||||
// IOCTL Method
|
||||
// This method allows User Space application to control the SharpMZ TTY device driver internal functionality.
|
||||
//
|
||||
static int ttymz_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
// Locals.
|
||||
|
||||
//PRINT_PROC_START();
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case TIOCGSERIAL:
|
||||
return ttymz_ioctl_tiocgserial(tty, cmd, arg);
|
||||
case TIOCMIWAIT:
|
||||
return ttymz_ioctl_tiocmiwait(tty, cmd, arg);
|
||||
case TIOCGICOUNT:
|
||||
return ttymz_ioctl_tiocgicount(tty, cmd, arg);
|
||||
|
||||
// Fetch last hotkey. This method returns any active hotkey to the caller. Normally this is queried after receiving a SIGUSR2 signal.
|
||||
case IOCTL_CMD_FETCH_HOTKEY:
|
||||
if(copy_to_user((int32_t*)arg, &ttymzCtrl.hotkey, sizeof(ttymzCtrl.hotkey)))
|
||||
{
|
||||
pr_err("Failed to send hotkey to user space.\n");
|
||||
}
|
||||
return(0);
|
||||
|
||||
// Suspend control. This method stops all physical hardware updates of the host framebuffer and keyboard
|
||||
// scan whilst maintining the functionality of the tty within the mirrored framebuffer. This mode is
|
||||
// necessary if the user wishes to switch into a Z80 driver and use the host as original.
|
||||
case IOCTL_CMD_SUSPEND_IO:
|
||||
mzSuspendIO();
|
||||
return(0);
|
||||
|
||||
// Resume control. This method re-initialises host hardware, updates the host framebuffer from the mirror
|
||||
// (refresh) and re-enabled hardware access and keyboard scanning.
|
||||
case IOCTL_CMD_RESUME_IO:
|
||||
mzResumeIO();
|
||||
return(0);
|
||||
}
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
|
||||
// Window resize method.
|
||||
// On the Sharp framebuffer this could be 40/80 chars wide.
|
||||
// On the SSD202 framebuffer, tba.
|
||||
static int ttymz_resize(struct tty_struct *tty, struct winsize *ws)
|
||||
{
|
||||
PRINT_PROC_START();
|
||||
|
||||
pr_info("Resize to:%d,%d\n", ws->ws_row, ws->ws_col);
|
||||
|
||||
// Check columns and setup the display according to requirement.
|
||||
if(ws->ws_col == 40)
|
||||
{
|
||||
ws->ws_row = VC_MAX_ROWS;
|
||||
} else
|
||||
if(ws->ws_col == 80)
|
||||
{
|
||||
ws->ws_row = VC_MAX_ROWS;
|
||||
} else
|
||||
{
|
||||
// Ignore all other values.
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Setup the hardware to accommodate new column width.
|
||||
mzSetDisplayWidth(ws->ws_col);
|
||||
tty->winsize = *ws;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//static void ttymz_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||
//{
|
||||
// // Locals.
|
||||
//
|
||||
// PRINT_PROC_START();
|
||||
//}
|
||||
|
||||
static void ttymz_cleanup(struct tty_struct *tty)
|
||||
{
|
||||
// tty_port_put(tty->port);
|
||||
}
|
||||
|
||||
static void ttymz_flush_buffer(struct tty_struct *tty)
|
||||
{
|
||||
// Locals.
|
||||
|
||||
//PRINT_PROC_START();
|
||||
}
|
||||
|
||||
// pty_chars_in_buffer - characters currently in our tx queue
|
||||
//
|
||||
// Report how much we have in the transmit queue. As everything is
|
||||
// instantly at the other end this is easy to implement.
|
||||
//
|
||||
static int ttymz_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The unthrottle routine is called by the line discipline to signal
|
||||
// that it can receive more characters. For PTY's, the TTY_THROTTLED
|
||||
// flag is always set, to force the line discipline to always call the
|
||||
// unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE
|
||||
// characters in the queue. This is necessary since each time this
|
||||
// happens, we need to wake up any sleeping processes that could be
|
||||
// (1) trying to send data to the pty, or (2) waiting in wait_until_sent()
|
||||
// for the pty buffer to be drained.
|
||||
//
|
||||
static void ttymz_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
//PRINT_PROC_START();
|
||||
tty_wakeup(tty->link);
|
||||
set_bit(TTY_THROTTLED, &tty->flags);
|
||||
}
|
||||
|
||||
// Structure to declare public API methods.
|
||||
// Standard Linux device driver structure to declare accessible methods within the driver.
|
||||
static const struct tty_operations serial_ops = {
|
||||
//.install = ttymz_install,
|
||||
.open = ttymz_open,
|
||||
.close = ttymz_close,
|
||||
.write = ttymz_write,
|
||||
.write_room = ttymz_write_room,
|
||||
.flush_buffer = ttymz_flush_buffer,
|
||||
.chars_in_buffer = ttymz_chars_in_buffer,
|
||||
.unthrottle = ttymz_unthrottle,
|
||||
.set_termios = ttymz_set_termios,
|
||||
.tiocmget = ttymz_tiocmget,
|
||||
.tiocmset = ttymz_tiocmset,
|
||||
.ioctl = ttymz_ioctl,
|
||||
.cleanup = ttymz_cleanup,
|
||||
.resize = ttymz_resize,
|
||||
// .remove = ttymz_remove
|
||||
};
|
||||
|
||||
|
||||
// Initialisation.
|
||||
// This is the entry point into the device driver when loaded into the kernel.
|
||||
// The method intialises any required hardware (ie. GPIO's, SPI etc), memory.
|
||||
// It also allocates the Major and Minor device numbers and sets up the device in /dev.
|
||||
static int __init ttymz_init(void)
|
||||
{
|
||||
// Locals.
|
||||
int retval;
|
||||
int i;
|
||||
char buf[80];
|
||||
|
||||
// Allocate the tty driver handles, one per potential device.
|
||||
ttymzCtrl.ttymzDriver = alloc_tty_driver(SHARPMZ_TTY_MINORS);
|
||||
if(!ttymzCtrl.ttymzDriver)
|
||||
return -ENOMEM;
|
||||
|
||||
// Initialize the tty driver
|
||||
ttymzCtrl.ttymzDriver->owner = THIS_MODULE;
|
||||
ttymzCtrl.ttymzDriver->driver_name = DRIVER_NAME;
|
||||
ttymzCtrl.ttymzDriver->name = DEVICE_NAME;
|
||||
ttymzCtrl.ttymzDriver->major = SHARPMZ_TTY_MAJOR,
|
||||
ttymzCtrl.ttymzDriver->type = TTY_DRIVER_TYPE_SERIAL,
|
||||
ttymzCtrl.ttymzDriver->subtype = SERIAL_TYPE_NORMAL,
|
||||
ttymzCtrl.ttymzDriver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV,
|
||||
ttymzCtrl.ttymzDriver->init_termios = tty_std_termios;
|
||||
ttymzCtrl.ttymzDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
||||
tty_set_operations(ttymzCtrl.ttymzDriver, &serial_ops);
|
||||
for (i = 0; i < SHARPMZ_TTY_MINORS; i++)
|
||||
{
|
||||
tty_port_init(ttymzCtrl.ttymzPort + i);
|
||||
tty_port_link_device(ttymzCtrl.ttymzPort + i, ttymzCtrl.ttymzDriver, i);
|
||||
}
|
||||
|
||||
// Register the tty driver
|
||||
retval = tty_register_driver(ttymzCtrl.ttymzDriver);
|
||||
if(retval)
|
||||
{
|
||||
pr_err("Failed to register SharpMZ tty driver");
|
||||
put_tty_driver(ttymzCtrl.ttymzDriver);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Register the devices.
|
||||
for (i = 0; i < SHARPMZ_TTY_MINORS; ++i)
|
||||
tty_register_device(ttymzCtrl.ttymzDriver, i, NULL);
|
||||
|
||||
// Initialise the hardware to host interface.
|
||||
z80io_init();
|
||||
|
||||
// Initialise the Sharp MZ interface.
|
||||
mzInit();
|
||||
|
||||
// Sign on.
|
||||
sprintf(buf, "%s %s", DRIVER_TITLE, DRIVER_VERSION); mzWriteString(0, 0, buf, -1);
|
||||
sprintf(buf, "%s %s\n", DRIVER_COPYRIGHT, DRIVER_AUTHOR); mzWriteString(0, 1, buf, -1);
|
||||
|
||||
pr_info(DRIVER_DESCRIPTION " " DRIVER_VERSION "\n");
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Exit
|
||||
// This method is called when the device driver is removed from the kernel with the rmmod command.
|
||||
// It is responsible for closing and freeing all allocated memory, disabling hardware and removing
|
||||
// the device from the /dev directory.
|
||||
static void __exit ttymz_exit(void)
|
||||
{
|
||||
// Locals.
|
||||
t_TTYMZ *ttymz;
|
||||
int idx;
|
||||
|
||||
// De-register the devices and driver.
|
||||
for(idx = 0; idx < SHARPMZ_TTY_MINORS; ++idx)
|
||||
{
|
||||
tty_unregister_device(ttymzCtrl.ttymzDriver, idx);
|
||||
tty_port_destroy(ttymzCtrl.ttymzPort + idx);
|
||||
}
|
||||
tty_unregister_driver(ttymzCtrl.ttymzDriver);
|
||||
|
||||
// Shut down all of the timers and free the memory.
|
||||
for(idx = 0; idx < SHARPMZ_TTY_MINORS; ++idx)
|
||||
{
|
||||
ttymz = ttymzConnections[idx];
|
||||
if (ttymz)
|
||||
{
|
||||
// Close the port.
|
||||
while (ttymz->open_count)
|
||||
do_close(ttymz);
|
||||
|
||||
// Shut down our timer and free the memory.
|
||||
del_timer(&ttymz->timerKeyboard);
|
||||
del_timer(&ttymz->timerDisplay);
|
||||
kfree(ttymz);
|
||||
ttymzConnections[idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("ttymz: unregistered!\n");
|
||||
}
|
||||
|
||||
module_init(ttymz_init);
|
||||
module_exit(ttymz_exit);
|
||||
143
software/FusionX/src/ttymz/ttymz.h
vendored
Normal file
143
software/FusionX/src/ttymz/ttymz.h
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: ttymz.h
|
||||
// Created: Feb 2023
|
||||
// Author(s): Philip Smart
|
||||
// Description: Sharp MZ TTY
|
||||
// This file contains the definitions required by the linux tty device driver ttymz.c.
|
||||
// This driver forms part of the FusionX developments and allows a user sitting at the
|
||||
// Sharp MZ Console to access the underlying FusionX Linux SOM.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Feb 2023 - v1.0 Initial write of the Sharp MZ tty driver software.
|
||||
// Apr 2023 - v1.1 Updated to include MZ-2000 mode.
|
||||
// Jul 2023 - v1.2 Updates and bug fixes.
|
||||
//
|
||||
// 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 TTYMZ_H
|
||||
#define TTYMZ_H
|
||||
|
||||
// Constants.
|
||||
#define DRIVER_LICENSE "GPL"
|
||||
#define DRIVER_AUTHOR "P.D.Smart"
|
||||
#define DRIVER_DESCRIPTION "Sharp MZ TTY Driver"
|
||||
#define DRIVER_VERSION "v1.2"
|
||||
#define DRIVER_VERSION_DATE "July 2023"
|
||||
#define DRIVER_COPYRIGHT "(C) 2018-23"
|
||||
#define DEVICE_NAME "ttymz"
|
||||
#define DRIVER_NAME "SharpMZ_tty"
|
||||
#define DEBUG_ENABLED 0 // 0 = disabled, 1 .. debug level.
|
||||
#define ARBITER_NAME "sharpbiter"
|
||||
#if (TARGET_HOST_MZ80A == 1)
|
||||
#define DRIVER_TITLE "Sharp MZ-80A TTY"
|
||||
#elif (TARGET_HOST_MZ700 == 1)
|
||||
#define DRIVER_TITLE "Sharp MZ-700 TTY"
|
||||
#elif (TARGET_HOST_MZ1500 == 1)
|
||||
#define DRIVER_TITLE "Sharp MZ-1500 TTY"
|
||||
#elif (TARGET_HOST_MZ2000 == 1)
|
||||
#define DRIVER_TITLE "Sharp MZ-2000 TTY"
|
||||
#elif (TARGET_HOST_PCW == 1)
|
||||
#define DRIVER_TITLE "Amstrad PCW-8XXX TTY"
|
||||
#else
|
||||
#define DRIVER_MODEL "not defined"
|
||||
#endif
|
||||
|
||||
// Fake UART values
|
||||
#define MCR_DTR 0x01
|
||||
#define MCR_RTS 0x02
|
||||
#define MCR_LOOP 0x04
|
||||
#define MSR_CTS 0x08
|
||||
#define MSR_CD 0x10
|
||||
#define MSR_RI 0x20
|
||||
#define MSR_DSR 0x40
|
||||
|
||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
||||
#define IOCTL_CMD_FETCH_HOTKEY _IOW('f', 'f', int32_t *)
|
||||
#define IOCTL_CMD_SUSPEND_IO _IOW('s', 's', int32_t *)
|
||||
#define IOCTL_CMD_RESUME_IO _IOW('r', 'r', int32_t *)
|
||||
|
||||
#define SHARPMZ_TTY_MAJOR 240 // Experimental range
|
||||
#define SHARPMZ_TTY_MINORS 3 // Assign 2 devices, 0) Sharp VRAM, 1) SigmaStar SSD202 Framebuffer, 2) Control.
|
||||
|
||||
// Macros.
|
||||
#define from_timer(var, callback_timer, timer_fieldname) container_of(callback_timer, typeof(*var), timer_fieldname)
|
||||
#define PRINT_PROC_START() do { pr_info("Start: %s\n", __func__); } while (0)
|
||||
#define PRINT_PROC_EXIT() do { pr_info("Finish: %s\n", __func__); } while (0)
|
||||
#define sendSignal(__task__, _signal_) { struct siginfo sigInfo;\
|
||||
if(__task__ != NULL)\
|
||||
{\
|
||||
memset(&sigInfo, 0, sizeof(struct siginfo));\
|
||||
sigInfo.si_signo = _signal_;\
|
||||
sigInfo.si_code = SI_QUEUE;\
|
||||
sigInfo.si_int = 1;\
|
||||
if(send_sig_info(_signal_, &sigInfo, __task__) < 0)\
|
||||
{\
|
||||
pr_info("Error: Failed to send signal:%02x to:%s\n", _signal_, __task__->comm);\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
#define resetZ80() {\
|
||||
sendSignal(Z80Ctrl->ioTask, SIGUSR1); \
|
||||
setupMemory(Z80Ctrl->defaultPageMode);\
|
||||
z80_instant_reset(&Z80CPU);\
|
||||
}
|
||||
|
||||
// TTY control structure, per port.
|
||||
typedef struct {
|
||||
struct tty_struct *tty; // pointer to the tty for this device
|
||||
int open_count; // number of times this port has been opened
|
||||
struct mutex mutex; // locks this structure
|
||||
struct timer_list timerKeyboard; // Keyboard sweep timer.
|
||||
struct timer_list timerDisplay; // Display service timer.
|
||||
|
||||
// for tiocmget and tiocmset functions
|
||||
int msr; // MSR shadow
|
||||
int mcr; // MCR shadow
|
||||
|
||||
// for ioctl
|
||||
struct serial_struct serial;
|
||||
wait_queue_head_t wait;
|
||||
struct async_icount icount;
|
||||
} t_TTYMZ;
|
||||
|
||||
// Driver control variables.
|
||||
typedef struct {
|
||||
struct tty_driver *ttymzDriver;
|
||||
struct tty_port ttymzPort[SHARPMZ_TTY_MINORS];
|
||||
struct task_struct *arbTask;
|
||||
int32_t hotkey;
|
||||
} t_TTYMZCtrl;
|
||||
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
struct debug {
|
||||
uint8_t level;
|
||||
};
|
||||
#endif
|
||||
struct ioctlCmd {
|
||||
int32_t cmd;
|
||||
union {
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
struct debug debug;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
// Prototypes.
|
||||
|
||||
#endif
|
||||
@@ -7,9 +7,13 @@
|
||||
// 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>
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
// History: Oct 2022 v1.0 - Initial write of the z80 kernel driver software.
|
||||
// Jan 2023 v1.1 - Numerous new tries at increasing throughput to the CPLD failed.
|
||||
// Maximum read throughput of an 8bit byte due to the SSD202 GPIO
|
||||
// structure is approx 2MB/s - or 512K/s for a needed 32bit word.
|
||||
// Write is slower as you have to clock the data so sticking with SPI.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
@@ -59,7 +63,6 @@
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// 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.
|
||||
@@ -184,7 +187,7 @@ int z80io_init(void)
|
||||
inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
volatile uint8_t result = 0;
|
||||
|
||||
// Byte according to flag.
|
||||
if(dataFlag)
|
||||
@@ -199,10 +202,31 @@ inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline uint8_t z80io_PRL_Read(void)
|
||||
{
|
||||
// Locals.
|
||||
volatile uint8_t result = 0;
|
||||
volatile uint32_t b7, b6, b5, b4, b3, b2, b1, b0;
|
||||
|
||||
// Read the input registers and set value accordingly. Quicker to read registers and then apply shift/logical operators. The I/O Bus is very slow!
|
||||
b7 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_7_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_7_ADDR & 1)));
|
||||
b6 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_6_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_6_ADDR & 1)));
|
||||
b5 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_5_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_5_ADDR & 1)));
|
||||
b4 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_4_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_4_ADDR & 1)));
|
||||
b3 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_3_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_3_ADDR & 1)));
|
||||
b2 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_2_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_2_ADDR & 1)));
|
||||
b1 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_1_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_1_ADDR & 1)));
|
||||
b0 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_0_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_0_ADDR & 1)));
|
||||
result = (b7 & 0x1) << 7 | (b6 & 0x1) << 6 | (b5 & 0x1) << 5 | (b4 & 0x1) << 4 | (b3 & 0x1) << 3 | (b2 & 0x1) << 2 | (b1 & 0x1) << 1 | (b0 & 0x1);
|
||||
|
||||
// Return 16bit value read from CPLD.
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline uint16_t z80io_PRL_Read16(void)
|
||||
{
|
||||
// Locals.
|
||||
uint16_t result = 0;
|
||||
volatile uint16_t result = 0;
|
||||
|
||||
// Low byte first.
|
||||
CLEAR_CPLD_HIGH_BYTE();
|
||||
@@ -407,7 +431,7 @@ uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData)
|
||||
//--------------------------------------------------------
|
||||
// Test Methods.
|
||||
//--------------------------------------------------------
|
||||
#ifdef INCLUDE_TEST_METHODS
|
||||
#if defined(INCLUDE_TEST_METHODS) && INCLUDE_TEST_METHODS == 1
|
||||
#include "z80io_test.c"
|
||||
#else
|
||||
uint8_t z80io_Z80_TestMemory(void)
|
||||
@@ -7,9 +7,13 @@
|
||||
// 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>
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
// History: Oct 2022 v1.0 - Initial write of the z80 kernel driver software.
|
||||
// Jan 2023 v1.1 - Numerous new tries at increasing throughput to the CPLD failed.
|
||||
// Maximum read throughput of an 8bit byte due to the SSD202 GPIO
|
||||
// structure is approx 2MB/s - or 512K/s for a needed 32bit word.
|
||||
// Write is slower as you have to clock the data so sticking with SPI.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
@@ -35,7 +39,7 @@
|
||||
#endif
|
||||
|
||||
// Definitions to control compilation.
|
||||
#define INCLUDE_TEST_METHODS 1
|
||||
#define INCLUDE_TEST_METHODS 0
|
||||
|
||||
// CPLD Commands.
|
||||
#define CPLD_CMD_FETCH_ADDR 0x10
|
||||
@@ -78,6 +82,14 @@
|
||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||
#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_REFRESH 0x51
|
||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||
@@ -103,10 +115,10 @@
|
||||
#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_LTSTATE PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_BUSRQ PAD_GPIO13
|
||||
#define PAD_Z80IO_BUSACK PAD_GPIO14
|
||||
#define PAD_Z80IO_INT PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_INT PAD_PM_IRIN // IRIN
|
||||
#define PAD_Z80IO_NMI PAD_UART0_TX // GPIO48
|
||||
#define PAD_Z80IO_WAIT PAD_HSYNC_OUT // GPIO85
|
||||
#define PAD_Z80IO_RESET PAD_VSYNC_OUT // GPIO86
|
||||
@@ -127,10 +139,10 @@
|
||||
#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_LTSTATE_ADDR 0x103C30 // GPIO47
|
||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
||||
#define PAD_Z80IO_INT_ADDR 0x103C30 // GPIO47
|
||||
#define PAD_Z80IO_INT_ADDR 0xF28 // IRIN
|
||||
#define PAD_Z80IO_NMI_ADDR 0x103C32 // GPIO48
|
||||
#define PAD_Z80IO_WAIT_ADDR 0x103C80 // GPIO85
|
||||
#define PAD_Z80IO_RESET_ADDR 0x103C82 // GPIO86
|
||||
@@ -380,8 +392,10 @@
|
||||
#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_)); \
|
||||
#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 SPI_SEND_8(_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); \
|
||||
@@ -390,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_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; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
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);\
|
||||
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); \
|
||||
@@ -400,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_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); \
|
||||
#define SPI_SEND_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
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); \
|
||||
@@ -411,6 +433,62 @@
|
||||
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_P_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
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_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_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
|
||||
// read 2 byte
|
||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||
@@ -434,7 +512,7 @@
|
||||
#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 MAX_CHECK_CNT 5000
|
||||
|
||||
#define MSPI_READ_INDEX 0x0
|
||||
#define MSPI_WRITE_INDEX 0x1
|
||||
@@ -453,6 +531,7 @@ uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData);
|
||||
uint8_t z80io_PRL_Send8(uint8_t txData);
|
||||
uint8_t z680io_PRL_Send16(uint16_t txData);
|
||||
#endif
|
||||
uint8_t z80io_PRL_Read(void);
|
||||
uint8_t z80io_PRL_Read8(uint8_t dataFlag);
|
||||
uint16_t z80io_PRL_Read16(void);
|
||||
uint8_t z80io_SPI_Test(void);
|
||||
1
software/FusionX/src/z80drv/6502
vendored
Submodule
1
software/FusionX/src/z80drv/6502
vendored
Submodule
Submodule software/FusionX/src/z80drv/6502 added at 8318be6089
90
software/FusionX/src/z80drv/Makefile
vendored
Normal file
90
software/FusionX/src/z80drv/Makefile
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
#MODEL := MZ2000
|
||||
#MODEL := MZ1500
|
||||
#MODEL := MZ700
|
||||
#MODEL := MZ80A
|
||||
#MODEL := PCW8XXX
|
||||
#MODEL := PCW9XXX
|
||||
KERNEL := $(PWD)/../../../linux/kernel
|
||||
FUSIONX := $(PWD)/../..
|
||||
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__ -DTARGET_HOST_$(MODEL)=1
|
||||
CTRLINC = -IZeta/API -IZ80/API -DTARGET_HOST_$(MODEL)=1
|
||||
|
||||
obj-m += z80drv.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/mhal_gpio.o
|
||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables.o
|
||||
|
||||
|
||||
all:
|
||||
@echo "Specify target host, ie. make <host>"
|
||||
@echo "Supported hosts: MZ80A, MZ700, MZ2000, PCW8XXX, PCW9XXX"
|
||||
|
||||
MZ80A: MODEL_MZ80A
|
||||
MZ700: MODEL_MZ700
|
||||
MZ1500: MODEL_MZ1500
|
||||
MZ2000: MODEL_MZ2000
|
||||
PCW8XXX: MODEL_PCW8XXX
|
||||
PCW9XXX: MODEL_PCW9XXX
|
||||
|
||||
MODEL_MZ80A:
|
||||
$(MAKE) MODEL=MZ80A BUILD_MZ80A
|
||||
MODEL_MZ700:
|
||||
$(MAKE) MODEL=MZ700 BUILD_MZ700
|
||||
MODEL_MZ1500:
|
||||
$(MAKE) MODEL=MZ1500 BUILD_MZ1500
|
||||
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_MZ1500: sharpbiter k64fcpu kmod z80ctrl
|
||||
BUILD_MZ2000: sharpbiter k64fcpu kmod z80ctrl
|
||||
BUILD_PCW8XXX: kmod z80ctrl
|
||||
BUILD_PCW9XXX: kmod z80ctrl
|
||||
|
||||
|
||||
sharpbiter:
|
||||
@echo ""
|
||||
@echo "Build Sharp MZ Arbiter for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) src/sharpbiter.c -o sharpbiter
|
||||
|
||||
k64fcpu:
|
||||
@echo ""
|
||||
@echo "Build K64F Daemon for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) src/k64fcpu.c -o k64fcpu
|
||||
|
||||
kmod:
|
||||
@echo ""
|
||||
@echo "Build driver for host: $(MODEL)"
|
||||
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
||||
|
||||
z80ctrl:
|
||||
@echo ""
|
||||
@echo "Build z80ctrl tool for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) src/z80ctrl.c -o z80ctrl
|
||||
|
||||
install:
|
||||
@echo "Copy kernel driver..."
|
||||
@cp z80drv.ko $(FUSIONX)/modules/
|
||||
@echo "Copy z80ctrl app..."
|
||||
@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:
|
||||
make -C $(KERNEL) M=$(PWD) clean
|
||||
@rm -f sharpbiter k64fcpu z80ctrl
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
Development Cycle
|
||||
-----------------
|
||||
|
||||
To avoid changes for one host affecting another the driver is split into seperate hosts containing almost identical code.
|
||||
The idea, after development is complete, is to merge them into a single drive which autodetects, via the CPLD, the host model
|
||||
and selects the code accordingly.
|
||||
z80drv now supports several machines, ie. MZ-80A, MZ-700, MZ-2000, PCW-8256 with more in the pipeline.
|
||||
|
||||
Please edit Makefile and set the model prior to changing the Model source. In theory this file will be deleted once the source is
|
||||
merged.
|
||||
Please edit Makefile and set the model prior to changing the Model source. Alternatively, isse make with the host name, ie. make MZ80A.
|
||||
|
||||
The virtual device concept (ie. an MZ-700 with a tranZPUter SW card) has been incorporated as virtual hardware modules, ie. z80vhw_rfs.c
|
||||
which adds the RFS card to the MZ-700/MZ-80A. These virtual devices are built and added to the target kernel module dependent on supported
|
||||
host.
|
||||
|
||||
Zeta
|
||||
----
|
||||
1
software/FusionX/src/z80drv/Z80
vendored
Submodule
1
software/FusionX/src/z80drv/Z80
vendored
Submodule
Submodule software/FusionX/src/z80drv/Z80 added at ada1e2921f
1
software/FusionX/src/z80drv/software/FusionX/src/driver/6502
vendored
Submodule
1
software/FusionX/src/z80drv/software/FusionX/src/driver/6502
vendored
Submodule
Submodule software/FusionX/src/z80drv/software/FusionX/src/driver/6502 added at 8318be6089
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
2999
software/FusionX/src/z80drv/src/k64fcpu.c
Normal file
2999
software/FusionX/src/z80drv/src/k64fcpu.c
Normal file
File diff suppressed because it is too large
Load Diff
505
software/FusionX/src/z80drv/src/sharpbiter.c
Normal file
505
software/FusionX/src/z80drv/src/sharpbiter.c
Normal file
@@ -0,0 +1,505 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: sharpbiter.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Sharp Host Arbiter
|
||||
// This daemon application is responsible for switching the FusionX between modes via
|
||||
// host keyboard hotkeys. It allows the host to assume a persona based on user
|
||||
// requirements.
|
||||
// Currently, the following persona's can be invoked:
|
||||
// 1. Original host mode (ie. the host behaves as original, no extensions).
|
||||
// 2. Original + Rom Filing System. Virtual RFS is installed and the RFS monitor invoked.
|
||||
// 3. Original + TZFS. Virtual tranZPUter SW is installed and the TZFS monitor invoked.
|
||||
// 4. Linux. Host will run as a smart terminal front to the FusionX Linux OS.
|
||||
//
|
||||
// The daemon listens for signals sent by the current active process. The signal will
|
||||
// indicate required persona and this daemon will invoke it accordingly.
|
||||
//
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Feb 2023 v1.0 - Initial write.
|
||||
// Apr 2023 v1.1 - Updates to include MZ-2000.
|
||||
// Apr 2023 v1.2 - Updates to include MZ-1500.
|
||||
//
|
||||
// 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/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <ctype.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.00"
|
||||
#define AUTHOR "P.D.Smart"
|
||||
#define COPYRIGHT "(c) 2018-23"
|
||||
|
||||
// Getopt_long is buggy so we use optparse.
|
||||
#define OPTPARSE_IMPLEMENTATION
|
||||
#define OPTPARSE_API static
|
||||
#include "optparse.h"
|
||||
|
||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
||||
#define IOCTL_CMD_FETCH_HOTKEY _IOW('f', 'f', int32_t *)
|
||||
#define IOCTL_CMD_SUSPEND_IO _IOW('s', 's', int32_t *)
|
||||
#define IOCTL_CMD_RESUME_IO _IOW('r', 'r', int32_t *)
|
||||
|
||||
// Device driver name.
|
||||
#define Z80_DEVICE_FILENAME "/dev/z80drv"
|
||||
#define TTY_DEVICE_FILENAME "/dev/ttymz2" // The Sharp MZ TTY is accessed via port 2, port 0 = host tty, 1 = SSD202 framebuffer tty.
|
||||
|
||||
// Structure to maintain all the control and management variables of the arbiter.
|
||||
//
|
||||
typedef struct {
|
||||
int fdZ80; // Handle to the Z80 kernel driver.
|
||||
int fdTTY; // Handle to the TTY kernel driver.
|
||||
uint8_t hotkey; // New or last hotkey received.
|
||||
uint8_t newHotkey; // Flag to indicate a hotkey has arrived.
|
||||
uint8_t runControl; // Run control for the daemon, 1 = run, 0 = terminate.
|
||||
} t_ArbiterControl;
|
||||
|
||||
// Global scope variables.
|
||||
//
|
||||
static t_ArbiterControl arbCtrl;
|
||||
|
||||
// Shared memory between this process and the Z80 driver.
|
||||
static t_Z80Ctrl *Z80Ctrl = NULL;
|
||||
static uint8_t *Z80RAM = NULL;
|
||||
static uint8_t *Z80ROM = NULL;
|
||||
|
||||
// Millisecond delay routine.
|
||||
void delay(int ms_delay)
|
||||
{
|
||||
usleep(1000 * ms_delay);
|
||||
}
|
||||
|
||||
// Method to reset the Z80 CPU.
|
||||
//
|
||||
void reqResetZ80(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
struct ioctlCmd ioctlCmd;
|
||||
|
||||
// Send command to driver to reset Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
|
||||
// Method to start the Z80 CPU.
|
||||
//
|
||||
void startZ80(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
struct ioctlCmd ioctlCmd;
|
||||
|
||||
// Send command to driver to reset Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
|
||||
// Method to stop the Z80 CPU.
|
||||
//
|
||||
void stopZ80(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
struct ioctlCmd ioctlCmd;
|
||||
|
||||
// Send command to driver to reset Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
|
||||
// Handler for the SIGUSR1 signal used by the Z80 Driver when a hotkey is detected.
|
||||
//
|
||||
void z80Request(int signalNo)
|
||||
{
|
||||
// Locals.
|
||||
|
||||
//printf("Received SIGUSR1 from Z80 Driver\n");
|
||||
|
||||
// If an existing hotkey has not been processed, wait.
|
||||
if(arbCtrl.newHotkey)
|
||||
{
|
||||
usleep(1000);
|
||||
}
|
||||
arbCtrl.hotkey = Z80Ctrl->keyportHotKey;
|
||||
arbCtrl.newHotkey = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handler for the SIGUSR2 signal used by the TTY Driver when a hotkey is detected.
|
||||
//
|
||||
void ttyRequest(int signalNo)
|
||||
{
|
||||
// Locals.
|
||||
int32_t result;
|
||||
|
||||
//printf("Received SIGUSR2 from TTY Driver\n");
|
||||
|
||||
// Send command to TTY driver to fetch hotkey.
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_FETCH_HOTKEY, &result);
|
||||
|
||||
// If an existing hotkey has not been processed, wait.
|
||||
if(arbCtrl.newHotkey)
|
||||
{
|
||||
usleep(1000);
|
||||
}
|
||||
arbCtrl.hotkey = (uint8_t)result;
|
||||
arbCtrl.newHotkey = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handler for the HUP, INT, QUIT or TERM signals. On receipt, start a shutdown request.
|
||||
void shutdownRequest(int signalNo)
|
||||
{
|
||||
// Locals.
|
||||
|
||||
// Terminate signals flag the request by clearing runControl.
|
||||
if(signalNo == SIGHUP || signalNo == SIGINT || signalNo == SIGQUIT || signalNo == SIGTERM)
|
||||
{
|
||||
printf("Terminate request.\n");
|
||||
arbCtrl.newHotkey = 0;
|
||||
arbCtrl.runControl = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// This is a daemon process, process arguments, initialise logic and enter a loop waiting for signals to arrive.
|
||||
// The signals indicate the active process has detected a hotkey combination and this daemon needs to process it
|
||||
// to invoke the required FusionX persona.
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uint32_t hexData = 0;
|
||||
int opt = 0;
|
||||
int verboseFlag = 0;
|
||||
int32_t result;
|
||||
struct ioctlCmd ioctlCmd;
|
||||
|
||||
// Define parameters to be processed.
|
||||
struct optparse options;
|
||||
static struct optparse_long long_options[] =
|
||||
{
|
||||
{"help", 'h', OPTPARSE_NONE},
|
||||
{"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':
|
||||
sscanf(options.optarg, "0x%08x", &hexData);
|
||||
printf("Hex data:%08x\n", hexData);
|
||||
break;
|
||||
|
||||
// Verbose mode.
|
||||
case 'v':
|
||||
verboseFlag = 1;
|
||||
break;
|
||||
|
||||
// Command help needed.
|
||||
case 'h':
|
||||
showArgs(argv[0], &options);
|
||||
return(1);
|
||||
|
||||
// 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.
|
||||
arbCtrl.fdZ80 = open(Z80_DEVICE_FILENAME, O_RDWR|O_NDELAY);
|
||||
if(arbCtrl.fdZ80 >= 0)
|
||||
{
|
||||
Z80Ctrl = (t_Z80Ctrl *)mmap(0, sizeof(t_Z80Ctrl), PROT_READ | PROT_WRITE, MAP_SHARED, arbCtrl.fdZ80, 0);
|
||||
if(Z80Ctrl == (void *)-1)
|
||||
{
|
||||
printf("Failed to attach to the Z80 Control structure, cannot continue, exiting....\n");
|
||||
close(arbCtrl.fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
Z80RAM = (uint8_t *)mmap(0, Z80_VIRTUAL_RAM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, arbCtrl.fdZ80, 0);
|
||||
if(Z80RAM == (void *)-1)
|
||||
{
|
||||
printf("Failed to attach to the Z80 RAM, cannot continue, exiting....\n");
|
||||
close(arbCtrl.fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
Z80ROM = (uint8_t *)mmap(0, Z80_VIRTUAL_ROM_SIZE+0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, arbCtrl.fdZ80, 0);
|
||||
if(Z80ROM == (void *)-1)
|
||||
{
|
||||
printf("Failed to attach to the Z80 ROM, cannot continue, exitting....\n");
|
||||
close(arbCtrl.fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
{
|
||||
printf("Failed to open the Z80 Driver, exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
arbCtrl.fdTTY = open(TTY_DEVICE_FILENAME, O_RDWR|O_NDELAY);
|
||||
if(arbCtrl.fdTTY >= 0)
|
||||
{
|
||||
printf("Opened device:%s\n", TTY_DEVICE_FILENAME);
|
||||
} else
|
||||
{
|
||||
printf("Failed to open the TTY Driver, exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Register the request handler for processing signals from the z80drv driver.
|
||||
signal(SIGUSR1, z80Request);
|
||||
|
||||
// Register the request handler for processing signals from the ttymz driver.
|
||||
signal(SIGUSR2, ttyRequest);
|
||||
|
||||
// Register close down handlers.
|
||||
signal(SIGHUP, shutdownRequest);
|
||||
signal(SIGINT, shutdownRequest);
|
||||
signal(SIGQUIT, shutdownRequest);
|
||||
signal(SIGTERM, shutdownRequest);
|
||||
|
||||
// Enter a loop, process requests as the come in and terminate if requested by signals.
|
||||
arbCtrl.runControl = 1;
|
||||
while(arbCtrl.runControl)
|
||||
{
|
||||
if(arbCtrl.newHotkey)
|
||||
{
|
||||
printf("New hotkey:%02x\n", arbCtrl.hotkey);
|
||||
switch(arbCtrl.hotkey)
|
||||
{
|
||||
case HOTKEY_ORIGINAL:
|
||||
// Disable TTY I/O.
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// Stop the Z80.
|
||||
stopZ80();
|
||||
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
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_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ1500 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ1500;
|
||||
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);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
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_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
#elif(TARGET_HOST_MZ1500 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ1500;
|
||||
#elif(TARGET_HOST_MZ2000 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
#endif
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Reset and start the Z80.
|
||||
delay(500);
|
||||
reqResetZ80();
|
||||
break;
|
||||
|
||||
case HOTKEY_RFS80:
|
||||
case HOTKEY_RFS40:
|
||||
// Disable TTY I/O.
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// Stop the Z80.
|
||||
stopZ80();
|
||||
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
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_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ1500 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ1500;
|
||||
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);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Add in the required driver.
|
||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||
ioctlCmd.vdev.device = (arbCtrl.hotkey == HOTKEY_RFS80) ? VIRTUAL_DEVICE_RFS80 : VIRTUAL_DEVICE_RFS40;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Reset and start the Z80.
|
||||
delay(500);
|
||||
reqResetZ80();
|
||||
break;
|
||||
|
||||
case HOTKEY_TZFS:
|
||||
// Disable TTY I/O.
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// Stop the Z80.
|
||||
stopZ80();
|
||||
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
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_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ1500 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ1500;
|
||||
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);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Add in the required driver.
|
||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
|
||||
case HOTKEY_LINUX:
|
||||
// Stop the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
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_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ1500 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ1500;
|
||||
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);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Enable TTY I/O.
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_RESUME_IO, &result);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
arbCtrl.newHotkey = 0;
|
||||
}
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
// Unmap shared memory and close the device.
|
||||
munmap(Z80Ctrl, sizeof(t_Z80Ctrl));
|
||||
close(arbCtrl.fdZ80);
|
||||
close(arbCtrl.fdTTY);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
2375
software/FusionX/src/z80drv/src/sharpmz.c
Normal file
2375
software/FusionX/src/z80drv/src/sharpmz.c
Normal file
File diff suppressed because it is too large
Load Diff
762
software/FusionX/src/z80drv/src/tzpu.h
vendored
Executable file
762
software/FusionX/src/z80drv/src/tzpu.h
vendored
Executable file
@@ -0,0 +1,762 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: tzpu.h
|
||||
// Created: May 2020
|
||||
// Author(s): Philip Smart
|
||||
// Description: The TranZPUter library.
|
||||
// This file is copied from the original zSoft tranZPUter library header file and
|
||||
// modified for the FusionX tranZPUter SW driver. It is used by the Z80 driver and the
|
||||
// user space daemon.
|
||||
// Hardware references have been removed as the K64F is a virtual process rather
|
||||
// than a physical MPU.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: May 2020 - Initial write of the TranZPUter software.
|
||||
// Jul 2020 - Updates to accommodate v2.1 of the tranZPUter board.
|
||||
// Sep 2020 - Updates to accommodate v2.2 of the tranZPUter board.
|
||||
// May 2021 - Changes to use 512K-1Mbyte Z80 Static RAM, build time configurable.
|
||||
// Feb 2023 - Adaptation of zSoft tranzputer.h for the FusionX tranZPUter SW driver.
|
||||
//
|
||||
// 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 TZPU_H
|
||||
#define TZPU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Configurable constants.
|
||||
//
|
||||
#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 HOST_MON_TEST_VECTOR 0x4 // Address in the host monitor to test to identify host type.
|
||||
#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_MZ1500 == 1)
|
||||
#define OS_BASE_DIR "/apps/FusionX/host/MZ-1500/"
|
||||
#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 TZ_MAX_Z80_MEM 0x100000 // Maximum Z80 memory available on the tranZPUter board.
|
||||
|
||||
// tranZPUter Memory Modes - select one of the 32 possible memory models using these constants.
|
||||
//
|
||||
#define TZMM_ORIG 0x00 // Original Sharp MZ80A mode, no tranZPUter features are selected except the I/O control registers (default: 0x60-063).
|
||||
#define TZMM_BOOT 0x01 // Original mode but E800-EFFF is mapped to tranZPUter RAM so TZFS can be booted.
|
||||
#define TZMM_TZFS 0x02 // 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.
|
||||
#define TZMM_TZFS2 0x03 // 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.
|
||||
#define TZMM_TZFS3 0x04 // 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.
|
||||
#define TZMM_TZFS4 0x05 // 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.
|
||||
#define TZMM_CPM 0x06 // 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.
|
||||
#define TZMM_CPM2 0x07 // 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, F3C0:F3FF & F7C0:F7FF (floppy disk paging vectors) which resides on the mainboard.
|
||||
#define TZMM_COMPAT 0x08 // Original mode but with main DRAM in Bank 0 to allow bootstrapping of programs from other machines such as the MZ700.
|
||||
#define TZMM_HOSTACCESS 0x09 // Mode to allow code running in Bank 0, address E800:FFFF to access host memory. 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.
|
||||
#define TZMM_MZ700_0 0x0a // 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.
|
||||
#define TZMM_MZ700_1 0x0b // 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.
|
||||
#define TZMM_MZ700_2 0x0c // 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.
|
||||
#define TZMM_MZ700_3 0x0d // 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.
|
||||
#define TZMM_MZ700_4 0x0e // 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.
|
||||
#define TZMM_MZ800 0x0f // MZ800 Mode - Host is an MZ-800 and mode provides for MZ-700/MZ-800 decoding per original machine.
|
||||
#define TZMM_MZ2000 0x10 // MZ2000 Mode - Running on MZ2000 hardware, configuration set according to runtime configuration registers.
|
||||
#define TZMM_FPGA 0x15 // Open up access for the K64F to the FPGA resources such as memory. All other access to RAM or mainboard is blocked.
|
||||
#define TZMM_TZPUM 0x16 // Everything is on mainboard, no access to tranZPUter memory.
|
||||
#define TZMM_TZPU 0x17 // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory. K64F drives A18-A16 allowing full access to RAM.
|
||||
//#define TZMM_TZPU0 0x18 // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
//#define TZMM_TZPU1 0x19 // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 1 is selected.
|
||||
//#define TZMM_TZPU2 0x1A // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 2 is selected.
|
||||
//#define TZMM_TZPU3 0x1B // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 3 is selected.
|
||||
//#define TZMM_TZPU4 0x1C // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 4 is selected.
|
||||
//#define TZMM_TZPU5 0x1D // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 5 is selected.
|
||||
//#define TZMM_TZPU6 0x1E // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 6 is selected.
|
||||
//#define TZMM_TZPU7 0x1F // Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 7 is selected.
|
||||
|
||||
// IO addresses on the tranZPUter or mainboard.
|
||||
//
|
||||
#define IO_TZ_CTRLLATCH 0x60 // Control latch which specifies the Memory Model/mode.
|
||||
#define IO_TZ_SETXMHZ 0x62 // Switch to alternate CPU frequency provided by K64F.
|
||||
#define IO_TZ_SET2MHZ 0x64 // Switch to system CPU frequency.
|
||||
#define IO_TZ_CLKSELRD 0x66 // Read the status of the clock select, ie. which clock is connected to the CPU.
|
||||
#define IO_TZ_SVCREQ 0x68 // Service request from the Z80 to be provided by the K64F.
|
||||
#define IO_TZ_SYSREQ 0x6A // System request from the Z80 to be provided by the K64F.
|
||||
#define IO_TZ_CPLDCMD 0x6B // Version 2.1 CPLD command register.
|
||||
#define IO_TZ_CPLDSTATUS 0x6B // Version 2.1 CPLD status register.
|
||||
#define IO_TZ_CPUCFG 0x6C // Version 2.2 CPU configuration register.
|
||||
#define IO_TZ_CPUSTATUS 0x6C // Version 2.2 CPU runtime status register.
|
||||
#define IO_TZ_CPUINFO 0x6D // Version 2.2 CPU information register.
|
||||
#define IO_TZ_CPLDCFG 0x6E // Version 2.1 CPLD configuration register.
|
||||
#define IO_TZ_CPLDINFO 0x6F // Version 2.1 CPLD version information register.
|
||||
#define IO_TZ_PALSLCTOFF 0xA3 // set the palette slot Off position to be adjusted.
|
||||
#define IO_TZ_PALSLCTON 0xA4 // set the palette slot On position to be adjusted.
|
||||
#define IO_TZ_PALSETRED 0xA5 // set the red palette value according to the PALETTE_PARAM_SEL address.
|
||||
#define IO_TZ_PALSETGREEN 0xA6 // set the green palette value according to the PALETTE_PARAM_SEL address.
|
||||
#define IO_TZ_PALSETBLUE 0xA7 // set the blue palette value according to the PALETTE_PARAM_SEL address.
|
||||
#define IO_TZ_OSDMNU_SZX 0xA8 // Get OSD Menu Horizontal Size (X).
|
||||
#define IO_TZ_OSDMNU_SZY 0xA9 // Get OSD Menu Vertical Size (Y).
|
||||
#define IO_TZ_OSDHDR_SZX 0xAA // Get OSD Status Header Horizontal Size (X).
|
||||
#define IO_TZ_OSDHDR_SZY 0xAB // Get OSD Status Header Vertical Size (Y).
|
||||
#define IO_TZ_OSDFTR_SZX 0xAC // Get OSD Status Footer Horizontal Size (X).
|
||||
#define IO_TZ_OSDFTR_SZY 0xAD // Get OSD Status Footer Vertical Size (Y).
|
||||
#define IO_TZ_PALETTE 0xB0 // Sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output.
|
||||
// Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input.
|
||||
#define IO_TZ_GPUPARAM 0xB2 // Set parameters. Store parameters in a long word to be used by the graphics command processor.
|
||||
// The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0.
|
||||
#define IO_TZ_GPUCMD 0xB3 // Set the graphics processor unit commands.
|
||||
// Bits [5:0] - 0 = Reset parameters.
|
||||
// 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter
|
||||
#define IO_TZ_VMCTRL 0xB8 // Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col.
|
||||
#define IO_TZ_VMGRMODE 0xB9 // Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used).
|
||||
#define IO_TZ_VMREDMASK 0xBA // Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
#define IO_TZ_VMGREENMASK 0xBB // Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
#define IO_TZ_VMBLUEMASK 0xBC // Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
#define IO_TZ_VMPAGE 0xBD // Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF.
|
||||
#define IO_TZ_VMVGATTR 0xBE // Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue, 4:3 = VGA Mode, 00 = Off, 01 = 640x480, 10 = 800x600, 11 = 50Hz Internal
|
||||
#define IO_TZ_VMVGAMODE 0xBF // Select VGA Output mode, ie. Internal, 640x480 etc. Bits [3:0] specify required mode. Undefined default to internal standard frequency.
|
||||
#define IO_TZ_GDGWF 0xCC // MZ-800 write format register
|
||||
#define IO_TZ_GDGRF 0xCD // MZ-800 read format register
|
||||
#define IO_TZ_GDCMD 0xCE // MZ-800 CRTC Mode register
|
||||
#define IO_TZ_GDCCTRL 0xCF // MZ-800 CRTC control register
|
||||
#define IO_TZ_MMIO0 0xE0 // MZ-700/MZ-800 Memory management selection ports.
|
||||
#define IO_TZ_MMIO1 0xE1 // ""
|
||||
#define IO_TZ_MMIO2 0xE2 // ""
|
||||
#define IO_TZ_MMIO3 0xE3 // ""
|
||||
#define IO_TZ_MMIO4 0xE4 // ""
|
||||
#define IO_TZ_MMIO5 0xE5 // ""
|
||||
#define IO_TZ_MMIO6 0xE6 // ""
|
||||
#define IO_TZ_MMIO7 0xE7 // MZ-700/MZ-800 Memory management selection ports.
|
||||
#define IO_TZ_PPIA 0xE0 // MZ80B/MZ2000 8255 PPI Port A
|
||||
#define IO_TZ_PPIB 0xE1 // MZ80B/MZ2000 8255 PPI Port B
|
||||
#define IO_TZ_PPIC 0xE2 // MZ80B/MZ2000 8255 PPI Port C
|
||||
#define IO_TZ_PPICTL 0xE3 // MZ80B/MZ2000 8255 PPI Control Register
|
||||
#define IO_TZ_PIT0 0xE4 // MZ80B/MZ2000 8253 PIT Timer 0
|
||||
#define IO_TZ_PIT1 0xE5 // MZ80B/MZ2000 8253 PIT Timer 1
|
||||
#define IO_TZ_PIT2 0xE6 // MZ80B/MZ2000 8253 PIT Timer 2
|
||||
#define IO_TZ_PITCTL 0xE7 // MZ80B/MZ2000 8253 PIT Control Register
|
||||
#define IO_TZ_PIOA 0xE8 // MZ80B/MZ2000 Z80 PIO Port A
|
||||
#define IO_TZ_PIOCTLA 0xE9 // MZ80B/MZ2000 Z80 PIO Port A Control Register
|
||||
#define IO_TZ_PIOB 0xEA // MZ80B/MZ2000 Z80 PIO Port B
|
||||
#define IO_TZ_PIOCTLB 0xEB // MZ80B/MZ2000 Z80 PIO Port B Control Register
|
||||
#define IO_TZ_SYSCTRL 0xF0 // System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus.
|
||||
#define IO_TZ_GRAMMODE 0xF4 // MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display.
|
||||
//#define IO_TZ_GRAMOPT 0xF4 // MZ80B/MZ2000 GRAM configuration option.
|
||||
#define IO_TZ_CRTGRPHPRIO 0xF5 // MZ2000 Graphics priority register, character or a graphics colour has front display priority.
|
||||
#define IO_TZ_CRTGRPHSEL 0xF6 // MZ2000 Graphics output select on CRT or external CRT
|
||||
#define IO_TZ_GRAMCOLRSEL 0xF7 // MZ2000 Graphics RAM colour bank select.
|
||||
|
||||
// Addresses on the tranZPUter board.
|
||||
//
|
||||
#define SRAM_BANK0_ADDR 0x00000 // Address of the 1st 64K RAM bank in the SRAM chip.
|
||||
#define SRAM_BANK1_ADDR 0x10000 // ""
|
||||
#define SRAM_BANK2_ADDR 0x20000 // ""
|
||||
#define SRAM_BANK3_ADDR 0x30000 // ""
|
||||
#define SRAM_BANK4_ADDR 0x40000 // ""
|
||||
#define SRAM_BANK5_ADDR 0x50000 // ""
|
||||
#define SRAM_BANK6_ADDR 0x60000 // ""
|
||||
#define SRAM_BANK7_ADDR 0x70000 // ""
|
||||
#define SRAM_BANK8_ADDR 0x80000 // ""
|
||||
#define SRAM_BANK9_ADDR 0x90000 // ""
|
||||
#define SRAM_BANKA_ADDR 0xA0000 // ""
|
||||
#define SRAM_BANKB_ADDR 0xB0000 // ""
|
||||
#define SRAM_BANKC_ADDR 0xC0000 // ""
|
||||
#define SRAM_BANKD_ADDR 0xD0000 // ""
|
||||
#define SRAM_BANKE_ADDR 0xE0000 // ""
|
||||
#define SRAM_BANKF_ADDR 0xF0000 // Address of the 16th 64K RAM bank in the SRAM chip.
|
||||
|
||||
// IO register constants.
|
||||
//
|
||||
#define CPUMODE_SET_Z80 0x00 // Set the CPU to the hard Z80.
|
||||
#define CPUMODE_SET_T80 0x01 // Set the CPU to the soft T80.
|
||||
#define CPUMODE_SET_ZPU_EVO 0x02 // Set the CPU to the soft ZPU Evolution.
|
||||
#define CPUMODE_SET_EMU_MZ 0x04 //
|
||||
#define CPUMODE_SET_BBB 0x08 // Place holder for a future soft CPU.
|
||||
#define CPUMODE_SET_CCC 0x10 // Place holder for a future soft CPU.
|
||||
#define CPUMODE_SET_DDD 0x20 // Place holder for a future soft CPU.
|
||||
#define CPUMODE_IS_Z80 0x00 // Status value to indicate if the hard Z80 available.
|
||||
#define CPUMODE_IS_T80 0x01 // Status value to indicate if the soft T80 available.
|
||||
#define CPUMODE_IS_ZPU_EVO 0x02 // Status value to indicate if the soft ZPU Evolution available.
|
||||
#define CPUMODE_IS_EMU_MZ 0x04 // Status value to indicate if the Sharp MZ Series Emulation is available.
|
||||
#define CPUMODE_IS_BBB 0x08 // Place holder to indicate if a future soft CPU is available.
|
||||
#define CPUMODE_IS_CCC 0x10 // Place holder to indicate if a future soft CPU is available.
|
||||
#define CPUMODE_IS_DDD 0x20 // Place holder to indicate if a future soft CPU is available.
|
||||
#define CPUMODE_CLK_EN 0x40 // Toggle the soft CPU clock, 1 = enable, 0 = disable.
|
||||
#define CPUMODE_RESET_CPU 0x80 // Reset the soft CPU. Active high, when high the CPU is held in RESET, when low the CPU runs.
|
||||
#define CPUMODE_IS_SOFT_AVAIL 0x040 // Marker to indicate if the underlying FPGA can support soft CPU's.
|
||||
#define CPUMODE_IS_SOFT_MASK 0x03F // Mask to filter out the Soft CPU availability flags.
|
||||
|
||||
// CPLD Configuration constants.
|
||||
#define HWMODE_MZ80K 0x00 // Hardware mode = MZ80K
|
||||
#define HWMODE_MZ80C 0x01 // Hardware mode = MZ80C
|
||||
#define HWMODE_MZ1500 0x02 // Hardware mode = MZ1500
|
||||
#define HWMODE_MZ80A 0x03 // Hardware mode = MZ80A
|
||||
#define HWMODE_MZ700 0x04 // Hardware mode = MZ700
|
||||
#define HWMODE_MZ800 0x05 // Hardware mode = MZ800
|
||||
#define HWMODE_MZ80B 0x06 // Hardware mode = MZ80B
|
||||
#define HWMODE_MZ2000 0x07 // Hardware mode = MZ2000
|
||||
#define MODE_VIDEO_MODULE_ENABLED 0x08 // Hardware enable (bit 3 = 1) or disable of the Video Module on the newer version, the one below will be removed.
|
||||
#define MODE_VIDEO_MODULE_DISABLED 0x00 // Hardware enable (bit 3 = 0) or disable of the Video Module.
|
||||
#define MODE_PRESERVE_CONFIG 0x80 // Preserve hardware configuration on RESET.
|
||||
#define CPLD_HAS_FPGA_VIDEO 0x00 // Flag to indicate if this device supports enhanced video.
|
||||
#define CPLD_VERSION 0x01 // Version of the CPLD which is being emulated. Version 1 was the original version.
|
||||
|
||||
// CPLD Command Instruction constants.
|
||||
#define CPLD_RESET_HOST 1 // CPLD level command to reset the host system.
|
||||
#define CPLD_HOLD_HOST_BUS 2 // CPLD command to hold the host bus.
|
||||
#define CPLD_RELEASE_HOST_BUS 3 // CPLD command to release the host bus.
|
||||
|
||||
// Video Module control bits.
|
||||
#define SYSMODE_MZ80A 0x00 // System board mode MZ80A, 2MHz CPU/Bus.
|
||||
#define SYSMODE_MZ80B 0x01 // System board mode MZ80B, 4MHz CPU/Bus.
|
||||
#define SYSMODE_MZ700 0x02 // System board mode MZ700, 3.54MHz CPU/Bus.
|
||||
#define VMMODE_MASK 0xF0 // Mask to mask out video mode.
|
||||
#define VMMODE_MZ80K 0x00 // Video mode = MZ80K
|
||||
#define VMMODE_MZ80C 0x01 // Video mode = MZ80C
|
||||
#define VMMODE_MZ1200 0x02 // Video mode = MZ1200
|
||||
#define VMMODE_MZ80A 0x03 // Video mode = MZ80A
|
||||
#define VMMODE_MZ700 0x04 // Video mode = MZ700
|
||||
#define VMMODE_MZ800 0x05 // Video mode = MZ800
|
||||
#define VMMODE_MZ1500 0x06 // Video mode = MZ1500
|
||||
#define VMMODE_MZ80B 0x07 // Video mode = MZ80B
|
||||
#define VMMODE_MZ2000 0x08 // Video mode = MZ2000
|
||||
#define VMMODE_MZ2200 0x09 // Video mode = MZ2200
|
||||
#define VMMODE_MZ2500 0x0A // Video mode = MZ2500
|
||||
#define VMMODE_80CHAR 0x10 // Enable 80 character display.
|
||||
#define VMMODE_80CHAR_MASK 0xEF // Mask to filter out display width control bit.
|
||||
#define VMMODE_COLOUR 0x20 // Enable colour display.
|
||||
#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit.
|
||||
#define VMMODE_PCGRAM 0x40 // Enable PCG RAM.
|
||||
#define VMMODE_VGA_MASK 0xF0 // Mask to filter out the VGA output mode bits.
|
||||
#define VMMODE_VGA_OFF 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
#define VMMODE_VGA_INT 0x00 // Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
#define VMMODE_VGA_INT50 0x01 // Set VGA mode off, external monitor is driven by standard internal 50Hz signals.
|
||||
#define VMMODE_VGA_640x480 0x02 // Set external monitor to VGA 640x480 @ 60Hz mode.
|
||||
#define VMMODE_VGA_800x600 0x03 // Set external monitor to VGA 800x600 @ 60Hz mode.
|
||||
|
||||
// VGA mode border control constants.
|
||||
//
|
||||
#define VMBORDER_BLACK 0x00 // VGA has a black border.
|
||||
#define VMBORDER_BLUE 0x01 // VGA has a blue border.
|
||||
#define VMBORDER_RED 0x02 // VGA has a red border.
|
||||
#define VMBORDER_PURPLE 0x03 // VGA has a purple border.
|
||||
#define VMBORDER_GREEN 0x04 // VGA has a green border.
|
||||
#define VMBORDER_CYAN 0x05 // VGA has a cyan border.
|
||||
#define VMBORDER_YELLOW 0x06 // VGA has a yellow border.
|
||||
#define VMBORDER_WHITE 0x07 // VGA has a white border.
|
||||
#define VMBORDER_MASK 0xF8 // Mask to filter out current border setting.
|
||||
|
||||
// Sharp MZ colour attributes.
|
||||
#define VMATTR_FG_BLACK 0x00 // Foreground black character attribute.
|
||||
#define VMATTR_FG_BLUE 0x10 // Foreground blue character attribute.
|
||||
#define VMATTR_FG_RED 0x20 // Foreground red character attribute.
|
||||
#define VMATTR_FG_PURPLE 0x30 // Foreground purple character attribute.
|
||||
#define VMATTR_FG_GREEN 0x40 // Foreground green character attribute.
|
||||
#define VMATTR_FG_CYAN 0x50 // Foreground cyan character attribute.
|
||||
#define VMATTR_FG_YELLOW 0x60 // Foreground yellow 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_MASKIN 0x70 // Mask to filter out foreground attribute.
|
||||
#define VMATTR_BG_BLACK 0x00 // Background black character attribute.
|
||||
#define VMATTR_BG_BLUE 0x01 // Background blue character attribute.
|
||||
#define VMATTR_BG_RED 0x02 // Background red character attribute.
|
||||
#define VMATTR_BG_PURPLE 0x03 // Background purple character attribute.
|
||||
#define VMATTR_BG_GREEN 0x04 // Background green character attribute.
|
||||
#define VMATTR_BG_CYAN 0x05 // Background cyan character attribute.
|
||||
#define VMATTR_BG_YELLOW 0x06 // Background yellow 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_MASKIN 0x07 // Mask to filter out background attribute.
|
||||
|
||||
// Sharp MZ constants.
|
||||
//
|
||||
#define MZ_MROM_ADDR 0x00000 // Monitor ROM start address.
|
||||
#define MZ_800_MROM_ADDR 0x70000 // MZ-800 Monitor ROM address.
|
||||
#define MZ_800_CGROM_ADDR 0x71000 // MZ-800 CGROM address during reset when it is loaded into the PCG.
|
||||
#define MZ_800_IPL_ADDR 0x7E000 // Address of the 9Z_504M IPL BIOS.
|
||||
#define MZ_800_IOCS_ADDR 0x7F400 // Address of the MZ-800 common IOCS bios.
|
||||
#define MZ_MROM_STACK_ADDR 0x01000 // Monitor ROM start stack address.
|
||||
#define MZ_MROM_STACK_SIZE 0x000EF // Monitor ROM stack size.
|
||||
#define MZ_UROM_ADDR 0x0E800 // User ROM start address.
|
||||
|
||||
#define MZ_FULLRAM_START_ADDR 0x01200 // Start of full memory area available for bank switching.
|
||||
#define MZ_FULLRAM_SIZE 0xD000 - 0x1200 // Size of full memory area.
|
||||
|
||||
#define MZ_BANKRAM_ADDR 0x0F000 // Floppy API address which is used in TZFS as the paged RAM for additional functionality.
|
||||
#define MZ_CMT_ADDR 0x010F0 // Address of the CMT (tape) header record.
|
||||
#define MZ_CMT_DEFAULT_LOAD_ADDR 0x01200 // The default load address for a CMT, anything below this is normally illegal.
|
||||
#define MZ_VID_RAM_ADDR 0x0D000 // Start of Video RAM
|
||||
#define MZ_VID_RAM_SIZE 2048 // Size of Video RAM.
|
||||
#define MZ_VID_MAX_COL 40 // Maximum column for the host display
|
||||
#define MZ_VID_MAX_ROW 25 // Maximum row for the host display
|
||||
#define MZ_VID_DFLT_BYTE 0x00 // Default character (SPACE) for video RAM.
|
||||
#define MZ_ATTR_RAM_ADDR 0xD800 // On machines with the upgrade, the start of the Attribute RAM.
|
||||
#define MZ_ATTR_RAM_SIZE 2048 // Size of the attribute RAM.
|
||||
#define MZ_ATTR_DFLT_BYTE 0x07 // Default colour (White on Black) for the attribute.
|
||||
#define MZ_SCROL_BASE 0xE200 // Base address of the hardware scroll registers.
|
||||
#define MZ_SCROL_END 0xE2FF // End address of the hardware scroll registers.
|
||||
#define MZ_MEMORY_SWAP 0xE00C // Address when read swaps the memory from 0000-0FFF -> C000-CFFF
|
||||
#define MZ_MEMORY_RESET 0xE010 // Address when read resets the memory to the default location 0000-0FFF.
|
||||
#define MZ_CRT_NORMAL 0xE014 // Address when read sets the CRT to normal display mode.
|
||||
#define MZ_CRT_INVERSE 0xE018 // Address when read sets the CRT to inverted display mode.
|
||||
#define MZ_80A_CPU_FREQ 2000000 // CPU Speed of the Sharp MZ-80A
|
||||
#define MZ_700_CPU_FREQ 3580000 // CPU Speed of the Sharp MZ-700
|
||||
#define MZ_80B_CPU_FREQ 4000000 // CPU Speed of the Sharp MZ-80B
|
||||
#define MZ_2000_CPU_FREQ 4000000 // CPU Speed of the Sharp MZ-2000
|
||||
#define MZ_800_CPU_FREQ 3580000 // CPU Speed of the Sharp MZ-800
|
||||
|
||||
// Service request constants.
|
||||
//
|
||||
#if (TARGET_HOST_MZ2000 == 1)
|
||||
#define TZSVC_CMD_STRUCT_ADDR_TZFS 0x06D80 // Address of the command structure within MZ-2000 IPL Mode
|
||||
#else
|
||||
#define TZSVC_CMD_STRUCT_ADDR_TZFS 0x0ED80 // Address of the command structure within TZFS - exists in 64K Block 0.
|
||||
#endif
|
||||
#define TZSVC_CMD_STRUCT_ADDR_CPM 0x4F560 // Address of the command structure within CP/M - exists in 64K Block 4.
|
||||
#define TZSVC_CMD_STRUCT_ADDR_MZ700 0x6FD80 // Address of the command structure within MZ700 compatible programs - exists in 64K Block 6.
|
||||
#define TZSVC_CMD_STRUCT_ADDR_ZOS 0x11FD80 // 0x7FD80 // Address of the command structure for zOS use, exists in shared memory rather than FPGA. Spans top of block 6 and all of block 7.
|
||||
#define TZSVC_CMD_STRUCT_ADDR_MZ2000_NST 0x6FD80 // Address of the command structure within MZ2000 compatible programs during normal state - exists in 64K Block 1.
|
||||
#define TZSVC_CMD_STRUCT_ADDR_MZ2000_IPL 0x07D80 // Address of the command structure within MZ2000 compatible programs during IPL state - exists in 64K Block 0.
|
||||
#define TZSVC_CMD_STRUCT_SIZE 0x280 // Size of the inter z80/K64 service command memory.
|
||||
#define TZSVC_CMD_SIZE (sizeof(t_svcControl)-TZSVC_SECTOR_SIZE)
|
||||
#define TZVC_MAX_CMPCT_DIRENT_BLOCK TZSVC_SECTOR_SIZE/TZSVC_CMPHDR_SIZE // Maximum number of directory entries per sector.
|
||||
#define TZSVC_MAX_DIR_ENTRIES 255 // Maximum number of files in one directory, any more than this will be ignored.
|
||||
#define TZSVC_CMPHDR_SIZE 32 // Compacted header size, contains everything except the comment field, padded out to 32bytes.
|
||||
#define MZF_FILLER_LEN 8 // Filler to pad a compacted header entry to a power of 2 length.
|
||||
#define TZVC_MAX_DIRENT_BLOCK TZSVC_SECTOR_SIZE/MZF_HEADER_SIZE // Maximum number of directory entries per sector.
|
||||
#define TZSVC_CMD_READDIR 0x01 // Service command to open a directory and return the first block of entries.
|
||||
#define TZSVC_CMD_NEXTDIR 0x02 // Service command to return the next block of an open directory.
|
||||
#define TZSVC_CMD_READFILE 0x03 // Service command to open a file and return the first block.
|
||||
#define TZSVC_CMD_NEXTREADFILE 0x04 // Service command to return the next block of an open file.
|
||||
#define TZSVC_CMD_WRITEFILE 0x05 // Service command to create a file and save the first block.
|
||||
#define TZSVC_CMD_NEXTWRITEFILE 0x06 // Service command to write the next block to the open file.
|
||||
#define TZSVC_CMD_CLOSE 0x07 // Service command to close any open file or directory.
|
||||
#define TZSVC_CMD_LOADFILE 0x08 // Service command to load a file directly into tranZPUter memory.
|
||||
#define TZSVC_CMD_SAVEFILE 0x09 // Service command to save a file directly from tranZPUter memory.
|
||||
#define TZSVC_CMD_ERASEFILE 0x0a // Service command to erase a file on the SD card.
|
||||
#define TZSVC_CMD_CHANGEDIR 0x0b // Service command to change active directory on the SD card.
|
||||
#define TZSVC_CMD_LOAD40ABIOS 0x20 // Service command requesting that the 40 column version of the SA1510 BIOS is loaded.
|
||||
#define TZSVC_CMD_LOAD80ABIOS 0x21 // Service command requesting that the 80 column version of the SA1510 BIOS is loaded.
|
||||
#define TZSVC_CMD_LOAD700BIOS40 0x22 // Service command requesting that the MZ700 1Z-013A 40 column BIOS is loaded.
|
||||
#define TZSVC_CMD_LOAD700BIOS80 0x23 // Service command requesting that the MZ700 1Z-013A 80 column patched BIOS is loaded.
|
||||
#define TZSVC_CMD_LOAD80BIPL 0x24 // Service command requesting the MZ-80B IPL is loaded.
|
||||
#define TZSVC_CMD_LOAD800BIOS 0x25 // Service command requesting that the MZ800 9Z-504M BIOS is loaded.
|
||||
#define TZSVC_CMD_LOAD2KIPL 0x26 // Service command requesting the MZ-2000 IPL is loaded.
|
||||
#define TZSVC_CMD_LOAD2KBASIC1 0x27 // Service command to load BASIC 1Z-001 for the MZ-2000.
|
||||
#define TZSVC_CMD_LOAD2KBASIC2 0x28 // Service command to load BASIC 1Z-002 for the MZ-2000.
|
||||
#define TZSVC_CMD_LOAD2KMON 0x29 // Service command to load Monitor 1Z001M for the MZ-2000 IPL.
|
||||
#define TZSVC_CMD_LOADTZFS 0x2F // Service command requesting the loading of TZFS. This service is for machines which normally dont have a monitor BIOS. ie. MZ-80B/MZ-2000 and manually request TZFS.
|
||||
#define TZSVC_CMD_LOADBDOS 0x30 // Service command to reload CPM BDOS+CCP.
|
||||
#define TZSVC_CMD_ADDSDDRIVE 0x31 // Service command to attach a CPM disk to a drive number.
|
||||
#define TZSVC_CMD_READSDDRIVE 0x32 // Service command to read an attached SD file as a CPM disk drive.
|
||||
#define TZSVC_CMD_WRITESDDRIVE 0x33 // Service command to write to a CPM disk drive which is an attached SD file.
|
||||
#define TZSVC_CMD_CPU_BASEFREQ 0x40 // Service command to switch to the mainboard frequency.
|
||||
#define TZSVC_CMD_CPU_ALTFREQ 0x41 // Service command to switch to the alternate frequency provided by the K64F.
|
||||
#define TZSVC_CMD_CPU_CHGFREQ 0x42 // Service command to set the alternate frequency in hertz.
|
||||
#define TZSVC_CMD_CPU_SETZ80 0x50 // Service command to switch to the external Z80 hard cpu.
|
||||
#define TZSVC_CMD_CPU_SETT80 0x51 // Service command to switch to the internal T80 soft cpu.
|
||||
#define TZSVC_CMD_CPU_SETZPUEVO 0x52 // Service command to switch to the internal ZPU Evolution cpu.
|
||||
#define TZSVC_CMD_EMU_SETMZ80K 0x53 // Service command to switch to the internal Sharp MZ Series Emulation of the MZ80K.
|
||||
#define TZSVC_CMD_EMU_SETMZ80C 0x54 // "" "" "" MZ80C.
|
||||
#define TZSVC_CMD_EMU_SETMZ1200 0x55 // "" "" "" MZ1200.
|
||||
#define TZSVC_CMD_EMU_SETMZ80A 0x56 // "" "" "" MZ80A.
|
||||
#define TZSVC_CMD_EMU_SETMZ700 0x57 // "" "" "" MZ700.
|
||||
#define TZSVC_CMD_EMU_SETMZ800 0x58 // "" "" "" MZ800.
|
||||
#define TZSVC_CMD_EMU_SETMZ1500 0x59 // "" "" "" MZ1500.
|
||||
#define TZSVC_CMD_EMU_SETMZ80B 0x5A // "" "" "" MZ80B.
|
||||
#define TZSVC_CMD_EMU_SETMZ2000 0x5B // "" "" "" MZ2000.
|
||||
#define TZSVC_CMD_EMU_SETMZ2200 0x5C // "" "" "" MZ2200.
|
||||
#define TZSVC_CMD_EMU_SETMZ2500 0x5D // "" "" "" MZ2500.
|
||||
#define TZSVC_CMD_SD_DISKINIT 0x60 // Service command to initialise and provide raw access to the underlying SD card.
|
||||
#define TZSVC_CMD_SD_READSECTOR 0x61 // Service command to provide raw read access to the underlying SD card.
|
||||
#define TZSVC_CMD_SD_WRITESECTOR 0x62 // Service command to provide raw write access to the underlying SD card.
|
||||
#define TZSVC_CMD_EXIT 0x7F // Service command to terminate TZFS and restart the machine in original mode.
|
||||
#define TZSVC_DEFAULT_TZFS_DIR "TZFS" // Default directory where TZFS files are stored.
|
||||
#define TZSVC_DEFAULT_ROM_DIR "ROMS" // Default directory where ROM files are stored.
|
||||
#define TZSVC_DEFAULT_CPM_DIR "CPM" // Default directory where CPM files are stored.
|
||||
#define TZSVC_DEFAULT_MZF_DIR "MZF" // Default directory where MZF files are stored.
|
||||
#define TZSVC_DEFAULT_CAS_DIR "CAS" // Default directory where BASIC CASsette files are stored.
|
||||
#define TZSVC_DEFAULT_BAS_DIR "BAS" // Default directory where BASIC text files are stored.
|
||||
#define TZSVC_DEFAULT_MZF_EXT "MZF" // Default file extension for MZF files.
|
||||
#define TZSVC_DEFAULT_CAS_EXT "CAS" // Default file extension for CASsette files.
|
||||
#define TZSVC_DEFAULT_BAS_EXT "BAS" // Default file extension for BASic script files stored in readable text.
|
||||
#define TZSVC_DEFAULT_WILDCARD "*" // Default wildcard file matching.
|
||||
#define TZSVC_RESULT_OFFSET 0x01 // Offset into structure of the result byte.
|
||||
#define TZSVC_DIRNAME_SIZE 20 // Limit is size of FAT32 directory name.
|
||||
#define TZSVC_WILDCARD_SIZE 20 // Very basic pattern matching so small size.
|
||||
#define TZSVC_FILENAME_SIZE MZF_FILENAME_LEN // Length of a Sharp MZF filename.
|
||||
#define TZSVC_LONG_FNAME_SIZE (sizeof(t_svcCmpDirEnt) - 1) // Length of a standard filename to fit inside a directory entry.
|
||||
#define TZSVC_LONG_FMT_FNAME_SIZE 20 // Length of a standard filename formatted in a directory listing.
|
||||
#define TZSVC_SECTOR_SIZE 512 // SD Card sector buffer size.
|
||||
#define TZSVC_STATUS_OK 0x00 // Flag to indicate the K64F processing completed successfully.
|
||||
#define TZSVC_STATUS_FILE_ERROR 0x01 // Flag to indicate a file or directory error.
|
||||
#define TZSVC_STATUS_BAD_CMD 0x02 // Flag to indicate a bad service command was requested.
|
||||
#define TZSVC_STATUS_BAD_REQ 0x03 // Flag to indicate a bad request was made, the service status request flag was not set.
|
||||
#define TZSVC_STATUS_REQUEST 0xFE // Flag to indicate Z80 has posted a request.
|
||||
#define TZSVC_STATUS_PROCESSING 0xFF // Flag to indicate the K64F is processing a command.
|
||||
#define TZSVC_OPEN 0x00 // Service request to open a directory or file.
|
||||
#define TZSVC_NEXT 0x01 // Service request to return the next directory block or file block or write the next file block.
|
||||
#define TZSVC_CLOSE 0x02 // Service request to close open dir/file.
|
||||
|
||||
// ROM file paths.
|
||||
#define MZ_ROM_SP1002 "SP1002.rom" // Original MZ-80K ROM
|
||||
#define MZ_ROM_SA1510_40C "SA1510.rom" // Original 40 character Monitor ROM.
|
||||
#define MZ_ROM_SA1510_80C "SA1510-8.rom" // Original Monitor ROM patched for 80 character screen mode.
|
||||
#define MZ_ROM_1Z_013A_40C "1Z-013A.rom" // Original 40 character Monitor ROM for the Sharp MZ700.
|
||||
#define MZ_ROM_1Z_013A_80C "1Z-013A-8.rom" // Original Monitor ROM patched for the Sharp MZ700 patched for 80 column mode.
|
||||
#define MZ_ROM_1Z_013A_KM_40C "1Z-013A-KM.rom" // Original 40 character Monitor ROM for the Sharp MZ700 with keyboard remapped for the MZ80A.
|
||||
#define MZ_ROM_1Z_013A_KM_80C "1Z-013A-KM-8.rom" // Original Monitor ROM patched for the Sharp MZ700 with keyboard remapped for the MZ80A and patched for 80 column mode.
|
||||
#define MZ_ROM_1Z_013A_2000 "1Z-013A-2000.rom" // Original 40 character Monitor ROM for the Sharp MZ700 modified to run on an MZ-2000.
|
||||
#define MZ_ROM_1Z_009B_40C "1Z-009B.rom" // Original 40 character MZ-1500 Monitor ROM.
|
||||
#define MZ_ROM_9Z_504M_COMBINED "MZ800_IPL.rom" // Original MZ-800 BIOS which comprises the 1Z_013B BIOS, 9Z_504M IPL, CGROM and IOCS.
|
||||
#define MZ_ROM_9Z_504M "MZ800_9Z_504M.rom" // Modified MZ-800 9Z_504M IPL to contain a select TZFS option.
|
||||
#define MZ_ROM_1Z_013B "MZ800_1Z_013B.rom" // Original MZ-800 1Z_013B MZ-700 compatible BIOS.
|
||||
#define MZ_ROM_800_CGROM "MZ800_CGROM.ori" // Original MZ-800 Character Generator ROM.
|
||||
#define MZ_ROM_800_IOCS "MZ800_IOCS.rom" // Original MZ-800 common IOCS bios.
|
||||
#define MZ_ROM_MZ80B_IPL "MZ80B_IPL.rom" // Original IPL ROM for the Sharp MZ-80B.
|
||||
#define MZ_ROM_MZ2000_IPL "MZ2000_IPL.rom" // Original IPL ROM for the Sharp MZ-2000.
|
||||
#define MZ_ROM_MZ2000_IPL_TZPU "MZ2000_IPL_TZPU.rom" // Modified IPL ROM for the tranZPUter running on the Sharp MZ-2000.
|
||||
#define MZ_ROM_MZ2000_CGROM "MZ2000_CGROM.rom" // MZ-2000 CGROM.
|
||||
#define MZ_ROM_TZFS "tzfs.rom" // tranZPUter Filing System ROM.
|
||||
#define MZ_ROM_MZ2000_1Z001 "mz2000_basic_1z001.rom" // MZ-2000 BASIC 1Z-001.
|
||||
#define MZ_ROM_MZ2000_1Z002 "mz2000_basic_1z002.rom" // MZ-2000 BASIC 1Z-002.
|
||||
#define MZ_ROM_MZ2000_1Z001M "mz2000_mon_1z001m.rom" // MZ-2000 BASIC 1Z-002.
|
||||
|
||||
// CP/M constants.
|
||||
//
|
||||
#define CPM_MAX_DRIVES 16 // Maximum number of drives in CP/M.
|
||||
#define CPM_SD_DRIVES_DIR TZSVC_DEFAULT_CPM_DIR "/SDC16M/RAW" // Default directory where CPM SD disk drive images are stored.
|
||||
#define CPM_DRIVE_TMPL "CPMDSK%02u.RAW" // Template for CPM disk drives stored on the SD card.
|
||||
#define CPM_SECTORS_PER_TRACK 32 // Number of sectors in a track on the virtual CPM disk.
|
||||
#define CPM_TRACKS_PER_DISK 1024 // Number of tracks on a disk.
|
||||
|
||||
|
||||
// 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.
|
||||
|
||||
// Constants for other handled file formats.
|
||||
//
|
||||
#define CAS_HEADER_SIZE 256 // Size of the CASsette header.
|
||||
|
||||
// Possible targets the K64F can read from/write to.
|
||||
enum TARGETS {
|
||||
MAINBOARD = 0,
|
||||
TRANZPUTER = 1
|
||||
};
|
||||
|
||||
// Possible machine hardware types the tranZPUter is functioning within.
|
||||
//
|
||||
enum MACHINE_HW_TYPES {
|
||||
HW_MZ80K = HWMODE_MZ80K, // Host hardware = MZ-80K.
|
||||
HW_MZ80C = HWMODE_MZ80C, // Host hardware = MZ-80C.
|
||||
HW_MZ1500 = HWMODE_MZ1500, // Host hardware = MZ-1500.
|
||||
HW_MZ80A = HWMODE_MZ80A, // Host hardware = MZ-80A.
|
||||
HW_MZ700 = HWMODE_MZ700, // Host hardware = MZ-700.
|
||||
HW_MZ800 = HWMODE_MZ800, // Host hardware = MZ-800.
|
||||
HW_MZ80B = HWMODE_MZ80B, // Host hardware = MZ-80B.
|
||||
HW_MZ2000 = HWMODE_MZ2000, // Host hardware = MZ-2000.
|
||||
HW_UNKNOWN = 0xFF // Host hardware unknown, fault or CPLD misconfiguration.
|
||||
};
|
||||
|
||||
// Groups to which the machines belong. This is a lineage route of the Sharp machines.
|
||||
//
|
||||
enum MACHINE_GROUP {
|
||||
GROUP_MZ80K = 0, // Machines in the MZ80K group, ie. MZ80K/C/1200/80A
|
||||
GROUP_MZ700 = 1, // Machines in the MZ700 group, ie. MZ700/800/1500
|
||||
GROUP_MZ80B = 2 // Machines in the MZ80B group, ie. MZ80B/2000/2200/2500
|
||||
};
|
||||
|
||||
// Types of file which have handlers and can be processed.
|
||||
//
|
||||
enum FILE_TYPE {
|
||||
MZF = 0, // Sharp MZF tape image files.
|
||||
MZFHDR = 1, // Sharp MZF Header from file only.
|
||||
CAS = 2, // BASIC CASsette image files.
|
||||
BAS = 3, // BASic ASCII text script files.
|
||||
|
||||
ALL = 10, // All files to be considered.
|
||||
ALLFMT = 11 // Special case for directory listings, all files but truncated and formatted.
|
||||
};
|
||||
|
||||
// File function return code (FRESULT) - From FatFS.
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
// Following are only required for the user space daemon which emulates the Cortex-M4 on the tranZPUter SW
|
||||
#ifndef __KERNEL_DRIVER__
|
||||
|
||||
// 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;
|
||||
|
||||
// Structure to define a compacted Sharp MZ80A MZF directory structure (no comment) for use in directory listings.
|
||||
// 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 filler[MZF_FILLER_LEN]; // Filler to pad to a power of 2 length.
|
||||
} t_svcCmpDirEnt;
|
||||
|
||||
// Structure to hold the map betwen an SD filename and the Sharp file it contains. The file is an MZF format file with a 128 byte header
|
||||
// and this header contains the name understood on the Sharp MZ80A.
|
||||
//
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8_t *sdFileName; // Name of file on the SD card.
|
||||
t_svcCmpDirEnt mzfHeader; // Compact Sharp header data of this file.
|
||||
} t_sharpToSDMap;
|
||||
|
||||
// Structure to define the control information for a CP/M disk drive.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t *fileName; // FQFN of the CPM disk image file.
|
||||
uint32_t lastTrack; // Track of last successful operation.
|
||||
uint32_t lastSector; // Sector of last successful operation.
|
||||
FILE *File; // Opened file handle of the CPM disk image.
|
||||
} t_cpmDrive;
|
||||
|
||||
// Structure to define which CP/M drives are added to the system, mapping a number from CP/M into a record containing the details of the file on the SD card.
|
||||
//
|
||||
typedef struct {
|
||||
t_cpmDrive *drive[CPM_MAX_DRIVES]; // 1:1 map of CP/M drive number to an actual file on the SD card.
|
||||
} t_cpmDriveMap;
|
||||
|
||||
// Structure to hold a map of an entire directory of files on the SD card and their associated Sharp MZ0A filename.
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8_t valid; // Is this mapping valid?
|
||||
uint8_t entries; // Number of entries in cache.
|
||||
uint8_t type; // Type of file being cached.
|
||||
char directory[TZSVC_DIRNAME_SIZE]; // Directory this mapping is associated with.
|
||||
union {
|
||||
t_sharpToSDMap *mzfFile[TZSVC_MAX_DIR_ENTRIES]; // File mapping of SD file to its Sharp MZ80A name.
|
||||
uint8_t *sdFileName[TZSVC_MAX_DIR_ENTRIES]; // No mapping for SD filenames, just the file name.
|
||||
};
|
||||
} t_dirMap;
|
||||
|
||||
// Structure to maintain all MZ700 hardware control information in order to emulate the machine.
|
||||
//
|
||||
typedef struct {
|
||||
uint32_t config; // Compacted control register, 31:19 = reserved, 18 = Inhibit mode, 17 = Upper D000:FFFF is RAM (=1), 16 = Lower 0000:0FFF is RAM (=1), 15:8 = old memory mode, 7:0 = current memory mode.
|
||||
//uint8_t memoryMode; // The memory mode the MZ700 is currently running under, this is determined by the memory control commands from the MZ700.
|
||||
//uint8_t lockMemoryMode; // The preserved memory mode when entering the locked state.
|
||||
//uint8_t inhibit; // The inhibit flag, blocks the upper 0xD000:0xFFFF region from being accessed, affects the memoryMode temporarily.
|
||||
//uint8_t update; // Update flag, indicates to the ISR that a memory mode update is needed.
|
||||
//uint8_t b0000; // Block 0000:0FFF mode.
|
||||
//uint8_t bD000; // Block D000:FFFF mode.
|
||||
} t_mz700;
|
||||
|
||||
// Structure to maintain all MZ-80B hardware control information in order to emulate the machine as near as possible.
|
||||
typedef struct {
|
||||
uint32_t config; // Compacted control register, 31:19 = reserved, 18 = Inhibit mode, 17 = Upper D000:FFFF is RAM (=1), 16 = Lower 0000:0FFF is RAM (=1), 15:8 = old memory mode, 7:0 = current memory mode.
|
||||
} t_mz80b;
|
||||
|
||||
// Structure to maintain all the control and management variables of the Z80 and underlying hardware so that the state of run is well known by any called method.
|
||||
//
|
||||
typedef struct {
|
||||
#if !defined(__APP__) || defined(__TZFLUPD__)
|
||||
uint32_t svcControlAddr; // Address of the service control record within the Z80 static RAM bank.
|
||||
uint8_t refreshAddr; // Refresh address for times when the K64F must issue refresh cycles on the Z80 bus.
|
||||
uint8_t disableRefresh; // Disable refresh if the mainboard DRAM isnt being used.
|
||||
|
||||
enum MACHINE_HW_TYPES hostType; // The underlying host machine, 0 = Sharp MZ-80A, 1 = MZ-700, 2 = MZ-80B
|
||||
uint8_t iplMode; // Flag to indicate if the host is in IPL (boot) or run mode. Applicable on the MZ-2000/MZ-80B only.
|
||||
uint8_t blockResetActions; // Flag to request reset actions are blocked on the next detected reset. This is useful on startup or when loading a monitor ROM set different to the default.
|
||||
t_mz700 mz700; // MZ700 emulation control to detect IO commands and adjust the memory map accordingly.
|
||||
t_mz80b mz80b; // MZ-80B emulation control to detect IO commands and adjust the memory map and I/O forwarding accordingly.
|
||||
|
||||
uint8_t resetEvent; // A Z80_RESET event occurred, probably user pressing RESET button.
|
||||
uint32_t freqMultiplier; // Multipler to be applied to CPU frequency.
|
||||
int fdZ80; // Handle to the Z80 kernel.
|
||||
#endif
|
||||
} t_z80Control;
|
||||
|
||||
// Structure to maintain higher level OS control and management variables typically used for TZFS and CPM.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t tzAutoBoot; // Autoboot the tranZPUter into TZFS mode.
|
||||
t_dirMap dirMap; // Directory map of SD filenames to Sharp MZ80A filenames.
|
||||
t_cpmDriveMap cpmDriveMap; // Map of file number to an open SD disk file to be used as a CPM drive.
|
||||
uint8_t *lastFile; // Last file loaded - typically used for CPM to reload itself.
|
||||
} t_osControl;
|
||||
|
||||
// Structure to contain inter CPU communications memory for command service processing and results.
|
||||
// Typically the z80 places a command into the structure in it's memory space and asserts an I/O request,
|
||||
// the K64F detects the request and reads the lower portion of the struct from z80 memory space,
|
||||
// determines the command and then either reads the remainder or writes to the remainder. This struct
|
||||
// exists in both the z80 and K64F domains and data is sync'd between them as needed.
|
||||
//
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8_t cmd; // Command request.
|
||||
uint8_t result; // Result code. 0xFE - set by Z80, command available, 0xFE - set by K64F, command ack and processing. 0x00-0xF0 = cmd complete and result of processing.
|
||||
union {
|
||||
uint8_t dirSector; // Virtual directory sector number.
|
||||
uint8_t fileSector; // Sector within open file to read/write.
|
||||
uint8_t vDriveNo; // Virtual or physical SD card drive number.
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
uint16_t trackNo; // For virtual drives with track and sector this is the track number
|
||||
uint16_t sectorNo; // For virtual drives with track and sector this is the sector number. NB For LBA access, this is 32bit and overwrites fileNo/fileType which arent used during raw SD access.
|
||||
};
|
||||
uint32_t sectorLBA; // For LBA access, this is 32bit and used during raw SD access.
|
||||
struct {
|
||||
uint8_t memTarget; // Target memory for operation, 0 = tranZPUter, 1 = mainboard.
|
||||
uint8_t spare1; // Unused variable.
|
||||
uint16_t spare2; // Unused variable.
|
||||
};
|
||||
};
|
||||
uint8_t fileNo; // File number of a file within the last directory listing to open/update.
|
||||
uint8_t fileType; // Type of file being processed.
|
||||
union {
|
||||
uint16_t loadAddr; // Load address for ROM/File images which need to be dynamic.
|
||||
uint16_t saveAddr; // Save address for ROM/File images which need to be dynamic.
|
||||
uint16_t cpuFreq; // CPU Frequency in KHz - used for setting of the alternate CPU clock frequency.
|
||||
};
|
||||
union {
|
||||
uint16_t loadSize; // Size for ROM/File to be loaded.
|
||||
uint16_t saveSize; // Size for ROM/File to be saved.
|
||||
};
|
||||
uint8_t directory[TZSVC_DIRNAME_SIZE]; // Directory in which to look for a file. If no directory is given default to MZF.
|
||||
uint8_t filename[TZSVC_FILENAME_SIZE]; // File to open or create.
|
||||
uint8_t wildcard[TZSVC_WILDCARD_SIZE]; // A basic wildcard pattern match filter to be applied to a directory search.
|
||||
uint8_t sector[TZSVC_SECTOR_SIZE]; // Sector buffer generally for disk read/write.
|
||||
} t_svcControl;
|
||||
|
||||
// Structure to define all the directory entries which are packed into a single SD sector which is used between the Z80<->K64F.
|
||||
//
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
t_svcDirEnt dirEnt[TZVC_MAX_DIRENT_BLOCK]; // Fixed number of directory entries per sector/block.
|
||||
} t_svcDirBlock;
|
||||
|
||||
// Structure to hold compacted directory entries which are packed into a single SD sector which is used between the Z80<->K64F.
|
||||
//
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
t_svcCmpDirEnt dirEnt[TZVC_MAX_CMPCT_DIRENT_BLOCK];// Fixed number of compacted directory entries per sector/block.
|
||||
} t_svcCmpDirBlock;
|
||||
|
||||
// Mapping table from Sharp MZ80A Ascii to real Ascii.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t asciiCode;
|
||||
} t_asciiMap;
|
||||
|
||||
// Mapping table from Ascii to Sharp MZ display code.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t dispCode;
|
||||
} t_dispCodeMap;
|
||||
|
||||
// Prototypes.
|
||||
//
|
||||
void reqResetZ80(uint8_t);
|
||||
void startZ80(uint8_t memoryMode);
|
||||
void stopZ80(uint8_t memoryMode);
|
||||
uint32_t setZ80CPUFrequency(float, uint8_t);
|
||||
uint8_t copyFromZ80(uint8_t *, uint32_t, uint32_t, enum TARGETS);
|
||||
uint8_t copyToZ80(uint32_t, uint8_t *, uint32_t, enum TARGETS);
|
||||
uint8_t writeZ80Memory(uint32_t, uint8_t, enum TARGETS);
|
||||
uint8_t readZ80Memory(uint32_t);
|
||||
void fillZ80Memory(uint32_t, uint32_t, uint8_t, enum TARGETS);
|
||||
FRESULT loadZ80Memory(const char *, uint32_t, uint32_t, uint32_t, uint32_t *, enum TARGETS);
|
||||
FRESULT saveZ80Memory(const char *, uint32_t, uint32_t, t_svcDirEnt *, enum TARGETS);
|
||||
FRESULT loadMZFZ80Memory(const char *, uint32_t, uint32_t *, uint8_t, enum TARGETS);
|
||||
int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryType, uint32_t memwidth, uint32_t dispaddr, uint8_t dispwidth);
|
||||
|
||||
// Getter/Setter methods!
|
||||
void convertSharpFilenameToAscii(char *, char *, uint8_t);
|
||||
void convertToFAT32FileNameFormat(char *);
|
||||
|
||||
// tranZPUter OS i/f methods.
|
||||
uint8_t setZ80SvcStatus(uint8_t);
|
||||
void svcSetDefaults(enum FILE_TYPE);
|
||||
uint8_t svcReadDir(uint8_t, enum FILE_TYPE);
|
||||
uint8_t svcFindFile(char *, char *, uint8_t, enum FILE_TYPE);
|
||||
uint8_t svcReadDirCache(uint8_t, enum FILE_TYPE);
|
||||
uint8_t svcFindFileCache(char *, char *, uint8_t, enum FILE_TYPE);
|
||||
uint8_t svcCacheDir(const char *, enum FILE_TYPE, uint8_t);
|
||||
uint8_t svcReadFile(uint8_t, enum FILE_TYPE);
|
||||
uint8_t svcWriteFile(uint8_t, enum FILE_TYPE);
|
||||
uint8_t svcLoadFile(enum FILE_TYPE);
|
||||
uint8_t svcSaveFile(enum FILE_TYPE);
|
||||
uint8_t svcEraseFile(enum FILE_TYPE);
|
||||
uint8_t svcAddCPMDrive(void);
|
||||
uint8_t svcReadCPMDrive(void);
|
||||
uint8_t svcWriteCPMDrive(void);
|
||||
uint32_t getServiceAddr(void);
|
||||
void processServiceRequest(void);
|
||||
uint8_t loadBIOS(const char *, uint32_t);
|
||||
FRESULT loadTZFS(char *, uint32_t);
|
||||
void loadTranZPUterDefaultROMS(uint8_t);
|
||||
uint8_t testTZFSAutoBoot(void);
|
||||
|
||||
#endif // __KERNEL_DRIVER__
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // TZPU_H
|
||||
@@ -12,10 +12,12 @@
|
||||
//
|
||||
// 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
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
// (c) 1999-2023 Manuel Sainz de Baranda y Goñi
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
// History: Oct 2022 v1.0 - v1.Initial write of the z80 kernel driver software.
|
||||
// Feb 2023 v1.1 - Extended to allow Rom upload for RFS and other drivers.
|
||||
// May 2023 v1.2 - Extended to accommodate MZ-1500 host.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
@@ -53,9 +55,9 @@
|
||||
#include <Z80.h>
|
||||
#include "z80driver.h"
|
||||
|
||||
#define VERSION "1.0"
|
||||
#define VERSION "1.2"
|
||||
#define AUTHOR "P.D.Smart"
|
||||
#define COPYRIGHT "(c) 2018-22"
|
||||
#define COPYRIGHT "(c) 2018-23"
|
||||
|
||||
// Getopt_long is buggy so we use optparse.
|
||||
#define OPTPARSE_IMPLEMENTATION
|
||||
@@ -111,14 +113,23 @@ enum CTRL_COMMANDS {
|
||||
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
|
||||
Z80_CMD_ADD_DEVICE = 10,
|
||||
Z80_CMD_DEL_DEVICE = 11,
|
||||
CPLD_CMD_SEND_CMD = 12,
|
||||
CPLD_CMD_SPI_TEST = 13,
|
||||
CPLD_CMD_PRL_TEST = 14,
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
Z80_CMD_DEBUG = 15,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// Shared memory between this process and the Z80 driver.
|
||||
static t_Z80Ctrl *Z80Ctrl = NULL;
|
||||
static t_Z80Ctrl *Z80Ctrl = NULL;
|
||||
static uint8_t *Z80RAM = NULL;
|
||||
static uint8_t *Z80ROM = NULL;
|
||||
static uint32_t *Z80PAGE[MEMORY_MODES+MEMORY_SUB_MODES];
|
||||
static uint8_t memoryPage = 0;
|
||||
|
||||
// Method to obtain and return the output screen width.
|
||||
//
|
||||
@@ -187,7 +198,7 @@ void delay(int number_of_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)
|
||||
int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryType, uint32_t memwidth, uint32_t dispaddr, uint8_t dispwidth)
|
||||
{
|
||||
uint8_t displayWidth = dispwidth;;
|
||||
uint32_t pnt = memaddr;
|
||||
@@ -199,10 +210,17 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t
|
||||
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)
|
||||
// Sanity check. memoryType == 0 required kernel driver to dump so we exit as it cannot be performed here.
|
||||
if(memoryType == 0)
|
||||
return(-1);
|
||||
|
||||
// Make sure the memory page is valid if we are dumping them out.
|
||||
if(memoryType == 3 && Z80PAGE[memoryPage] == NULL)
|
||||
{
|
||||
printf("Page %d is not allocated.\n", memoryPage);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
// Reconfigure terminal to allow non-blocking key input.
|
||||
//
|
||||
set_conio_terminal_mode();
|
||||
@@ -237,7 +255,10 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t
|
||||
{
|
||||
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]);
|
||||
printf("%04X", memoryType == 1 ? (uint16_t)Z80RAM[pnt+i] :
|
||||
memoryType == 2 ? (uint16_t)Z80ROM[pnt+i] :
|
||||
memoryType == 3 ? (uint16_t)*(*(Z80PAGE + memoryPage) + (pnt+i)) :
|
||||
(uint16_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
@@ -245,7 +266,10 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t
|
||||
|
||||
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]);
|
||||
printf("%08lX", memoryType == 1 ? (uint32_t)Z80RAM[pnt+i] :
|
||||
memoryType == 2 ? (uint32_t)Z80ROM[pnt+i] :
|
||||
memoryType == 3 ? (uint32_t)*(*(Z80PAGE + memoryPage) + (pnt+i)) :
|
||||
(uint32_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
@@ -254,7 +278,10 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t
|
||||
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]);
|
||||
printf("%02X", memoryType == 1 ? (uint8_t)Z80RAM[pnt+i] :
|
||||
memoryType == 2 ? (uint8_t)Z80ROM[pnt+i] :
|
||||
memoryType == 3 ? (uint8_t)*(*(Z80PAGE + memoryPage) + (pnt+i)) :
|
||||
(uint8_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
@@ -269,7 +296,9 @@ int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t
|
||||
// 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];
|
||||
c = memoryType == 1 ? (char)Z80RAM[pnt+i] : memoryType == 2 ? (char)Z80ROM[pnt+i] :
|
||||
memoryType == 3 ? (char)*(*(Z80PAGE + (uint32_t)memoryPage) + (pnt+i)) :
|
||||
(char)Z80Ctrl->iopage[pnt+i];
|
||||
if ((pnt+i < endAddr) && (c >= ' ') && (c <= '~'))
|
||||
fputc((char)c, stdout);
|
||||
else
|
||||
@@ -315,67 +344,187 @@ memoryDumpExit:
|
||||
|
||||
// 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)
|
||||
int z80load(int fdZ80, char *fileName, uint32_t memLoadAddr, long fileOffset, long fileLen, uint8_t memoryType, uint8_t isMZF)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
int ret = 0;
|
||||
int result = 0;
|
||||
long fileSize;
|
||||
t_svcDirEnt mzfHeader;
|
||||
FILE *ptr;
|
||||
|
||||
// Sanity check.
|
||||
if(isMZF == 0 && (fileOffset == -1 && fileLen != -1 || fileOffset != -1 && fileLen == -1))
|
||||
{
|
||||
printf("Error: Both --offset and --len are required, dont specify to use entire file.\n");
|
||||
result = 1;
|
||||
}
|
||||
if(result == 0)
|
||||
{
|
||||
// Open the file and read directly into the Virtual memory via the share.
|
||||
ptr = fopen(fileName, "rb");
|
||||
if(ptr)
|
||||
{
|
||||
// Get size of file for sanity checks.
|
||||
fseek(ptr, 0, SEEK_END);
|
||||
fileSize = ftell(ptr);
|
||||
fseek(ptr, 0, SEEK_SET);
|
||||
|
||||
// Sanity checks.
|
||||
if(isMZF == 0)
|
||||
{
|
||||
fileSize = (fileLen == -1 ? fileSize : fileLen);
|
||||
if((memoryType == 1 && (memLoadAddr+fileSize) > Z80_VIRTUAL_RAM_SIZE) || (memoryType == 2 && (memLoadAddr+fileSize) > Z80_VIRTUAL_ROM_SIZE))
|
||||
{
|
||||
printf("Error: Binary file out of memory bounds (Size=%ld, Load=%08x)\n", fileSize, memLoadAddr);
|
||||
result = 1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// First the header.
|
||||
fread((uint8_t *)&mzfHeader, MZF_HEADER_SIZE, 1, ptr);
|
||||
if((mzfHeader.loadAddr + mzfHeader.fileSize) > Z80_VIRTUAL_RAM_SIZE)
|
||||
{
|
||||
printf("Error: MZF file out of RAM bounds (Size=%ld, Load=%08x)\n", fileSize, memLoadAddr);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Couldnt open file:%s\n", fileName);
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// No file errors, read contents into Z80 memory.
|
||||
if(result == 0)
|
||||
{
|
||||
// Pause the Z80.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
if(isMZF == 0)
|
||||
{
|
||||
// Position file if offset provided.
|
||||
if(fileOffset != -1) fseek(ptr, fileOffset, SEEK_SET);
|
||||
|
||||
// Now read in the data.
|
||||
switch(memoryType)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case 2:
|
||||
fread(&Z80ROM[memLoadAddr], fileSize, 1, ptr);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fread(&Z80Ctrl->page[memLoadAddr], fileSize, 1, ptr);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
fread(&Z80Ctrl->iopage[memLoadAddr], fileSize, 1, ptr);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
default:
|
||||
fread(&Z80RAM[memLoadAddr], fileSize, 1, ptr);
|
||||
break;
|
||||
}
|
||||
printf("Loaded %s, Size:%08x, Addr:%08x, memoryType:%d\n", fileName, fileSize, memLoadAddr, memoryType);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
|
||||
if(mzfHeader.loadAddr > 0x1000)
|
||||
{
|
||||
#endif
|
||||
// Copy in the header.
|
||||
memcpy((uint8_t *)&Z80RAM[MZ_CMT_ADDR], (uint8_t *)&mzfHeader, MZF_HEADER_SIZE);
|
||||
|
||||
// Now read in the data.
|
||||
fread(&Z80RAM[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_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 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_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
|
||||
// MZ-700 or MZ-80A 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);
|
||||
}
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Method to save FusionX memory to a local file.
|
||||
//
|
||||
int z80save(int fdZ80, char *fileName, long addr, long size, uint8_t memoryType)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
int result = 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.
|
||||
//ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
||||
//ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Open the file and write directly into the file from the shared memory segment.
|
||||
FILE *ptr;
|
||||
ptr = fopen(fileName, "rb");
|
||||
ptr = fopen(fileName, "wb");
|
||||
if(ptr)
|
||||
{
|
||||
// First the header.
|
||||
fread((uint8_t *)&mzfHeader, MZF_HEADER_SIZE, 1, ptr);
|
||||
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
if(mzfHeader.loadAddr > 0x1000)
|
||||
switch(memoryType)
|
||||
{
|
||||
#endif
|
||||
// Copy in the header.
|
||||
memcpy((uint8_t *)&Z80Ctrl->memory[MZ_CMT_ADDR], (uint8_t *)&mzfHeader, MZF_HEADER_SIZE);
|
||||
case 0:
|
||||
break;
|
||||
|
||||
// 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)
|
||||
case 2:
|
||||
fwrite(&Z80ROM[addr], size, 1, ptr);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fwrite(&Z80Ctrl->page[addr], size, 1, ptr);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
fwrite(&Z80Ctrl->iopage[addr], size, 1, ptr);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
default:
|
||||
fwrite(&Z80RAM[addr], size, 1, ptr);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
fclose(ptr);
|
||||
|
||||
// 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;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Method to request basic Z80 operations.
|
||||
//
|
||||
@@ -384,7 +533,7 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
uint32_t idx;
|
||||
int ret = 0;
|
||||
int result = 0;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
@@ -422,7 +571,7 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
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;
|
||||
result = -1;
|
||||
} else
|
||||
{
|
||||
// Use IOCTL to request Z80 cpu freq change.
|
||||
@@ -431,6 +580,87 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
break;
|
||||
case Z80_CMD_ADD_DEVICE:
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_NONE;
|
||||
if(strcasecmp((char *)param1, "RFS") == 0 || strcasecmp((char *)param1, "RFS80") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
}
|
||||
if(strcasecmp((char *)param1, "RFS40") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "TZPU") == 0)
|
||||
{
|
||||
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, "MZ1500") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ1500;
|
||||
}
|
||||
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)
|
||||
{
|
||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
break;
|
||||
case Z80_CMD_DEL_DEVICE:
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_NONE;
|
||||
if(strcasecmp((char *)param1, "RFS") == 0 || strcasecmp((char *)param1, "RFS80") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "RFS40") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "TZPU") == 0)
|
||||
{
|
||||
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, "MZ1500") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ1500;
|
||||
}
|
||||
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)
|
||||
{
|
||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||
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;
|
||||
@@ -441,7 +671,7 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
// 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);
|
||||
memoryDump((uint32_t)param2, (uint32_t)param3, (uint8_t)param1, (uint8_t)param1 == 3 || (uint8_t)param1 == 4 ? 32 : 8, (uint32_t)param2, 0);
|
||||
} else
|
||||
{
|
||||
// Build an IOCTL command to get the driver to dump the memory.
|
||||
@@ -462,6 +692,14 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
ioctlCmd.cmd = IOCTL_CMD_USE_VIRTUAL_RAM;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
case Z80_CMD_DEBUG:
|
||||
// Send command to enable/disable debugging output.
|
||||
ioctlCmd.cmd = IOCTL_CMD_DEBUG;
|
||||
ioctlCmd.debug.level = (uint8_t)param1;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
#endif
|
||||
case Z80_CMD_MEMORY_TEST:
|
||||
// Send command to test the SPI.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_MEMTEST;
|
||||
@@ -480,11 +718,11 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
|
||||
default:
|
||||
printf("Command not supported!\n");
|
||||
ret = -1;
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Method to perform some simple tests on the Z80 emulator.
|
||||
@@ -493,7 +731,7 @@ int z80test(int fdZ80)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
int ret = 0;
|
||||
int result = 0;
|
||||
|
||||
// Stop the Z80.
|
||||
//
|
||||
@@ -505,7 +743,7 @@ printf("Send STOP\n");
|
||||
ptr = fopen("/customer/mz700.rom", "rb");
|
||||
if(ptr)
|
||||
{
|
||||
fread(&Z80Ctrl->memory, 65536, 1, ptr);
|
||||
fread(&Z80RAM, 65536, 1, ptr);
|
||||
} else printf("Couldnt open file\n");
|
||||
|
||||
// Configure the Z80.
|
||||
@@ -530,7 +768,7 @@ printf("Send STOP\n");
|
||||
|
||||
memoryDump(0, 65536, 1, 8, 0, 0);
|
||||
out:
|
||||
return ret;
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Output usage screen. So mamy commands you do need to be prompted!!
|
||||
@@ -538,23 +776,31 @@ 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");
|
||||
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(" = ADDDEV --device <RFS40, RFS80, TZPU> # Add a virtual device into the Z80 configuration.\n");
|
||||
printf(" = DELDEV --device <RFS40, RFS80, TZPU> # Remove a virtual device from the Z80 configuration.\n");
|
||||
printf(" = SPEED --mult <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 RAM.\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(" = 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..41>]\n");
|
||||
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
printf(" = DEBUG --level <level> # 0 = off, 1..15 debug level, 15 is very verbose.\n");
|
||||
#endif
|
||||
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, ie. --start.\n");
|
||||
|
||||
}
|
||||
|
||||
@@ -564,14 +810,21 @@ int main(int argc, char *argv[])
|
||||
char buff[64];
|
||||
char cmd[64] = { 0 };
|
||||
char fileName[256] = { 0 };
|
||||
char devName[32] = { 0 };
|
||||
int idx;
|
||||
int opt;
|
||||
uint32_t hexData = 0;
|
||||
long speedMultiplier = 1;
|
||||
long startAddr = 0x0000;
|
||||
long endAddr = 0x1000;
|
||||
int virtualMemory = 0;
|
||||
long fileOffset = -1;
|
||||
long fileLen = -1;
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
int debugLevel = 0;
|
||||
#endif
|
||||
int helpFlag = 0;
|
||||
int verboseFlag = 0;
|
||||
uint8_t memoryType = 0;
|
||||
|
||||
// Define parameters to be processed.
|
||||
struct optparse options;
|
||||
@@ -581,21 +834,33 @@ int main(int argc, char *argv[])
|
||||
{"cmd", 'c', OPTPARSE_REQUIRED},
|
||||
{"file", 'f', OPTPARSE_REQUIRED},
|
||||
{"data", 'd', OPTPARSE_REQUIRED},
|
||||
{"speed", 'S', OPTPARSE_REQUIRED},
|
||||
{"virtual", 'V', OPTPARSE_REQUIRED},
|
||||
{"mult", 'S', OPTPARSE_REQUIRED},
|
||||
{"type", 'T', OPTPARSE_REQUIRED},
|
||||
{"addr", 'a', OPTPARSE_REQUIRED},
|
||||
{"end", 'e', OPTPARSE_REQUIRED},
|
||||
{"size", 's', OPTPARSE_REQUIRED},
|
||||
{"device", 'D', OPTPARSE_REQUIRED},
|
||||
{"offset", 'O', OPTPARSE_REQUIRED},
|
||||
{"len", 'L', OPTPARSE_REQUIRED},
|
||||
{"memorypage", 'm', OPTPARSE_REQUIRED},
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
{"level", 'l', OPTPARSE_REQUIRED},
|
||||
#endif
|
||||
{"verbose", 'v', OPTPARSE_NONE},
|
||||
{"save", '0', 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},
|
||||
{"loadrom", '3', OPTPARSE_NONE},
|
||||
{"reset", '4', OPTPARSE_NONE},
|
||||
{"stop", '5', OPTPARSE_NONE},
|
||||
{"start", '6', OPTPARSE_NONE},
|
||||
{"pause", '7', OPTPARSE_NONE},
|
||||
{"continue", '8', OPTPARSE_NONE},
|
||||
{"speed", '9', OPTPARSE_NONE},
|
||||
{"cpldcmd", '+', OPTPARSE_NONE},
|
||||
{"debug", 'x', OPTPARSE_NONE},
|
||||
{"adddev", '-', OPTPARSE_NONE},
|
||||
{"deldev", ':', OPTPARSE_NONE},
|
||||
{0}
|
||||
};
|
||||
|
||||
@@ -636,23 +901,56 @@ int main(int argc, char *argv[])
|
||||
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);
|
||||
|
||||
// File offset.
|
||||
case 'O':
|
||||
fileOffset = strtol(options.optarg, NULL, 0);
|
||||
//printf("File Offset:%04x\n", fileOffset);
|
||||
break;
|
||||
|
||||
// Length.
|
||||
case 'L':
|
||||
fileLen = strtol(options.optarg, NULL, 0);
|
||||
//printf("File Len:%04x\n", fileLen);
|
||||
break;
|
||||
|
||||
// Memory type flag, 0 = host, 1 = virtual RAM, 2 = virtual ROM, 3 = page table, 4 = iopage table.
|
||||
case 'T':
|
||||
memoryType = atoi(options.optarg);
|
||||
break;
|
||||
|
||||
// Memory Page - which page, in the page table, to view.
|
||||
case 'm':
|
||||
memoryPage = atoi(options.optarg);
|
||||
//printf("Memory Page:%02x\n", memoryPage);
|
||||
break;
|
||||
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
// Debug level, 0 = off, 1..15 debug level, 15 is very verbose.
|
||||
case 'l':
|
||||
debugLevel = atoi(options.optarg);
|
||||
break;
|
||||
#endif
|
||||
|
||||
// Filename.
|
||||
case 'f':
|
||||
strcpy(fileName, options.optarg);
|
||||
break;
|
||||
|
||||
// Device name.
|
||||
case 'D':
|
||||
strcpy(devName, options.optarg);
|
||||
break;
|
||||
|
||||
// Command to execute.
|
||||
case 'c':
|
||||
strcpy(cmd, options.optarg);
|
||||
break;
|
||||
|
||||
// Quick command flags.
|
||||
case '0':
|
||||
strcpy(cmd, "SAVE");
|
||||
break;
|
||||
case '1':
|
||||
strcpy(cmd, "DUMP");
|
||||
break;
|
||||
@@ -660,26 +958,40 @@ int main(int argc, char *argv[])
|
||||
strcpy(cmd, "LOADMZF");
|
||||
break;
|
||||
case '3':
|
||||
strcpy(cmd, "RESET");
|
||||
strcpy(cmd, "LOADMEM");
|
||||
break;
|
||||
case '4':
|
||||
strcpy(cmd, "STOP");
|
||||
strcpy(cmd, "RESET");
|
||||
break;
|
||||
case '5':
|
||||
strcpy(cmd, "START");
|
||||
strcpy(cmd, "STOP");
|
||||
break;
|
||||
case '6':
|
||||
strcpy(cmd, "PAUSE");
|
||||
strcpy(cmd, "START");
|
||||
break;
|
||||
case '7':
|
||||
strcpy(cmd, "CONTINUE");
|
||||
strcpy(cmd, "PAUSE");
|
||||
break;
|
||||
case '8':
|
||||
strcpy(cmd, "SPEED");
|
||||
strcpy(cmd, "CONTINUE");
|
||||
break;
|
||||
case '9':
|
||||
strcpy(cmd, "SPEED");
|
||||
break;
|
||||
case '+':
|
||||
strcpy(cmd, "CPLDCMD");
|
||||
break;
|
||||
case '-':
|
||||
strcpy(cmd, "ADDDEV");
|
||||
break;
|
||||
case ':':
|
||||
strcpy(cmd, "DELDEV");
|
||||
break;
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
case 'x':
|
||||
strcpy(cmd, "DEBUG");
|
||||
break;
|
||||
#endif
|
||||
|
||||
// Verbose mode.
|
||||
case 'v':
|
||||
@@ -689,7 +1001,6 @@ int main(int argc, char *argv[])
|
||||
// Command help needed.
|
||||
case 'h':
|
||||
helpFlag = 1;
|
||||
showArgs(argv[0], &options);
|
||||
break;
|
||||
|
||||
// Unrecognised, show synopsis.
|
||||
@@ -705,22 +1016,48 @@ int main(int argc, char *argv[])
|
||||
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");
|
||||
printf("Failed to attach to the Z80 Control structure, cannot continue, exiting....\n");
|
||||
close(fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
Z80RAM = (uint8_t *)mmap(0, Z80_VIRTUAL_RAM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0);
|
||||
if(Z80RAM == (void *)-1)
|
||||
{
|
||||
printf("Failed to attach to the Z80 RAM, cannot continue, exiting....\n");
|
||||
close(fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
Z80ROM = (uint8_t *)mmap(0, Z80_VIRTUAL_ROM_SIZE+0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0);
|
||||
if(Z80ROM == (void *)-1)
|
||||
{
|
||||
printf("Failed to attach to the Z80 ROM, cannot continue, exitting....\n");
|
||||
close(fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
// Loop through all the memory mapping pages, each page specifies a 64K mapping block, all memory accesses go through this map.
|
||||
for(idx=0; idx < MEMORY_MODES+MEMORY_SUB_MODES; idx++)
|
||||
{
|
||||
// Try and bind the page, if it doesnt exist, then the pointer will be NULL so it wont be used.
|
||||
Z80PAGE[idx] = (uint32_t *)mmap(0, ((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)) + (0x1000*(idx+1))), PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0);
|
||||
if(Z80PAGE[idx] == (void *)-1) Z80PAGE[idx] = NULL;
|
||||
}
|
||||
} else
|
||||
{
|
||||
printf("Failed to open the Z80 Driver, exitting...\n");
|
||||
printf("Failed to open the Z80 Driver, exiting...\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);
|
||||
z80load(fdZ80, fileName, 0, -1, -1, 1, 1);
|
||||
} else
|
||||
if(strcasecmp(cmd, "LOADMEM") == 0)
|
||||
{
|
||||
z80load(fdZ80, fileName, startAddr, fileOffset, fileLen, memoryType, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "RESET") == 0)
|
||||
{
|
||||
@@ -748,7 +1085,11 @@ int main(int argc, char *argv[])
|
||||
} else
|
||||
if(strcasecmp(cmd, "DUMP") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_DUMP_MEMORY, virtualMemory, startAddr, (endAddr - startAddr));
|
||||
ctrlCmd(fdZ80, Z80_CMD_DUMP_MEMORY, memoryType, startAddr, (endAddr - startAddr));
|
||||
} else
|
||||
if(strcasecmp(cmd, "SAVE") == 0)
|
||||
{
|
||||
z80save(fdZ80, fileName, startAddr, (endAddr - startAddr), memoryType);
|
||||
} else
|
||||
if(strcasecmp(cmd, "HOSTRAM") == 0)
|
||||
{
|
||||
@@ -758,10 +1099,24 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_VIRTUAL_RAM, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "ADDDEV") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_ADD_DEVICE, (long)&devName, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "DELDEV") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_DEL_DEVICE, (long)&devName, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "CPLDCMD") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, CPLD_CMD_SEND_CMD, hexData, 0, 0);
|
||||
} else
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
if(strcasecmp(cmd, "DEBUG") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_DEBUG, (long)debugLevel, 0, 0);
|
||||
} else
|
||||
#endif
|
||||
|
||||
// Test methods, if the code is built-in to the driver.
|
||||
if(strcasecmp(cmd, "Z80TEST") == 0)
|
||||
@@ -783,7 +1138,8 @@ int main(int argc, char *argv[])
|
||||
else
|
||||
{
|
||||
showArgs(argv[0], &options);
|
||||
printf("No command given, nothing done!\n");
|
||||
if(helpFlag == 0)
|
||||
printf("No command given, nothing done!\n");
|
||||
}
|
||||
|
||||
// Unmap shared memory and close the device.
|
||||
2233
software/FusionX/src/z80drv/src/z80driver.c
Normal file
2233
software/FusionX/src/z80drv/src/z80driver.c
Normal file
File diff suppressed because it is too large
Load Diff
848
software/FusionX/src/z80drv/src/z80driver.h
vendored
Normal file
848
software/FusionX/src/z80drv/src/z80driver.h
vendored
Normal file
@@ -0,0 +1,848 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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-2023 Philip Smart <philip.smart@net2net.org>
|
||||
// (c) 1999-2023 Manuel Sainz de Baranda y Goñi
|
||||
//
|
||||
// History: Oct 2022 - v1.0 Initial write of the z80 kernel driver software.
|
||||
// Jan 2023 - v1.1 Added MZ-2000/MZ-80A modes.
|
||||
// Feb 2023 - v1.2 Added RFS virtual driver.
|
||||
// Apr 2023 - v1.4.1 Completed MZ2000 mode to work with arbiter and ttymz.
|
||||
// May 2023 - v1.5 Added MZ1500 modes.
|
||||
// Jul 2023 - v1.6 Updated MZ-700 code, adding sub-memory maps to increase page mapping
|
||||
// speed specifically to enable reliable tape read/write.
|
||||
//
|
||||
// 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
|
||||
|
||||
// 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_MZ1500 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ2000)
|
||||
#define TARGET_HOST_MZ2000 1
|
||||
#define TARGET_HOST_MZ1500 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ1500)
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ1500 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_MZ1500 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_MZ1500 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_MZ1500 0 // MZ1500
|
||||
#define TARGET_HOST_MZ80A 0 // MZ80A
|
||||
#define TARGET_HOST_PCW 0 // Amstrad PCW8XXX/9XXX
|
||||
#endif
|
||||
|
||||
// Constants.
|
||||
#define DRIVER_LICENSE "GPL"
|
||||
#define DRIVER_AUTHOR "Philip D Smart"
|
||||
#define DRIVER_DESCRIPTION "Z80 CPU Emulator and Hardware Interface Driver"
|
||||
#define DRIVER_VERSION "v1.6"
|
||||
#define DRIVER_VERSION_DATE "July 2023"
|
||||
#define DRIVER_COPYRIGHT "(C) 2018-2023"
|
||||
#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_MEMORY_PAGE_SIZE 16
|
||||
#define MAX_SCREEN_WIDTH 132 // Maximum terminal screen width for memory dump output.
|
||||
#define MAX_VIRTUAL_DEVICES 5 // Maximum number of allowed virtual devices.
|
||||
#define DEVICE_NAME "z80drv"
|
||||
#define CLASS_NAME "mogu"
|
||||
#define IO_PROCESSOR_NAME "k64fcpu" // Name of the I/O processor user space application.
|
||||
#define ARBITER_NAME "sharpbiter" // Name of the Sharp MZ Arbiter process user space application.
|
||||
#define DEBUG_ENABLED 0 // 0 = disabled, 1 = z80driver, 2 = k64fcpu, 3 = both.
|
||||
|
||||
// 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_RAM_RO 0x02000000
|
||||
#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_VIRTUAL_HW 0x40000000
|
||||
|
||||
// Hotkeys handled.
|
||||
#define HOTKEY_ORIGINAL 0xE0
|
||||
#define HOTKEY_RFS40 0xE1
|
||||
#define HOTKEY_RFS80 0xE2
|
||||
#define HOTKEY_TZFS 0xE3
|
||||
#define HOTKEY_LINUX 0xE4
|
||||
|
||||
//*********************************************************************************************
|
||||
// Delay periods for the various hosts, which need adding to the primary opcode fetch in
|
||||
// order to govern the virtual Z80 to a known speed. The timings are only used within
|
||||
// virtual memory, if an opcode is being fetched from physical memory will self govern to the
|
||||
// host speed.
|
||||
// NB. As of v1.0 FusionX hardware, unless a method is forthcoming due to the low speed of the
|
||||
// SSD202 CPU GPIO access (72MHz bus speed, 1x72MHz per bit, in theory 2.2M 32bit words per
|
||||
// second, in practice 2MBytes per second! This is a shortcoming of the SSD202 CPU, others,
|
||||
// such as the NXP K64FX512 Cortex-M4 has 32bit registers where a single access can write
|
||||
// /read/toggle/clear 32bits and the bus is operating at 85MHz! If SigmaStar release an updated
|
||||
// CPU, or another compatible system becomes available, v1.1 of the FusionX hardware will be
|
||||
// created in order to allow full speed program execution within host memory.
|
||||
// NBB: Actual Z80 transactions run at full speed, it is just the period from completion
|
||||
// of 1 cycle to the next taking too much time in the SSD202 to setup. Workarounds using
|
||||
// lookahead and queue techniques have been adopted to ensure I/O timing for things such as
|
||||
// floppy drives functions as per the original host.
|
||||
//*********************************************************************************************
|
||||
|
||||
// Approximate governor delays to regulate emulated CPU speed.
|
||||
// MZ-700
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
#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
|
||||
#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 240
|
||||
#define INSTRUCTION_DELAY_RAM_7MHZ 120
|
||||
#define INSTRUCTION_DELAY_RAM_14MHZ 60
|
||||
#define INSTRUCTION_DELAY_RAM_28MHZ 30
|
||||
#define INSTRUCTION_DELAY_RAM_56MHZ 15
|
||||
#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_7MHZ 7000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_14MHZ 14000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_28MHZ 28000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_56MHZ 56000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_112MHZ 112000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_224MHZ 224000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_448MHZ 448000000
|
||||
#define INSTRUCTION_GOVERNOR_IO_SKIP 10
|
||||
|
||||
enum Z80_INSTRUCTION_DELAY {
|
||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_3_54MHZ,
|
||||
ROM_DELAY_X2 = INSTRUCTION_DELAY_ROM_7MHZ,
|
||||
ROM_DELAY_X4 = INSTRUCTION_DELAY_ROM_14MHZ,
|
||||
ROM_DELAY_X8 = INSTRUCTION_DELAY_ROM_28MHZ,
|
||||
ROM_DELAY_X16 = INSTRUCTION_DELAY_ROM_56MHZ,
|
||||
ROM_DELAY_X32 = INSTRUCTION_DELAY_ROM_112MHZ,
|
||||
ROM_DELAY_X64 = INSTRUCTION_DELAY_ROM_224MHZ,
|
||||
ROM_DELAY_X128 = INSTRUCTION_DELAY_ROM_448MHZ,
|
||||
RAM_DELAY_NORMAL = INSTRUCTION_DELAY_RAM_3_54MHZ,
|
||||
RAM_DELAY_X2 = INSTRUCTION_DELAY_RAM_7MHZ,
|
||||
RAM_DELAY_X4 = INSTRUCTION_DELAY_RAM_14MHZ,
|
||||
RAM_DELAY_X8 = INSTRUCTION_DELAY_RAM_28MHZ,
|
||||
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_56MHZ,
|
||||
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_112MHZ,
|
||||
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_224MHZ,
|
||||
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_448MHZ,
|
||||
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_3_54MHZ,
|
||||
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_7MHZ,
|
||||
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_14MHZ,
|
||||
CPU_FREQUENCY_X8 = INSTRUCTION_EQUIV_FREQ_28MHZ,
|
||||
CPU_FREQUENCY_X16 = INSTRUCTION_EQUIV_FREQ_56MHZ,
|
||||
CPU_FREQUENCY_X32 = INSTRUCTION_EQUIV_FREQ_112MHZ,
|
||||
CPU_FREQUENCY_X64 = INSTRUCTION_EQUIV_FREQ_224MHZ,
|
||||
CPU_FREQUENCY_X128 = INSTRUCTION_EQUIV_FREQ_448MHZ,
|
||||
};
|
||||
#endif
|
||||
//
|
||||
// MZ-1500
|
||||
#if(TARGET_HOST_MZ1500 == 1)
|
||||
#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
|
||||
#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_7MHZ 7000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_14MHZ 14000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_28MHZ 28000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_56MHZ 56000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_112MHZ 112000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_224MHZ 224000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_448MHZ 448000000
|
||||
#define INSTRUCTION_GOVERNOR_IO_SKIP 10
|
||||
|
||||
enum Z80_INSTRUCTION_DELAY {
|
||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_3_54MHZ,
|
||||
ROM_DELAY_X2 = INSTRUCTION_DELAY_ROM_7MHZ,
|
||||
ROM_DELAY_X4 = INSTRUCTION_DELAY_ROM_14MHZ,
|
||||
ROM_DELAY_X8 = INSTRUCTION_DELAY_ROM_28MHZ,
|
||||
ROM_DELAY_X16 = INSTRUCTION_DELAY_ROM_56MHZ,
|
||||
ROM_DELAY_X32 = INSTRUCTION_DELAY_ROM_112MHZ,
|
||||
ROM_DELAY_X64 = INSTRUCTION_DELAY_ROM_224MHZ,
|
||||
ROM_DELAY_X128 = INSTRUCTION_DELAY_ROM_448MHZ,
|
||||
RAM_DELAY_NORMAL = INSTRUCTION_DELAY_RAM_3_54MHZ,
|
||||
RAM_DELAY_X2 = INSTRUCTION_DELAY_RAM_7MHZ,
|
||||
RAM_DELAY_X4 = INSTRUCTION_DELAY_RAM_14MHZ,
|
||||
RAM_DELAY_X8 = INSTRUCTION_DELAY_RAM_28MHZ,
|
||||
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_56MHZ,
|
||||
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_112MHZ,
|
||||
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_224MHZ,
|
||||
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_448MHZ,
|
||||
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_3_54MHZ,
|
||||
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_7MHZ,
|
||||
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_14MHZ,
|
||||
CPU_FREQUENCY_X8 = INSTRUCTION_EQUIV_FREQ_28MHZ,
|
||||
CPU_FREQUENCY_X16 = INSTRUCTION_EQUIV_FREQ_56MHZ,
|
||||
CPU_FREQUENCY_X32 = INSTRUCTION_EQUIV_FREQ_112MHZ,
|
||||
CPU_FREQUENCY_X64 = INSTRUCTION_EQUIV_FREQ_224MHZ,
|
||||
CPU_FREQUENCY_X128 = INSTRUCTION_EQUIV_FREQ_448MHZ,
|
||||
};
|
||||
#endif
|
||||
|
||||
// MZ-2000
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
|
||||
#if(DEBUG_ENABLED > 0)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 213
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 109
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 54
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 27
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 14
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 3
|
||||
#define INSTRUCTION_DELAY_ROM_512MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 212
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 106
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 53
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 26
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 13
|
||||
#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_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 4
|
||||
|
||||
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
|
||||
|
||||
// MZ-80A - These values are dependent on the CPU Freq of the SSD202. Values are for 1.2GHz, in brackets for 1.0GHz
|
||||
// The reason for having 2 sets of delays is due to original coding where ROM memory required less instructions
|
||||
// than RAM. Also depending upon build slight differences need to be catered for, ie. when including debug logic
|
||||
// there are extra instructions to process during the fetch cycle.
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
|
||||
#if(DEBUG_ENABLED > 0)
|
||||
#define INSTRUCTION_DELAY_ROM_2MHZ 427 // (420)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 218
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 109
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 54
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 27
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 14
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_2MHZ 425
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 212
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 106
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 53
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 26
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 13
|
||||
#define INSTRUCTION_DELAY_RAM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_RAM_256MHZ 0
|
||||
#endif
|
||||
#if(DEBUG_ENABLED == 0)
|
||||
#define INSTRUCTION_DELAY_ROM_2MHZ 429 // (420)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 218
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 109
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 54
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 27
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 14
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_2MHZ 429
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 210
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 105
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 52
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 26
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 13
|
||||
#define INSTRUCTION_DELAY_RAM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_RAM_256MHZ 0
|
||||
#endif
|
||||
#define INSTRUCTION_EQUIV_FREQ_2MHZ 2000000
|
||||
#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_GOVERNOR_IO_SKIP 2
|
||||
|
||||
// Table of governor delays to be used to control run frequency,
|
||||
enum Z80_INSTRUCTION_DELAY {
|
||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_2MHZ,
|
||||
ROM_DELAY_X2 = INSTRUCTION_DELAY_ROM_4MHZ,
|
||||
ROM_DELAY_X4 = INSTRUCTION_DELAY_ROM_8MHZ,
|
||||
ROM_DELAY_X8 = INSTRUCTION_DELAY_ROM_16MHZ,
|
||||
ROM_DELAY_X16 = INSTRUCTION_DELAY_ROM_32MHZ,
|
||||
ROM_DELAY_X32 = INSTRUCTION_DELAY_ROM_64MHZ,
|
||||
ROM_DELAY_X64 = INSTRUCTION_DELAY_ROM_128MHZ,
|
||||
ROM_DELAY_X128 = INSTRUCTION_DELAY_ROM_256MHZ,
|
||||
RAM_DELAY_NORMAL = INSTRUCTION_DELAY_RAM_2MHZ,
|
||||
RAM_DELAY_X2 = INSTRUCTION_DELAY_RAM_4MHZ,
|
||||
RAM_DELAY_X4 = INSTRUCTION_DELAY_RAM_8MHZ,
|
||||
RAM_DELAY_X8 = INSTRUCTION_DELAY_RAM_16MHZ,
|
||||
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_32MHZ,
|
||||
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_64MHZ,
|
||||
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_128MHZ,
|
||||
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_256MHZ,
|
||||
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_2MHZ,
|
||||
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_4MHZ,
|
||||
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_8MHZ,
|
||||
CPU_FREQUENCY_X8 = INSTRUCTION_EQUIV_FREQ_16MHZ,
|
||||
CPU_FREQUENCY_X16 = INSTRUCTION_EQUIV_FREQ_32MHZ,
|
||||
CPU_FREQUENCY_X32 = INSTRUCTION_EQUIV_FREQ_64MHZ,
|
||||
CPU_FREQUENCY_X64 = INSTRUCTION_EQUIV_FREQ_128MHZ,
|
||||
CPU_FREQUENCY_X128 = INSTRUCTION_EQUIV_FREQ_256MHZ,
|
||||
};
|
||||
#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.
|
||||
#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_ADD_DEVICE 'A'
|
||||
#define IOCTL_CMD_DEL_DEVICE 'D'
|
||||
#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_DEBUG 'd'
|
||||
#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.
|
||||
// The memory page arrays dont check for allocation due to speed, it is assumed a memory mode page has been allocated and defined prior to the memoryMode
|
||||
// variable being set to that page.
|
||||
#define MEMORY_MODES 32 // Maximum number of different memory modes.
|
||||
#define MEMORY_SUB_MODES 6 // Number of possible alternate memory maps for a given memory mode.
|
||||
#define MEMORY_PAGE_SIZE 0x10000 // Total size of directly addressable memory.
|
||||
#define MEMORY_BLOCK_GRANULARITY 0x1 // Any change update MEMORY_BLOCK_SHIFT and mask in MEMORY_BLOCK_MASK
|
||||
#define MEMORY_BLOCK_SHIFT 0
|
||||
#define MEMORY_BLOCK_SLOTS (MEMORY_PAGE_SIZE / MEMORY_BLOCK_GRANULARITY)
|
||||
#define MEMORY_BLOCK_MASK (MEMORY_PAGE_SIZE - MEMORY_BLOCK_GRANULARITY)
|
||||
#define IO_PAGE_SIZE 0x10000 // Total size of directly addressable I/O.
|
||||
#define IO_BLOCK_GRANULARITY 0x1 // Any change update MEMORY_BLOCK_SHIFT and mask in MEMORY_BLOCK_MASK
|
||||
#define IO_BLOCK_SHIFT 0
|
||||
#define IO_BLOCK_SLOTS (IO_PAGE_SIZE / IO_BLOCK_GRANULARITY)
|
||||
#define IO_BLOCK_MASK (IO_PAGE_SIZE - IO_BLOCK_GRANULARITY)
|
||||
//#define getPageData(a) (Z80Ctrl->page[(a & 0xFFFF) >> MEMORY_BLOCK_SHIFT])
|
||||
//#define getIOPageData(a) (Z80Ctrl->iopage[(a & 0xFFFF])
|
||||
#define getPageData(a) (*(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + ((a & MEMORY_BLOCK_MASK) >> MEMORY_BLOCK_SHIFT)))
|
||||
#define getIOPageData(a) (Z80Ctrl->iopage[(a & IO_BLOCK_MASK])
|
||||
|
||||
#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 realAddress(a) (*(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + (getPageAddr(a, MEMORY_TYPE_REAL_MASK))))
|
||||
#define realPort(a) (Z80Ctrl->iopage[a & IO_BLOCK_MASK] & 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 & IO_BLOCK_MASK] & IO_TYPE_PHYSICAL_HW)
|
||||
#define isVirtualRAM(a) (getPageType(a, (MEMORY_TYPE_VIRTUAL_RAM | MEMORY_TYPE_VIRTUAL_RAM_RO)))
|
||||
#define isVirtualRO(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_RAM_RO))
|
||||
#define isVirtualRW(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 | MEMORY_TYPE_VIRTUAL_RAM_RO)))
|
||||
#define isVirtualHW(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_HW))
|
||||
#define isVirtualIO(a) (Z80Ctrl->iopage[a & IO_BLOCK_MASK] & IO_TYPE_VIRTUAL_HW)
|
||||
#define isVirtual(a) (getPageType(a, (MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_RAM | MEMORY_TYPE_VIRTUAL_RAM_RO | MEMORY_TYPE_VIRTUAL_HW)))
|
||||
#define isVirtualDevice(a, d) (Z80Ctrl->iopage[a & IO_BLOCK_MASK] & d)
|
||||
#define isHW(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_VIRTUAL_HW)))
|
||||
#define readVirtualRAM(a) (Z80Ctrl->ram[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ])
|
||||
#define readVirtualROM(a) (Z80Ctrl->rom[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ])
|
||||
#define writeVirtualRAM(a, d) { Z80Ctrl->ram[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ] = d; }
|
||||
#define writeVirtualROM(a, d) { Z80Ctrl->rom[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ] = d; }
|
||||
//#define setMemoryType(_block_,_type_,_addr_) { Z80Ctrl->page[_block_] = _type_ | _addr_; }
|
||||
#define setMemoryType(_block_,_type_,_addr_) { *(*(Z80Ctrl->page + Z80Ctrl->memoryMode) +_block_) = _type_ | _addr_; }
|
||||
#define backupMemoryType(_block_) { Z80Ctrl->shadowPage[_block_] = *(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + (_block_)); }
|
||||
//#define restoreMemoryType(_block_) { Z80Ctrl->page[_block_] = Z80Ctrl->shadowPage[_block_]; }
|
||||
#define restoreMemoryType(_block_) { *(*(Z80Ctrl->page + Z80Ctrl->memoryMode) + (_block_)) = Z80Ctrl->shadowPage[_block_]; }
|
||||
#define sendSignal(__task__, _signal_) { struct siginfo sigInfo;\
|
||||
if(__task__ != NULL)\
|
||||
{\
|
||||
memset(&sigInfo, 0, sizeof(struct siginfo));\
|
||||
sigInfo.si_signo = _signal_;\
|
||||
sigInfo.si_code = SI_QUEUE;\
|
||||
sigInfo.si_int = 1;\
|
||||
if(send_sig_info(_signal_, &sigInfo, __task__) < 0)\
|
||||
{\
|
||||
pr_info("Error: Failed to send signal:%02x to:%s\n", _signal_, __task__->comm);\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
#define resetZ80() {\
|
||||
setupMemory(Z80Ctrl->defaultPageMode);\
|
||||
z80_instant_reset(&Z80CPU);\
|
||||
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_TZPU)\
|
||||
{\
|
||||
Z80RunMode = Z80_STOPPED;\
|
||||
sendSignal(Z80Ctrl->ioTask, SIGUSR1); \
|
||||
}\
|
||||
}
|
||||
|
||||
#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
|
||||
};
|
||||
enum VIRTUAL_DEVICE {
|
||||
VIRTUAL_DEVICE_NONE = 0x00000000,
|
||||
VIRTUAL_DEVICE_MZ80A = 0x00000001,
|
||||
VIRTUAL_DEVICE_MZ700 = 0x00000002,
|
||||
VIRTUAL_DEVICE_MZ1500 = 0x00000004,
|
||||
VIRTUAL_DEVICE_MZ2000 = 0x00000008,
|
||||
VIRTUAL_DEVICE_PCW = 0x00000010,
|
||||
VIRTUAL_DEVICE_RFS40 = 0x01000000,
|
||||
VIRTUAL_DEVICE_RFS80 = 0x02000000,
|
||||
VIRTUAL_DEVICE_RFS = 0x03000000,
|
||||
VIRTUAL_DEVICE_TZPU = 0x04000000,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// Main RAM/ROM memory, linear but indexed as though it were banks in 1K pages.
|
||||
uint8_t *ram;
|
||||
uint8_t *rom;
|
||||
|
||||
// Compatibility mode, enables virtual mapping and virtual hardware to make the Z80 with the underlying host appear
|
||||
// as a host equipped with a specific hardware add on.
|
||||
// The devices are stored in an array for ease of reference and lookup in the driver and ctrl program, in actual
|
||||
// use they are a bit map for performance as scanning an array is time consuming.
|
||||
//
|
||||
enum VIRTUAL_DEVICE virtualDevice[MAX_VIRTUAL_DEVICES];
|
||||
uint32_t virtualDeviceBitMap;
|
||||
uint8_t virtualDeviceCnt;
|
||||
|
||||
// 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 0x1 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 *page[MEMORY_MODES+MEMORY_SUB_MODES];
|
||||
uint32_t shadowPage[MEMORY_BLOCK_SLOTS]; // Shadow page is for manipulation and backup of an existing page.
|
||||
|
||||
// Current memory modes as used by an active driver.
|
||||
uint8_t memoryMode;
|
||||
|
||||
// I/O Page map.
|
||||
//
|
||||
// This is a map to indicate the use of the I/O page and allow any required remapping.
|
||||
// <0x8000><I/O Address> - physical host hardware
|
||||
// <0x4000><I/O Address> - virtual host hardware
|
||||
// <0x3FFF><I/O Address> - bit map to indicate allocated device.
|
||||
// 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;
|
||||
|
||||
#if defined(TARGET_HOST_MZ1500)
|
||||
// Flag to indicate PCG active, all memory accesses from D000:FFFF are sent to hardware.
|
||||
uint8_t pcgMode;
|
||||
#endif
|
||||
|
||||
// I/O lookahead flags - to overcome SSD202 io slowness.
|
||||
uint8_t ioReadAhead;
|
||||
uint8_t ioWriteAhead;
|
||||
|
||||
// Keyboard strobe and data. Required to detect hotkey press.
|
||||
uint8_t keyportStrobe;
|
||||
uint8_t keyportShiftCtrl;
|
||||
uint8_t keyportHotKey;
|
||||
uint8_t keyportTrigger;
|
||||
uint8_t keyportTriggerLast;
|
||||
|
||||
// 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;
|
||||
uint8_t governorSkip;
|
||||
|
||||
// An I/O processor, running as a User Space daemon, can register to receive signals and events.
|
||||
struct task_struct *ioTask;
|
||||
|
||||
// Sharp MZ Arbiter, running as a User Space daemon, registers to receive signals and events in order to direct the persona of the FusionX.
|
||||
struct task_struct *arbTask;
|
||||
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
// Debugging flag.
|
||||
uint8_t debug;
|
||||
#endif
|
||||
} 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 virtual_device {
|
||||
enum VIRTUAL_DEVICE device;
|
||||
};
|
||||
struct cpld_ctrl {
|
||||
uint32_t cmd;
|
||||
};
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
struct debug {
|
||||
uint8_t level;
|
||||
};
|
||||
#endif
|
||||
struct ioctlCmd {
|
||||
int32_t cmd;
|
||||
union {
|
||||
struct z80_addr addr;
|
||||
struct z80_ctrl z80;
|
||||
struct speed speed;
|
||||
struct virtual_device vdev;
|
||||
struct cpld_ctrl cpld;
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
struct debug debug;
|
||||
#endif
|
||||
};
|
||||
};
|
||||
|
||||
// Prototypes.
|
||||
void setupMemory(enum Z80_MEMORY_PROFILE);
|
||||
int thread_z80(void *);
|
||||
|
||||
#endif
|
||||
@@ -7,9 +7,13 @@
|
||||
// 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>
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
// History: Oct 2022 v1.0 - Initial write of the z80 kernel driver software.
|
||||
// Jan 2023 v1.1 - Numerous new tries at increasing throughput to the CPLD failed.
|
||||
// Maximum read throughput of an 8bit byte due to the SSD202 GPIO
|
||||
// structure is approx 2MB/s - or 512K/s for a needed 32bit word.
|
||||
// Write is slower as you have to clock the data so sticking with SPI.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
@@ -59,7 +63,6 @@
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// 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.
|
||||
@@ -184,7 +187,7 @@ int z80io_init(void)
|
||||
inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
volatile uint8_t result = 0;
|
||||
|
||||
// Byte according to flag.
|
||||
if(dataFlag)
|
||||
@@ -199,10 +202,31 @@ inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline uint8_t z80io_PRL_Read(void)
|
||||
{
|
||||
// Locals.
|
||||
volatile uint8_t result = 0;
|
||||
volatile uint32_t b7, b6, b5, b4, b3, b2, b1, b0;
|
||||
|
||||
// Read the input registers and set value accordingly. Quicker to read registers and then apply shift/logical operators. The I/O Bus is very slow!
|
||||
b7 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_7_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_7_ADDR & 1)));
|
||||
b6 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_6_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_6_ADDR & 1)));
|
||||
b5 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_5_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_5_ADDR & 1)));
|
||||
b4 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_4_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_4_ADDR & 1)));
|
||||
b3 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_3_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_3_ADDR & 1)));
|
||||
b2 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_2_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_2_ADDR & 1)));
|
||||
b1 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_1_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_1_ADDR & 1)));
|
||||
b0 = READ_LONG(((gRIUBaseAddr) + (((PAD_Z80IO_IN_DATA_0_ADDR) & ~1)<<1) + (PAD_Z80IO_IN_DATA_0_ADDR & 1)));
|
||||
result = (b7 & 0x1) << 7 | (b6 & 0x1) << 6 | (b5 & 0x1) << 5 | (b4 & 0x1) << 4 | (b3 & 0x1) << 3 | (b2 & 0x1) << 2 | (b1 & 0x1) << 1 | (b0 & 0x1);
|
||||
|
||||
// Return 16bit value read from CPLD.
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline uint16_t z80io_PRL_Read16(void)
|
||||
{
|
||||
// Locals.
|
||||
uint16_t result = 0;
|
||||
volatile uint16_t result = 0;
|
||||
|
||||
// Low byte first.
|
||||
CLEAR_CPLD_HIGH_BYTE();
|
||||
@@ -7,9 +7,13 @@
|
||||
// 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>
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
// History: Oct 2022 v1.0 - Initial write of the z80 kernel driver software.
|
||||
// Jan 2023 v1.1 - Numerous new tries at increasing throughput to the CPLD failed.
|
||||
// Maximum read throughput of an 8bit byte due to the SSD202 GPIO
|
||||
// structure is approx 2MB/s - or 512K/s for a needed 32bit word.
|
||||
// Write is slower as you have to clock the data so sticking with SPI.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
@@ -78,6 +82,14 @@
|
||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||
#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_REFRESH 0x51
|
||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||
@@ -103,10 +115,10 @@
|
||||
#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_LTSTATE PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_BUSRQ PAD_GPIO13
|
||||
#define PAD_Z80IO_BUSACK PAD_GPIO14
|
||||
#define PAD_Z80IO_INT PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_INT PAD_PM_IRIN // IRIN
|
||||
#define PAD_Z80IO_NMI PAD_UART0_TX // GPIO48
|
||||
#define PAD_Z80IO_WAIT PAD_HSYNC_OUT // GPIO85
|
||||
#define PAD_Z80IO_RESET PAD_VSYNC_OUT // GPIO86
|
||||
@@ -126,11 +138,11 @@
|
||||
#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_READY_ADDR 0x103C18 // GPIO12
|
||||
#define PAD_Z80IO_LTSTATE_ADDR 0x103C30 // GPIO47
|
||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
||||
#define PAD_Z80IO_INT_ADDR 0x103C30 // GPIO47
|
||||
#define PAD_Z80IO_INT_ADDR 0xF28 // IRIN
|
||||
#define PAD_Z80IO_NMI_ADDR 0x103C32 // GPIO48
|
||||
#define PAD_Z80IO_WAIT_ADDR 0x103C80 // GPIO85
|
||||
#define PAD_Z80IO_RESET_ADDR 0x103C82 // GPIO86
|
||||
@@ -380,8 +392,10 @@
|
||||
#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_)); \
|
||||
#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 SPI_SEND_8(_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); \
|
||||
@@ -390,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_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; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
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);\
|
||||
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); \
|
||||
@@ -400,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_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); \
|
||||
#define SPI_SEND_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
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); \
|
||||
@@ -411,6 +433,62 @@
|
||||
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_P_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
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_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_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
|
||||
// read 2 byte
|
||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||
@@ -434,7 +512,7 @@
|
||||
#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 MAX_CHECK_CNT 5000
|
||||
|
||||
#define MSPI_READ_INDEX 0x0
|
||||
#define MSPI_WRITE_INDEX 0x1
|
||||
@@ -453,6 +531,7 @@ uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData);
|
||||
uint8_t z80io_PRL_Send8(uint8_t txData);
|
||||
uint8_t z680io_PRL_Send16(uint16_t txData);
|
||||
#endif
|
||||
uint8_t z80io_PRL_Read(void);
|
||||
uint8_t z80io_PRL_Read8(uint8_t dataFlag);
|
||||
uint16_t z80io_PRL_Read16(void);
|
||||
uint8_t z80io_SPI_Test(void);
|
||||
@@ -54,7 +54,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
spinlock_t spinLock;
|
||||
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);
|
||||
udelay(100);
|
||||
@@ -71,16 +71,16 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
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);
|
||||
}
|
||||
// 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");
|
||||
@@ -185,7 +185,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x10;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -223,7 +223,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x20;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -254,7 +254,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x11;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -280,7 +280,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x21;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -306,7 +306,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
}
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
@@ -322,7 +322,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
606
software/FusionX/src/z80drv/src/z80vhw_mz1500.c
Normal file
606
software/FusionX/src/z80drv/src/z80vhw_mz1500.c
Normal file
@@ -0,0 +1,606 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80vhw_mz1500.c
|
||||
// Created: May 2023
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Virtual Hardware Driver - MZ-1500
|
||||
// This file contains the methods used to emulate the original Sharp MZ-1500 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: May 2023 v1.0 - Initial write based on the MZ700 module.
|
||||
// Jul 2023 - v1.6 - Updated MZ-700 code, adding sub-memory maps to increase page mapping
|
||||
// speed specifically to enable reliable tape read/write. Code changes
|
||||
// reflected in MZ-1500 module. Addition of MZ-1R18 emulation.
|
||||
//
|
||||
// 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.
|
||||
uint8_t loDRAMen; // Lower bank 0000:0FFF DRAM enabled, else monitor.
|
||||
uint8_t hiDRAMen; // Higher bank D000:FFFF DRAM enabled, else memory mapped I/O.
|
||||
uint32_t *ramFileMem; // 64K RamFile memory.
|
||||
uint16_t ramFileAddr; // Address pointer of the MZ-1R18 64K Ram File Board memory.
|
||||
} t_MZ1500Ctrl;
|
||||
|
||||
// RFS Board control.
|
||||
static t_MZ1500Ctrl MZ1500Ctrl;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Method to setup the memory page config to reflect the PCW configuration.
|
||||
void mz1500SetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t subMode;
|
||||
uint32_t idx;
|
||||
|
||||
// Setup defaults.
|
||||
MZ1500Ctrl.regCtrl = 0x00;
|
||||
MZ1500Ctrl.loDRAMen = 0; // Default is monitor ROM is enabled.
|
||||
MZ1500Ctrl.hiDRAMen = 0; // Default is memory mapped I/O enabled.
|
||||
Z80Ctrl->inhibitMode = 0;
|
||||
|
||||
// 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++)
|
||||
{
|
||||
if((idx&0x00ff) == 0xEA || (idx&0x00ff) == 0xEB)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_VIRTUAL_HW;
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
}
|
||||
// Setup sub-memory pages to enable rapid switch according to memory bank commands.
|
||||
for(subMode=0; subMode < MEMORY_SUB_MODES; subMode++)
|
||||
{
|
||||
if(Z80Ctrl->page[MEMORY_MODES+subMode] == NULL)
|
||||
{
|
||||
#if(DEBUG_ENABLED & 0x01)
|
||||
if(Z80Ctrl->debug >=3) pr_info("Allocating memory sub page:%d\n", subMode);
|
||||
#endif
|
||||
(Z80Ctrl->page[MEMORY_MODES+subMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL);
|
||||
if ((Z80Ctrl->page[MEMORY_MODES+subMode]) == NULL)
|
||||
{
|
||||
pr_info("z80drv: failed to allocate memory sub mapping page:%d memory!", subMode);
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate current mode into the sub page prior to setting up specific config.
|
||||
memcpy((uint8_t *)Z80Ctrl->page[MEMORY_MODES+subMode], (uint8_t *)Z80Ctrl->page[0], MEMORY_BLOCK_SLOTS*sizeof(uint32_t));
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + subMode;
|
||||
|
||||
// MZ1500 memory mode switches.
|
||||
//
|
||||
// MZ-1500
|
||||
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||
// ------------------------------
|
||||
// OUT 0xE0 = |DRAM |DRAM |<last>
|
||||
// OUT 0xE1 = |<last> |DRAM |DRAM
|
||||
// OUT 0xE2 = |MONITOR |DRAM |<last>
|
||||
// OUT 0xE3 = |<last> |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE5 = |<last> |DRAM |PCG Enable
|
||||
// OUT 0xE6 = |<last> |DRAM |PCG Disable
|
||||
//
|
||||
// Sub-memory page maps:
|
||||
//
|
||||
// LOW BANK HIGH BANK PAGE MAP
|
||||
// DRAM 0
|
||||
// DRAM MEMORY MAP 1
|
||||
// Inhibit 2
|
||||
// DRAM 3
|
||||
// MONITOR MEMORY MAP 4
|
||||
// Inhibit 5
|
||||
//
|
||||
if(subMode >= 0 && subMode < 3)
|
||||
{
|
||||
// Enable lower 4K block as DRAM
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
}
|
||||
if(subMode >= 3 && subMode < 6)
|
||||
{
|
||||
// Enable lower 4K block as Monitor ROM
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
}
|
||||
if(subMode == 0 || subMode == 3)
|
||||
{
|
||||
// Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM.
|
||||
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);
|
||||
}
|
||||
}
|
||||
if(subMode == 1 || subMode == 4)
|
||||
{
|
||||
// Enable Video RAM and Memory mapped peripherals in upper 12K block.
|
||||
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
for(idx=0xE000; idx < 0xE800; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
for(idx=0xE800; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
}
|
||||
if(subMode == 2 || subMode == 5)
|
||||
{
|
||||
// Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it.
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 4;
|
||||
|
||||
// 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-1500 Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the RAM memory.
|
||||
//
|
||||
uint8_t mz1500LoadROM(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 mz1500Init(uint8_t mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
#if(DEBUG_ENABLED & 0x01)
|
||||
if(Z80Ctrl->debug >=3) pr_info("Allocating MZ-1R18 memory\n");
|
||||
#endif
|
||||
// Allocate memory for the MZ-1R18 64K Ram File board.
|
||||
MZ1500Ctrl.ramFileMem = (uint32_t *)kmalloc((65536 * sizeof(uint8_t)), GFP_KERNEL);
|
||||
if(MZ1500Ctrl.ramFileMem == NULL)
|
||||
{
|
||||
pr_info("z80drv: failed to allocate MZ-1R18 Ram File memory!");
|
||||
}
|
||||
MZ1500Ctrl.ramFileAddr = 0x0000;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial memory config.
|
||||
mz1500SetupMemory(Z80Ctrl->defaultPageMode);
|
||||
|
||||
pr_info("Enabling MZ-1500 driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void mz1500Remove(void)
|
||||
{
|
||||
pr_info("Removing MZ-1500 driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to decode an address and make any system memory map changes as required.
|
||||
//
|
||||
static inline void mz1500DecodeMemoryMapSetup(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 >= 3)
|
||||
{
|
||||
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 : MZ1500 = Colour VRAM (MZ1500)
|
||||
// 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 (MZ1500)
|
||||
// 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 >= 3)
|
||||
{
|
||||
pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||
}
|
||||
#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.
|
||||
if(((address&0xFF) - 0xE0) >= 0 && ((address&0xFF) - 0xE0) < 7)
|
||||
{
|
||||
// MZ1500 memory mode switch.
|
||||
//
|
||||
// MZ-1500
|
||||
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||
// ------------------------------
|
||||
// OUT 0xE0 = |DRAM |DRAM |<last>
|
||||
// OUT 0xE1 = |<last> |DRAM |DRAM
|
||||
// OUT 0xE2 = |MONITOR |DRAM |<last>
|
||||
// OUT 0xE3 = |<last> |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE5 = |<last> |DRAM |PCG Enable
|
||||
// OUT 0xE6 = |<last> |DRAM |PCG Disable
|
||||
//
|
||||
// Sub-memory page maps:
|
||||
//
|
||||
// LOW BANK HIGH BANK PAGE MAP
|
||||
// DRAM 0
|
||||
// DRAM MEMORY MAP 1
|
||||
// Inhibit 2
|
||||
// DRAM 3
|
||||
// MONITOR MEMORY MAP 4
|
||||
// Inhibit 5
|
||||
//
|
||||
// Determine if this is a memory management port and update the memory page if required.
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
case IO_ADDR_E0:
|
||||
MZ1500Ctrl.loDRAMen = 1;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E1:
|
||||
MZ1500Ctrl.hiDRAMen = 1;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E2:
|
||||
MZ1500Ctrl.loDRAMen = 0;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E3:
|
||||
MZ1500Ctrl.hiDRAMen = 0;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E4:
|
||||
MZ1500Ctrl.loDRAMen = 0;
|
||||
MZ1500Ctrl.hiDRAMen = 0;
|
||||
Z80Ctrl->inhibitMode = 0;
|
||||
Z80Ctrl->pcgMode = 0;
|
||||
break;
|
||||
|
||||
// PCG Bank Switching.
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// 0 0 - CGROM
|
||||
// 0 1 - PCG Blue Plane
|
||||
// 1 0 - PCG Red Plane
|
||||
// 1 1 - PCG Green Plane
|
||||
case IO_ADDR_E5:
|
||||
// Any PCG access goes to hardware, set flag and access occurs in primary read/write routines.
|
||||
Z80Ctrl->pcgMode = 1;
|
||||
break;
|
||||
|
||||
// Disable PCG Bank Switching.
|
||||
case IO_ADDR_E6:
|
||||
// Disable PCG mode.
|
||||
Z80Ctrl->pcgMode = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Setup memory mode based on flag state.
|
||||
if(Z80Ctrl->inhibitMode)
|
||||
{
|
||||
if(MZ1500Ctrl.loDRAMen)
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 2;
|
||||
else
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 5;
|
||||
} else
|
||||
if(MZ1500Ctrl.loDRAMen)
|
||||
{
|
||||
if(MZ1500Ctrl.hiDRAMen && !Z80Ctrl->pcgMode)
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 0;
|
||||
else
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 1;
|
||||
} else
|
||||
{
|
||||
if(MZ1500Ctrl.hiDRAMen && !Z80Ctrl->pcgMode)
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 3;
|
||||
else
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 4;
|
||||
}
|
||||
Z80Ctrl->governorSkip = 0;
|
||||
} else
|
||||
if((address&0xff) >= 0xD8 && (address&0xff) < 0xDF)
|
||||
{
|
||||
// Do nothing for the Disk interface.
|
||||
} else
|
||||
if((address&0xff) >= 0xF4 && (address&0xff) < 0xF8)
|
||||
{
|
||||
Z80Ctrl->governorSkip = 0;
|
||||
} else
|
||||
{
|
||||
// Z80Ctrl->governorSkip = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||
static inline uint8_t mz1500Read(zuint16 address, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t data = 0xFF;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch((address&0xff))
|
||||
{
|
||||
// MZ-1R18 Ram File Data Register.
|
||||
case 0xEA:
|
||||
data = MZ1500Ctrl.ramFileMem[MZ1500Ctrl.ramFileAddr];
|
||||
MZ1500Ctrl.ramFileAddr++;
|
||||
break;
|
||||
|
||||
// MZ-1R18 Ram File Control Register.
|
||||
case 0xEB:
|
||||
break;
|
||||
|
||||
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 mz1500Write(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
// uint32_t idx;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch((address&0xff))
|
||||
{
|
||||
// MZ-1R18 Ram File Data Register.
|
||||
case 0xEA:
|
||||
MZ1500Ctrl.ramFileMem[MZ1500Ctrl.ramFileAddr] = data;
|
||||
MZ1500Ctrl.ramFileAddr++;
|
||||
break;
|
||||
|
||||
// MZ-1R18 Ram File Control Register.
|
||||
case 0xEB:
|
||||
MZ1500Ctrl.ramFileAddr = (address & 0xff00) | data;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualRAM(address))
|
||||
{
|
||||
// Update virtual memory.
|
||||
writeVirtualRAM(address, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
530
software/FusionX/src/z80drv/src/z80vhw_mz2000.c
Normal file
530
software/FusionX/src/z80drv/src/z80vhw_mz2000.c
Normal file
@@ -0,0 +1,530 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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>
|
||||
|
||||
#include "tzpu.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_original.rom"
|
||||
#define ROM_IPL_FUSIONX_FILENAME ROM_DIR "mz2000_ipl_fusionx.rom"
|
||||
#define ROM_IPL_TZPU_FILENAME ROM_DIR "mz2000_ipl_tzpu.rom"
|
||||
#define ROM_1Z001M_FILENAME ROM_DIR "1Z001M.rom"
|
||||
|
||||
// Boot ROM rom load and size definitions.
|
||||
#define ROM_BOOT_LOAD_ADDR 0x000000
|
||||
#define ROM_1Z001M_LOAD_ADDR 0x000000
|
||||
#define ROM_ORIG_BOOT_SIZE 0x800
|
||||
#define ROM_TZPU_BOOT_SIZE 0x1000
|
||||
#define ROM_FUSIONX_BOOT_SIZE 0x1000
|
||||
#define ROM_1Z001M_BOOT_SIZE 0x10FB
|
||||
|
||||
// Sharp MZ-2000 constants.
|
||||
#define MBADDR_FDC 0x0D8 // MB8866 IO Region 0D8h - 0DBh
|
||||
#define MBADDR_FDC_CR MBADDR_FDC + 0x00 // Command Register
|
||||
#define MBADDR_FDC_STR MBADDR_FDC + 0x00 // Status Register
|
||||
#define MBADDR_FDC_TR MBADDR_FDC + 0x01 // Track Register
|
||||
#define MBADDR_FDC_SCR MBADDR_FDC + 0x02 // Sector Register
|
||||
#define MBADDR_FDC_DR MBADDR_FDC + 0x03 // Data Register
|
||||
#define MBADDR_FDC_MOTOR MBADDR_FDC + 0x04 // DS[0-3] and Motor control. 4 drives DS= BIT 0 -> Bit 2 = Drive number, 2=1,1=0,0=0 DS0, 2=1,1=0,0=1 DS1 etc
|
||||
// bit 7 = 1 MOTOR ON LOW (Active)
|
||||
#define MBADDR_FDC_SIDE MBADDR_FDC + 0x05 // Side select, Bit 0 when set = SIDE SELECT LOW,
|
||||
#define MBADDR_FDC_DDEN MBADDR_FDC + 0x06 // Double density enable, 0 = double density, 1 = single density disks.
|
||||
#define MBADDR_PPIA 0x0E0 // 8255 Port A
|
||||
#define MBADDR_PPIB 0x0E1 // 8255 Port B
|
||||
#define MBADDR_PPIC 0x0E2 // 8255 Port C
|
||||
#define MBADDR_PPICTL 0x0E3 // 8255 Control Port
|
||||
#define MBADDR_PIOA 0x0E8 // Z80 PIO Port A
|
||||
#define MBADDR_PIOCTLA 0x0E9 // Z80 PIO Port A Control Port
|
||||
#define MBADDR_PIOB 0x0EA // Z80 PIO Port B
|
||||
#define MBADDR_PIOCTLB 0x0EB // Z80 PIO Port B Control Port
|
||||
#define MBADDR_CRTBKCOLR 0x0F4 // Configure external CRT background colour.
|
||||
#define MBADDR_CRTGRPHPRIO 0x0F5 // Graphics priority register, character or a graphics colour has front display priority.
|
||||
#define MBADDR_CRTGRPHSEL 0x0F6 // Graphics output select on CRT or external CRT
|
||||
#define MBADDR_GRAMCOLRSEL 0x0F7 // Graphics RAM colour bank select.
|
||||
#define MBADDR_GRAMADDRL 0x0C000 // Graphics RAM base address.
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// tranZPUter I/O Ports need to be declared virtual to process locally.
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx+=0x0100)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// Ensure 40 char mode is enabled.
|
||||
// SPI_SEND_32(MBADDR_PIOA, 0x13);
|
||||
|
||||
pr_info("MZ-2000 Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the RAM memory.
|
||||
//
|
||||
uint8_t mz2000LoadROM(const char* romFileName, uint8_t useROM, 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, useROM == 1 ? &Z80Ctrl->rom[loadAddr] : &Z80Ctrl->ram[loadAddr], loadSize);
|
||||
if(noBytes < loadSize)
|
||||
{
|
||||
pr_info("Short load, 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 Z80 PIO/8255 controllers.
|
||||
// //
|
||||
// SPI_SEND_32(MBADDR_PPICTL, 0x82); // 8255 A=OUT B=IN C=OUT
|
||||
// SPI_SEND_32(MBADDR_PPIC, 0x58); // BST=1 NST=0 OPEN=1 WRITE=1
|
||||
// SPI_SEND_32(MBADDR_PPIA, 0xF7); // All signals inactive, stop cassette.
|
||||
// SPI_SEND_32(MBADDR_PIOCTLA, 0x0F); // Setup PIO A
|
||||
// SPI_SEND_32(MBADDR_PIOCTLB, 0xCF); // Setup PIO B
|
||||
// SPI_SEND_32(MBADDR_PIOCTLB, 0xFF);
|
||||
//
|
||||
// // Initialise video hardware.
|
||||
// //
|
||||
// SPI_SEND_32(MBADDR_CRTGRPHSEL, 0x00); // Set Graphics VRAM to default, no access to GRAM.
|
||||
// SPI_SEND_32(MBADDR_CRTBKCOLR, 0x00); // Set background colour on external output to black.
|
||||
// SPI_SEND_32(MBADDR_GRAMCOLRSEL, 0x01); // Activate Blue graphics RAM bank for graphics operations (this is the default installed bank, red and green are optional).
|
||||
// SPI_SEND_32(MBADDR_CRTGRPHPRIO, 0x07); // Enable all colour bank graphic output with character priority.
|
||||
// SPI_SEND_32(MBADDR_PIOA, 0x13); // A7 : H 0xD000:0xD7FF or 0xC000:0xFFFF VRAN paged in.
|
||||
// // A6 : H Select Character VRAM (H) or Graphics VRAM (L)
|
||||
// // A5 : H Select 80 char mode, 40 char mode = L
|
||||
// // A4 : L Select all key strobe lines active, for detection of any key press.
|
||||
// // A3-A0: Keyboard strobe lines
|
||||
// SPI_SEND_32(MBADDR_PPIA, 0xFF); // A7 : L APSS Search for next program
|
||||
// // A6 : L Automatic playback at end of rewind
|
||||
// // A5 : L Automatic rewind during playback(recording)
|
||||
// // A4 : L Invert Video
|
||||
// // A3 : L Stop Cassette
|
||||
// // A2 : L Play Cassette
|
||||
// // A1 : L Fast Forward
|
||||
// // A0 : L Rewind
|
||||
|
||||
// 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);
|
||||
|
||||
// Overwrite the ROM with a modified version (comment out) if needed.
|
||||
//mz2000LoadROM(ROM_IPL_ORIG_FILENAME, ROM_BOOT_LOAD_ADDR, ROM_ORIG_BOOT_SIZE);
|
||||
//mz2000LoadROM(ROM_IPL_TZPU_FILENAME, ROM_BOOT_LOAD_ADDR, ROM_TZPU_BOOT_SIZE);
|
||||
mz2000LoadROM(ROM_IPL_FUSIONX_FILENAME, 1, ROM_BOOT_LOAD_ADDR, ROM_FUSIONX_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)
|
||||
{
|
||||
pr_info("NST Reset\n");
|
||||
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)
|
||||
{
|
||||
pr_info("IPL Reset\n");
|
||||
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)
|
||||
{
|
||||
// Only the lower 8 bits of the I/O address are processed as the upper byte is not used in the Sharp models.
|
||||
//
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
case IO_TZ_SVCREQ:
|
||||
#if(DEBUG_ENABLED & 0x01)
|
||||
if(Z80Ctrl->debug >= 3) pr_info("SVCREQ:%02x\n", data);
|
||||
#endif
|
||||
|
||||
// If a k64f process has registered, send it a service request signal.
|
||||
pr_info("Sending signal,%02x\n", data);
|
||||
sendSignal(Z80Ctrl->ioTask, SIGIO);
|
||||
break;
|
||||
|
||||
case IO_TZ_SYSREQ:
|
||||
#if(DEBUG_ENABLED & 0x01)
|
||||
if(Z80Ctrl->debug >= 3) pr_info("SYSREQ:%02x\n", data);
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_info("PORT:%02x\n", data);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualRAM(address))
|
||||
{
|
||||
// Update virtual memory.
|
||||
writeVirtualRAM(address, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
603
software/FusionX/src/z80drv/src/z80vhw_mz700.c
Normal file
603
software/FusionX/src/z80drv/src/z80vhw_mz700.c
Normal file
@@ -0,0 +1,603 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
// Jul 2023 - v1.6 - Updated MZ-700 code, adding sub-memory maps to increase page mapping
|
||||
// speed specifically to enable reliable tape read/write. Addition of
|
||||
// MZ-1R18 emulation.
|
||||
//
|
||||
// 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.
|
||||
uint8_t loDRAMen; // Lower bank 0000:0FFF DRAM enabled, else monitor.
|
||||
uint8_t hiDRAMen; // Higher bank D000:FFFF DRAM enabled, else memory mapped I/O.
|
||||
uint32_t *ramFileMem; // 64K RamFile memory.
|
||||
uint16_t ramFileAddr; // Address pointer of the MZ-1R18 64K Ram File Board memory.
|
||||
} 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.
|
||||
uint8_t subMode;
|
||||
uint32_t idx;
|
||||
|
||||
// Setup defaults.
|
||||
MZ700Ctrl.regCtrl = 0x00;
|
||||
MZ700Ctrl.loDRAMen = 0; // Default is monitor ROM is enabled.
|
||||
MZ700Ctrl.hiDRAMen = 0; // Default is memory mapped I/O enabled.
|
||||
Z80Ctrl->inhibitMode = 0;
|
||||
|
||||
// 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++)
|
||||
{
|
||||
if((idx&0x00ff) == 0xEA || (idx&0x00ff) == 0xEB)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_VIRTUAL_HW;
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
}
|
||||
// Setup sub-memory pages to enable rapid switch according to memory bank commands.
|
||||
for(subMode=0; subMode < MEMORY_SUB_MODES; subMode++)
|
||||
{
|
||||
if(Z80Ctrl->page[MEMORY_MODES+subMode] == NULL)
|
||||
{
|
||||
#if(DEBUG_ENABLED & 0x01)
|
||||
if(Z80Ctrl->debug >=3) pr_info("Allocating memory sub page:%d\n", subMode);
|
||||
#endif
|
||||
(Z80Ctrl->page[MEMORY_MODES+subMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL);
|
||||
if ((Z80Ctrl->page[MEMORY_MODES+subMode]) == NULL)
|
||||
{
|
||||
pr_info("z80drv: failed to allocate memory sub mapping page:%d memory!", subMode);
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate current mode into the sub page prior to setting up specific config.
|
||||
memcpy((uint8_t *)Z80Ctrl->page[MEMORY_MODES+subMode], (uint8_t *)Z80Ctrl->page[0], MEMORY_BLOCK_SLOTS*sizeof(uint32_t));
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + subMode;
|
||||
|
||||
// MZ700 memory mode switch.
|
||||
//
|
||||
// MZ-700
|
||||
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||
// ------------------------------
|
||||
// OUT 0xE0 = |DRAM |DRAM |<last>
|
||||
// OUT 0xE1 = |<last> |DRAM |DRAM
|
||||
// OUT 0xE2 = |MONITOR |DRAM |<last>
|
||||
// OUT 0xE3 = |<last> |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE5 = |<last> |DRAM |Inhibit
|
||||
// OUT 0xE6 = |<last> |DRAM |<return to last>
|
||||
//
|
||||
// Sub-memory page maps:
|
||||
//
|
||||
// LOW BANK HIGH BANK PAGE MAP
|
||||
// DRAM 0
|
||||
// DRAM MEMORY MAP 1
|
||||
// Inhibit 2
|
||||
// DRAM 3
|
||||
// MONITOR MEMORY MAP 4
|
||||
// Inhibit 5
|
||||
//
|
||||
if(subMode >= 0 && subMode < 3)
|
||||
{
|
||||
// Enable lower 4K block as DRAM
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
}
|
||||
if(subMode >= 3 && subMode < 6)
|
||||
{
|
||||
// Enable lower 4K block as Monitor ROM
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
}
|
||||
if(subMode == 0 || subMode == 3)
|
||||
{
|
||||
// Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM.
|
||||
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);
|
||||
}
|
||||
}
|
||||
if(subMode == 1 || subMode == 4)
|
||||
{
|
||||
// Enable Video RAM and Memory mapped peripherals in upper 12K block.
|
||||
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
for(idx=0xE000; idx < 0xE800; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
for(idx=0xE800; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
}
|
||||
if(subMode == 2 || subMode == 5)
|
||||
{
|
||||
// Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it.
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 4;
|
||||
|
||||
// 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;
|
||||
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
#if(DEBUG_ENABLED & 0x01)
|
||||
if(Z80Ctrl->debug >=3) pr_info("Allocating MZ-1R18 memory\n");
|
||||
#endif
|
||||
// Allocate memory for the MZ-1R18 64K Ram File board.
|
||||
MZ700Ctrl.ramFileMem = (uint32_t *)kmalloc((65536 * sizeof(uint8_t)), GFP_KERNEL);
|
||||
if(MZ700Ctrl.ramFileMem == NULL)
|
||||
{
|
||||
pr_info("z80drv: failed to allocate MZ-1R18 Ram File memory!");
|
||||
}
|
||||
MZ700Ctrl.ramFileAddr = 0x0000;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial memory config.
|
||||
mz700SetupMemory(Z80Ctrl->defaultPageMode);
|
||||
|
||||
// Add in a test program to guage execution speed.
|
||||
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;
|
||||
|
||||
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 >= 3)
|
||||
{
|
||||
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 >= 3)
|
||||
{
|
||||
pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||
}
|
||||
#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.
|
||||
if(((address&0xFF) - 0xE0) >= 0 && ((address&0xFF) - 0xE0) < 7)
|
||||
{
|
||||
// MZ700 memory mode switch.
|
||||
//
|
||||
// MZ-700
|
||||
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||
// ------------------------------
|
||||
// OUT 0xE0 = |DRAM |DRAM |<last>
|
||||
// OUT 0xE1 = |<last> |DRAM |DRAM
|
||||
// OUT 0xE2 = |MONITOR |DRAM |<last>
|
||||
// OUT 0xE3 = |<last> |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE5 = |<last> |DRAM |Inhibit
|
||||
// OUT 0xE6 = |<last> |DRAM |<return to last>
|
||||
//
|
||||
// Sub-memory page maps:
|
||||
//
|
||||
// LOW BANK HIGH BANK PAGE MAP
|
||||
// DRAM 0
|
||||
// DRAM MEMORY MAP 1
|
||||
// Inhibit 2
|
||||
// DRAM 3
|
||||
// MONITOR MEMORY MAP 4
|
||||
// Inhibit 5
|
||||
//
|
||||
// Determine if this is a memory management port and update the memory page if required.
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
case IO_ADDR_E0:
|
||||
MZ700Ctrl.loDRAMen = 1;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E1:
|
||||
MZ700Ctrl.hiDRAMen = 1;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E2:
|
||||
MZ700Ctrl.loDRAMen = 0;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E3:
|
||||
MZ700Ctrl.hiDRAMen = 0;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E4:
|
||||
MZ700Ctrl.loDRAMen = 0;
|
||||
MZ700Ctrl.hiDRAMen = 0;
|
||||
Z80Ctrl->inhibitMode = 0;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E5:
|
||||
Z80Ctrl->inhibitMode = 1;
|
||||
break;
|
||||
|
||||
case IO_ADDR_E6:
|
||||
Z80Ctrl->inhibitMode = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Setup memory mode based on flag state.
|
||||
if(Z80Ctrl->inhibitMode)
|
||||
{
|
||||
if(MZ700Ctrl.loDRAMen)
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 2;
|
||||
else
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 5;
|
||||
} else
|
||||
if(MZ700Ctrl.loDRAMen)
|
||||
{
|
||||
if(MZ700Ctrl.hiDRAMen)
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 0;
|
||||
else
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 1;
|
||||
} else
|
||||
{
|
||||
if(MZ700Ctrl.hiDRAMen)
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 3;
|
||||
else
|
||||
Z80Ctrl->memoryMode = MEMORY_MODES + 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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&0xff))
|
||||
{
|
||||
// MZ-1R18 Ram File Data Register.
|
||||
case 0xEA:
|
||||
data = MZ700Ctrl.ramFileMem[MZ700Ctrl.ramFileAddr];
|
||||
MZ700Ctrl.ramFileAddr++;
|
||||
break;
|
||||
|
||||
// MZ-1R18 Ram File Control Register.
|
||||
case 0xEB:
|
||||
break;
|
||||
|
||||
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&0xff))
|
||||
{
|
||||
// MZ-1R18 Ram File Data Register.
|
||||
case 0xEA:
|
||||
MZ700Ctrl.ramFileMem[MZ700Ctrl.ramFileAddr] = data;
|
||||
MZ700Ctrl.ramFileAddr++;
|
||||
break;
|
||||
|
||||
// MZ-1R18 Ram File Control Register.
|
||||
case 0xEB:
|
||||
MZ700Ctrl.ramFileAddr = (address & 0xff00) | data;
|
||||
break;
|
||||
|
||||
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;
|
||||
}
|
||||
382
software/FusionX/src/z80drv/src/z80vhw_pcw.c
Normal file
382
software/FusionX/src/z80drv/src/z80vhw_pcw.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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;
|
||||
|
||||
// Initial memory config.
|
||||
pcwSetupMemory(Z80Ctrl->defaultPageMode);
|
||||
|
||||
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;
|
||||
}
|
||||
852
software/FusionX/src/z80drv/src/z80vhw_rfs.c
Normal file
852
software/FusionX/src/z80drv/src/z80vhw_rfs.c
Normal file
@@ -0,0 +1,852 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80vhw_rfs.c.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Virtual Hardware Driver - Rom Filing System (RFS)
|
||||
// This file contains the methods used to emulate the Rom Filing System add on for the
|
||||
// MZ-80A.
|
||||
//
|
||||
// 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: Feb 2023 v1.0 - Initial write based on the RFS hardware.
|
||||
// v1.1 - Bug fix, write logic was one byte out of kinter.
|
||||
//
|
||||
// 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 MROM_ADDR 0x00000 // Base address of the 512K Monitor ROM.
|
||||
#define USER_ROM_I_ADDR 0x80000 // Base address of the first 512K User ROM.
|
||||
#define USER_ROM_II_ADDR 0x100000 // Base address of the second 512K User ROM.
|
||||
#define USER_ROM_III_ADDR 0x180000 // Base address of the third 512K User ROM.
|
||||
|
||||
// RFS Control Registers.
|
||||
#define BNKCTRLRST 0xEFF8 // Bank control reset, returns all registers to power up default.
|
||||
#define BNKCTRLDIS 0xEFF9 // Disable bank control registers by resetting the coded latch.
|
||||
#define HWSPIDATA 0xEFFB // Hardware SPI Data register (read/write).
|
||||
#define HWSPISTART 0xEFFC // Start an SPI transfer.
|
||||
#define BNKSELMROM 0xEFFD // Select RFS Bank1 (MROM)
|
||||
#define BNKSELUSER 0xEFFE // Select RFS Bank2 (User ROM)
|
||||
#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.
|
||||
//
|
||||
#define BBCLK 1 // BitBang SPI Clock.
|
||||
#define SDCS 2 // SD Card Chip Select, active low.
|
||||
#define BBMOSI 4 // BitBang MOSI (Master Out Serial In).
|
||||
#define CDLTCH1 8 // Coded latch up count bit 1
|
||||
#define CDLTCH2 16 // Coded latch up count bit 2
|
||||
#define CDLTCH3 32 // Coded latch up count bit 3
|
||||
#define BK2A19 64 // User ROM Device Select Bit 0 (or Address bit 19).
|
||||
#define BK2A20 128 // User ROM Device Select Bit 1 (or Address bit 20).
|
||||
// BK2A20 : BK2A19
|
||||
// 0 0 = Flash RAM 0 (default).
|
||||
// 0 1 = Flash RAM 1.
|
||||
// 1 0 = Flasm RAM 2 or Static RAM 0.
|
||||
// 1 1 = Reserved.`
|
||||
|
||||
#define BNKCTRLDEF BBMOSI+SDCS+BBCLK // Default on startup for the Bank Control register.
|
||||
|
||||
// RFS Board ROM rom filename definitions.
|
||||
#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/"
|
||||
#elif(TARGET_HOST_MZ1500 == 1)
|
||||
#define ROM_DIR "/apps/FusionX/host/MZ-1500/RFS/"
|
||||
#else
|
||||
#error "Unknown host configured."
|
||||
#endif
|
||||
#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_II_40C_FILENAME ROM_DIR "USER_ROM_II_256_40c.bin"
|
||||
#define ROM_USER_III_40C_FILENAME ROM_DIR "USER_ROM_III_256_40c.bin"
|
||||
#define ROM_MROM_80C_FILENAME ROM_DIR "MROM_256_80c.bin"
|
||||
#define ROM_USER_I_80C_FILENAME ROM_DIR "USER_ROM_256_80c.bin"
|
||||
#define ROM_USER_II_80C_FILENAME ROM_DIR "USER_ROM_II_256_80c.bin"
|
||||
#define ROM_USER_III_80C_FILENAME ROM_DIR "USER_ROM_III_256_80c.bin"
|
||||
#define ROM_MZ_1E05_FILENAME ROM_DIR "mz-1e05.bin"
|
||||
|
||||
// RFS Board ROM rom load and size definitions.
|
||||
#define ROM_MROM_LOAD_ADDR 0x000000
|
||||
#define ROM_USER_I_LOAD_ADDR 0x080000
|
||||
#define ROM_USER_II_LOAD_ADDR 0x100000
|
||||
#define ROM_USER_III_LOAD_ADDR 0x180000
|
||||
#define ROM_MZ_1E05_ADDR ((Z80_VIRTUAL_ROM_SIZE-0x10000)+0xF000)
|
||||
#define ROM_MROM_SIZE 0x80000
|
||||
#define ROM_USER_I_SIZE 0x80000
|
||||
#define ROM_USER_II_SIZE 0x80000
|
||||
#define ROM_USER_III_SIZE 0x80000
|
||||
#define ROM_MZ_1E05_SIZE 0x1000
|
||||
|
||||
// SD Drive constants.
|
||||
#define SD_DIR "/apps/FusionX/host/MZ-80A/RFS/"
|
||||
#define SD_CARD_FILENAME SD_DIR "SHARP_MZ80A_RFS_CPM_IMAGE_1.img" // SD Card Binary Image.
|
||||
|
||||
// MMC/SD command (SPI mode)
|
||||
#define CMD0 0x40 + 0 // GO_IDLE_STATE
|
||||
#define CMD1 0x40 + 1 // SEND_OP_COND
|
||||
#define ACMD41 0x40 + 41 // SEND_OP_COND (SDC)
|
||||
#define CMD8 0x40 + 8 // SEND_IF_COND
|
||||
#define CMD9 0x40 + 9 // SEND_CSD
|
||||
#define CMD10 0x40 + 10 // SEND_CID
|
||||
#define CMD12 0x40 + 12 // STOP_TRANSMISSION
|
||||
#define CMD13 0x40 + 13 // SEND_STATUS
|
||||
#define ACMD13 0x40 + 13 // SD_STATUS (SDC)
|
||||
#define CMD16 0x40 + 16 // SET_BLOCKLEN
|
||||
#define CMD17 0x40 + 17 // READ_SINGLE_BLOCK
|
||||
#define CMD18 0x40 + 18 // READ_MULTIPLE_BLOCK
|
||||
#define CMD23 0x40 + 23 // SET_BLOCK_COUNT
|
||||
#define ACMD23 0x40 + 23 // SET_WR_BLK_ERASE_COUNT (SDC)
|
||||
#define CMD24 0x40 + 24 // WRITE_BLOCK
|
||||
#define CMD25 0x40 + 25 // WRITE_MULTIPLE_BLOCK
|
||||
#define CMD32 0x40 + 32 // ERASE_ER_BLK_START
|
||||
#define CMD33 0x40 + 33 // ERASE_ER_BLK_END
|
||||
#define CMD38 0x40 + 38 // ERASE
|
||||
#define CMD55 0x40 + 55 // APP_CMD
|
||||
#define CMD58 0x40 + 58 // READ_OCR
|
||||
#define SD_SECSIZE 512 // Default size of an SD Sector
|
||||
#define SD_RETRIES 0x0100 // Number of retries before giving up.
|
||||
|
||||
// Card type flags (CardType)
|
||||
#define CT_MMC 0x01 // MMC ver 3
|
||||
#define CT_SD1 0x02 // SD ver 1
|
||||
#define CT_SD2 0x04 // SD ver 2
|
||||
#define CT_SDC CT_SD1|CT_SD2 // SD
|
||||
#define CT_BLOCK 0x08 // Block addressing
|
||||
|
||||
// SD Card control variables.
|
||||
typedef struct {
|
||||
uint8_t trainingCnt; // Count of training bits to indicate card being initialised.
|
||||
uint8_t initialised; // Flag to indicate the SD card has been initialised.
|
||||
uint8_t writeFlag; // Flag to indicate an SD Write is taking place, assembling data prior to file write.
|
||||
uint8_t cmdBuf[6+SD_SECSIZE]; // SD Command Input Buffer.
|
||||
uint16_t rcvCntr; // SD Received byte counter.
|
||||
uint8_t const *respBuf; // SD Response buffer.
|
||||
uint16_t respCntr; // SD Response buffer counter.
|
||||
uint16_t respLen; // SD size of data in response buffer.
|
||||
struct file *fhandle; // Filehandle for the SD card image.
|
||||
uint8_t regDataIn; // SD Card data in (from virtual card) register.
|
||||
uint8_t regDataOut; // SD Card data out (to virtual card) register.
|
||||
uint8_t dataOutFlag; // Flag to indicate data written to the SPI.
|
||||
} t_SDCtrl;
|
||||
|
||||
// RFS Board registers.
|
||||
typedef struct {
|
||||
uint8_t regBank1; // Bank 1, MROM, bank select register.
|
||||
uint8_t regBank2; // Bank 2, UROM, bank select register.
|
||||
uint8_t regCtrl; // Control register.
|
||||
uint8_t upCntr; // Register enable up counter.
|
||||
uint32_t mromAddr; // Actual address in MROM 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_RFSCtrl;
|
||||
|
||||
// RFS Board control.
|
||||
static t_RFSCtrl RFSCtrl;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Method to setup the memory page config to reflect installation of an RFS Board.
|
||||
void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// The RFS Board occupies the MROM slot 0x0000:0x0FFF and the User ROM slot 0xE800:0xEFFF. The actual part of the ROM which appears in these windows
|
||||
// is controlled by the REG_BANK1 (MROM) and REG_BANK2 (UROM) registers with the upper UROM registers provided in REG_CTRL.
|
||||
// So on initial setup, map the MROM page to point to the Z80 ROM area 0x00000 which is the base of the first 512K Flash ROM (virtual).
|
||||
|
||||
// Setup defaults.
|
||||
RFSCtrl.regBank1 = 0x00;
|
||||
RFSCtrl.regBank2 = 0x00;
|
||||
RFSCtrl.regCtrl = 0x00;
|
||||
RFSCtrl.mromAddr = MROM_ADDR;
|
||||
RFSCtrl.uromAddr = USER_ROM_I_ADDR;
|
||||
RFSCtrl.memSwitch = 0;
|
||||
RFSCtrl.sd.trainingCnt = 0;
|
||||
RFSCtrl.sd.initialised = 0;
|
||||
RFSCtrl.sd.dataOutFlag = 0;
|
||||
RFSCtrl.sd.rcvCntr = 0;
|
||||
RFSCtrl.sd.writeFlag = 0;
|
||||
RFSCtrl.sd.respCntr = 0;
|
||||
RFSCtrl.sd.respLen = 0;
|
||||
RFSCtrl.sd.fhandle = NULL;
|
||||
|
||||
// Setup the initial state of the latch up-counter, used to enable access to the programmable registers.
|
||||
RFSCtrl.upCntr = ((RFSCtrl.regCtrl & 0x20) >> 2) | ((RFSCtrl.regCtrl & 0x10) >> 2) | ((RFSCtrl.regCtrl & 0x08) >> 2);
|
||||
|
||||
// Initialise the page pointers and memory to reflect an MZ-80A with an RFS board installed.
|
||||
for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0x0000 && idx < 0x1000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+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)
|
||||
{
|
||||
// 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)));
|
||||
}
|
||||
else if(idx >= 0xF000 && idx < 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 || TARGET_HOST_MZ1500 == 1)
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
#if (TARGET_HOST_MZ1500 == 1)
|
||||
// MZ-1500, E4 reset closes the PCG access.
|
||||
Z80Ctrl->pcgMode = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// No I/O Ports on the RFS board.
|
||||
pr_info("RFS Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the ROM memory.
|
||||
//
|
||||
uint8_t rfsLoadROM(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.
|
||||
void rfsInit(uint8_t mode80c)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Load ROMS according to the display configuration, 40 char = standard, 80 char = 40/80 board installed.
|
||||
rfsLoadROM(mode80c == 0 ? ROM_MROM_40C_FILENAME : ROM_MROM_80C_FILENAME, ROM_MROM_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);
|
||||
rfsLoadROM(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_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.
|
||||
for(idx=0xF000; idx < 0x10000; idx++)
|
||||
{
|
||||
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->rom[idx+(Z80_VIRTUAL_ROM_SIZE-0x10000)] = z80io_PRL_Read8(1);
|
||||
}
|
||||
rfsLoadROM(ROM_MZ_1E05_FILENAME, ROM_MZ_1E05_ADDR, ROM_MZ_1E05_SIZE);
|
||||
|
||||
#if (TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
#if (TARGET_HOST_MZ1500 == 1)
|
||||
// MZ-1500, E4 reset closes the PCG access.
|
||||
Z80Ctrl->pcgMode = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
pr_info("Enabling RFS(%d) driver.\n", mode80c == 1 ? 80 : 40);
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void rfsRemove(void)
|
||||
{
|
||||
pr_info("Removing RFS driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to decode an address and make any system memory map changes as required.
|
||||
//
|
||||
static inline void rfsDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Memory map switch.
|
||||
if(readFlag)
|
||||
{
|
||||
if(address == 0xE00C || address == 0xE00D || address == 0xE00E || address == 0xE00F)
|
||||
{
|
||||
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, (RFSCtrl.mromAddr+idx));
|
||||
}
|
||||
RFSCtrl.memSwitch = 0x01;
|
||||
}
|
||||
|
||||
// Reset memory map switch.
|
||||
else if(address == 0xE010 || address == 0xE011 || address == 0xE012 || address == 0xE013)
|
||||
{
|
||||
if(readFlag)
|
||||
{
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
||||
}
|
||||
}
|
||||
RFSCtrl.memSwitch = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emulation of the RFS SD card. The emulation is made easier as the RFS uses automatic shift registers so we just handle byte data not assembly
|
||||
// of bit data.
|
||||
//
|
||||
// All SD commands are added to the processor but logic (apart from a standard response) is only added for commands which RFS uses.
|
||||
//
|
||||
void rfsSDCard(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
uint32_t lbaAddr;
|
||||
int noBytes;
|
||||
|
||||
// If Chip select is active and we arent initialised, exit, need to initialise before processing data.
|
||||
if((RFSCtrl.regCtrl & SDCS) == 0 && RFSCtrl.sd.initialised == 0)
|
||||
return;
|
||||
|
||||
// If the Chip select is inactive and we are initialised, exit, can only process data if selected.
|
||||
if((RFSCtrl.regCtrl & SDCS) && RFSCtrl.sd.initialised == 1)
|
||||
return;
|
||||
|
||||
// SD Card initialised? If not, follow the SD protocol.
|
||||
//
|
||||
if(RFSCtrl.sd.initialised == 0)
|
||||
{
|
||||
// RFS initialisation sends 10 x 8bits, which is a little more than standard 74bits. Just check for 7 bytes and then set initialised flag.
|
||||
if(++RFSCtrl.sd.trainingCnt >= 7)
|
||||
{
|
||||
// Try and open the SD Card image. If it cannot be open then the SD card isnt registered as initialised.
|
||||
RFSCtrl.sd.fhandle = filp_open(SD_CARD_FILENAME, O_RDWR, S_IWUSR | S_IRUSR);
|
||||
if(IS_ERR(RFSCtrl.sd.fhandle))
|
||||
{
|
||||
pr_info("Error opening SD Card Image:%s\n:", SD_CARD_FILENAME);
|
||||
} else
|
||||
{
|
||||
RFSCtrl.sd.initialised = 1;
|
||||
RFSCtrl.sd.trainingCnt = 0;
|
||||
}
|
||||
}
|
||||
//pr_info("Training:%d, Initialised:%d\n", RFSCtrl.sd.trainingCnt, RFSCtrl.sd.initialised);
|
||||
|
||||
} else
|
||||
{
|
||||
// If we are not receiving a command and response data is available, send it.
|
||||
if((RFSCtrl.sd.rcvCntr == 0 && RFSCtrl.sd.regDataOut == 0xFF) || RFSCtrl.sd.respBuf || RFSCtrl.sd.dataOutFlag == 0)
|
||||
{
|
||||
if(RFSCtrl.sd.respBuf)
|
||||
{
|
||||
RFSCtrl.sd.regDataIn = RFSCtrl.sd.respBuf[RFSCtrl.sd.respCntr++];
|
||||
//pr_info("Sending Response:%02x(%d)\n", RFSCtrl.sd.regDataIn, RFSCtrl.sd.respCntr);
|
||||
if(RFSCtrl.sd.respCntr == RFSCtrl.sd.respLen)
|
||||
{
|
||||
RFSCtrl.sd.respBuf = NULL;
|
||||
RFSCtrl.sd.respCntr = 0;
|
||||
}
|
||||
} else
|
||||
{
|
||||
//pr_info("Sending Response filler:0xFF\n");
|
||||
RFSCtrl.sd.regDataIn = 0xFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clear out response buffer as latest data maybe an override, such as cancel.
|
||||
RFSCtrl.sd.respBuf = NULL;
|
||||
RFSCtrl.sd.respCntr = 0;
|
||||
|
||||
// Clear out data write flag, this indicates when data is written into the SPI for transmission.
|
||||
RFSCtrl.sd.dataOutFlag = 0;
|
||||
|
||||
// Store incoming data.
|
||||
RFSCtrl.sd.cmdBuf[RFSCtrl.sd.rcvCntr++] = RFSCtrl.sd.regDataOut;
|
||||
//pr_info("Received:%02x(%d)\n", RFSCtrl.sd.regDataOut, RFSCtrl.sd.rcvCntr);
|
||||
|
||||
// 0xFE, <sector> <crc>
|
||||
if(RFSCtrl.sd.rcvCntr == (SD_SECSIZE+3) && RFSCtrl.sd.writeFlag == 1)
|
||||
{
|
||||
static uint8_t response[] = { 0x05 };
|
||||
|
||||
// Write the sector to the SD card image.
|
||||
// RFSCtrl.sd.cmdBuf[SD_SECSIZE+2] = 0x00; // CRC but we dont set, not needed in this application.
|
||||
// RFSCtrl.sd.cmdBuf[SD_SECSIZE+3] = 0x00;
|
||||
noBytes = kernel_write(RFSCtrl.sd.fhandle, &RFSCtrl.sd.cmdBuf[1], SD_SECSIZE, RFSCtrl.sd.fhandle->f_pos);
|
||||
if(noBytes == 0) response[0] = 0x06; // Write error.
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
//pr_info("Writing %d bytes, CRC(%02x,%02x)\n", noBytes, RFSCtrl.sd.cmdBuf[SD_SECSIZE+2], RFSCtrl.sd.cmdBuf[SD_SECSIZE+3]);
|
||||
|
||||
// Reset to idle.
|
||||
RFSCtrl.sd.rcvCntr = 0;
|
||||
RFSCtrl.sd.writeFlag = 0;
|
||||
}
|
||||
|
||||
// If we are not writing (receiving data from the Z80) and we have assembled a full command, process.
|
||||
else if(RFSCtrl.sd.rcvCntr == 6 && RFSCtrl.sd.writeFlag == 0)
|
||||
{
|
||||
RFSCtrl.sd.rcvCntr = 0;
|
||||
|
||||
//pr_info("Received Command:%02x,%02x,%02x,%02x,%02x,%02x\n", RFSCtrl.sd.cmdBuf[0],RFSCtrl.sd.cmdBuf[1],RFSCtrl.sd.cmdBuf[2],RFSCtrl.sd.cmdBuf[3],RFSCtrl.sd.cmdBuf[4],RFSCtrl.sd.cmdBuf[5]);
|
||||
switch(RFSCtrl.sd.cmdBuf[0])
|
||||
{
|
||||
case CMD0: // GO_IDLE_STATE
|
||||
//pr_info("GO_IDLE_STATE\n");
|
||||
{
|
||||
// Initialise to SPI Mode. RFS doesnt support other modes.
|
||||
static const uint8_t response[] = { 0x01 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD1: // SEND_OP_COND
|
||||
//pr_info("SEND_OP_COND\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMD41: // SEND_OP_COND (SDC)
|
||||
//pr_info("SEND_OP_COND\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 }; // 0 = Ready, 1 = Idle
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD8: // SEND_IF_COND
|
||||
//pr_info("SEND_IF_COND\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x01, 0x00, 0x00, 0x01, 0xAA };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD9: // SEND_CSD
|
||||
//pr_info("SEND_CSD\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD10: // SEND_CID
|
||||
//pr_info("SEND_CID\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD12: // STOP_TRANSMISSION
|
||||
//pr_info("STOP_TRANSMISSION\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMD13: // SD_STATUS (SDC)
|
||||
//pr_info("SD_STATUS\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD16: // SET_BLOCKLEN
|
||||
//pr_info("SD: Set Block Size:%d\n", (RFSCtrl.sd.cmdBuf[2] << 8 | RFSCtrl.sd.cmdBuf[3]));
|
||||
{
|
||||
static const uint8_t response[] = { 0x01 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD17: // READ_SINGLE_BLOCK
|
||||
//pr_info("READ_SINGLE_BLOCK\n");
|
||||
{
|
||||
static uint8_t response[6 + SD_SECSIZE];
|
||||
memset(response, 0, sizeof(response));
|
||||
|
||||
// Assemble LBA address and seek to the right location in the SD card image.
|
||||
lbaAddr = RFSCtrl.sd.cmdBuf[1] << 24 | RFSCtrl.sd.cmdBuf[2] << 16 | RFSCtrl.sd.cmdBuf[3] << 8 | RFSCtrl.sd.cmdBuf[4];
|
||||
//pr_info("Reading LBA %d\n", lbaAddr);
|
||||
vfs_llseek(RFSCtrl.sd.fhandle, lbaAddr * SD_SECSIZE, SEEK_SET);
|
||||
|
||||
// Assemble response buffer including SD card sector.
|
||||
response[0] = 0x00; // Response R1
|
||||
response[1] = 0xFE; // Start of Data marker.
|
||||
noBytes = kernel_read(RFSCtrl.sd.fhandle, RFSCtrl.sd.fhandle->f_pos, &response[2], SD_SECSIZE);
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = SD_SECSIZE + 2 + 2; // Sector Size + 2 bytes (R1 + Data Start) + 2 CRC
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD18: // READ_MULTIPLE_BLOCK
|
||||
//pr_info("READ_MULTIPLE_BLOCK\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACMD23: // SET_WR_BLK_ERASE_COUNT (SDC)
|
||||
//pr_info("SET_WR_BLK_ERASE_COUNT\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD24: // WRITE_BLOCK
|
||||
//pr_info("WRITE_BLOCK\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
|
||||
// Assemble LBA address and seek to the right location in the SD card image.
|
||||
lbaAddr = RFSCtrl.sd.cmdBuf[1] << 24 | RFSCtrl.sd.cmdBuf[2] << 16 | RFSCtrl.sd.cmdBuf[3] << 8 | RFSCtrl.sd.cmdBuf[4];
|
||||
//pr_info("Writing LBA %d\n", lbaAddr);
|
||||
vfs_llseek(RFSCtrl.sd.fhandle, lbaAddr * SD_SECSIZE, SEEK_SET);
|
||||
|
||||
// Assemble response which is Ready, data can now be sent for sector. Set write flag so we know data is being received as sector data.
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
RFSCtrl.sd.writeFlag = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD25: // WRITE_MULTIPLE_BLOCK
|
||||
//pr_info("WRITE_MULTIPLE_BLOCK\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD32: // ERASE_ER_BLK_START
|
||||
//pr_info("ERASE_ER_BLK_START\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD33: // ERASE_ER_BLK_END
|
||||
//pr_info("ERASE_ER_BLK_END\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD38: // ERASE
|
||||
//pr_info("ERASE\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD55: // APP_CMD
|
||||
//pr_info("APP_CMD\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x01 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD58: // READ_OCR
|
||||
//pr_info("READ_OCR\n");
|
||||
{
|
||||
static const uint8_t response[] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_info("UNHANDLED REQUEST:%02x,%02x,%02x,%02x,%02x,%02x\n", RFSCtrl.sd.cmdBuf[0],RFSCtrl.sd.cmdBuf[1],RFSCtrl.sd.cmdBuf[2],RFSCtrl.sd.cmdBuf[3],RFSCtrl.sd.cmdBuf[4],RFSCtrl.sd.cmdBuf[5]);
|
||||
{
|
||||
static const uint8_t response[] = { 0x00 };
|
||||
RFSCtrl.sd.respBuf = response;
|
||||
RFSCtrl.sd.respLen = sizeof(response);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Standard response when a byte is received but not enough assembled to process.
|
||||
RFSCtrl.sd.regDataIn = 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to read from either the memory mapped registers if enabled else the ROM.
|
||||
static inline uint8_t rfsRead(zuint16 address, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t data = 0xFF;
|
||||
|
||||
//pr_info("RFS+Read:%04x, BK1:%02x, BK2:%02x, CTRL:%02x, MROM:%08x, UROM:%08x\n", address, RFSCtrl.regBank1, RFSCtrl.regBank2, RFSCtrl.regCtrl, RFSCtrl.mromAddr, RFSCtrl.uromAddr);
|
||||
|
||||
// Any access to the control region increments the enable counter till it reaches terminal count and enables writes to the registers. When the counter
|
||||
// gets to 15 the registers are enabled and the EPROM, in the control region, is disabled.
|
||||
if((address >= BNKCTRLRST && address <= BNKCTRL) && RFSCtrl.upCntr < 15)
|
||||
{
|
||||
RFSCtrl.upCntr++;
|
||||
}
|
||||
|
||||
// Address in control region and register bank enabled?
|
||||
//
|
||||
if(RFSCtrl.upCntr >= 15 && (address >= BNKCTRLRST && address <= BNKCTRL))
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
// Bank control reset, returns all registers to power up default.
|
||||
case BNKCTRLRST:
|
||||
break;
|
||||
|
||||
// Disable bank control registers by resetting the coded latch.
|
||||
case BNKCTRLDIS:
|
||||
RFSCtrl.upCntr = (RFSCtrl.regCtrl >> 2) & 0x0E;
|
||||
break;
|
||||
|
||||
// Hardware SPI Data register (read/write).
|
||||
case HWSPIDATA:
|
||||
// Action data, ie. run the SD emulation.
|
||||
data = RFSCtrl.sd.regDataIn;
|
||||
//pr_info("HWSPIDATA ReadOut:%02x\n", data);
|
||||
break;
|
||||
|
||||
// Start an SPI transfer.
|
||||
case HWSPISTART:
|
||||
break;
|
||||
|
||||
// Select RFS Bank1 (MROM) - No action for read, real hardware would store an undefined value into register.
|
||||
case BNKSELMROM:
|
||||
break;
|
||||
|
||||
// Select RFS Bank2 (User ROM) - No action for read.
|
||||
case BNKSELUSER:
|
||||
break;
|
||||
|
||||
// Bank Control register (read/write).
|
||||
case BNKCTRL:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Return the contents of the ROM at given address.
|
||||
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||
}
|
||||
|
||||
//pr_info("RFS-Read:%04x, Data:%02x, BK1:%02x, BK2:%02x, CTRL:%02x, MROM:%08x, UROM:%08x\n", address, data, RFSCtrl.regBank1, RFSCtrl.regBank2, RFSCtrl.regCtrl, RFSCtrl.mromAddr, RFSCtrl.uromAddr);
|
||||
return(data);
|
||||
}
|
||||
|
||||
// Method to handle writes to the RFS board. Generally the RFS board.
|
||||
static inline void rfsWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
//pr_info("RFS+Write:%04x, Data:%02x, BK1:%02x, BK2:%02x, CTRL:%02x, MROM:%08x, UROM:%08x\n", address, data, RFSCtrl.regBank1, RFSCtrl.regBank2, RFSCtrl.regCtrl, RFSCtrl.mromAddr, RFSCtrl.uromAddr);
|
||||
|
||||
// Any access to the control region increments the enable counter till it reaches terminal count and enables writes to the registers. When the counter
|
||||
// gets to 15 the registers are enabled and the EPROM, in the control region, is disabled.
|
||||
if((address >= BNKCTRLRST && address <= BNKCTRL) && RFSCtrl.upCntr < 15)
|
||||
{
|
||||
RFSCtrl.upCntr++;
|
||||
}
|
||||
|
||||
// Address in control region and register bank enabled?
|
||||
//
|
||||
if(RFSCtrl.upCntr >= 15 && (address >= BNKCTRLRST && address <= BNKCTRL))
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
// Bank control reset, returns all registers to power up default.
|
||||
case BNKCTRLRST: // 0xEFF8
|
||||
break;
|
||||
|
||||
// Disable bank control registers by resetting the coded latch.
|
||||
case BNKCTRLDIS: // 0xEFF9
|
||||
default:
|
||||
RFSCtrl.upCntr = (RFSCtrl.regCtrl >> 2) & 0x0E;
|
||||
break;
|
||||
|
||||
// Hardware SPI Data register (read/write).
|
||||
case HWSPIDATA:
|
||||
RFSCtrl.sd.regDataOut = data;
|
||||
RFSCtrl.sd.dataOutFlag = 1;
|
||||
//pr_info("HWSPIDATA WriteIn:%02x\n", data);
|
||||
break;
|
||||
|
||||
// Start an SPI transfer.
|
||||
case HWSPISTART:
|
||||
// Action data, ie. run the SD emulation as a write to this address starts the SPI clock which clocks out 8bit and clocks in 8 bits.
|
||||
//pr_info("HWSPISTART\n");
|
||||
rfsSDCard();
|
||||
break;
|
||||
|
||||
// Select RFS Bank1 (MROM)
|
||||
case BNKSELMROM:
|
||||
RFSCtrl.regBank1 = data;
|
||||
|
||||
// Update monitor ROM address as register contains upper address bits of the ROM.
|
||||
RFSCtrl.mromAddr = (uint32_t)(RFSCtrl.regBank1 << 12);
|
||||
|
||||
// Update memory map to reflect register change.
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(RFSCtrl.memSwitch)
|
||||
{
|
||||
// Monitor ROM is located at 0xC000.
|
||||
setMemoryType((0xC000+idx)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Monitor ROM is located at 0x000.
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Select RFS Bank2 (User ROM)
|
||||
case BNKSELUSER:
|
||||
// Bank Control register (read/write).
|
||||
case BNKCTRL:
|
||||
if(address == BNKSELUSER) { RFSCtrl.regBank2 = data; } else { RFSCtrl.regCtrl = data; }
|
||||
|
||||
// Update user ROM address as register contain upper address bits of the ROM.
|
||||
RFSCtrl.uromAddr = (uint32_t)(((((RFSCtrl.regCtrl&0xB0) << 2) | RFSCtrl.regBank2) << 11) + USER_ROM_I_ADDR);
|
||||
|
||||
// Update memory map to reflect register change.
|
||||
for(idx=0xE800; idx < 0xF000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
// 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)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Any unprocessed write is commited to RAM.
|
||||
writeVirtualRAM(address, data);
|
||||
}
|
||||
//pr_info("RFS-Write:%04x, Data:%02x, BK1:%02x, BK2:%02x, CTRL:%02x, MROM:%08x, UROM:%08x\n", address, data, RFSCtrl.regBank1, RFSCtrl.regBank2, RFSCtrl.regCtrl, RFSCtrl.mromAddr, RFSCtrl.uromAddr);
|
||||
return;
|
||||
}
|
||||
1078
software/FusionX/src/z80drv/src/z80vhw_tzpu.c
Normal file
1078
software/FusionX/src/z80drv/src/z80vhw_tzpu.c
Normal file
File diff suppressed because it is too large
Load Diff
83
software/FusionX/start_FusionX.sh
Normal file → Executable file
83
software/FusionX/start_FusionX.sh
Normal file → Executable file
@@ -1,6 +1,83 @@
|
||||
#!/bin/sh
|
||||
#########################################################################################################
|
||||
##
|
||||
## Name: start_FusionX.sh
|
||||
## Created: March 2023
|
||||
## Author(s): Philip Smart
|
||||
## Description: Sharp MZ series FusionX start script.
|
||||
## This script starts required services which form the FusionX ecosphere.
|
||||
## tranZPUter SW memory as a User ROM application.
|
||||
##
|
||||
## Credits:
|
||||
## Copyright: (c) 2018-2023 Philip Smart <philip.smart@net2net.org>
|
||||
##
|
||||
## History: March 2023 - Initial script written.
|
||||
##
|
||||
#########################################################################################################
|
||||
## 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/>.
|
||||
#########################################################################################################
|
||||
|
||||
ROOTDIR=/apps/FusionX
|
||||
# Constants.
|
||||
FUSIONXDIR=/apps/FusionX
|
||||
|
||||
cd ${ROOTDIR}
|
||||
#nohup ${ROOTDIR}/bin/FusionX &
|
||||
cd ${FUSIONXDIR}
|
||||
|
||||
# If not already installed, install the Sharp MZ TTY terminal driver.
|
||||
if [ "`lsmod | grep ttymzdrv`" = "" ]; then
|
||||
echo "Loading SharpMZ TTY Driver."
|
||||
cd ${FUSIONXDIR}/modules
|
||||
insmod ttymzdrv.ko
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Start a Getty login process on the SharpMZ TTY terminal.
|
||||
setsid getty 9600 /dev/ttymz0 ansi &
|
||||
|
||||
# Detach CPU 1 from scheduler and IRQ's as it will be dedicated to the z80drv.
|
||||
for f in `ps -eaf |grep -v kthread_z80 | awk '{print $1}'`
|
||||
do
|
||||
taskset -pc 0 $f >/dev/null 2>/dev/null
|
||||
done
|
||||
|
||||
# Detach IRQ's
|
||||
for I in $(ls /proc/irq)
|
||||
do
|
||||
if [[ -d "/proc/irq/$I" ]]
|
||||
then
|
||||
echo 0 > /proc/irq/$I/smp_affinity_list 2>/dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
# Load the Z80 driver. Small pause to ensure the driver is fully loaded and initialsed prior to loading ROM images.
|
||||
echo "Loading Z80 Driver."
|
||||
cd ${FUSIONXDIR}/modules
|
||||
rmmod z80drv 2>/dev/null
|
||||
insmod z80drv.ko
|
||||
sleep 1
|
||||
|
||||
# Start the K64F virtual cpu.
|
||||
echo "Starting K64F Virtual CPU."
|
||||
${FUSIONXDIR}/bin/k64fcpu &
|
||||
|
||||
# Start the Sharp MZ Arbiter.
|
||||
echo "Starting Sharp MZ Arbiter."
|
||||
${FUSIONXDIR}/bin/sharpbiter &
|
||||
|
||||
# Ensure the system is set for performance mode with max frequency.
|
||||
# NB: Enabling this prior to starting the Z80 results in a kernel error.
|
||||
echo performance > /sys/devices//system/cpu/cpufreq/policy0/scaling_governor
|
||||
echo 1200000 > /sys/devices//system/cpu/cpufreq/policy0/scaling_min_freq
|
||||
|
||||
# Done.
|
||||
echo "FusionX running."
|
||||
|
||||
1
software/asm/1Z001M.asm
Symbolic link
1
software/asm/1Z001M.asm
Symbolic link
@@ -0,0 +1 @@
|
||||
/srv2/SharpSoft/MZ-2000/ASM/1Z001M.asm
|
||||
3303
software/asm/1z-013a-km.asm
Normal file
3303
software/asm/1z-013a-km.asm
Normal file
File diff suppressed because it is too large
Load Diff
25545
software/asm/5z009-1b.asm
Normal file
25545
software/asm/5z009-1b.asm
Normal file
File diff suppressed because it is too large
Load Diff
1658
software/asm/SFD700.asm
Normal file
1658
software/asm/SFD700.asm
Normal file
File diff suppressed because it is too large
Load Diff
2298
software/asm/asm.asm
Normal file
2298
software/asm/asm.asm
Normal file
File diff suppressed because it is too large
Load Diff
5908
software/asm/basic_sp-5025.asm
Normal file
5908
software/asm/basic_sp-5025.asm
Normal file
File diff suppressed because it is too large
Load Diff
1615
software/asm/cbios.asm
Normal file
1615
software/asm/cbios.asm
Normal file
File diff suppressed because it is too large
Load Diff
3908
software/asm/cbiosII.asm
Normal file
3908
software/asm/cbiosII.asm
Normal file
File diff suppressed because it is too large
Load Diff
35
software/asm/cpm22-bios.asm
Normal file
35
software/asm/cpm22-bios.asm
Normal file
@@ -0,0 +1,35 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: cpm22-bios.asm
|
||||
;- Created: January 2020
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: CPM BIOS for CPM v2.23 on the Sharp MZ80A with the Rom Filing System.
|
||||
;- Most of the code is stored in the ROM based CBIOS which is part of the
|
||||
;- Rom Filing System upgrade. Declarations in this file are for tables
|
||||
;- which need to reside in RAM.
|
||||
;-
|
||||
;- Credits: Some of the comments and parts of the deblocking/blocking algorithm come from the
|
||||
; Z80-MBC2 project, (C) SuperFabius.
|
||||
;- Copyright: (c) 2020 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: January 2020 - Initial creation.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
ORG CPMBIOS
|
||||
|
||||
; All CBIOS code, tables and variables are now stored in the cbios.asm and cbiosII.asm as a seperate assembled
|
||||
; binary.
|
||||
3764
software/asm/cpm22.asm
Normal file
3764
software/asm/cpm22.asm
Normal file
File diff suppressed because it is too large
Load Diff
1
software/asm/include/MSBASIC_BuildVersion.asm
Normal file
1
software/asm/include/MSBASIC_BuildVersion.asm
Normal file
@@ -0,0 +1 @@
|
||||
BUILD_VERSION EQU 3
|
||||
1
software/asm/include/cpm_buildversion.asm
Normal file
1
software/asm/include/cpm_buildversion.asm
Normal file
@@ -0,0 +1 @@
|
||||
BUILD_VERSION EQU 2
|
||||
536
software/asm/include/cpm_definitions.asm
Normal file
536
software/asm/include/cpm_definitions.asm
Normal file
@@ -0,0 +1,536 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: CPM_Definitions.asm
|
||||
;- Created: January 2020
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Sharp MZ series CPM v2.23
|
||||
;- Definitions for the Sharp MZ80A CPM v2.23 OS used in the RFS
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-21 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: Jan 2020 - Initial version.
|
||||
; May 2020 - Advent of the new RFS PCB v2.0, quite a few changes to accommodate the
|
||||
; additional and different hardware. The SPI is now onboard the PCB and
|
||||
; not using the printer interface card.
|
||||
; May 2020 - Cut from the RFS version of CPM for the tranZPUter SW board.
|
||||
;- Apr 2021 - Updates backported from the RFS version of CPM.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
;-----------------------------------------------
|
||||
; Features.
|
||||
;-----------------------------------------------
|
||||
; CPM for MZ-700 with with Video Module and 80 Columns display.
|
||||
IF BUILD_VERSION = 0
|
||||
BUILD_VIDEOMODULE EQU 1 ; Build for the Video Module v2 board (=1) otherwise build for the 80Char Colour Board v1.0
|
||||
BUILD_MZ80A EQU 0 ; Build for the Sharp MZ-80A base hardware.
|
||||
BUILD_MZ700 EQU 1 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_80C EQU 1 ; Build for an 80 column (Video Module or 40/80 Colour Card) equipped machine, 0 = standard 40 column.
|
||||
ENDIF
|
||||
; CPM for MZ-80A with with Video Module (if not present expects 40/80 Colour Board) and 80 Columns display.
|
||||
IF BUILD_VERSION = 1
|
||||
BUILD_VIDEOMODULE EQU 1 ; Build for the Video Module v2 board (=1) otherwise build for the 80Char Colour Board v1.0
|
||||
BUILD_MZ80A EQU 1 ; Build for the Sharp MZ-80A base hardware.
|
||||
BUILD_MZ700 EQU 0 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_80C EQU 1 ; Build for an 80 column (Video Module or 40/80 Colour Card) equipped machine, 0 = standard 40 column.
|
||||
ENDIF
|
||||
; CPM for MZ-80A with with standard 40 column display.
|
||||
IF BUILD_VERSION = 2
|
||||
BUILD_VIDEOMODULE EQU 0 ; Build for the Video Module v2 board (=1) otherwise build for the 80Char Colour Board v1.0
|
||||
BUILD_MZ80A EQU 1 ; Build for the Sharp MZ-80A base hardware.
|
||||
BUILD_MZ700 EQU 0 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_80C EQU 0 ; Build for an 80 column (Video Module or 40/80 Colour Card) equipped machine, 0 = standard 40 column.
|
||||
ENDIF
|
||||
|
||||
;-----------------------------------------------
|
||||
; Configurable settings.
|
||||
;-----------------------------------------------
|
||||
MAXRDRETRY EQU 002h
|
||||
MAXWRRETRY EQU 002h
|
||||
BLKSIZ EQU 4096 ; CP/M allocation size
|
||||
HSTSIZ EQU 512 ; host disk sector size
|
||||
HSTSPT EQU 32 ; host disk sectors/trk
|
||||
HSTBLK EQU HSTSIZ/128 ; CP/M sects/host buff
|
||||
CPMSPT EQU HSTBLK * HSTSPT ; CP/M sectors/track
|
||||
SECMSK EQU HSTBLK-1 ; sector mask
|
||||
WRALL EQU 0 ; write to allocated
|
||||
WRDIR EQU 1 ; write to directory
|
||||
WRUAL EQU 2 ; write to unallocated
|
||||
TMRTICKINTV EQU 5 ; Number of 0.010mSec ticks per interrupt, ie. resolution of RTC.
|
||||
MTROFFMSECS EQU 100 ; Time from last access to motor being switched off in seconds in TMRTICKINTV ticks.
|
||||
IF BUILD_80C = 1
|
||||
COLW EQU 80 ; Width of the display screen (ie. columns).
|
||||
ELSE
|
||||
COLW EQU 40 ; Width of the display screen (ie. columns).
|
||||
ENDIF
|
||||
ROW EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
SCRLW EQU COLW / 8 ; Number of 8 byte regions in a line for hardware scroll.
|
||||
|
||||
; BIOS equates
|
||||
MAXDISKS EQU 7 ; Max number of Drives supported
|
||||
KEYBUFSIZE EQU 64 ; Ensure this is a power of 2, max size 256.
|
||||
|
||||
; Debugging
|
||||
ENADEBUG EQU 1 ; Enable debugging logic, 1 = enable, 0 = disable
|
||||
|
||||
;-----------------------------------------------
|
||||
; Entry/compilation start points.
|
||||
;-----------------------------------------------
|
||||
MROMADDR EQU 00000H ; Start of SA1510 Monitor ROM.
|
||||
CBASE EQU 0DA00H
|
||||
CPMCCP EQU CBASE ; CP/M System entry
|
||||
CPMBDOS EQU CPMCCP + 0806H ; BDOS entry
|
||||
CPMBIOS EQU CPMCCP + 01600H ; Original CPM22 BIOS entry
|
||||
CBIOSSTART EQU CPMBIOS ; Start of the actual CBIOS code.
|
||||
CPMCOPYRMSG EQU CBASE+8 ; Copyright message stored in CP/M binary.
|
||||
BOOT EQU CBIOSSTART + 0
|
||||
WBOOT EQU CBIOSSTART + 3
|
||||
WBOOTE EQU CBIOSSTART + 3
|
||||
CONST EQU CBIOSSTART + 6
|
||||
CONIN EQU CBIOSSTART + 9
|
||||
CONOUT EQU CBIOSSTART + 12
|
||||
LIST EQU CBIOSSTART + 15
|
||||
PUNCH EQU CBIOSSTART + 18
|
||||
READER EQU CBIOSSTART + 21
|
||||
HOME EQU CBIOSSTART + 24
|
||||
SELDSK EQU CBIOSSTART + 27
|
||||
SETTRK EQU CBIOSSTART + 30
|
||||
SETSEC EQU CBIOSSTART + 33
|
||||
SETDMA EQU CBIOSSTART + 36
|
||||
READ EQU CBIOSSTART + 39
|
||||
WRITE EQU CBIOSSTART + 42
|
||||
FRSTAT EQU CBIOSSTART + 45
|
||||
SECTRN EQU CBIOSSTART + 48
|
||||
QDEBUG EQU CBIOSSTART + 51
|
||||
CCP EQU CBASE
|
||||
CCPCLRBUF EQU CBASE + 3
|
||||
IOBYT EQU 00003H ; IOBYTE address
|
||||
CDISK EQU 00004H ; Address of Current drive name and user number
|
||||
CPMUSERDMA EQU 00080h ; Default CPM User DMA address.
|
||||
DPSIZE EQU 16 ; Size of a Disk Parameter Block
|
||||
; Old Flash RAM mapping
|
||||
;FDCJMP1BLK EQU 0F3C0H ; The memory mapping FlashRAM only has 64byte granularity so we need to block 64 bytes per FDC vector.
|
||||
;FDCJMP1 EQU 0F3FEH ; ROM paged vector 1.
|
||||
;FDCJMP2BLK EQU 0F7C0H ; The memory mapping FlashRAM only has 64byte granularity so we need to block 64 bytes per FDC vector.
|
||||
;FDCJMP2 EQU 0F7FEH ; ROM paged vector 2.
|
||||
; New CPLD mapping
|
||||
FDCJMP1BLK EQU 0F3FEH ; The memory mapping CPLD has 1byte granularity so we need to block just 2 bytes per FDC vector.
|
||||
FDCJMP1 EQU 0F3FEH ; ROM paged vector 1.
|
||||
FDCJMP2BLK EQU 0F7FEH ; The memory mapping CPLD has 1byte granularity so we need to block just 2 bytes per FDC vector.
|
||||
FDCJMP2 EQU 0F7FEH ; ROM paged vector 2.
|
||||
|
||||
|
||||
;-----------------------------------------------
|
||||
; Memory mapped ports in hardware.
|
||||
;-----------------------------------------------
|
||||
SCRN: EQU 0D000H
|
||||
ARAM: EQU 0D800H
|
||||
DSPCTL: EQU 0DFFFH ; Screen 40/80 select register (bit 7)
|
||||
KEYPA: EQU 0E000h
|
||||
KEYPB: EQU 0E001h
|
||||
KEYPC: EQU 0E002h
|
||||
KEYPF: EQU 0E003h
|
||||
CSTR: EQU 0E002h
|
||||
CSTPT: EQU 0E003h
|
||||
CONT0: EQU 0E004h
|
||||
CONT1: EQU 0E005h
|
||||
CONT2: EQU 0E006h
|
||||
CONTF: EQU 0E007h
|
||||
SUNDG: EQU 0E008h
|
||||
TEMP: EQU 0E008h
|
||||
MEMSW: EQU 0E00CH
|
||||
MEMSWR: EQU 0E010H
|
||||
INVDSP: EQU 0E014H
|
||||
NRMDSP: EQU 0E015H
|
||||
SCLDSP: EQU 0E200H
|
||||
SCLBASE: EQU 0E2H
|
||||
|
||||
;-----------------------------------------------
|
||||
; IO ports in hardware and values.
|
||||
;-----------------------------------------------
|
||||
MMCFG EQU 060H ; Memory management configuration latch.
|
||||
SETXMHZ EQU 062H ; Select the alternate clock frequency.
|
||||
SET2MHZ EQU 064H ; Select the system 2MHz clock frequency.
|
||||
CLKSELRD EQU 066H ; Read clock selected setting, 0 = 2MHz, 1 = XMHz
|
||||
SVCREQ EQU 068H ; I/O Processor service request.
|
||||
CPLDSTATUS EQU 06BH ; Version 2.1 CPLD status register.
|
||||
CPUCFG EQU 06CH ; Version 2.2 CPU configuration register.
|
||||
CPUSTATUS EQU 06CH ; Version 2.2 CPU runtime status register.
|
||||
CPUINFO EQU 06DH ; Version 2.2 CPU information register.
|
||||
CPLDCFG EQU 06EH ; Version 2.1 CPLD configuration register.
|
||||
CPLDINFO EQU 06FH ; Version 2.1 CPLD version information register.
|
||||
VMPNUM EQU 0A0H ; Set the parameter number to update.
|
||||
VMPLBYTE EQU 0A1H ; Update the lower selected parameter byte.
|
||||
VMPUBYTE EQU 0A2H ; Update the upper selected parameter byte.
|
||||
PALSLCTOFF EQU 0A3H ; set the palette slot Off position to be adjusted.
|
||||
PALSLCTON EQU 0A4H ; set the palette slot On position to be adjusted.
|
||||
PALSETRED EQU 0A5H ; set the red palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETGREEN EQU 0A6H ; set the green palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETBLUE EQU 0A7H ; set the blue palette value according to the PALETTE_PARAM_SEL address.
|
||||
VMPALETTE EQU 0B0H ; Select Palette:
|
||||
; 0xB0 sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output.
|
||||
; Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input.
|
||||
; GPU:
|
||||
GPUPARAM EQU 0B2H ; 0xB2 set parameters. Store parameters in a long word to be used by the graphics command processor.
|
||||
; The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0.
|
||||
GPUCMD EQU 0B3H ; 0xB3 set the graphics processor unit commands.
|
||||
GPUSTATUS EQU 0B3H ; [7;1] - FSM state, [0] - 1 = busy, 0 = idle
|
||||
; Bits [5:0] - 0 = Reset parameters.
|
||||
; 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter
|
||||
;
|
||||
VMCTRL EQU 0B8H ; Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col.
|
||||
VMGRMODE EQU 0B9H ; Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used).
|
||||
VMREDMASK EQU 0BAH ; Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMGREENMASK EQU 0BBH ; Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMBLUEMASK EQU 0BCH ; Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMPAGE EQU 0BDH ; Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF.
|
||||
VMVGATTR EQU 0BEH ; Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue.
|
||||
VMVGAMODE EQU 0BFH ; Select VGA output mode. Bits [3:0] - Output mode.
|
||||
|
||||
GDCRTC EQU 0CFH ; MZ-800 CRTC control register
|
||||
GDCMD EQU 0CEH ; MZ-800 CRTC Mode register
|
||||
GDGRF EQU 0CDH ; MZ-800 read format register
|
||||
GDGWF EQU 0CCH ; MZ-800 write format register
|
||||
MMIO0 EQU 0E0H ; MZ-700/MZ-800 Memory Management Set 0
|
||||
MMIO1 EQU 0E1H ; MZ-700/MZ-800 Memory Management Set 1
|
||||
MMIO2 EQU 0E2H ; MZ-700/MZ-800 Memory Management Set 2
|
||||
MMIO3 EQU 0E3H ; MZ-700/MZ-800 Memory Management Set 3
|
||||
MMIO4 EQU 0E4H ; MZ-700/MZ-800 Memory Management Set 4
|
||||
MMIO5 EQU 0E5H ; MZ-700/MZ-800 Memory Management Set 5
|
||||
MMIO6 EQU 0E6H ; MZ-700/MZ-800 Memory Management Set 6
|
||||
MMIO7 EQU 0E7H ; MZ-700/MZ-800 Memory Management Set 7
|
||||
SYSCTRL EQU 0F0H ; System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus.
|
||||
GRAMMODE EQU 0F4H ; MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display.
|
||||
|
||||
;-----------------------------------------------
|
||||
; IO Registers
|
||||
;-----------------------------------------------
|
||||
FDC EQU 0D8h ; MB8866 IO Region 0D8h - 0DBh
|
||||
FDC_CR EQU FDC + 000h ; Command Register
|
||||
FDC_STR EQU FDC + 000h ; Status Register
|
||||
FDC_TR EQU FDC + 001h ; Track Register
|
||||
FDC_SCR EQU FDC + 002h ; Sector Register
|
||||
FDC_DR EQU FDC + 003h ; Data Register
|
||||
FDC_MOTOR EQU FDC + 004h ; DS[0-3] and Motor control. 4 drives DS= BIT 0 -> Bit 2 = Drive number, 2=1,1=0,0=0 DS0, 2=1,1=0,0=1 DS1 etc
|
||||
; bit 7 = 1 MOTOR ON LOW (Active)
|
||||
FDC_SIDE EQU FDC + 005h ; Side select, Bit 0 when set = SIDE SELECT LOW
|
||||
|
||||
;-----------------------------------------------
|
||||
; Common character definitions.
|
||||
;-----------------------------------------------
|
||||
SCROLL EQU 001H ;Set scroll direction UP.
|
||||
BELL EQU 007H
|
||||
SPACE EQU 020H
|
||||
TAB EQU 009H ;TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||
CR EQU 00DH
|
||||
LF EQU 00AH
|
||||
FF EQU 00CH
|
||||
CS EQU 0CH ; Clear screen
|
||||
DELETE EQU 07FH
|
||||
BACKS EQU 008H
|
||||
SOH EQU 1 ; For XModem etc.
|
||||
EOT EQU 4
|
||||
ACK EQU 6
|
||||
NAK EQU 015H
|
||||
NUL EQU 000H
|
||||
NULL EQU 000H
|
||||
CTRL_A EQU 001H
|
||||
CTRL_B EQU 002H
|
||||
CTRL_C EQU 003H
|
||||
CTRL_D EQU 004H
|
||||
CTRL_E EQU 005H
|
||||
CTRL_F EQU 006H
|
||||
CTRL_G EQU 007H
|
||||
CTRL_H EQU 008H
|
||||
CTRL_I EQU 009H
|
||||
CTRL_J EQU 00AH
|
||||
CTRL_K EQU 00BH
|
||||
CTRL_L EQU 00CH
|
||||
CTRL_M EQU 00DH
|
||||
CTRL_N EQU 00EH
|
||||
CTRL_O EQU 00FH
|
||||
CTRL_P EQU 010H
|
||||
CTRL_Q EQU 011H
|
||||
CTRL_R EQU 012H
|
||||
CTRL_S EQU 013H
|
||||
CTRL_T EQU 014H
|
||||
CTRL_U EQU 015H
|
||||
CTRL_V EQU 016H
|
||||
CTRL_W EQU 017H
|
||||
CTRL_X EQU 018H
|
||||
CTRL_Y EQU 019H
|
||||
CTRL_Z EQU 01AH
|
||||
ESC EQU 01BH
|
||||
CTRL_SLASH EQU 01CH
|
||||
CTRL_LB EQU 01BH
|
||||
CTRL_RB EQU 01DH
|
||||
CTRL_CAPPA EQU 01EH
|
||||
CTRL_UNDSCR EQU 01FH
|
||||
CTRL_AT EQU 000H
|
||||
NOKEY EQU 0F0H
|
||||
CURSRIGHT EQU 0F1H
|
||||
CURSLEFT EQU 0F2H
|
||||
CURSUP EQU 0F3H
|
||||
CURSDOWN EQU 0F4H
|
||||
DBLZERO EQU 0F5H
|
||||
INSERT EQU 0F6H
|
||||
CLRKEY EQU 0F7H
|
||||
HOMEKEY EQU 0F8H
|
||||
BREAKKEY EQU 0FBH
|
||||
GRAPHKEY EQU 0FCH
|
||||
ALPHAKEY EQU 0FDH
|
||||
|
||||
|
||||
; MMC/SD command (SPI mode)
|
||||
CMD0 EQU 64 + 0 ; GO_IDLE_STATE
|
||||
CMD1 EQU 64 + 1 ; SEND_OP_COND
|
||||
ACMD41 EQU 0x40+41 ; SEND_OP_COND (SDC)
|
||||
CMD8 EQU 64 + 8 ; SEND_IF_COND
|
||||
CMD9 EQU 64 + 9 ; SEND_CSD
|
||||
CMD10 EQU 64 + 10 ; SEND_CID
|
||||
CMD12 EQU 64 + 12 ; STOP_TRANSMISSION
|
||||
CMD13 EQU 64 + 13 ; SEND_STATUS
|
||||
ACMD13 EQU 0x40+13 ; SD_STATUS (SDC)
|
||||
CMD16 EQU 64 + 16 ; SET_BLOCKLEN
|
||||
CMD17 EQU 64 + 17 ; READ_SINGLE_BLOCK
|
||||
CMD18 EQU 64 + 18 ; READ_MULTIPLE_BLOCK
|
||||
CMD23 EQU 64 + 23 ; SET_BLOCK_COUNT
|
||||
ACMD23 EQU 0x40+23 ; SET_WR_BLK_ERASE_COUNT (SDC)
|
||||
CMD24 EQU 64 + 24 ; WRITE_BLOCK
|
||||
CMD25 EQU 64 + 25 ; WRITE_MULTIPLE_BLOCK
|
||||
CMD32 EQU 64 + 32 ; ERASE_ER_BLK_START
|
||||
CMD33 EQU 64 + 33 ; ERASE_ER_BLK_END
|
||||
CMD38 EQU 64 + 38 ; ERASE
|
||||
CMD55 EQU 64 + 55 ; APP_CMD
|
||||
CMD58 EQU 64 + 58 ; READ_OCR
|
||||
SD_SECSIZE EQU 512 ; Default size of an SD Sector
|
||||
SD_RETRIES EQU 00100H ; Number of retries before giving up.
|
||||
|
||||
; Card type flags (CardType)
|
||||
CT_MMC EQU 001H ; MMC ver 3
|
||||
CT_SD1 EQU 002H ; SD ver 1
|
||||
CT_SD2 EQU 004H ; SD ver 2
|
||||
CT_SDC EQU CT_SD1|CT_SD2 ; SD
|
||||
CT_BLOCK EQU 008H ; Block addressing
|
||||
|
||||
; Disk types.
|
||||
DSKTYP_FDC EQU 0 ; Type of disk is a Floppy disk and handled by the FDC controller.
|
||||
;DSKTYP_ROM EQU 1 ; Type of disk is a ROM and handled by the ROM methods.
|
||||
DSKTYP_SDC EQU 2 ; Type of disk is an SD Card and handled by the SD Card methods.
|
||||
DSKTYP_RAM EQU 3 ; Type of disk is a RAM Drive handled by ROM/RAM methods.
|
||||
|
||||
;
|
||||
;-----------------------------------------------
|
||||
; CPLD Configuration constants.
|
||||
;-----------------------------------------------
|
||||
MODE_MZ80K EQU 0 ; Set to MZ-80K mode.
|
||||
MODE_MZ80C EQU 1 ; Set to MZ-80C mode.
|
||||
MODE_MZ1200 EQU 2 ; Set to MZ-1200 mode.
|
||||
MODE_MZ80A EQU 3 ; Set to MZ-80A mode (base mode on MZ-80A hardware).
|
||||
MODE_MZ700 EQU 4 ; Set to MZ-700 mode (base mode on MZ-700 hardware).
|
||||
MODE_MZ800 EQU 5 ; Set to MZ-800 mode.
|
||||
MODE_MZ80B EQU 6 ; Set to MZ-80B mode.
|
||||
MODE_MZ2000 EQU 7 ; Set to MZ-2000 mode.
|
||||
MODE_VIDEO_FPGA EQU 8 ; Bit flag (bit 3) to switch CPLD into using the new FPGA video hardware.
|
||||
MODE_RESET_PRESERVE EQU 080H ; Preserve register configuration through reset.
|
||||
|
||||
;-----------------------------------------------
|
||||
; CPLD Command Instruction constants.
|
||||
;-----------------------------------------------
|
||||
CPLD_RESET_HOST EQU 1 ; CPLD level command to reset the host system.
|
||||
CPLD_HOLD_HOST_BUS EQU 2 ; CPLD command to hold the host bus.
|
||||
CPLD_RELEASE_HOST_BUS EQU 3 ; CPLD command to release the host bus.
|
||||
|
||||
;-----------------------------------------------
|
||||
; FPGA CPU enhancement control bits.
|
||||
;-----------------------------------------------
|
||||
CPUMODE_SET_Z80 EQU 000H ; Set the CPU to the hard Z80.
|
||||
CPUMODE_SET_T80 EQU 001H ; Set the CPU to the soft T80.
|
||||
CPUMODE_SET_ZPU_EVO EQU 002H ; Set the CPU to the soft ZPU Evolution.
|
||||
CPUMODE_SET_AAA EQU 004H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_BBB EQU 008H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_CCC EQU 010H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_DDD EQU 020H ; Place holder for a future soft CPU.
|
||||
CPUMODE_IS_Z80 EQU 000H ; Status value to indicate if the hard Z80 available.
|
||||
CPUMODE_IS_T80 EQU 001H ; Status value to indicate if the soft T80 available.
|
||||
CPUMODE_IS_ZPU_EVO EQU 002H ; Status value to indicate if the soft ZPU Evolution available.
|
||||
CPUMODE_IS_AAA EQU 004H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_BBB EQU 008H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_CCC EQU 010H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_DDD EQU 020H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_RESET_CPU EQU 080H ; Reset the soft CPU. Active high, when high the CPU is held in RESET, when low the CPU runs.
|
||||
CPUMODE_IS_SOFT_AVAIL EQU 040H ; Marker to indicate if the underlying FPGA can support soft CPU's.
|
||||
CPUMODE_IS_SOFT_MASK EQU 0C0H ; Mask to filter out the Soft CPU availability flags.
|
||||
CPUMODE_IS_CPU_MASK EQU 03FH ; Mask to filter out which soft CPU's are available.
|
||||
|
||||
;-----------------------------------------------
|
||||
; Video Module control bits.
|
||||
;-----------------------------------------------
|
||||
MODE_80CHAR EQU 010H ; Enable 80 character display.
|
||||
MODE_COLOUR EQU 020H ; Enable colour display.
|
||||
SYSMODE_MZ80A EQU 000H ; System board mode MZ80A, 2MHz CPU/Bus.
|
||||
SYSMODE_MZ80B EQU 020H ; System board mode MZ80B, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ2000 EQU 020H ; System board mode MZ2000, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ700 EQU 042H ; System board mode MZ700, 3.54MHz CPU/Bus.
|
||||
VMMODE_MZ80K EQU 000H ; Video mode = MZ80K
|
||||
VMMODE_MZ80C EQU 001H ; Video mode = MZ80C
|
||||
VMMODE_MZ1200 EQU 002H ; Video mode = MZ1200
|
||||
VMMODE_MZ80A EQU 003H ; Video mode = MZ80A
|
||||
VMMODE_MZ700 EQU 004H ; Video mode = MZ700
|
||||
VMMODE_MZ800 EQU 005H ; Video mode = MZ800
|
||||
VMMODE_MZ1500 EQU 006H ; Video mode = MZ1500
|
||||
VMMODE_MZ80B EQU 007H ; Video mode = MZ80B
|
||||
VMMODE_MZ2000 EQU 008H ; Video mode = MZ2000
|
||||
VMMODE_MZ2200 EQU 009H ; Video mode = MZ2200
|
||||
VMMODE_MZ2500 EQU 00AH ; Video mode = MZ2500
|
||||
VMMODE_PCGRAM EQU 020H ; Enable PCG RAM.
|
||||
VMMODE_VGA_OFF EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT50 EQU 001H ; Set VGA mode off, external monitor is driven by standard internal 50Hz signals.
|
||||
VMMODE_VGA_640x480 EQU 002H ; Set external monitor to VGA 640x480 @ 60Hz mode.
|
||||
VMMODE_VGA_800x600 EQU 003H ; Set external monitor to VGA 800x600 @ 60Hz mode.
|
||||
|
||||
;-----------------------------------------------
|
||||
; GPU commands.
|
||||
;-----------------------------------------------
|
||||
GPUCLEARVRAM EQU 001H ; Clear the VRAM without updating attributes.
|
||||
GPUCLEARVRAMCA EQU 002H ; Clear the VRAM/ARAM with given attribute byte,
|
||||
GPUCLEARVRAMP EQU 003H ; Clear the VRAM/ARAM with parameters.
|
||||
GPUCLEARGRAM EQU 081H ; Clear the entire Framebuffer.
|
||||
GPUCLEARGRAMP EQU 082H ; Clear the Framebuffer according to parameters.
|
||||
GPURESET EQU 0FFH ; Reset the GPU, return to idle state.
|
||||
|
||||
;-----------------------------------------------
|
||||
; tranZPUter SW Memory Management modes
|
||||
;-----------------------------------------------
|
||||
TZMM_ENIOWAIT EQU 020H ; Memory management IO Wait State enable - insert a wait state when an IO operation to E0-FF is executed.
|
||||
TZMM_ORIG EQU 000H ; Original Sharp MZ80A mode, no tranZPUter features are selected except the I/O control registers (default: 0x60-063).
|
||||
TZMM_BOOT EQU 001H ; Original mode but E800-EFFF is mapped to tranZPUter RAM so TZFS can be booted.
|
||||
TZMM_TZFS EQU 002H ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS2 EQU 003H ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS3 EQU 004H ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS4 EQU 005H ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_CPM EQU 006H ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_CPM2 EQU 007H ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_COMPAT EQU 008H ; TZMM_ENIOWAIT ; Original mode but with main DRAM in Bank 0 to allow bootstrapping of programs from other machines such as the MZ700.
|
||||
TZMM_HOSTACCESS EQU 009H ; TZMM_ENIOWAIT ; Mode to allow code running in Bank 0, address E800:FFFF to access host memory. 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.
|
||||
TZMM_MZ700_0 EQU 00AH ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_1 EQU 00BH ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_2 EQU 00CH ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_3 EQU 00DH ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_4 EQU 00EH ; TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ800 EQU 00FH ; TZMM_ENIOWAIT ; MZ800 Mode - Tracks original hardware mode offering MZ700/MZ800 configurations.
|
||||
TZMM_MZ2000 EQU 010H + TZMM_ENIOWAIT; ; MZ2000 Mode - Running on MZ2000 hardware, configuration set according to runtime configuration registers.
|
||||
TZMM_FPGA EQU 015H ; TZMM_ENIOWAIT ; Open up access for the K64F to the FPGA resources such as memory. All other access to RAM or mainboard is blocked.
|
||||
TZMM_TZPUM EQU 016H ; TZMM_ENIOWAIT ; Everything in on mainboard, no access to tranZPUter memory.
|
||||
TZMM_TZPU EQU 017H ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU0 EQU 018H ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU1 EQU 019H ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 1 is selected.
|
||||
;TZMM_TZPU2 EQU 01AH ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 2 is selected.
|
||||
;TZMM_TZPU3 EQU 01BH ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 3 is selected.
|
||||
;TZMM_TZPU4 EQU 01CH ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 4 is selected.
|
||||
;TZMM_TZPU5 EQU 01DH ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 5 is selected.
|
||||
;TZMM_TZPU6 EQU 01EH ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 6 is selected.
|
||||
;TZMM_TZPU7 EQU 01FH ; TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 7 is selected.
|
||||
|
||||
;-----------------------------------------------
|
||||
; TZ File System Header (MZF)
|
||||
;-----------------------------------------------
|
||||
TZFS_ATRB: EQU 00000h ; Code Type, 01 = Machine Code.
|
||||
TZFS_NAME: EQU 00001h ; Title/Name (17 bytes).
|
||||
TZFS_SIZE: EQU 00012h ; Size of program.
|
||||
TZFS_DTADR: EQU 00014h ; Load address of program.
|
||||
TZFS_EXADR: EQU 00016h ; Exec address of program.
|
||||
TZFS_COMNT: EQU 00018h ; Comment
|
||||
TZFS_MZFLEN: EQU 128 ; Length of the MZF header.
|
||||
TZFS_CMTLEN: EQU 104 ; Length of the comment field
|
||||
|
||||
;
|
||||
; CPM constants
|
||||
;
|
||||
CPM_SD_SEC EQU 32
|
||||
CPM_SD_TRK EQU 1024
|
||||
CPM_SD_IMGSZ EQU CPM_SD_TRK * CPM_SD_SEC * SD_SECSIZE
|
||||
|
||||
;-----------------------------------------------
|
||||
; BIOS WORK AREA (MZ80A)
|
||||
;-----------------------------------------------
|
||||
TZVARMEM: EQU 0F4A0H
|
||||
TZSVCMEM: EQU 0F560H ; Start of a memory structure used to communicate with the K64F I/O processor for services such as disk access.
|
||||
TZSVCSIZE: EQU 00280H ;
|
||||
TZSVCDIRSZ: EQU 20 ; Size of the directory/file name.
|
||||
TZSVCFILESZ: EQU 17 ; Size of a Sharp filename.
|
||||
TZSVCLONGFILESZ: EQU 31 ; Size of a standard filename.
|
||||
TZSVCLONGFMTSZ: EQU 20 ; Size of a formatted standard filename for use in directory listings.
|
||||
TZSVCWILDSZ: EQU 20 ; Size of the wildcard.
|
||||
TZSVCSECSIZE: EQU 512
|
||||
TZSVCDIR_ENTSZ: EQU 32 ; Size of a directory entry.
|
||||
TZSVCWAITIORETRIES: EQU 500 ; Wait retries for IO response.
|
||||
TZSVCWAITCOUNT: EQU 65535 ; Wait retries for IO request response.
|
||||
TZSVC_FTYPE_MZF: EQU 0 ; File type being handled is an MZF
|
||||
TZSVC_FTYPE_MZFHDR: EQU 1 ; File type being handled is an MZF Header.
|
||||
TZSVC_FTYPE_CAS: EQU 2 ; File type being handled is an CASsette BASIC script.
|
||||
TZSVC_FTYPE_BAS: EQU 3 ; File type being handled is an BASic script
|
||||
TZSVC_FTYPE_ALL: EQU 10 ; Handle any filetype.
|
||||
TZSVC_FTYPE_ALLFMT: EQU 11 ; Special case for directory listings, all files but truncated and formatted.
|
||||
|
||||
TZSVC_CMD_READDIR EQU 01H ; Service command to open a directory and return the first block of entries.
|
||||
TZSVC_CMD_NEXTDIR EQU 02H ; Service command to return the next block of an open directory.
|
||||
TZSVC_CMD_READFILE EQU 03H ; Service command to open a file and return the first block.
|
||||
TZSVC_CMD_NEXTREADFILE EQU 04H ; Service command to return the next block of an open file.
|
||||
TZSVC_CMD_WRITEFILE EQU 05H ; Service command to create a file and save the first block.
|
||||
TZSVC_CMD_NEXTWRITEFILE EQU 06H ; Service command to write the next block to the open file.
|
||||
TZSVC_CMD_CLOSE EQU 07H ; Service command to close any open file or directory.
|
||||
TZSVC_CMD_LOADFILE EQU 08H ; Service command to load a file directly into tranZPUter memory.
|
||||
TZSVC_CMD_SAVEFILE EQU 09H ; Service command to save a file directly from tranZPUter memory.
|
||||
TZSVC_CMD_ERASEFILE EQU 0aH ; Service command to erase a file on the SD card.
|
||||
TZSVC_CMD_CHANGEDIR EQU 0bH ; Service command to change the active directory on the SD card.
|
||||
TZSVC_CMD_LOAD40ABIOS EQU 20H ; Service command requesting that the 40 column version of the SA1510 BIOS is loaded.
|
||||
TZSVC_CMD_LOAD80ABIOS EQU 21H ; Service command requesting that the 80 column version of the SA1510 BIOS is loaded.
|
||||
TZSVC_CMD_LOAD700BIOS40 EQU 22H ; Service command requesting that the MZ700 1Z-013A 40 column BIOS is loaded.
|
||||
TZSVC_CMD_LOAD700BIOS80 EQU 23H ; Service command requesting that the MZ700 1Z-013A 80 column patched BIOS is loaded.
|
||||
TZSVC_CMD_LOAD80BIPL EQU 24H ; Service command requesting the MZ-80B IPL is loaded.
|
||||
TZSVC_CMD_LOAD800BIOS EQU 25H ; Service command requesting that the MZ800 9Z-504M BIOS is loaded.
|
||||
TZSVC_CMD_LOAD2000IPL EQU 26H ; Service command requesting the MZ-2000 IPL is loaded.
|
||||
TZSVC_CMD_LOADTZFS EQU 2FH ; Service command requesting the loading of TZFS. This service is for machines which normally dont have a monitor BIOS. ie. MZ-80B/MZ-2000 and manually request TZFS.
|
||||
TZSVC_CMD_LOADBDOS EQU 30H ; Service command to reload CPM BDOS+CCP.
|
||||
TZSVC_CMD_ADDSDDRIVE EQU 31H ; Service command to attach a CPM disk to a drive number.
|
||||
TZSVC_CMD_READSDDRIVE EQU 32H ; Service command to read an attached SD file as a CPM disk drive.
|
||||
TZSVC_CMD_WRITESDDRIVE EQU 33H ; Service command to write to a CPM disk drive which is an attached SD file.
|
||||
TZSVC_CMD_CPU_BASEFREQ EQU 40H ; Service command to switch to the mainboard frequency.
|
||||
TZSVC_CMD_CPU_ALTFREQ EQU 41H ; Service command to switch to the alternate frequency provided by the K64F.
|
||||
TZSVC_CMD_CPU_CHGFREQ EQU 42H ; Service command to set the alternate frequency in hertz.
|
||||
TZSVC_CMD_CPU_SETZ80 EQU 50H ; Service command to switch to the external Z80 hard cpu.
|
||||
TZSVC_CMD_CPU_SETT80 EQU 51H ; Service command to switch to the internal T80 soft cpu.
|
||||
TZSVC_CMD_CPU_SETZPUEVO EQU 52H ; Service command to switch to the internal ZPU Evolution soft cpu.
|
||||
TZSVC_CMD_EMU_SETMZ80K EQU 53H ; Service command to switch to the internal Sharp MZ Series Emulation of the MZ80K.
|
||||
TZSVC_CMD_EMU_SETMZ80C EQU 54H ; "" "" "" MZ80C.
|
||||
TZSVC_CMD_EMU_SETMZ1200 EQU 55H ; "" "" "" MZ1200.
|
||||
TZSVC_CMD_EMU_SETMZ80A EQU 56H ; "" "" "" MZ80A.
|
||||
TZSVC_CMD_EMU_SETMZ700 EQU 57H ; "" "" "" MZ700.
|
||||
TZSVC_CMD_EMU_SETMZ800 EQU 58H ; "" "" "" MZ800.
|
||||
TZSVC_CMD_EMU_SETMZ1500 EQU 59H ; "" "" "" MZ1500.
|
||||
TZSVC_CMD_EMU_SETMZ80B EQU 5AH ; "" "" "" MZ80B.
|
||||
TZSVC_CMD_EMU_SETMZ2000 EQU 5BH ; "" "" "" MZ2000.
|
||||
TZSVC_CMD_EMU_SETMZ2200 EQU 5CH ; "" "" "" MZ2200.
|
||||
TZSVC_CMD_EMU_SETMZ2500 EQU 5DH ; "" "" "" MZ2500.
|
||||
TZSVC_CMD_EXIT EQU 07FH ; Service command to terminate TZFS and restart the machine in original mode.
|
||||
TZSVC_STATUS_OK EQU 000H ; Flag to indicate the K64F processing completed successfully.
|
||||
TZSVC_STATUS_REQUEST EQU 0FEH ; Flag to indicate the Z80 has made a request to the K64F.
|
||||
TZSVC_STATUS_PROCESSING EQU 0FFH ; Flag to indicate the K64F is processing a command.
|
||||
152
software/asm/include/macros.asm
Normal file
152
software/asm/include/macros.asm
Normal file
@@ -0,0 +1,152 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: Macros.asm
|
||||
;- Created: July 2019
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Z80 Assembler Macros Library
|
||||
;- This is an aassembly language macro source file containing resusable code in the form
|
||||
; of Macros for the various Z80 projects under development.
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2018-2020 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: May 2020 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
; the following is only to get the original length of 2048 bytes
|
||||
ALIGN: MACRO ?boundary
|
||||
DS ?boundary - 1 - ($ + ?boundary - 1) % ?boundary, 0FFh
|
||||
ENDM
|
||||
|
||||
; the following is only to get the original length of 2048 bytes
|
||||
ALIGN_NOPS: MACRO ?boundary
|
||||
DS ?boundary - 1 - ($ + ?boundary - 1) % ?boundary, 000h
|
||||
ENDM
|
||||
|
||||
;
|
||||
; Pads up to a certain address.
|
||||
; Gives an error message if that address is already exceeded.
|
||||
;
|
||||
PAD: MACRO ?address
|
||||
IF $ > ?address
|
||||
ERROR "Alignment exceeds %s"; % ?address
|
||||
ENDIF
|
||||
DS ?address - $
|
||||
ENDM
|
||||
|
||||
;
|
||||
; Pads up to the next multiple of the specified address.
|
||||
;
|
||||
;ALIGN: MACRO ?boundary
|
||||
; ds ?boundary - 1 - ($ + ?boundary - 1) % ?boundary
|
||||
; ENDM
|
||||
|
||||
;
|
||||
; Pads to ensure a section of the given size does not cross a 100H boundary.
|
||||
;
|
||||
ALIGN_FIT8: MACRO ?size
|
||||
DS (($ + ?size - 1) >> 8) != ($ >> 8) && (100H - ($ & 0FFH)) || 0
|
||||
ENDM
|
||||
|
||||
; Macro to create a Jump table entry point for a Bank to Bank function call.
|
||||
; The address of the real function in the required page is given as ?addr
|
||||
; and the bank in which it will reside is given in ?bank. The logic then takes
|
||||
; care of stack and memory mode manipulation to call the method and return to the
|
||||
; caller with all registers unaffected going to the called function and returning from
|
||||
; the called function. This allows any method to be placed in a bank as space dictates.
|
||||
CALLBNK: MACRO ?addr, ?bank
|
||||
EXX
|
||||
EX AF,AF'
|
||||
LD HL,?addr ; Real function to call.
|
||||
LD A,?bank ; Bank in which the function resides.
|
||||
JP BANKTOBANK_
|
||||
ENDM
|
||||
|
||||
; As above but just jump to the required location in the alternate bank, no return.
|
||||
JMPBNK: MACRO ?addr, ?bank
|
||||
EX AF,AF'
|
||||
LD A,?bank ; Bank in which the function resides.
|
||||
LD (MMCFGVAL),A ; Store the value in a memory variable as we cant read the latch once programmed.
|
||||
OUT (MMCFG),A ; Switch to the TZFS memory mode, SA1510 is now in RAM at 0000H
|
||||
EX AF,AF'
|
||||
LD HL,?addr ; Real function to jump to.
|
||||
JP (HL)
|
||||
ENDM
|
||||
|
||||
; Method to allow one bank to call a routine in another bank with all registers preserved in and out and
|
||||
; reentrant so banks can call banks. It is costly in processing time and should only be
|
||||
; used infrequently.
|
||||
;
|
||||
; Input: A = Memory mode to switch into.
|
||||
; (HLSAVE)= Original HL to pass to caller.
|
||||
; HL = Address to call.
|
||||
; AF = Stored on stack to pass to called function.
|
||||
; All other registers passed to called function.
|
||||
; All registers are passed untouched to the caller.
|
||||
; Stack; BKTOBKRET:AF (original memory mode) : Caller return address.
|
||||
; Output: All registers and flags returned to caller.
|
||||
;
|
||||
JMPTOBNK: MACRO
|
||||
LD (FNADDR),HL ; Save the function to call address stored in HL
|
||||
LD L,A ; Save A to retrieve the old Memory mode and push it on the stack so it can be restored after return.
|
||||
LD A,(MMCFGVAL)
|
||||
PUSH AF
|
||||
LD A,L
|
||||
; NB. Dont disable interrupts, goes to mode 7 then returns to MMCFGVAL,so apart from a double switch there should be no race state.
|
||||
LD (MMCFGVAL),A ; Store the value in a memory variable as we cant read the latch once programmed.
|
||||
OUT (MMCFG),A ; Switch to the TZFS memory mode, SA1510 is now in RAM at 0000H
|
||||
LD HL,BKTOBKRET ; Store the return address which must come back to this functionality before original caller.
|
||||
PUSH HL
|
||||
LD HL,(FNADDR) ; Push the address of the function to call onto the stack.
|
||||
PUSH HL
|
||||
EXX
|
||||
EX AF,AF'
|
||||
RET ; Call the required function by popping address off stack.
|
||||
BKTOBKRET: EX (SP),HL ; Retrieve original memory mode from stack.
|
||||
EX AF,AF'
|
||||
LD A,H
|
||||
LD (MMCFGVAL),A ; Store the value in a memory variable as we cant read the latch once programmed.
|
||||
OUT (MMCFG),A ; Switch to the TZFS memory mode, SA1510 is now in RAM at 0000H
|
||||
EX AF,AF'
|
||||
POP HL ; Restore HL.
|
||||
RET
|
||||
ENDM
|
||||
|
||||
; Alternate version which preserves caller stack and creates local stack, used in CPM where the caller (CPM) has a tiny stack
|
||||
; and the CBIOS needs more space. This version isnt reentrant, it is only used one way, CPM -> CBIOS.
|
||||
JMPTOBNK2: MACRO
|
||||
LD (STKSAVE),SP
|
||||
LD SP,CBIOSSTACK
|
||||
LD (FNADDR),HL ; Save the function to call address stored in HL
|
||||
; NB. Dont disable interrupts, goes to mode 7 then returns to MMCFGVAL,so apart from a double switch there should be no race state.
|
||||
LD A,TZMM_CPM2
|
||||
LD (MMCFGVAL),A ; Store the value in a memory variable as we cant read the latch once programmed.
|
||||
OUT (MMCFG),A ; Switch to the TZFS memory mode, SA1510 is now in RAM at 0000H
|
||||
LD HL,BKTOBKRET2 ; Store the return address which must come back to this functionality before original caller.
|
||||
PUSH HL
|
||||
LD HL,(FNADDR) ; Push the address of the function to call onto the stack.
|
||||
PUSH HL
|
||||
EXX
|
||||
EX AF,AF'
|
||||
RET ; Call the required function by popping address off stack.
|
||||
BKTOBKRET2: EX AF,AF'
|
||||
LD A,TZMM_CPM
|
||||
LD (MMCFGVAL),A ; Store the value in a memory variable as we cant read the latch once programmed.
|
||||
OUT (MMCFG),A ; Switch to the TZFS memory mode, SA1510 is now in RAM at 0000H
|
||||
EX AF,AF'
|
||||
LD SP,(STKSAVE)
|
||||
RET
|
||||
ENDM
|
||||
1
software/asm/include/msbasic_buildversion.asm
Normal file
1
software/asm/include/msbasic_buildversion.asm
Normal file
@@ -0,0 +1 @@
|
||||
BUILD_VERSION EQU 3
|
||||
534
software/asm/include/msbasic_definitions.asm
Normal file
534
software/asm/include/msbasic_definitions.asm
Normal file
@@ -0,0 +1,534 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: MSBASIC_Definitions.asm
|
||||
;- Created: June 2020
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Sharp MZ series CPM v2.23
|
||||
;- Definitions for the Sharp MZ80A CPM v2.23 OS used in the RFS
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-20 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: Jan 2020 - Initial version.
|
||||
; May 2020 - Advent of the new RFS PCB v2.0, quite a few changes to accommodate the
|
||||
; additional and different hardware. The SPI is now onboard the PCB and
|
||||
; not using the printer interface card.
|
||||
; Jun 2020 - Copied and strpped from TZFS for BASIC.
|
||||
; Mar 2021 - Updates to backport changes from the RFS version after v2.1 hw changes.
|
||||
;
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
;-----------------------------------------------
|
||||
; Features.
|
||||
;-----------------------------------------------
|
||||
|
||||
;-----------------------------------------------
|
||||
|
||||
;-----------------------------------------------
|
||||
; Configurable settings.
|
||||
;-----------------------------------------------
|
||||
; Build options. Set just one to '1' the rest to '0'.
|
||||
; NB: As there are now 4 versions and 1 or more need to be built, ie. MZ-80A and RFS version for RFS, a flag is set in the file
|
||||
; BASIC_build.asm which configures the equates below for the correct build.
|
||||
|
||||
; MZ-80A Standard Machine Configuration.
|
||||
IF BUILD_VERSION = 0
|
||||
BUILD_MZ80A EQU 1 ; Build for the standard Sharp MZ80A, no lower memory. Manually change MAXMEM above.
|
||||
BUILD_MZ700 EQU 0 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_MZ80A_TZFS EQU 0 ; Build for TZFS running on an MZ-80A where extended memory is available.
|
||||
BUILD_MZ700_TZFS EQU 0 ; Build for TZFS running on an MZ-700 where extended memory is available.
|
||||
BUILD_VIDEOMODULE EQU 0 ; Build for the Video Module v2 board (=1) otherwise build for the 80Char Colour Board v1.0
|
||||
BUILD_80C EQU 0
|
||||
INCLUDE_ANSITERM EQU 1 ; Include the Ansi terminal emulation processor in the build.
|
||||
ENDIF
|
||||
; MZ-700 Standard Machine Configuration.
|
||||
IF BUILD_VERSION = 1
|
||||
BUILD_MZ80A EQU 0
|
||||
BUILD_MZ700 EQU 1 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_MZ80A_TZFS EQU 0 ; Build for TZFS running on an MZ-80A where extended memory is available.
|
||||
BUILD_MZ700_TZFS EQU 0 ; Build for TZFS running on an MZ-700 where extended memory is available.
|
||||
BUILD_VIDEOMODULE EQU 0 ; Build for the Video Module v2 board (=1) otherwise build for the 80Char Colour Board v1.0
|
||||
BUILD_80C EQU 0
|
||||
INCLUDE_ANSITERM EQU 1 ; Include the Ansi terminal emulation processor in the build.
|
||||
ENDIF
|
||||
; TZFS Enhanced MZ-80A/MZ-700 with no video card upgrade.
|
||||
IF BUILD_VERSION = 2
|
||||
BUILD_MZ80A EQU 0
|
||||
BUILD_MZ700 EQU 0 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_MZ80A_TZFS EQU 0 ; Build for TZFS running on an MZ-80A where extended memory is available.
|
||||
BUILD_MZ700_TZFS EQU 1 ; Build for TZFS running on an MZ-700 where extended memory is available.
|
||||
BUILD_VIDEOMODULE EQU 0 ; Build for the Video Module v2 board (=1) otherwise build for the 80Char Colour Board v1.0
|
||||
BUILD_80C EQU 0
|
||||
INCLUDE_ANSITERM EQU 1 ; Include the Ansi terminal emulation processor in the build.
|
||||
ENDIF
|
||||
; TZFS Enhanced MZ-80A/MZ-700 with VideoModule (or 40/80 Colour Board on MZ-80A).
|
||||
IF BUILD_VERSION = 3
|
||||
BUILD_MZ700 EQU 0 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_MZ80A EQU 0
|
||||
BUILD_MZ80A_TZFS EQU 0 ; Build for TZFS running on an MZ-80A where extended memory is available.
|
||||
BUILD_MZ700_TZFS EQU 1 ; Build for TZFS running on an MZ-700 where extended memory is available.
|
||||
BUILD_VIDEOMODULE EQU 1 ; Build for the Video Module v2 board (=1) otherwise build for the 80Char Colour Board v1.0
|
||||
BUILD_80C EQU 1
|
||||
INCLUDE_ANSITERM EQU 1 ; Include the Ansi terminal emulation processor in the build.
|
||||
ENDIF
|
||||
IF BUILD_80C = 1
|
||||
COLW: EQU 80 ; Width of the display screen (ie. columns).
|
||||
ELSE
|
||||
COLW: EQU 40 ; Width of the display screen (ie. columns).
|
||||
ENDIF
|
||||
TMRTICKINTV EQU 5 ; Number of 0.010mSec ticks per interrupt, ie. resolution of RTC.
|
||||
ROW: EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ: EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
SCRLW: EQU COLW / 8 ; Number of 8 byte regions in a line for hardware scroll.
|
||||
|
||||
; BIOS equates
|
||||
KEYBUFSIZE EQU 64 ; Ensure this is a power of 2, max size 256.
|
||||
IF BUILD_MZ80A = 1
|
||||
MAXMEM EQU 0CFFFH ; Top of RAM on a standard Sharp MZ80A.
|
||||
ELSE
|
||||
MAXMEM EQU 10000H - TZSVCSIZE ; Top of RAM on the tranZPUter
|
||||
ENDIF
|
||||
|
||||
; Tape load/save modes. Used as a flag to enable common code.
|
||||
TAPELOAD EQU 1
|
||||
CTAPELOAD EQU 2
|
||||
TAPESAVE EQU 3
|
||||
CTAPESAVE EQU 4
|
||||
|
||||
; Debugging
|
||||
ENADEBUG EQU 0 ; Enable debugging logic, 1 = enable, 0 = disable
|
||||
|
||||
;-----------------------------------------------
|
||||
; CMT Object types.
|
||||
;-----------------------------------------------
|
||||
ATR_OBJ EQU 1
|
||||
ATR_BASIC_PROG EQU 2
|
||||
ATR_BASIC_DATA EQU 3
|
||||
ATR_SRC_FILE EQU 4
|
||||
ATR_RELOC_FILE EQU 5
|
||||
ATR_BASIC_MSCAS EQU 07EH
|
||||
ATR_BASIC_MSTXT EQU 07FH
|
||||
ATR_PASCAL_PROG EQU 0A0H
|
||||
ATR_PASCAL_DATA EQU 0A1H
|
||||
CMTATRB EQU 010F0H
|
||||
CMTNAME EQU 010F1H
|
||||
|
||||
;-------------------------------------------------------
|
||||
; Function entry points in the standard SA-1510 Monitor.
|
||||
;-------------------------------------------------------
|
||||
QWRI EQU 00021h
|
||||
QWRD EQU 00024h
|
||||
QRDI EQU 00027h
|
||||
QRDD EQU 0002Ah
|
||||
QVRFY EQU 0002Dh
|
||||
|
||||
;-----------------------------------------------
|
||||
; BASIC ERROR CODE VALUES
|
||||
;-----------------------------------------------
|
||||
NF EQU 00H ; NEXT without FOR
|
||||
SN EQU 02H ; Syntax error
|
||||
RG EQU 04H ; RETURN without GOSUB
|
||||
OD EQU 06H ; Out of DATA
|
||||
FC EQU 08H ; Function call error
|
||||
OV EQU 0AH ; Overflow
|
||||
OM EQU 0CH ; Out of memory
|
||||
UL EQU 0EH ; Undefined line number
|
||||
BS EQU 10H ; Bad subscript
|
||||
DDA EQU 12H ; Re-DIMensioned array
|
||||
DZ EQU 14H ; Division by zero (/0)
|
||||
ID EQU 16H ; Illegal direct
|
||||
TM EQU 18H ; Type miss-match
|
||||
OS EQU 1AH ; Out of string space
|
||||
LS EQU 1CH ; String too long
|
||||
ST EQU 1EH ; String formula too complex
|
||||
CN EQU 20H ; Can't CONTinue
|
||||
UF EQU 22H ; UnDEFined FN function
|
||||
MO EQU 24H ; Missing operand
|
||||
HX EQU 26H ; HEX error
|
||||
BN EQU 28H ; BIN error
|
||||
BV EQU 2AH ; Bad Value error
|
||||
IO EQU 2CH ; IO error
|
||||
|
||||
;-----------------------------------------------
|
||||
; Memory mapped ports in hardware.
|
||||
;-----------------------------------------------
|
||||
SCRN: EQU 0D000H
|
||||
ARAM: EQU 0D800H
|
||||
DSPCTL: EQU 0DFFFH ; Screen 40/80 select register (bit 7)
|
||||
KEYPA: EQU 0E000h
|
||||
KEYPB: EQU 0E001h
|
||||
KEYPC: EQU 0E002h
|
||||
KEYPF: EQU 0E003h
|
||||
CSTR: EQU 0E002h
|
||||
CSTPT: EQU 0E003h
|
||||
CONT0: EQU 0E004h
|
||||
CONT1: EQU 0E005h
|
||||
CONT2: EQU 0E006h
|
||||
CONTF: EQU 0E007h
|
||||
SUNDG: EQU 0E008h
|
||||
TEMP: EQU 0E008h
|
||||
MEMSW: EQU 0E00CH
|
||||
MEMSWR: EQU 0E010H
|
||||
INVDSP: EQU 0E014H
|
||||
NRMDSP: EQU 0E015H
|
||||
SCLDSP: EQU 0E200H
|
||||
SCLBASE: EQU 0E2H
|
||||
|
||||
;-----------------------------------------------
|
||||
; IO Registers
|
||||
;-----------------------------------------------
|
||||
FDC EQU 0D8h ; MB8866 IO Region 0D8h - 0DBh
|
||||
FDC_CR EQU FDC + 000h ; Command Register
|
||||
FDC_STR EQU FDC + 000h ; Status Register
|
||||
FDC_TR EQU FDC + 001h ; Track Register
|
||||
FDC_SCR EQU FDC + 002h ; Sector Register
|
||||
FDC_DR EQU FDC + 003h ; Data Register
|
||||
FDC_MOTOR EQU FDC + 004h ; DS[0-3] and Motor control. 4 drives DS= BIT 0 -> Bit 2 = Drive number, 2=1,1=0,0=0 DS0, 2=1,1=0,0=1 DS1 etc
|
||||
; bit 7 = 1 MOTOR ON LOW (Active)
|
||||
FDC_SIDE EQU FDC + 005h ; Side select, Bit 0 when set = SIDE SELECT LOW
|
||||
|
||||
;-----------------------------------------------
|
||||
; Common character definitions.
|
||||
;-----------------------------------------------
|
||||
SCROLL EQU 001H ;Set scroll direction UP.
|
||||
BELL EQU 007H
|
||||
SPACE EQU 020H
|
||||
TAB EQU 009H ;TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||
CR EQU 00DH
|
||||
LF EQU 00AH
|
||||
FF EQU 00CH
|
||||
CS EQU 0CH ; Clear screen
|
||||
DELETE EQU 07FH
|
||||
BACKS EQU 008H
|
||||
SOH EQU 1 ; For XModem etc.
|
||||
EOT EQU 4
|
||||
ACK EQU 6
|
||||
NAK EQU 015H
|
||||
NUL EQU 000H
|
||||
;NULL EQU 000H
|
||||
CTRL_A EQU 001H
|
||||
CTRL_B EQU 002H
|
||||
CTRL_C EQU 003H
|
||||
CTRL_D EQU 004H
|
||||
CTRL_E EQU 005H
|
||||
CTRL_F EQU 006H
|
||||
CTRL_G EQU 007H
|
||||
CTRL_H EQU 008H
|
||||
CTRL_I EQU 009H
|
||||
CTRL_J EQU 00AH
|
||||
CTRL_K EQU 00BH
|
||||
CTRL_L EQU 00CH
|
||||
CTRL_M EQU 00DH
|
||||
CTRL_N EQU 00EH
|
||||
CTRL_O EQU 00FH
|
||||
CTRL_P EQU 010H
|
||||
CTRL_Q EQU 011H
|
||||
CTRL_R EQU 012H
|
||||
CTRL_S EQU 013H
|
||||
CTRL_T EQU 014H
|
||||
CTRL_U EQU 015H
|
||||
CTRL_V EQU 016H
|
||||
CTRL_W EQU 017H
|
||||
CTRL_X EQU 018H
|
||||
CTRL_Y EQU 019H
|
||||
CTRL_Z EQU 01AH
|
||||
ESC EQU 01BH
|
||||
CTRL_SLASH EQU 01CH
|
||||
CTRL_LB EQU 01BH
|
||||
CTRL_RB EQU 01DH
|
||||
CTRL_CAPPA EQU 01EH
|
||||
CTRL_UNDSCR EQU 01FH
|
||||
CTRL_AT EQU 000H
|
||||
NOKEY EQU 0F0H
|
||||
CURSRIGHT EQU 0F1H
|
||||
CURSLEFT EQU 0F2H
|
||||
CURSUP EQU 0F3H
|
||||
CURSDOWN EQU 0F4H
|
||||
DBLZERO EQU 0F5H
|
||||
INSERT EQU 0F6H
|
||||
CLRKEY EQU 0F7H
|
||||
HOMEKEY EQU 0F8H
|
||||
BREAKKEY EQU 0FBH
|
||||
GRAPHKEY EQU 0FCH
|
||||
ALPHAKEY EQU 0FDH
|
||||
|
||||
;-----------------------------------------------
|
||||
; IO ports in hardware and values.
|
||||
;-----------------------------------------------
|
||||
MMCFG EQU 060H ; Memory management configuration latch.
|
||||
SETXMHZ EQU 062H ; Select the alternate clock frequency.
|
||||
SET2MHZ EQU 064H ; Select the system 2MHz clock frequency.
|
||||
CLKSELRD EQU 066H ; Read clock selected setting, 0 = 2MHz, 1 = XMHz
|
||||
SVCREQ EQU 068H ; I/O Processor service request.
|
||||
CPLDSTATUS EQU 06BH ; Version 2.1 CPLD status register.
|
||||
CPUCFG EQU 06CH ; Version 2.2 CPU configuration register.
|
||||
CPUSTATUS EQU 06CH ; Version 2.2 CPU runtime status register.
|
||||
CPUINFO EQU 06DH ; Version 2.2 CPU information register.
|
||||
CPLDCFG EQU 06EH ; Version 2.1 CPLD configuration register.
|
||||
CPLDINFO EQU 06FH ; Version 2.1 CPLD version information register.
|
||||
VMPNUM EQU 0A0H ; Set the parameter number to update.
|
||||
VMPLBYTE EQU 0A1H ; Update the lower selected parameter byte.
|
||||
VMPUBYTE EQU 0A2H ; Update the upper selected parameter byte.
|
||||
PALSLCTOFF EQU 0A3H ; set the palette slot Off position to be adjusted.
|
||||
PALSLCTON EQU 0A4H ; set the palette slot On position to be adjusted.
|
||||
PALSETRED EQU 0A5H ; set the red palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETGREEN EQU 0A6H ; set the green palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETBLUE EQU 0A7H ; set the blue palette value according to the PALETTE_PARAM_SEL address.
|
||||
VMPALETTE EQU 0B0H ; Select Palette:
|
||||
; 0xB0 sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output.
|
||||
; Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input.
|
||||
; GPU:
|
||||
GPUPARAM EQU 0B2H ; 0xB2 set parameters. Store parameters in a long word to be used by the graphics command processor.
|
||||
; The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0.
|
||||
GPUCMD EQU 0B3H ; 0xB3 set the graphics processor unit commands.
|
||||
GPUSTATUS EQU 0B3H ; [7;1] - FSM state, [0] - 1 = busy, 0 = idle
|
||||
; Bits [5:0] - 0 = Reset parameters.
|
||||
; 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter
|
||||
;
|
||||
VMCTRL EQU 0B8H ; Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col.
|
||||
VMGRMODE EQU 0B9H ; Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used).
|
||||
VMREDMASK EQU 0BAH ; Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMGREENMASK EQU 0BBH ; Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMBLUEMASK EQU 0BCH ; Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMPAGE EQU 0BDH ; Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF.
|
||||
VMVGATTR EQU 0BEH ; Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue.
|
||||
VMVGAMODE EQU 0BFH ; Select VGA output mode. Bits [3:0] - Output mode.
|
||||
GDCRTC EQU 0CFH ; MZ-800 CRTC control register
|
||||
GDCMD EQU 0CEH ; MZ-800 CRTC Mode register
|
||||
GDGRF EQU 0CDH ; MZ-800 read format register
|
||||
GDGWF EQU 0CCH ; MZ-800 write format register
|
||||
MMIO0 EQU 0E0H ; MZ-700/MZ-800 Memory Management Set 0
|
||||
MMIO1 EQU 0E1H ; MZ-700/MZ-800 Memory Management Set 1
|
||||
MMIO2 EQU 0E2H ; MZ-700/MZ-800 Memory Management Set 2
|
||||
MMIO3 EQU 0E3H ; MZ-700/MZ-800 Memory Management Set 3
|
||||
MMIO4 EQU 0E4H ; MZ-700/MZ-800 Memory Management Set 4
|
||||
MMIO5 EQU 0E5H ; MZ-700/MZ-800 Memory Management Set 5
|
||||
MMIO6 EQU 0E6H ; MZ-700/MZ-800 Memory Management Set 6
|
||||
MMIO7 EQU 0E7H ; MZ-700/MZ-800 Memory Management Set 7
|
||||
SYSCTRL EQU 0F0H ; System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus.
|
||||
GRAMMODE EQU 0F4H ; MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display.
|
||||
|
||||
;-----------------------------------------------
|
||||
; CPLD Configuration constants.
|
||||
;-----------------------------------------------
|
||||
MODE_MZ80K EQU 0 ; Set to MZ-80K mode.
|
||||
MODE_MZ80C EQU 1 ; Set to MZ-80C mode.
|
||||
MODE_MZ1200 EQU 2 ; Set to MZ-1200 mode.
|
||||
MODE_MZ80A EQU 3 ; Set to MZ-80A mode (base mode on MZ-80A hardware).
|
||||
MODE_MZ700 EQU 4 ; Set to MZ-700 mode (base mode on MZ-700 hardware).
|
||||
MODE_MZ800 EQU 5 ; Set to MZ-800 mode.
|
||||
MODE_MZ80B EQU 6 ; Set to MZ-80B mode.
|
||||
MODE_MZ2000 EQU 7 ; Set to MZ-2000 mode.
|
||||
MODE_VIDEO_FPGA EQU 8 ; Bit flag (bit 3) to switch CPLD into using the new FPGA video hardware.
|
||||
MODE_RESET_PRESERVE EQU 080H ; Preserve register configuration through reset.
|
||||
|
||||
;-----------------------------------------------
|
||||
; CPLD Command Instruction constants.
|
||||
;-----------------------------------------------
|
||||
CPLD_RESET_HOST EQU 1 ; CPLD level command to reset the host system.
|
||||
CPLD_HOLD_HOST_BUS EQU 2 ; CPLD command to hold the host bus.
|
||||
CPLD_RELEASE_HOST_BUS EQU 3 ; CPLD command to release the host bus.
|
||||
|
||||
;-----------------------------------------------
|
||||
; FPGA CPU enhancement control bits.
|
||||
;-----------------------------------------------
|
||||
CPUMODE_SET_Z80 EQU 000H ; Set the CPU to the hard Z80.
|
||||
CPUMODE_SET_T80 EQU 001H ; Set the CPU to the soft T80.
|
||||
CPUMODE_SET_ZPU_EVO EQU 002H ; Set the CPU to the soft ZPU Evolution.
|
||||
CPUMODE_SET_AAA EQU 004H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_BBB EQU 008H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_CCC EQU 010H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_DDD EQU 020H ; Place holder for a future soft CPU.
|
||||
CPUMODE_IS_Z80 EQU 000H ; Status value to indicate if the hard Z80 available.
|
||||
CPUMODE_IS_T80 EQU 001H ; Status value to indicate if the soft T80 available.
|
||||
CPUMODE_IS_ZPU_EVO EQU 002H ; Status value to indicate if the soft ZPU Evolution available.
|
||||
CPUMODE_IS_AAA EQU 004H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_BBB EQU 008H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_CCC EQU 010H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_DDD EQU 020H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_RESET_CPU EQU 080H ; Reset the soft CPU. Active high, when high the CPU is held in RESET, when low the CPU runs.
|
||||
CPUMODE_IS_SOFT_AVAIL EQU 040H ; Marker to indicate if the underlying FPGA can support soft CPU's.
|
||||
CPUMODE_IS_SOFT_MASK EQU 0C0H ; Mask to filter out the Soft CPU availability flags.
|
||||
CPUMODE_IS_CPU_MASK EQU 03FH ; Mask to filter out which soft CPU's are available.
|
||||
|
||||
;-----------------------------------------------
|
||||
; Video Module control bits.
|
||||
;-----------------------------------------------
|
||||
MODE_80CHAR EQU 010H ; Enable 80 character display.
|
||||
MODE_COLOUR EQU 020H ; Enable colour display.
|
||||
SYSMODE_MZ80A EQU 000H ; System board mode MZ80A, 2MHz CPU/Bus.
|
||||
SYSMODE_MZ80B EQU 020H ; System board mode MZ80B, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ2000 EQU 020H ; System board mode MZ2000, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ700 EQU 042H ; System board mode MZ700, 3.54MHz CPU/Bus.
|
||||
VMMODE_MZ80K EQU 000H ; Video mode = MZ80K
|
||||
VMMODE_MZ80C EQU 001H ; Video mode = MZ80C
|
||||
VMMODE_MZ1200 EQU 002H ; Video mode = MZ1200
|
||||
VMMODE_MZ80A EQU 003H ; Video mode = MZ80A
|
||||
VMMODE_MZ700 EQU 004H ; Video mode = MZ700
|
||||
VMMODE_MZ800 EQU 005H ; Video mode = MZ800
|
||||
VMMODE_MZ1500 EQU 006H ; Video mode = MZ1500
|
||||
VMMODE_MZ80B EQU 007H ; Video mode = MZ80B
|
||||
VMMODE_MZ2000 EQU 008H ; Video mode = MZ2000
|
||||
VMMODE_MZ2200 EQU 009H ; Video mode = MZ2200
|
||||
VMMODE_MZ2500 EQU 00AH ; Video mode = MZ2500
|
||||
VMMODE_PCGRAM EQU 020H ; Enable PCG RAM.
|
||||
VMMODE_VGA_OFF EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT50 EQU 001H ; Set VGA mode off, external monitor is driven by standard internal 50Hz signals.
|
||||
VMMODE_VGA_640x480 EQU 002H ; Set external monitor to VGA 640x480 @ 60Hz mode.
|
||||
VMMODE_VGA_800x600 EQU 003H ; Set external monitor to VGA 800x600 @ 60Hz mode.
|
||||
|
||||
;-----------------------------------------------
|
||||
; GPU commands.
|
||||
;-----------------------------------------------
|
||||
GPUCLEARVRAM EQU 001H ; Clear the VRAM without updating attributes.
|
||||
GPUCLEARVRAMCA EQU 002H ; Clear the VRAM/ARAM with given attribute byte,
|
||||
GPUCLEARVRAMP EQU 003H ; Clear the VRAM/ARAM with parameters.
|
||||
GPUCLEARGRAM EQU 081H ; Clear the entire Framebuffer.
|
||||
GPUCLEARGRAMP EQU 082H ; Clear the Framebuffer according to parameters.
|
||||
GPURESET EQU 0FFH ; Reset the GPU, return to idle state.
|
||||
|
||||
;-----------------------------------------------
|
||||
; tranZPUter SW Memory Management modes
|
||||
;-----------------------------------------------
|
||||
TZMM_ENIOWAIT EQU 020H ; Memory management IO Wait State enable - insert a wait state when an IO operation to E0-FF is executed.
|
||||
TZMM_ORIG EQU 000H ; Original Sharp MZ80A mode, no tranZPUter features are selected except the I/O control registers (default: 0x60-063).
|
||||
TZMM_BOOT EQU 001H ; Original mode but E800-EFFF is mapped to tranZPUter RAM so TZFS can be booted.
|
||||
TZMM_TZFS EQU 002H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS2 EQU 003H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS3 EQU 004H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS4 EQU 005H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_CPM EQU 006H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_CPM2 EQU 007H + TZMM_ENIOWAIT ; 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, F3C0:F3FF & F7C0:F7FF (floppy disk paging vectors) which resides on the mainboard.
|
||||
TZMM_COMPAT EQU 008H + TZMM_ENIOWAIT ; Original mode but with main DRAM in Bank 0 to allow bootstrapping of programs from other machines such as the MZ700.
|
||||
TZMM_HOSTACCESS EQU 009H + TZMM_ENIOWAIT ; Mode to allow code running in Bank 0, address E800:FFFF to access host memory. 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.
|
||||
TZMM_MZ700_0 EQU 00AH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_1 EQU 00BH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_2 EQU 00CH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_3 EQU 00DH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_4 EQU 00EH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ800 EQU 00FH + TZMM_ENIOWAIT ; MZ800 Mode - Tracks original hardware mode offering MZ700/MZ800 configurations.
|
||||
TZMM_MZ2000 EQU 010H + TZMM_ENIOWAIT; ; MZ2000 Mode - Running on MZ2000 hardware, configuration set according to runtime configuration registers.
|
||||
TZMM_FPGA EQU 015H + TZMM_ENIOWAIT ; Open up access for the K64F to the FPGA resources such as memory. All other access to RAM or mainboard is blocked.
|
||||
TZMM_TZPUM EQU 016H + TZMM_ENIOWAIT ; Everything in on mainboard, no access to tranZPUter memory.
|
||||
TZMM_TZPU EQU 017H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU0 EQU 018H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU1 EQU 019H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 1 is selected.
|
||||
;TZMM_TZPU2 EQU 01AH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 2 is selected.
|
||||
;TZMM_TZPU3 EQU 01BH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 3 is selected.
|
||||
;TZMM_TZPU4 EQU 01CH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 4 is selected.
|
||||
;TZMM_TZPU5 EQU 01DH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 5 is selected.
|
||||
;TZMM_TZPU6 EQU 01EH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 6 is selected.
|
||||
;TZMM_TZPU7 EQU 01FH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 7 is selected.
|
||||
|
||||
;-----------------------------------------------
|
||||
; TZ File System Header (MZF)
|
||||
;-----------------------------------------------
|
||||
TZFS_ATRB: EQU 00000h ; Code Type, 01 = Machine Code.
|
||||
TZFS_NAME: EQU 00001h ; Title/Name (17 bytes).
|
||||
TZFS_SIZE: EQU 00012h ; Size of program.
|
||||
TZFS_DTADR: EQU 00014h ; Load address of program.
|
||||
TZFS_EXADR: EQU 00016h ; Exec address of program.
|
||||
TZFS_COMNT: EQU 00018h ; Comment
|
||||
TZFS_MZFLEN: EQU 128 ; Length of the MZF header.
|
||||
TZFS_CMTLEN: EQU 104 ; Length of the comment field
|
||||
|
||||
;-----------------------------------------------
|
||||
; BIOS WORK AREA (MZ80A)
|
||||
;-----------------------------------------------
|
||||
; Variables and control structure used by the I/O processor for service calls and requests.
|
||||
ORG TZSVCMEM
|
||||
|
||||
TZSVCMEM: EQU 0FD80H ; Start of a memory structure used to communicate with the K64F I/O processor for services such as disk access.
|
||||
TZSVCSIZE: EQU 00280H ;
|
||||
TZSVCDIRSZ: EQU 20 ; Size of the directory/file name.
|
||||
TZSVCFILESZ: EQU 17 ; Size of a Sharp filename.
|
||||
TZSVCLONGFILESZ: EQU 31 ; Size of a standard filename.
|
||||
TZSVCLONGFMTSZ: EQU 20 ; Size of a formatted standard filename for use in directory listings.
|
||||
TZSVCWILDSZ: EQU 20 ; Size of the wildcard.
|
||||
TZSVCSECSIZE: EQU 512
|
||||
TZSVCDIR_ENTSZ: EQU 32 ; Size of a directory entry.
|
||||
TZSVCWAITIORETRIES: EQU 500 ; Wait retries for IO response.
|
||||
TZSVCWAITCOUNT: EQU 65535 ; Wait retries for IO request response.
|
||||
TZSVC_FTYPE_MZF: EQU 0 ; File type being handled is an MZF
|
||||
TZSVC_FTYPE_MZFHDR: EQU 1 ; File type being handled is an MZF Header.
|
||||
TZSVC_FTYPE_CAS: EQU 2 ; File type being handled is an CASsette BASIC script.
|
||||
TZSVC_FTYPE_BAS: EQU 3 ; File type being handled is an BASic script
|
||||
TZSVC_FTYPE_ALL: EQU 10 ; Handle any filetype.
|
||||
TZSVC_FTYPE_ALLFMT: EQU 11 ; Special case for directory listings, all files but truncated and formatted.
|
||||
TZSVCCMD: DS virtual 1 ; Service command.
|
||||
TZSVCRESULT: DS virtual 1 ; Service command result.
|
||||
TZSVCDIRSEC: DS virtual 1 ; Storage for the directory sector number.
|
||||
TZSVC_FILE_SEC: EQU TZSVCDIRSEC ; Union of the file and directory sector as only one can be used at a time.
|
||||
TZSVC_TRACK_NO: DS virtual 2 ; Storage for the virtual drive track number.
|
||||
TZSVC_SECTOR_NO: DS virtual 2 ; Storage for the virtual drive sector number.
|
||||
TZSVC_FILE_NO: DS virtual 1 ; File number to be opened in a file service command.
|
||||
TZSVC_FILE_TYPE: DS virtual 1 ; Type of file being accessed to differentiate between Sharp MZF files and other handled files.
|
||||
TZSVC_LOADADDR: DS virtual 2 ; Dynamic load address for rom/images.
|
||||
TZSVC_SAVEADDR: EQU TZSVC_LOADADDR ; Union of the load address and the cpu frequency change value, the address of data to be saved.
|
||||
TZSVC_CPU_FREQ: EQU TZSVC_LOADADDR ; Union of the load address and the save address value, only one can be used at a time.
|
||||
TZSVC_LOADSIZE: DS virtual 2 ; Size of image to load.
|
||||
TZSVC_SAVESIZE: EQU TZSVC_LOADSIZE ; Size of image to be saved.
|
||||
TZSVC_DIRNAME: DS virtual TZSVCDIRSZ ; Service directory/file name.
|
||||
TZSVC_FILENAME: DS virtual TZSVCFILESZ ; Filename to be opened/created.
|
||||
TZSVCWILDC: DS virtual TZSVCWILDSZ ; Directory wildcard for file pattern matching.
|
||||
TZSVCSECTOR: DS virtual TZSVCSECSIZE ; Service command sector - to store directory entries, file sector read or writes.
|
||||
|
||||
TZSVC_CMD_READDIR EQU 01H ; Service command to open a directory and return the first block of entries.
|
||||
TZSVC_CMD_NEXTDIR EQU 02H ; Service command to return the next block of an open directory.
|
||||
TZSVC_CMD_READFILE EQU 03H ; Service command to open a file and return the first block.
|
||||
TZSVC_CMD_NEXTREADFILE EQU 04H ; Service command to return the next block of an open file.
|
||||
TZSVC_CMD_WRITEFILE EQU 05H ; Service command to create a file and save the first block.
|
||||
TZSVC_CMD_NEXTWRITEFILE EQU 06H ; Service command to write the next block to the open file.
|
||||
TZSVC_CMD_CLOSE EQU 07H ; Service command to close any open file or directory.
|
||||
TZSVC_CMD_LOADFILE EQU 08H ; Service command to load a file directly into tranZPUter memory.
|
||||
TZSVC_CMD_SAVEFILE EQU 09H ; Service command to save a file directly from tranZPUter memory.
|
||||
TZSVC_CMD_ERASEFILE EQU 0aH ; Service command to erase a file on the SD card.
|
||||
TZSVC_CMD_CHANGEDIR EQU 0bH ; Service command to change the active directory on the SD card.
|
||||
TZSVC_CMD_LOAD40ABIOS EQU 20H ; Service command requesting that the 40 column version of the SA1510 BIOS is loaded.
|
||||
TZSVC_CMD_LOAD80ABIOS EQU 21H ; Service command requesting that the 80 column version of the SA1510 BIOS is loaded.
|
||||
TZSVC_CMD_LOAD700BIOS40 EQU 22H ; Service command requesting that the MZ700 1Z-013A 40 column BIOS is loaded.
|
||||
TZSVC_CMD_LOAD700BIOS80 EQU 23H ; Service command requesting that the MZ700 1Z-013A 80 column patched BIOS is loaded.
|
||||
TZSVC_CMD_LOAD80BIPL EQU 24H ; Service command requesting the MZ-80B IPL is loaded.
|
||||
TZSVC_CMD_LOAD800BIOS EQU 25H ; Service command requesting that the MZ800 9Z-504M BIOS is loaded.
|
||||
TZSVC_CMD_LOAD2000IPL EQU 26H ; Service command requesting the MZ-2000 IPL is loaded.
|
||||
TZSVC_CMD_LOADTZFS EQU 2FH ; Service command requesting the loading of TZFS. This service is for machines which normally dont have a monitor BIOS. ie. MZ-80B/MZ-2000 and manually request TZFS.
|
||||
TZSVC_CMD_LOADBDOS EQU 30H ; Service command to reload CPM BDOS+CCP.
|
||||
TZSVC_CMD_ADDSDDRIVE EQU 31H ; Service command to attach a CPM disk to a drive number.
|
||||
TZSVC_CMD_READSDDRIVE EQU 32H ; Service command to read an attached SD file as a CPM disk drive.
|
||||
TZSVC_CMD_WRITESDDRIVE EQU 33H ; Service command to write to a CPM disk drive which is an attached SD file.
|
||||
TZSVC_CMD_CPU_BASEFREQ EQU 40H ; Service command to switch to the mainboard frequency.
|
||||
TZSVC_CMD_CPU_ALTFREQ EQU 41H ; Service command to switch to the alternate frequency provided by the K64F.
|
||||
TZSVC_CMD_CPU_CHGFREQ EQU 42H ; Service command to set the alternate frequency in hertz.
|
||||
TZSVC_CMD_CPU_SETZ80 EQU 50H ; Service command to switch to the external Z80 hard cpu.
|
||||
TZSVC_CMD_CPU_SETT80 EQU 51H ; Service command to switch to the internal T80 soft cpu.
|
||||
TZSVC_CMD_CPU_SETZPUEVO EQU 52H ; Service command to switch to the internal ZPU Evolution soft cpu.
|
||||
TZSVC_CMD_EMU_SETMZ80K EQU 53H ; Service command to switch to the internal Sharp MZ Series Emulation of the MZ80K.
|
||||
TZSVC_CMD_EMU_SETMZ80C EQU 54H ; "" "" "" MZ80C.
|
||||
TZSVC_CMD_EMU_SETMZ1200 EQU 55H ; "" "" "" MZ1200.
|
||||
TZSVC_CMD_EMU_SETMZ80A EQU 56H ; "" "" "" MZ80A.
|
||||
TZSVC_CMD_EMU_SETMZ700 EQU 57H ; "" "" "" MZ700.
|
||||
TZSVC_CMD_EMU_SETMZ800 EQU 58H ; "" "" "" MZ800.
|
||||
TZSVC_CMD_EMU_SETMZ1500 EQU 59H ; "" "" "" MZ1500.
|
||||
TZSVC_CMD_EMU_SETMZ80B EQU 5AH ; "" "" "" MZ80B.
|
||||
TZSVC_CMD_EMU_SETMZ2000 EQU 5BH ; "" "" "" MZ2000.
|
||||
TZSVC_CMD_EMU_SETMZ2200 EQU 5CH ; "" "" "" MZ2200.
|
||||
TZSVC_CMD_EMU_SETMZ2500 EQU 5DH ; "" "" "" MZ2500.
|
||||
TZSVC_CMD_EXIT EQU 07FH ; Service command to terminate TZFS and restart the machine in original mode.
|
||||
TZSVC_STATUS_OK EQU 000H ; Flag to indicate the K64F processing completed successfully.
|
||||
TZSVC_STATUS_REQUEST EQU 0FEH ; Flag to indicate the Z80 has made a request to the K64F.
|
||||
TZSVC_STATUS_PROCESSING EQU 0FFH ; Flag to indicate the K64F is processing a command.
|
||||
316
software/asm/include/testtz_definitions.asm
Normal file
316
software/asm/include/testtz_definitions.asm
Normal file
@@ -0,0 +1,316 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: TESTTZ_Definitions.asm
|
||||
;- Created: June 2020
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: tranZPUter tester program
|
||||
;- A small program to exercise parts of the tranZPUter to aid in problem resolution.
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-20 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: Jun 2020 - Initial version.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
;-----------------------------------------------
|
||||
; Features.
|
||||
;-----------------------------------------------
|
||||
|
||||
;-----------------------------------------------
|
||||
; Configurable settings.
|
||||
;-----------------------------------------------
|
||||
COLW: EQU 80 ; Width of the display screen (ie. columns).
|
||||
ROW: EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ: EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
SCRLW: EQU COLW / 8 ; Number of 8 byte regions in a line for hardware scroll.
|
||||
MODE80C: EQU 1
|
||||
|
||||
; Debugging
|
||||
ENADEBUG EQU 0 ; Enable debugging logic, 1 = enable, 0 = disable
|
||||
|
||||
;-----------------------------------------------
|
||||
; Memory mapped ports in hardware.
|
||||
;-----------------------------------------------
|
||||
SCRN: EQU 0D000H
|
||||
ARAM: EQU 0D800H
|
||||
DSPCTL: EQU 0DFFFH ; Screen 40/80 select register (bit 7)
|
||||
KEYPA: EQU 0E000h
|
||||
KEYPB: EQU 0E001h
|
||||
KEYPC: EQU 0E002h
|
||||
KEYPF: EQU 0E003h
|
||||
CSTR: EQU 0E002h
|
||||
CSTPT: EQU 0E003h
|
||||
CONT0: EQU 0E004h
|
||||
CONT1: EQU 0E005h
|
||||
CONT2: EQU 0E006h
|
||||
CONTF: EQU 0E007h
|
||||
SUNDG: EQU 0E008h
|
||||
TEMP: EQU 0E008h
|
||||
MEMSW: EQU 0E00CH
|
||||
MEMSWR: EQU 0E010H
|
||||
INVDSP: EQU 0E014H
|
||||
NRMDSP: EQU 0E015H
|
||||
SCLDSP: EQU 0E200H
|
||||
SCLBASE: EQU 0E2H
|
||||
|
||||
;-----------------------------------------------
|
||||
; Common character definitions.
|
||||
;-----------------------------------------------
|
||||
SCROLL EQU 001H ;Set scroll direction UP.
|
||||
BELL EQU 007H
|
||||
SPACE EQU 020H
|
||||
TAB EQU 009H ;TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||
CR EQU 00DH
|
||||
LF EQU 00AH
|
||||
FF EQU 00CH
|
||||
DELETE EQU 07FH
|
||||
BACKS EQU 008H
|
||||
SOH EQU 1 ; For XModem etc.
|
||||
EOT EQU 4
|
||||
ACK EQU 6
|
||||
NAK EQU 015H
|
||||
NUL EQU 000H
|
||||
NULL EQU 000H
|
||||
CTRL_A EQU 001H
|
||||
CTRL_B EQU 002H
|
||||
CTRL_C EQU 003H
|
||||
CTRL_D EQU 004H
|
||||
CTRL_E EQU 005H
|
||||
CTRL_F EQU 006H
|
||||
CTRL_G EQU 007H
|
||||
CTRL_H EQU 008H
|
||||
CTRL_I EQU 009H
|
||||
CTRL_J EQU 00AH
|
||||
CTRL_K EQU 00BH
|
||||
CTRL_L EQU 00CH
|
||||
CTRL_M EQU 00DH
|
||||
CTRL_N EQU 00EH
|
||||
CTRL_O EQU 00FH
|
||||
CTRL_P EQU 010H
|
||||
CTRL_Q EQU 011H
|
||||
CTRL_R EQU 012H
|
||||
CTRL_S EQU 013H
|
||||
CTRL_T EQU 014H
|
||||
CTRL_U EQU 015H
|
||||
CTRL_V EQU 016H
|
||||
CTRL_W EQU 017H
|
||||
CTRL_X EQU 018H
|
||||
CTRL_Y EQU 019H
|
||||
CTRL_Z EQU 01AH
|
||||
ESC EQU 01BH
|
||||
CTRL_SLASH EQU 01CH
|
||||
CTRL_RB EQU 01DH
|
||||
CTRL_CAPPA EQU 01EH
|
||||
CTRL_UNDSCR EQU 01FH
|
||||
CTRL_AT EQU 000H
|
||||
NOKEY EQU 0F0H
|
||||
CURSRIGHT EQU 0F1H
|
||||
CURSLEFT EQU 0F2H
|
||||
CURSUP EQU 0F3H
|
||||
CURSDOWN EQU 0F4H
|
||||
DBLZERO EQU 0F5H
|
||||
INSERT EQU 0F6H
|
||||
CLRKEY EQU 0F7H
|
||||
HOMEKEY EQU 0F8H
|
||||
BREAKKEY EQU 0FBH
|
||||
|
||||
|
||||
;-----------------------------------------------
|
||||
; IO ports in hardware and values.
|
||||
;-----------------------------------------------
|
||||
MMCFG EQU 060H ; Memory management configuration latch.
|
||||
SETXMHZ EQU 062H ; Select the alternate clock frequency.
|
||||
SET2MHZ EQU 064H ; Select the system 2MHz clock frequency.
|
||||
CLKSELRD EQU 066H ; Read clock selected setting, 0 = 2MHz, 1 = XMHz
|
||||
SVCREQ EQU 068H ; I/O Processor service request.
|
||||
CPLDSTATUS EQU 06BH ; Version 2.1 CPLD status register.
|
||||
CPUCFG EQU 06CH ; Version 2.2 CPU configuration register.
|
||||
CPUSTATUS EQU 06CH ; Version 2.2 CPU runtime status register.
|
||||
CPUINFO EQU 06DH ; Version 2.2 CPU information register.
|
||||
CPLDCFG EQU 06EH ; Version 2.1 CPLD configuration register.
|
||||
CPLDINFO EQU 06FH ; Version 2.1 CPLD version information register.
|
||||
VMPNUM EQU 0A0H ; Set the parameter number to update.
|
||||
VMPLBYTE EQU 0A1H ; Update the lower selected parameter byte.
|
||||
VMPUBYTE EQU 0A2H ; Update the upper selected parameter byte.
|
||||
PALSLCTOFF EQU 0A3H ; set the palette slot Off position to be adjusted.
|
||||
PALSLCTON EQU 0A4H ; set the palette slot On position to be adjusted.
|
||||
PALSETRED EQU 0A5H ; set the red palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETGREEN EQU 0A6H ; set the green palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETBLUE EQU 0A7H ; set the blue palette value according to the PALETTE_PARAM_SEL address.
|
||||
VMPALETTE EQU 0B0H ; Select Palette:
|
||||
; 0xB0 sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output.
|
||||
; Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input.
|
||||
; GPU:
|
||||
GPUPARAM EQU 0B2H ; 0xB2 set parameters. Store parameters in a long word to be used by the graphics command processor.
|
||||
; The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0.
|
||||
GPUCMD EQU 0B3H ; 0xB3 set the graphics processor unit commands.
|
||||
GPUSTATUS EQU 0B3H ; [7;1] - FSM state, [0] - 1 = busy, 0 = idle
|
||||
; Bits [5:0] - 0 = Reset parameters.
|
||||
; 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter
|
||||
;
|
||||
VMCTRL EQU 0B8H ; Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col.
|
||||
VMGRMODE EQU 0B9H ; Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used).
|
||||
VMREDMASK EQU 0BAH ; Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMGREENMASK EQU 0BBH ; Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMBLUEMASK EQU 0BCH ; Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMPAGE EQU 0BDH ; Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF.
|
||||
VMVGATTR EQU 0BEH ; Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue.
|
||||
VMVGAMODE EQU 0BFH ; Select VGA output mode. Bits [3:0] - Output mode.
|
||||
|
||||
GDCRTC EQU 0CFH ; MZ-800 CRTC control register
|
||||
GDCMD EQU 0CEH ; MZ-800 CRTC Mode register
|
||||
GDGRF EQU 0CDH ; MZ-800 read format register
|
||||
GDGWF EQU 0CCH ; MZ-800 write format register
|
||||
MMIO0 EQU 0E0H ; MZ-700/MZ-800 Memory Management Set 0
|
||||
MMIO1 EQU 0E1H ; MZ-700/MZ-800 Memory Management Set 1
|
||||
MMIO2 EQU 0E2H ; MZ-700/MZ-800 Memory Management Set 2
|
||||
MMIO3 EQU 0E3H ; MZ-700/MZ-800 Memory Management Set 3
|
||||
MMIO4 EQU 0E4H ; MZ-700/MZ-800 Memory Management Set 4
|
||||
MMIO5 EQU 0E5H ; MZ-700/MZ-800 Memory Management Set 5
|
||||
MMIO6 EQU 0E6H ; MZ-700/MZ-800 Memory Management Set 6
|
||||
MMIO7 EQU 0E7H ; MZ-700/MZ-800 Memory Management Set 7
|
||||
SYSCTRL EQU 0F0H ; System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus.
|
||||
GRAMMODE EQU 0F4H ; MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display.
|
||||
|
||||
;-----------------------------------------------
|
||||
; CPLD Configuration constants.
|
||||
;-----------------------------------------------
|
||||
MODE_MZ80K EQU 0 ; Set to MZ-80K mode.
|
||||
MODE_MZ80C EQU 1 ; Set to MZ-80C mode.
|
||||
MODE_MZ1200 EQU 2 ; Set to MZ-1200 mode.
|
||||
MODE_MZ80A EQU 3 ; Set to MZ-80A mode (base mode on MZ-80A hardware).
|
||||
MODE_MZ700 EQU 4 ; Set to MZ-700 mode (base mode on MZ-700 hardware).
|
||||
MODE_MZ800 EQU 5 ; Set to MZ-800 mode.
|
||||
MODE_MZ80B EQU 6 ; Set to MZ-80B mode.
|
||||
MODE_MZ2000 EQU 7 ; Set to MZ-2000 mode.
|
||||
MODE_VIDEO_FPGA EQU 8 ; Bit flag (bit 3) to switch CPLD into using the new FPGA video hardware.
|
||||
MODE_RESET_PRESERVE EQU 080H ; Preserve register configuration through reset.
|
||||
|
||||
;-----------------------------------------------
|
||||
; CPLD Command Instruction constants.
|
||||
;-----------------------------------------------
|
||||
CPLD_RESET_HOST EQU 1 ; CPLD level command to reset the host system.
|
||||
CPLD_HOLD_HOST_BUS EQU 2 ; CPLD command to hold the host bus.
|
||||
CPLD_RELEASE_HOST_BUS EQU 3 ; CPLD command to release the host bus.
|
||||
|
||||
;-----------------------------------------------
|
||||
; FPGA CPU enhancement control bits.
|
||||
;-----------------------------------------------
|
||||
CPUMODE_SET_Z80 EQU 000H ; Set the CPU to the hard Z80.
|
||||
CPUMODE_SET_T80 EQU 001H ; Set the CPU to the soft T80.
|
||||
CPUMODE_SET_ZPU_EVO EQU 002H ; Set the CPU to the soft ZPU Evolution.
|
||||
CPUMODE_SET_EMU_MZ EQU 004H ; Set the hardware to enable the Sharp MZ Series emulations.
|
||||
CPUMODE_SET_BBB EQU 008H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_CCC EQU 010H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_DDD EQU 020H ; Place holder for a future soft CPU.
|
||||
CPUMODE_IS_Z80 EQU 000H ; Status value to indicate if the hard Z80 available.
|
||||
CPUMODE_IS_T80 EQU 001H ; Status value to indicate if the soft T80 available.
|
||||
CPUMODE_IS_ZPU_EVO EQU 002H ; Status value to indicate if the soft ZPU Evolution available.
|
||||
CPUMODE_IS_EMU_MZ EQU 004H ; Status value to indicate the Sharp MZ Series Hardware Emulation logic is available.
|
||||
CPUMODE_IS_BBB EQU 008H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_CCC EQU 010H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_DDD EQU 020H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_RESET_CPU EQU 080H ; Reset the soft CPU. Active high, when high the CPU is held in RESET, when low the CPU runs.
|
||||
CPUMODE_IS_SOFT_AVAIL EQU 040H ; Marker to indicate if the underlying FPGA can support soft CPU's.
|
||||
CPUMODE_IS_SOFT_MASK EQU 0C0H ; Mask to filter out the Soft CPU availability flags.
|
||||
CPUMODE_IS_CPU_MASK EQU 03FH ; Mask to filter out which soft CPU's are available.
|
||||
|
||||
;-----------------------------------------------
|
||||
; Video Module control bits.
|
||||
;-----------------------------------------------
|
||||
MODE_80CHAR EQU 010H ; Enable 80 character display.
|
||||
MODE_COLOUR EQU 020H ; Enable colour display.
|
||||
SYSMODE_MZ80A EQU 000H ; System board mode MZ80A, 2MHz CPU/Bus.
|
||||
SYSMODE_MZ80B EQU 020H ; System board mode MZ80B, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ2000 EQU 020H ; System board mode MZ2000, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ700 EQU 042H ; System board mode MZ700, 3.54MHz CPU/Bus.
|
||||
VMMODE_MZ80K EQU 000H ; Video mode = MZ80K
|
||||
VMMODE_MZ80C EQU 001H ; Video mode = MZ80C
|
||||
VMMODE_MZ1200 EQU 002H ; Video mode = MZ1200
|
||||
VMMODE_MZ80A EQU 003H ; Video mode = MZ80A
|
||||
VMMODE_MZ700 EQU 004H ; Video mode = MZ700
|
||||
VMMODE_MZ800 EQU 005H ; Video mode = MZ800
|
||||
VMMODE_MZ1500 EQU 006H ; Video mode = MZ1500
|
||||
VMMODE_MZ80B EQU 007H ; Video mode = MZ80B
|
||||
VMMODE_MZ2000 EQU 008H ; Video mode = MZ2000
|
||||
VMMODE_MZ2200 EQU 009H ; Video mode = MZ2200
|
||||
VMMODE_MZ2500 EQU 00AH ; Video mode = MZ2500
|
||||
VMMODE_PCGRAM EQU 020H ; Enable PCG RAM.
|
||||
VMMODE_VGA_OFF EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT50 EQU 001H ; Set VGA mode off, external monitor is driven by standard internal 50Hz signals.
|
||||
VMMODE_VGA_640x480 EQU 002H ; Set external monitor to VGA 640x480 @ 60Hz mode.
|
||||
VMMODE_VGA_800x600 EQU 003H ; Set external monitor to VGA 800x600 @ 60Hz mode.
|
||||
|
||||
;-----------------------------------------------
|
||||
; GPU commands.
|
||||
;-----------------------------------------------
|
||||
GPUCLEARVRAM EQU 001H ; Clear the VRAM without updating attributes.
|
||||
GPUCLEARVRAMCA EQU 002H ; Clear the VRAM/ARAM with given attribute byte,
|
||||
GPUCLEARVRAMP EQU 003H ; Clear the VRAM/ARAM with parameters.
|
||||
GPUCLEARGRAM EQU 081H ; Clear the entire Framebuffer.
|
||||
GPUCLEARGRAMP EQU 082H ; Clear the Framebuffer according to parameters.
|
||||
GPURESET EQU 0FFH ; Reset the GPU, return to idle state.
|
||||
|
||||
;-----------------------------------------------
|
||||
; tranZPUter SW Memory Management modes
|
||||
;-----------------------------------------------
|
||||
TZMM_ORIG EQU 000H ; Original Sharp MZ80A mode, no tranZPUter features are selected except the I/O control registers (default: 0x60-063).
|
||||
TZMM_BOOT EQU 001H ; Original mode but E800-EFFF is mapped to tranZPUter RAM so TZFS can be booted.
|
||||
TZMM_TZFS EQU 002H ; 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.
|
||||
TZMM_TZFS2 EQU 003H ; 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.
|
||||
TZMM_TZFS3 EQU 004H ; 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.
|
||||
TZMM_TZFS4 EQU 005H ; 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.
|
||||
TZMM_CPM EQU 006H ; 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.
|
||||
TZMM_CPM2 EQU 007H ; 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, F3C0:F3FF & F7C0:F7FF (floppy disk paging vectors) which resides on the mainboard.
|
||||
TZMM_COMPAT EQU 008H + TZMM_ENIOWAIT ; Original mode but with main DRAM in Bank 0 to allow bootstrapping of programs from other machines such as the MZ700.
|
||||
TZMM_HOSTACCESS EQU 009H + TZMM_ENIOWAIT ; Mode to allow code running in Bank 0, address E800:FFFF to access host memory. 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.
|
||||
TZMM_MZ700_0 EQU 00AH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_1 EQU 00BH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_2 EQU 00CH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_3 EQU 00DH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_4 EQU 00EH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ800 EQU 00FH + TZMM_ENIOWAIT ; MZ800 Mode - Tracks original hardware mode offering MZ700/MZ800 configurations.
|
||||
TZMM_MZ2000 EQU 010H + TZMM_ENIOWAIT; ; MZ2000 Mode - Running on MZ2000 hardware, configuration set according to runtime configuration registers.
|
||||
TZMM_FPGA EQU 015H + TZMM_ENIOWAIT ; Open up access for the K64F to the FPGA resources such as memory. All other access to RAM or mainboard is blocked.
|
||||
TZMM_TZPUM EQU 016H + TZMM_ENIOWAIT ; Everything in on mainboard, no access to tranZPUter memory.
|
||||
TZMM_TZPU EQU 017H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU0 EQU 018H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU1 EQU 019H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 1 is selected.
|
||||
;TZMM_TZPU2 EQU 01AH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 2 is selected.
|
||||
;TZMM_TZPU3 EQU 01BH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 3 is selected.
|
||||
;TZMM_TZPU4 EQU 01CH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 4 is selected.
|
||||
;TZMM_TZPU5 EQU 01DH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 5 is selected.
|
||||
;TZMM_TZPU6 EQU 01EH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 6 is selected.
|
||||
;TZMM_TZPU7 EQU 01FH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 7 is selected.
|
||||
|
||||
;-----------------------------------------------
|
||||
; TZ File System Header (MZF)
|
||||
;-----------------------------------------------
|
||||
TZFS_ATRB: EQU 00000h ; Code Type, 01 = Machine Code.
|
||||
TZFS_NAME: EQU 00001h ; Title/Name (17 bytes).
|
||||
TZFS_SIZE: EQU 00012h ; Size of program.
|
||||
TZFS_DTADR: EQU 00014h ; Load address of program.
|
||||
TZFS_EXADR: EQU 00016h ; Exec address of program.
|
||||
TZFS_COMNT: EQU 00018h ; Comment
|
||||
TZFS_MZFLEN: EQU 128 ; Length of the MZF header.
|
||||
TZFS_CMTLEN: EQU 104 ; Length of the comment field
|
||||
|
||||
;-----------------------------------------------
|
||||
; BIOS WORK AREA (MZ80A)
|
||||
;-----------------------------------------------
|
||||
362
software/asm/include/tzfs_definitions.asm
Normal file
362
software/asm/include/tzfs_definitions.asm
Normal file
@@ -0,0 +1,362 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: TZFS_Definitions.asm
|
||||
;- Created: September 2019
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Sharp MZ series tzfs (tranZPUter Filing System).
|
||||
;- This assembly language program is a branch from the original RFS written for the
|
||||
;- MZ80A_RFS upgrade board. It is adapted to work within the similar yet different
|
||||
;- environment of the tranZPUter SW which has a large RAM capacity (512K) and an
|
||||
;- I/O processor in the K64F/ZPU.
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-21 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: May 2020 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW.
|
||||
;- July 2020 - Updates to accommodate v2.1 of the tranZPUter board.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
;-----------------------------------------------
|
||||
; Features.
|
||||
;-----------------------------------------------
|
||||
BUILD_MZ80A EQU 0 ; Build for the standard Sharp MZ80A, no lower memory.
|
||||
BUILD_MZ700 EQU 0 ; Build for the Sharp MZ-700 base hardware.
|
||||
BUILD_MZ2000 EQU 1 ; Build for the Sharp MZ-2000 base hardware.
|
||||
|
||||
; Debugging
|
||||
ENADEBUG EQU 0 ; Enable debugging logic, 1 = enable, 0 = disable
|
||||
|
||||
;-----------------------------------------------
|
||||
; Entry/compilation start points.
|
||||
;-----------------------------------------------
|
||||
MROMADDR EQU 00000H ; Start of SA1510 Monitor ROM.
|
||||
UROMADDR EQU 0E800H ; Start of User ROM Address space.
|
||||
UROMBSTBL EQU UROMADDR + 020H ; Entry point to the bank switching table.
|
||||
TZFSJMPTABLE EQU UROMADDR + 00080H ; Start of jump table.
|
||||
BANKRAMADDR EQU 0F000H ; Start address of the banked RAM used for TZFS functionality.
|
||||
FDCROMADDR EQU 0F000H
|
||||
FDCJMP1 EQU 0F3FEH ; ROM paged vector 1.
|
||||
FDCJMP2 EQU 0F7FEH ; ROM paged vector 2.
|
||||
FDCJMP3 EQU 0F7FEH ; ROM paged vector 3.
|
||||
FDCJMP4 EQU 0F7FEH ; ROM paged vector 4.
|
||||
PRGBOOTJMP EQU 0CF00H ; Location to load bootstrap for original host program.
|
||||
|
||||
;-----------------------------------------------
|
||||
; Common character definitions.
|
||||
;-----------------------------------------------
|
||||
SCROLL EQU 001H ;Set scroll direction UP.
|
||||
BELL EQU 007H
|
||||
SPACE EQU 020H
|
||||
TAB EQU 009H ;TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||
CR EQU 00DH
|
||||
LF EQU 00AH
|
||||
FF EQU 00CH
|
||||
CS EQU 0CH ; Clear screen
|
||||
DELETE EQU 07FH
|
||||
BACKS EQU 008H
|
||||
SOH EQU 1 ; For XModem etc.
|
||||
EOT EQU 4
|
||||
ACK EQU 6
|
||||
NAK EQU 015H
|
||||
NUL EQU 000H
|
||||
NULL EQU 000H
|
||||
CTRL_A EQU 001H
|
||||
CTRL_B EQU 002H
|
||||
CTRL_C EQU 003H
|
||||
CTRL_D EQU 004H
|
||||
CTRL_E EQU 005H
|
||||
CTRL_F EQU 006H
|
||||
CTRL_G EQU 007H
|
||||
CTRL_H EQU 008H
|
||||
CTRL_I EQU 009H
|
||||
CTRL_J EQU 00AH
|
||||
CTRL_K EQU 00BH
|
||||
CTRL_L EQU 00CH
|
||||
CTRL_M EQU 00DH
|
||||
CTRL_N EQU 00EH
|
||||
CTRL_O EQU 00FH
|
||||
CTRL_P EQU 010H
|
||||
CTRL_Q EQU 011H
|
||||
CTRL_R EQU 012H
|
||||
CTRL_S EQU 013H
|
||||
CTRL_T EQU 014H
|
||||
CTRL_U EQU 015H
|
||||
CTRL_V EQU 016H
|
||||
CTRL_W EQU 017H
|
||||
CTRL_X EQU 018H
|
||||
CTRL_Y EQU 019H
|
||||
CTRL_Z EQU 01AH
|
||||
ESC EQU 01BH
|
||||
CTRL_SLASH EQU 01CH
|
||||
CTRL_LB EQU 01BH
|
||||
CTRL_RB EQU 01DH
|
||||
CTRL_CAPPA EQU 01EH
|
||||
CTRL_UNDSCR EQU 01FH
|
||||
CTRL_AT EQU 000H
|
||||
NOKEY EQU 0F0H
|
||||
CURSRIGHT EQU 0F1H
|
||||
CURSLEFT EQU 0F2H
|
||||
CURSUP EQU 0F3H
|
||||
CURSDOWN EQU 0F4H
|
||||
DBLZERO EQU 0F5H
|
||||
INSERT EQU 0F6H
|
||||
CLRKEY EQU 0F7H
|
||||
HOMEKEY EQU 0F8H
|
||||
BREAKKEY EQU 0FBH
|
||||
GRAPHKEY EQU 0FCH
|
||||
ALPHAKEY EQU 0FDH
|
||||
|
||||
;-----------------------------------------------
|
||||
; Memory mapped ports in hardware.
|
||||
;-----------------------------------------------
|
||||
SCRN: EQU 0D000H
|
||||
ARAM: EQU 0D800H
|
||||
DSPCTL: EQU 0DFFFH ; Screen 40/80 select register (bit 7)
|
||||
KEYPA: EQU 0E000h
|
||||
KEYPB: EQU 0E001h
|
||||
KEYPC: EQU 0E002h
|
||||
KEYPF: EQU 0E003h
|
||||
CSTR: EQU 0E002h
|
||||
CSTPT: EQU 0E003h
|
||||
CONT0: EQU 0E004h
|
||||
CONT1: EQU 0E005h
|
||||
CONT2: EQU 0E006h
|
||||
CONTF: EQU 0E007h
|
||||
SUNDG: EQU 0E008h
|
||||
TEMP: EQU 0E008h
|
||||
MEMSW: EQU 0E00CH
|
||||
MEMSWR: EQU 0E010H
|
||||
INVDSP: EQU 0E014H
|
||||
NRMDSP: EQU 0E015H
|
||||
SCLDSP: EQU 0E200H
|
||||
SCLBASE: EQU 0E2H
|
||||
|
||||
;-----------------------------------------------
|
||||
; IO ports in hardware and values.
|
||||
;-----------------------------------------------
|
||||
MMCFG EQU 060H ; Memory management configuration latch.
|
||||
SETXMHZ EQU 062H ; Select the alternate clock frequency.
|
||||
SET2MHZ EQU 064H ; Select the system 2MHz clock frequency.
|
||||
CLKSELRD EQU 066H ; Read clock selected setting, 0 = 2MHz, 1 = XMHz
|
||||
SVCREQ EQU 068H ; I/O Processor service request.
|
||||
CPLDSTATUS EQU 06BH ; Version 2.1 CPLD status register.
|
||||
CPUCFG EQU 06CH ; Version 2.2 CPU configuration register.
|
||||
CPUSTATUS EQU 06CH ; Version 2.2 CPU runtime status register.
|
||||
CPUINFO EQU 06DH ; Version 2.2 CPU information register.
|
||||
CPLDCFG EQU 06EH ; Version 2.1 CPLD configuration register.
|
||||
CPLDINFO EQU 06FH ; Version 2.1 CPLD version information register.
|
||||
VMPNUM EQU 0A0H ; Set the parameter number to update.
|
||||
VMPLBYTE EQU 0A1H ; Update the lower selected parameter byte.
|
||||
VMPUBYTE EQU 0A2H ; Update the upper selected parameter byte.
|
||||
PALSLCTOFF EQU 0A3H ; set the palette slot Off position to be adjusted.
|
||||
PALSLCTON EQU 0A4H ; set the palette slot On position to be adjusted.
|
||||
PALSETRED EQU 0A5H ; set the red palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETGREEN EQU 0A6H ; set the green palette value according to the PALETTE_PARAM_SEL address.
|
||||
PALSETBLUE EQU 0A7H ; set the blue palette value according to the PALETTE_PARAM_SEL address.
|
||||
VMPALETTE EQU 0B0H ; Select Palette:
|
||||
; 0xB0 sets the palette. The Video Module supports 4 bit per colour output but there is only enough RAM for 1 bit per colour so the pallette is used to change the colours output.
|
||||
; Bits [7:0] defines the pallete number. This indexes a lookup table which contains the required 4bit output per 1bit input.
|
||||
; GPU:
|
||||
GPUPARAM EQU 0B2H ; 0xB2 set parameters. Store parameters in a long word to be used by the graphics command processor.
|
||||
; The parameter word is 128 bit and each write to the parameter word shifts left by 8 bits and adds the new byte at bits 7:0.
|
||||
GPUCMD EQU 0B3H ; 0xB3 set the graphics processor unit commands.
|
||||
GPUSTATUS EQU 0B3H ; [7;1] - FSM state, [0] - 1 = busy, 0 = idle
|
||||
; Bits [5:0] - 0 = Reset parameters.
|
||||
; 1 = Clear to val. Start Location (16 bit), End Location (16 bit), Red Filter, Green Filter, Blue Filter
|
||||
;
|
||||
VMCTRL EQU 0B8H ; Video Module control register. [2:0] - 000 (default) = MZ80A, 001 = MZ-700, 010 = MZ800, 011 = MZ80B, 100 = MZ80K, 101 = MZ80C, 110 = MZ1200, 111 = MZ2000. [3] = 0 - 40 col, 1 - 80 col.
|
||||
VMGRMODE EQU 0B9H ; Video Module graphics mode. 7/6 = Operator (00=OR,01=AND,10=NAND,11=XOR), 5=GRAM Output Enable, 4 = VRAM Output Enable, 3/2 = Write mode (00=Page 1:Red, 01=Page 2:Green, 10=Page 3:Blue, 11=Indirect), 1/0=Read mode (00=Page 1:Red, 01=Page2:Green, 10=Page 3:Blue, 11=Not used).
|
||||
VMREDMASK EQU 0BAH ; Video Module Red bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMGREENMASK EQU 0BBH ; Video Module Green bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMBLUEMASK EQU 0BCH ; Video Module Blue bit mask (1 bit = 1 pixel, 8 pixels per byte).
|
||||
VMPAGE EQU 0BDH ; Video Module memory page register. [1:0] switches in 1 16Kb page (3 pages) of graphics ram to C000 - FFFF. Bits [1:0] = page, 00 = off, 01 = Red, 10 = Green, 11 = Blue. This overrides all MZ700/MZ80B page switching functions. [7] 0 - normal, 1 - switches in CGROM for upload at D000:DFFF.
|
||||
VMVGATTR EQU 0BEH ; Select VGA Border colour and attributes. Bit 2 = Red, 1 = Green, 0 = Blue.
|
||||
VMVGAMODE EQU 0BFH ; Select VGA output mode. Bits [3:0] - Output mode.
|
||||
GDCRTC EQU 0CFH ; MZ-800 CRTC control register
|
||||
GDCMD EQU 0CEH ; MZ-800 CRTC Mode register
|
||||
GDGRF EQU 0CDH ; MZ-800 read format register
|
||||
GDGWF EQU 0CCH ; MZ-800 write format register
|
||||
MMIO0 EQU 0E0H ; MZ-700/MZ-800 Memory Management Set 0
|
||||
MMIO1 EQU 0E1H ; MZ-700/MZ-800 Memory Management Set 1
|
||||
MMIO2 EQU 0E2H ; MZ-700/MZ-800 Memory Management Set 2
|
||||
MMIO3 EQU 0E3H ; MZ-700/MZ-800 Memory Management Set 3
|
||||
MMIO4 EQU 0E4H ; MZ-700/MZ-800 Memory Management Set 4
|
||||
MMIO5 EQU 0E5H ; MZ-700/MZ-800 Memory Management Set 5
|
||||
MMIO6 EQU 0E6H ; MZ-700/MZ-800 Memory Management Set 6
|
||||
MMIO7 EQU 0E7H ; MZ-700/MZ-800 Memory Management Set 7
|
||||
SYSCTRL EQU 0F0H ; System board control register. [2:0] - 000 MZ80A Mode, 2MHz CPU/Bus, 001 MZ80B Mode, 4MHz CPU/Bus, 010 MZ700 Mode, 3.54MHz CPU/Bus.
|
||||
GRAMMODE EQU 0F4H ; MZ80B Graphics mode. Bit 0 = 0, Write to Graphics RAM I, Bit 0 = 1, Write to Graphics RAM II. Bit 1 = 1, blend Graphics RAM I output on display, Bit 2 = 1, blend Graphics RAM II output on display.
|
||||
|
||||
;-----------------------------------------------
|
||||
; CPLD Configuration constants.
|
||||
;-----------------------------------------------
|
||||
MODE_MZ80K EQU 0 ; Set to MZ-80K mode.
|
||||
MODE_MZ80C EQU 1 ; Set to MZ-80C mode.
|
||||
MODE_MZ1200 EQU 2 ; Set to MZ-1200 mode.
|
||||
MODE_MZ80A EQU 3 ; Set to MZ-80A mode (base mode on MZ-80A hardware).
|
||||
MODE_MZ700 EQU 4 ; Set to MZ-700 mode (base mode on MZ-700 hardware).
|
||||
MODE_MZ800 EQU 5 ; Set to MZ-800 mode.
|
||||
MODE_MZ80B EQU 6 ; Set to MZ-80B mode.
|
||||
MODE_MZ2000 EQU 7 ; Set to MZ-2000 mode.
|
||||
MODE_VIDEO_FPGA EQU 8 ; Bit flag (bit 3) to switch CPLD into using the new FPGA video hardware.
|
||||
MODE_RESET_PRESERVE EQU 080H ; Preserve register configuration through reset.
|
||||
|
||||
;-----------------------------------------------
|
||||
; CPLD Command Instruction constants.
|
||||
;-----------------------------------------------
|
||||
CPLD_RESET_HOST EQU 1 ; CPLD level command to reset the host system.
|
||||
CPLD_HOLD_HOST_BUS EQU 2 ; CPLD command to hold the host bus.
|
||||
CPLD_RELEASE_HOST_BUS EQU 3 ; CPLD command to release the host bus.
|
||||
|
||||
;-----------------------------------------------
|
||||
; FPGA CPU enhancement control bits.
|
||||
;-----------------------------------------------
|
||||
CPUMODE_SET_Z80 EQU 000H ; Set the CPU to the hard Z80.
|
||||
CPUMODE_SET_T80 EQU 001H ; Set the CPU to the soft T80.
|
||||
CPUMODE_SET_ZPU_EVO EQU 002H ; Set the CPU to the soft ZPU Evolution.
|
||||
CPUMODE_SET_EMU_MZ EQU 004H ; Set the hardware to enable the Sharp MZ Series emulations.
|
||||
CPUMODE_SET_BBB EQU 008H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_CCC EQU 010H ; Place holder for a future soft CPU.
|
||||
CPUMODE_SET_DDD EQU 020H ; Place holder for a future soft CPU.
|
||||
CPUMODE_IS_Z80 EQU 000H ; Status value to indicate if the hard Z80 available.
|
||||
CPUMODE_IS_T80 EQU 001H ; Status value to indicate if the soft T80 available.
|
||||
CPUMODE_IS_ZPU_EVO EQU 002H ; Status value to indicate if the soft ZPU Evolution available.
|
||||
CPUMODE_IS_EMU_MZ EQU 004H ; Status value to indicate the Sharp MZ Series Hardware Emulation logic is available.
|
||||
CPUMODE_IS_BBB EQU 008H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_CCC EQU 010H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_IS_DDD EQU 020H ; Place holder to indicate if a future soft CPU is available.
|
||||
CPUMODE_RESET_CPU EQU 080H ; Reset the soft CPU. Active high, when high the CPU is held in RESET, when low the CPU runs.
|
||||
CPUMODE_IS_SOFT_AVAIL EQU 040H ; Marker to indicate if the underlying FPGA can support soft CPU's.
|
||||
CPUMODE_IS_SOFT_MASK EQU 0C0H ; Mask to filter out the Soft CPU availability flags.
|
||||
CPUMODE_IS_CPU_MASK EQU 03FH ; Mask to filter out which soft CPU's are available.
|
||||
|
||||
;-----------------------------------------------
|
||||
; Video Module control bits.
|
||||
;-----------------------------------------------
|
||||
MODE_80CHAR EQU 010H ; Enable 80 character display.
|
||||
MODE_COLOUR EQU 020H ; Enable colour display.
|
||||
SYSMODE_MZ80A EQU 000H ; System board mode MZ80A, 2MHz CPU/Bus.
|
||||
SYSMODE_MZ80B EQU 020H ; System board mode MZ80B, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ2000 EQU 020H ; System board mode MZ2000, 4MHz CPU/Bus.
|
||||
SYSMODE_MZ700 EQU 042H ; System board mode MZ700, 3.54MHz CPU/Bus.
|
||||
VMMODE_MZ80K EQU 000H ; Video mode = MZ80K
|
||||
VMMODE_MZ80C EQU 001H ; Video mode = MZ80C
|
||||
VMMODE_MZ1200 EQU 002H ; Video mode = MZ1200
|
||||
VMMODE_MZ80A EQU 003H ; Video mode = MZ80A
|
||||
VMMODE_MZ700 EQU 004H ; Video mode = MZ700
|
||||
VMMODE_MZ800 EQU 005H ; Video mode = MZ800
|
||||
VMMODE_MZ1500 EQU 006H ; Video mode = MZ1500
|
||||
VMMODE_MZ80B EQU 007H ; Video mode = MZ80B
|
||||
VMMODE_MZ2000 EQU 008H ; Video mode = MZ2000
|
||||
VMMODE_MZ2200 EQU 009H ; Video mode = MZ2200
|
||||
VMMODE_MZ2500 EQU 00AH ; Video mode = MZ2500
|
||||
VMMODE_PCGRAM EQU 020H ; Enable PCG RAM.
|
||||
VMMODE_VGA_OFF EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT EQU 000H ; Set VGA mode off, external monitor is driven by standard internal 60Hz signals.
|
||||
VMMODE_VGA_INT50 EQU 001H ; Set VGA mode off, external monitor is driven by standard internal 50Hz signals.
|
||||
VMMODE_VGA_640x480 EQU 002H ; Set external monitor to VGA 640x480 @ 60Hz mode.
|
||||
VMMODE_VGA_800x600 EQU 003H ; Set external monitor to VGA 800x600 @ 60Hz mode.
|
||||
|
||||
;-----------------------------------------------
|
||||
; GPU commands.
|
||||
;-----------------------------------------------
|
||||
GPUCLEARVRAM EQU 001H ; Clear the VRAM without updating attributes.
|
||||
GPUCLEARVRAMCA EQU 002H ; Clear the VRAM/ARAM with given attribute byte,
|
||||
GPUCLEARVRAMP EQU 003H ; Clear the VRAM/ARAM with parameters.
|
||||
GPUCLEARGRAM EQU 081H ; Clear the entire Framebuffer.
|
||||
GPUCLEARGRAMP EQU 082H ; Clear the Framebuffer according to parameters.
|
||||
GPURESET EQU 0FFH ; Reset the GPU, return to idle state.
|
||||
|
||||
;-----------------------------------------------
|
||||
; tranZPUter SW Memory Management modes
|
||||
;-----------------------------------------------
|
||||
TZMM_ENIOWAIT EQU 020H ; Memory management IO Wait State enable - insert a wait state when an IO operation to E0-FF is executed.
|
||||
TZMM_ORIG EQU 000H ; Original Sharp MZ80A mode, no tranZPUter features are selected except the I/O control registers (default: 0x60-063).
|
||||
TZMM_BOOT EQU 001H ; Original mode but E800-EFFF is mapped to tranZPUter RAM so TZFS can be booted.
|
||||
TZMM_TZFS EQU 002H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS2 EQU 003H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS3 EQU 004H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_TZFS4 EQU 005H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_CPM EQU 006H + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_CPM2 EQU 007H + TZMM_ENIOWAIT ; 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, F3C0:F3FF & F7C0:F7FF (floppy disk paging vectors) which resides on the mainboard.
|
||||
TZMM_COMPAT EQU 008H + TZMM_ENIOWAIT ; Original mode but with main DRAM in Bank 0 to allow bootstrapping of programs from other machines such as the MZ700.
|
||||
TZMM_HOSTACCESS EQU 009H + TZMM_ENIOWAIT ; Mode to allow code running in Bank 0, address E800:FFFF to access host memory. 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.
|
||||
TZMM_MZ700_0 EQU 00AH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_1 EQU 00BH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_2 EQU 00CH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_3 EQU 00DH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ700_4 EQU 00EH + TZMM_ENIOWAIT ; 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.
|
||||
TZMM_MZ800 EQU 00FH + TZMM_ENIOWAIT ; MZ800 Mode - Tracks original hardware mode offering MZ700/MZ800 configurations.
|
||||
TZMM_MZ2000 EQU 010H + TZMM_ENIOWAIT; ; MZ2000 Mode - Running on MZ2000 hardware, configuration set according to runtime configuration registers.
|
||||
TZMM_FPGA EQU 015H + TZMM_ENIOWAIT ; Open up access for the K64F to the FPGA resources such as memory. All other access to RAM or mainboard is blocked.
|
||||
TZMM_TZPUM EQU 016H + TZMM_ENIOWAIT ; Everything in on mainboard, no access to tranZPUter memory.
|
||||
TZMM_TZPU EQU 017H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU0 EQU 018H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 0 is selected.
|
||||
;TZMM_TZPU1 EQU 019H + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 1 is selected.
|
||||
;TZMM_TZPU2 EQU 01AH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 2 is selected.
|
||||
;TZMM_TZPU3 EQU 01BH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 3 is selected.
|
||||
;TZMM_TZPU4 EQU 01CH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 4 is selected.
|
||||
;TZMM_TZPU5 EQU 01DH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 5 is selected.
|
||||
;TZMM_TZPU6 EQU 01EH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 6 is selected.
|
||||
;TZMM_TZPU7 EQU 01FH + TZMM_ENIOWAIT ; Everything is in tranZPUter domain, no access to underlying Sharp mainboard unless memory management mode is switched. tranZPUter RAM 64K block 7 is selected.
|
||||
|
||||
;-----------------------------------------------
|
||||
; TZ File System Header (MZF)
|
||||
;-----------------------------------------------
|
||||
TZFS_ATRB: EQU 00000h ; Code Type, 01 = Machine Code.
|
||||
TZFS_NAME: EQU 00001h ; Title/Name (17 bytes).
|
||||
TZFS_SIZE: EQU 00012h ; Size of program.
|
||||
TZFS_DTADR: EQU 00014h ; Load address of program.
|
||||
TZFS_EXADR: EQU 00016h ; Exec address of program.
|
||||
TZFS_COMNT: EQU 00018h ; Comment
|
||||
TZFS_MZFLEN: EQU 128 ; Length of the MZF header.
|
||||
TZFS_CMTLEN: EQU 104 ; Length of the comment field
|
||||
|
||||
;-----------------------------------------------
|
||||
; Entry/compilation start points.
|
||||
;-----------------------------------------------
|
||||
TPSTART: EQU 010F0h
|
||||
MEMSTART: EQU 01200h
|
||||
MSTART: EQU 0E900h
|
||||
MZFHDRSZ EQU 128
|
||||
TZFSSECTSZ EQU 256
|
||||
MROMSIZE EQU 4096
|
||||
UROMSIZE EQU 2048
|
||||
FNSIZE EQU 17
|
||||
|
||||
;-----------------------------------------------
|
||||
; RAM Banks, 0-3 are reserved for TZFS code in
|
||||
; the User/Floppy ROM bank area.
|
||||
;-----------------------------------------------
|
||||
USRROMPAGES EQU 3 ; User ROM
|
||||
ROMBANK0 EQU 0 ; TZFS Bank 0 - Main RFS Entry point and functions.
|
||||
ROMBANK1 EQU 1 ; TZFS Bank 1 -
|
||||
ROMBANK2 EQU 2 ; TZFS Bank 2 -
|
||||
ROMBANK3 EQU 3 ; TZFS Bank 3 -
|
||||
|
||||
OBJCD EQU 001H ; MZF contains a binary object.
|
||||
BTX1CD EQU 002H ; MZF contains a BASIC program.
|
||||
BTX2CD EQU 005H ; MZF contains a BASIC program.
|
||||
TZOBJCD0 EQU 0F8H ; MZF contains a TZFS binary object for page 0.
|
||||
TZOBJCD1 EQU 0F9H
|
||||
TZOBJCD2 EQU 0FAH
|
||||
TZOBJCD3 EQU 0FBH
|
||||
TZOBJCD4 EQU 0FCH
|
||||
TZOBJCD5 EQU 0FDH
|
||||
TZOBJCD6 EQU 0FEH
|
||||
TZOBJCD7 EQU 0FFH ; MZF contains a TZFS binary object for page 7.
|
||||
193
software/asm/include/tzfs_mondef.asm
Normal file
193
software/asm/include/tzfs_mondef.asm
Normal file
@@ -0,0 +1,193 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: tzfs_mondef.asm
|
||||
;- Created: September 2019
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Sharp MZ series tzfs (tranZPUter Filing System).
|
||||
;- This assembly language program is a branch from the original RFS written for the
|
||||
;- MZ80A_RFS upgrade board. It is adapted to work within the similar yet different
|
||||
;- environment of the tranZPUter SW which has a large RAM capacity (512K) and an
|
||||
;- I/O processor in the K64F/ZPU.
|
||||
;-
|
||||
;- This file contains the SA-1510/1Z-013A monitor specific definitions.
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-21 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: May 2020 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW.
|
||||
;- July 2020 - Updates to accommodate v2.1 of the tranZPUter board.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
;-------------------------------------------------------
|
||||
; Function entry points in the standard SA-1510 Monitor.
|
||||
;-------------------------------------------------------
|
||||
GETL: EQU 00003h
|
||||
LETNL: EQU 00006h
|
||||
NL: EQU 00009h
|
||||
PRNTS: EQU 0000Ch
|
||||
PRNT: EQU 00012h
|
||||
MSG: EQU 00015h
|
||||
MSGX: EQU 00018h
|
||||
GETKY EQU 0001Bh
|
||||
BRKEY EQU 0001Eh
|
||||
?WRI EQU 00021h
|
||||
?WRD EQU 00024h
|
||||
?RDI EQU 00027h
|
||||
?RDD EQU 0002Ah
|
||||
?VRFY EQU 0002Dh
|
||||
MELDY EQU 00030h
|
||||
?TMST EQU 00033h
|
||||
MONIT: EQU 00000h
|
||||
;SS: EQU 00089h
|
||||
;ST1: EQU 00095h
|
||||
HLHEX EQU 00410h
|
||||
_2HEX EQU 0041Fh
|
||||
;?MODE: EQU 0074DH
|
||||
;?KEY EQU 008CAh
|
||||
PRNT3 EQU 0096Ch
|
||||
?ADCN EQU 00BB9h
|
||||
?DACN EQU 00BCEh
|
||||
?DSP: EQU 00DB5H
|
||||
?BLNK EQU 00DA6h
|
||||
?DPCT EQU 00DDCh
|
||||
PRTHL: EQU 003BAh
|
||||
PRTHX: EQU 003C3h
|
||||
HEX: EQU 003F9h
|
||||
DPCT: EQU 00DDCh
|
||||
;DLY12: EQU 00DA7h
|
||||
;DLY12A: EQU 00DAAh
|
||||
?RSTR1: EQU 00EE6h
|
||||
;MOTOR: EQU 006A3H
|
||||
CKSUM: EQU 0071AH
|
||||
GAP: EQU 0077AH
|
||||
;WTAPE: EQU 00485H
|
||||
MSTOP: EQU 00700H
|
||||
|
||||
; ROM location differences between the MZ80A and MZ-700.
|
||||
IF BUILD_MZ80A > 0
|
||||
SS: EQU 00089h
|
||||
ST1: EQU 00095h
|
||||
WTAPE: EQU 00485H
|
||||
MOTOR: EQU 006A3H
|
||||
?MODE: EQU 0074DH
|
||||
?KEY EQU 008CAh
|
||||
DLY12: EQU 00DA7h
|
||||
DLY12A: EQU 00DAAh
|
||||
ELSE
|
||||
SS: EQU 000A2H
|
||||
ST1: EQU 000ADH
|
||||
WTAPE: EQU 0048AH
|
||||
MOTOR: EQU 0069FH
|
||||
?MODE: EQU 0073EH
|
||||
?KEY EQU 009B3H
|
||||
DLY12: EQU 00996H
|
||||
ENDIF
|
||||
|
||||
;-----------------------------------------------
|
||||
; SA-1510 MONITOR WORK AREA (MZ80A)
|
||||
;-----------------------------------------------
|
||||
STACK: EQU 010F0H
|
||||
;
|
||||
ORG STACK
|
||||
;
|
||||
SPV:
|
||||
IBUFE: ; TAPE BUFFER (128 BYTES)
|
||||
ATRB: DS virtual 1 ; ATTRIBUTE
|
||||
NAME: DS virtual FNSIZE ; FILE NAME
|
||||
SIZE: DS virtual 2 ; BYTESIZE
|
||||
DTADR: DS virtual 2 ; DATA ADDRESS
|
||||
EXADR: DS virtual 2 ; EXECUTION ADDRESS
|
||||
COMNT: DS virtual 92 ; COMMENT
|
||||
SWPW: DS virtual 10 ; SWEEP WORK
|
||||
KDATW: DS virtual 2 ; KEY WORK
|
||||
KANAF: DS virtual 1 ; KANA FLAG (01=GRAPHIC MODE)
|
||||
DSPXY: DS virtual 2 ; DISPLAY COORDINATES
|
||||
MANG: DS virtual 6 ; COLUMN MANAGEMENT
|
||||
MANGE: DS virtual 1 ; COLUMN MANAGEMENT END
|
||||
PBIAS: DS virtual 1 ; PAGE BIAS
|
||||
ROLTOP: DS virtual 1 ; ROLL TOP BIAS
|
||||
MGPNT: DS virtual 1 ; COLUMN MANAG. POINTER
|
||||
PAGETP: DS virtual 2 ; PAGE TOP
|
||||
ROLEND: DS virtual 1 ; ROLL END
|
||||
DS virtual 14 ; BIAS
|
||||
FLASH: DS virtual 1 ; FLASHING DATA
|
||||
SFTLK: DS virtual 1 ; SHIFT LOCK
|
||||
REVFLG: DS virtual 1 ; REVERSE FLAG
|
||||
SPAGE: DS virtual 1 ; PAGE CHANGE
|
||||
FLSDT: DS virtual 1 ; CURSOR DATA
|
||||
STRGF: DS virtual 1 ; STRING FLAG
|
||||
DPRNT: DS virtual 1 ; TAB COUNTER
|
||||
TMCNT: DS virtual 2 ; TAPE MARK COUNTER
|
||||
SUMDT: DS virtual 2 ; CHECK SUM DATA
|
||||
CSMDT: DS virtual 2 ; FOR COMPARE SUM DATA
|
||||
AMPM: DS virtual 1 ; AMPM DATA
|
||||
TIMFG: DS virtual 1 ; TIME FLAG
|
||||
SWRK: DS virtual 1 ; KEY SOUND FLAG
|
||||
TEMPW: DS virtual 1 ; TEMPO WORK
|
||||
ONTYO: DS virtual 1 ; ONTYO WORK
|
||||
OCTV: DS virtual 1 ; OCTAVE WORK
|
||||
RATIO: DS virtual 2 ; ONPU RATIO
|
||||
BUFER: DS virtual 81 ; GET LINE BUFFER
|
||||
|
||||
; Quickdisk work area
|
||||
;QDPA EQU 01130h ; QD code 1
|
||||
;QDPB EQU 01131h ; QD code 2
|
||||
;QDPC EQU 01132h ; QD header startaddress
|
||||
;QDPE EQU 01134h ; QD header length
|
||||
;QDCPA EQU 0113Bh ; QD error flag
|
||||
;HDPT EQU 0113Ch ; QD new headpoint possition
|
||||
;HDPT0 EQU 0113Dh ; QD actual headpoint possition
|
||||
;FNUPS EQU 0113Eh
|
||||
;FNUPF EQU 01140h
|
||||
;FNA EQU 01141h ; File Number A (actual file number)
|
||||
;FNB EQU 01142h ; File Number B (next file number)
|
||||
;MTF EQU 01143h ; QD motor flag
|
||||
;RTYF EQU 01144h
|
||||
;SYNCF EQU 01146h ; SyncFlags
|
||||
;RETSP EQU 01147h
|
||||
;BUFER EQU 011A3h
|
||||
;QDIRBF EQU 0CD90h
|
||||
|
||||
|
||||
|
||||
;SPV:
|
||||
;IBUFE: ; TAPE BUFFER (128 BYTES)
|
||||
;ATRB: DS virtual 1 ; Code Type, 01 = Machine Code.
|
||||
;NAME: DS virtual 17 ; Title/Name (17 bytes).
|
||||
;SIZE: DS virtual 2 ; Size of program.
|
||||
;DTADR: DS virtual 2 ; Load address of program.
|
||||
;EXADR: DS virtual 2 ; Exec address of program.
|
||||
;COMNT: DS virtual 104 ; COMMENT
|
||||
;KANAF: DS virtual 1 ; KANA FLAG (01=GRAPHIC MODE)
|
||||
;DSPXY: DS virtual 2 ; DISPLAY COORDINATES
|
||||
;MANG: DS virtual 27 ; COLUMN MANAGEMENT
|
||||
;FLASH: DS virtual 1 ; FLASHING DATA
|
||||
;FLPST: DS virtual 2 ; FLASHING POSITION
|
||||
;FLSST: DS virtual 1 ; FLASHING STATUS
|
||||
;FLSDT: DS virtual 1 ; CURSOR DATA
|
||||
;STRGF: DS virtual 1 ; STRING FLAG
|
||||
;DPRNT: DS virtual 1 ; TAB COUNTER
|
||||
;TMCNT: DS virtual 2 ; TAPE MARK COUNTER
|
||||
;SUMDT: DS virtual 2 ; CHECK SUM DATA
|
||||
;CSMDT: DS virtual 2 ; FOR COMPARE SUM DATA
|
||||
;AMPM: DS virtual 1 ; AMPM DATA
|
||||
;TIMFG: DS virtual 1 ; TIME FLAG
|
||||
;SWRK: DS virtual 1 ; KEY SOUND FLAG
|
||||
;TEMPW: DS virtual 1 ; TEMPO WORK
|
||||
;ONTYO: DS virtual 1 ; ONTYO WORK
|
||||
;OCTV: DS virtual 1 ; OCTAVE WORK
|
||||
;RATIO: DS virtual 2 ; ONPU RATIO
|
||||
123
software/asm/include/tzfs_svcstruct.asm
Normal file
123
software/asm/include/tzfs_svcstruct.asm
Normal file
@@ -0,0 +1,123 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: tzfs_svcstruct.asm
|
||||
;- Created: September 2019
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Sharp MZ series tzfs (tranZPUter Filing System).
|
||||
;- This assembly language program is a branch from the original RFS written for the
|
||||
;- MZ80A_RFS upgrade board. It is adapted to work within the similar yet different
|
||||
;- environment of the tranZPUter SW which has a large RAM capacity (512K) and an
|
||||
;- I/O processor in the K64F/ZPU.
|
||||
;-
|
||||
;- This file holds the TZFS service structure definition.
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-21 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: May 2020 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW.
|
||||
;- July 2020 - Updates to accommodate v2.1 of the tranZPUter board.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
TZSVC_CMD_READDIR EQU 01H ; Service command to open a directory and return the first block of entries.
|
||||
TZSVC_CMD_NEXTDIR EQU 02H ; Service command to return the next block of an open directory.
|
||||
TZSVC_CMD_READFILE EQU 03H ; Service command to open a file and return the first block.
|
||||
TZSVC_CMD_NEXTREADFILE EQU 04H ; Service command to return the next block of an open file.
|
||||
TZSVC_CMD_WRITEFILE EQU 05H ; Service command to create a file and save the first block.
|
||||
TZSVC_CMD_NEXTWRITEFILE EQU 06H ; Service command to write the next block to the open file.
|
||||
TZSVC_CMD_CLOSE EQU 07H ; Service command to close any open file or directory.
|
||||
TZSVC_CMD_LOADFILE EQU 08H ; Service command to load a file directly into tranZPUter memory.
|
||||
TZSVC_CMD_SAVEFILE EQU 09H ; Service command to save a file directly from tranZPUter memory.
|
||||
TZSVC_CMD_ERASEFILE EQU 0aH ; Service command to erase a file on the SD card.
|
||||
TZSVC_CMD_CHANGEDIR EQU 0bH ; Service command to change the active directory on the SD card.
|
||||
TZSVC_CMD_LOAD40ABIOS EQU 20H ; Service command requesting that the 40 column version of the SA1510 BIOS is loaded.
|
||||
TZSVC_CMD_LOAD80ABIOS EQU 21H ; Service command requesting that the 80 column version of the SA1510 BIOS is loaded.
|
||||
TZSVC_CMD_LOAD700BIOS40 EQU 22H ; Service command requesting that the MZ700 1Z-013A 40 column BIOS is loaded.
|
||||
TZSVC_CMD_LOAD700BIOS80 EQU 23H ; Service command requesting that the MZ700 1Z-013A 80 column patched BIOS is loaded.
|
||||
TZSVC_CMD_LOAD80BIPL EQU 24H ; Service command requesting the MZ-80B IPL is loaded.
|
||||
TZSVC_CMD_LOAD800BIOS EQU 25H ; Service command requesting that the MZ800 9Z-504M BIOS is loaded.
|
||||
TZSVC_CMD_LOAD2KIPL EQU 26H ; Service command requesting the MZ-2000 IPL is loaded.
|
||||
TZSVC_CMD_LOAD2KBASIC1 EQU 27H ; Service command to load BASIC 1Z-001 for the MZ-2000.
|
||||
TZSVC_CMD_LOAD2KBASIC2 EQU 28H ; Service command to load BASIC 1Z-002 for the MZ-2000.
|
||||
TZSVC_CMD_LOAD2KMON EQU 29H ; Service command to load Monitor 1Z001M for the MZ-2000 IPL.
|
||||
TZSVC_CMD_LOADTZFS EQU 2FH ; Service command requesting the loading of TZFS. This service is for machines which normally dont have a monitor BIOS. ie. MZ-80B/MZ-2000 and manually request TZFS.
|
||||
TZSVC_CMD_LOADBDOS EQU 30H ; Service command to reload CPM BDOS+CCP.
|
||||
TZSVC_CMD_ADDSDDRIVE EQU 31H ; Service command to attach a CPM disk to a drive number.
|
||||
TZSVC_CMD_READSDDRIVE EQU 32H ; Service command to read an attached SD file as a CPM disk drive.
|
||||
TZSVC_CMD_WRITESDDRIVE EQU 33H ; Service command to write to a CPM disk drive which is an attached SD file.
|
||||
TZSVC_CMD_CPU_BASEFREQ EQU 40H ; Service command to switch to the mainboard frequency.
|
||||
TZSVC_CMD_CPU_ALTFREQ EQU 41H ; Service command to switch to the alternate frequency provided by the K64F.
|
||||
TZSVC_CMD_CPU_CHGFREQ EQU 42H ; Service command to set the alternate frequency in hertz.
|
||||
TZSVC_CMD_CPU_SETZ80 EQU 50H ; Service command to switch to the external Z80 hard cpu.
|
||||
TZSVC_CMD_CPU_SETT80 EQU 51H ; Service command to switch to the internal T80 soft cpu.
|
||||
TZSVC_CMD_CPU_SETZPUEVO EQU 52H ; Service command to switch to the internal ZPU Evolution soft cpu.
|
||||
TZSVC_CMD_EMU_SETMZ80K EQU 53H ; Service command to switch to the internal Sharp MZ Series Emulation of the MZ80K.
|
||||
TZSVC_CMD_EMU_SETMZ80C EQU 54H ; "" "" "" MZ80C.
|
||||
TZSVC_CMD_EMU_SETMZ1200 EQU 55H ; "" "" "" MZ1200.
|
||||
TZSVC_CMD_EMU_SETMZ80A EQU 56H ; "" "" "" MZ80A.
|
||||
TZSVC_CMD_EMU_SETMZ700 EQU 57H ; "" "" "" MZ700.
|
||||
TZSVC_CMD_EMU_SETMZ800 EQU 58H ; "" "" "" MZ800.
|
||||
TZSVC_CMD_EMU_SETMZ1500 EQU 59H ; "" "" "" MZ1500.
|
||||
TZSVC_CMD_EMU_SETMZ80B EQU 5AH ; "" "" "" MZ80B.
|
||||
TZSVC_CMD_EMU_SETMZ2000 EQU 5BH ; "" "" "" MZ2000.
|
||||
TZSVC_CMD_EMU_SETMZ2200 EQU 5CH ; "" "" "" MZ2200.
|
||||
TZSVC_CMD_EMU_SETMZ2500 EQU 5DH ; "" "" "" MZ2500.
|
||||
TZSVC_CMD_EXIT EQU 07FH ; Service command to terminate TZFS and restart the machine in original mode.
|
||||
TZSVC_STATUS_OK EQU 000H ; Flag to indicate the K64F processing completed successfully.
|
||||
TZSVC_STATUS_REQUEST EQU 0FEH ; Flag to indicate the Z80 has made a request to the K64F.
|
||||
TZSVC_STATUS_PROCESSING EQU 0FFH ; Flag to indicate the K64F is processing a command.
|
||||
|
||||
|
||||
; Variables and control structure used by the I/O processor for service calls and requests.
|
||||
ORG TZSVCMEM
|
||||
|
||||
;TZSVCMEM: EQU 0ED80H ; Start of a memory structure used to communicate with the K64F I/O processor for services such as disk access.
|
||||
TZSVCSIZE: EQU 00280H ;
|
||||
TZSVCDIRSZ: EQU 20 ; Size of the directory/file name.
|
||||
TZSVCFILESZ: EQU 17 ; Size of a Sharp filename.
|
||||
TZSVCLONGFILESZ: EQU 31 ; Size of a standard filename.
|
||||
TZSVCLONGFMTSZ: EQU 20 ; Size of a formatted standard filename for use in directory listings.
|
||||
TZSVCWILDSZ: EQU 20 ; Size of the wildcard.
|
||||
TZSVCSECSIZE: EQU 512
|
||||
TZSVCDIR_ENTSZ: EQU 32 ; Size of a directory entry.
|
||||
TZSVCWAITIORETRIES: EQU 5 ; Wait retries for IO response.
|
||||
TZSVCWAITCOUNT: EQU 65535 ; Wait retries for IO request response.
|
||||
TZSVC_FTYPE_MZF: EQU 0 ; File type being handled is an MZF
|
||||
TZSVC_FTYPE_MZFHDR: EQU 1 ; File type being handled is an MZF Header.
|
||||
TZSVC_FTYPE_CAS: EQU 2 ; File type being handled is an CASsette BASIC script.
|
||||
TZSVC_FTYPE_BAS: EQU 3 ; File type being handled is an BASic script
|
||||
TZSVC_FTYPE_ALL: EQU 10 ; Handle any filetype.
|
||||
TZSVC_FTYPE_ALLFMT: EQU 11 ; Special case for directory listings, all files but truncated and formatted.
|
||||
TZSVCCMD: DS virtual 1 ; Service command.
|
||||
TZSVCRESULT: DS virtual 1 ; Service command result.
|
||||
TZSVCDIRSEC: DS virtual 1 ; Storage for the directory sector number.
|
||||
TZSVC_FILE_SEC: EQU TZSVCDIRSEC ; Union of the file and directory sector as only one can be used at a time.
|
||||
TZSVC_TRACK_NO: DS virtual 2 ; Storage for the virtual drive track number.
|
||||
TZSVC_SECTOR_NO: DS virtual 2 ; Storage for the virtual drive sector number.
|
||||
TZSVC_SECTOR_LBA: EQU TZSVC_TRACK_NO ; Sector in 32bit LBA format.
|
||||
TZSVC_MEM_TARGET: EQU TZSVC_TRACK_NO ; Memory command should target, 0 = tranZPUter, 1 = mainboard.
|
||||
TZSVC_FILE_NO: DS virtual 1 ; File number to be opened in a file service command.
|
||||
TZSVC_FILE_TYPE: DS virtual 1 ; Type of file being accessed to differentiate between Sharp MZF files and other handled files.
|
||||
TZSVC_LOADADDR: DS virtual 2 ; Dynamic load address for rom/images.
|
||||
TZSVC_SAVEADDR: EQU TZSVC_LOADADDR ; Union of the load address and the cpu frequency change value, the address of data to be saved.
|
||||
TZSVC_CPU_FREQ: EQU TZSVC_LOADADDR ; Union of the load address and the save address value, only one can be used at a time.
|
||||
TZSVC_LOADSIZE: DS virtual 2 ; Size of image to load.
|
||||
TZSVC_SAVESIZE: EQU TZSVC_LOADSIZE ; Size of image to be saved.
|
||||
TZSVC_DIRNAME: DS virtual TZSVCDIRSZ ; Service directory/file name.
|
||||
TZSVC_FILENAME: DS virtual TZSVCFILESZ ; Filename to be opened/created.
|
||||
TZSVCWILDC: DS virtual TZSVCWILDSZ ; Directory wildcard for file pattern matching.
|
||||
TZSVCSECTOR: DS virtual TZSVCSECSIZE ; Service command sector - to store directory entries, file sector read or writes.
|
||||
|
||||
498
software/asm/include/tzfs_utilities.asm
Normal file
498
software/asm/include/tzfs_utilities.asm
Normal file
@@ -0,0 +1,498 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: RFS_Utilities.asm
|
||||
;- Created: September 2019
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Sharp MZ series tzfs (tranZPUter Filing System).
|
||||
;- This assembly language program is a branch from the original RFS written for the
|
||||
;- MZ80A_RFS upgrade board. It is adapted to work within the similar yet different
|
||||
;- environment of the tranZPUter SW which has a large RAM capacity (512K) and an
|
||||
;- I/O processor in the K64F/ZPU.
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-20 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: May 2020 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
; Comparing Strings
|
||||
; IN HL Address of string1.
|
||||
; DE Address of string2.
|
||||
; BC Max bytes to compare, 0x00 or 0x0d will early terminate.
|
||||
; OUT zero Set if string1 = string2, reset if string1 != string2.
|
||||
; carry Set if string1 > string2, reset if string1 <= string2.
|
||||
CMPSTRING: IF USE_CMPSTRING = 1
|
||||
PUSH HL
|
||||
PUSH DE
|
||||
|
||||
CMPSTR1: LD A, (DE) ; Compare bytes.
|
||||
CP 000h ; Check for end of string.
|
||||
JR Z, CMPSTR3
|
||||
CP 00Dh
|
||||
JR Z, CMPSTR3
|
||||
CPI ; Compare bytes.
|
||||
JR NZ, CMPSTR2 ; If (HL) != (DE), abort.
|
||||
INC DE ; Update pointer.
|
||||
JP PE, CMPSTR1 ; Next byte if BC not zero.
|
||||
|
||||
CMPSTR2: DEC HL
|
||||
CP (HL) ; Compare again to affect carry.
|
||||
CMPSTR4: POP DE
|
||||
POP HL
|
||||
RET
|
||||
|
||||
CMPSTR3: LD A, (HL)
|
||||
CP 000h ; Check for end of string.
|
||||
JR Z, CMPSTR4
|
||||
CP 00Dh
|
||||
JR Z, CMPSTR4
|
||||
SCF ; String 1 greater than string 2
|
||||
JR CMPSTR4
|
||||
ENDIF
|
||||
|
||||
|
||||
; IN HL Address of source string, length-prefixed.
|
||||
; DE Address of destination string, length-prefixed.
|
||||
; B Start index. 1 = first character.
|
||||
; C Length of substring to return.
|
||||
;
|
||||
; OUT carry Set if an error condition happened:
|
||||
; If B is zero, then uses index of 1.
|
||||
; If index > source length, an empty string is returned.
|
||||
; If index + return length > source length, returns all
|
||||
; characters from index to end-of-string.
|
||||
|
||||
SUBSTRING: IF USE_SUBSTRING = 1
|
||||
PUSH DE ; It would be convenient to keep DE pointing to
|
||||
; the start of the destination string
|
||||
OR A ; Boolean OR resets carry
|
||||
PUSH AF ; Save carry
|
||||
LD A, B ; Is index beyond source length?
|
||||
CP (HL)
|
||||
DEC A ; Decrement A so NC can be used
|
||||
JR NC,SUBST3
|
||||
|
||||
ADD A, C ; If index+len is > 255, error
|
||||
JR C, SUBST1
|
||||
INC A ; Increment A so C can be used
|
||||
CP (HL) ; If index+len is beyond source length, then error
|
||||
JR C, SUBST2
|
||||
|
||||
SUBST1: POP AF ; Set carry flag
|
||||
SCF
|
||||
PUSH AF
|
||||
LD A, (HL) ; Get source length
|
||||
SUB B ; Subtract start index
|
||||
INC A ; Compensate
|
||||
LD C, A ; New size of string
|
||||
|
||||
SUBST2: LD A, C ; Size of sting to get
|
||||
LD (DE), A ; Save length index
|
||||
INC DE ; To body of string
|
||||
LD A, B ; Get index
|
||||
LD B, 0 ; Zero-extend BC for LDIR
|
||||
|
||||
ADD A, L ; This is a sneaky way to add A to HL
|
||||
LD L, A ; without using up another 16-bit register
|
||||
ADC A, H ;
|
||||
SUB L ;
|
||||
LD H, A ;
|
||||
|
||||
LDIR ; Copy substring over
|
||||
POP AF ; Restore flags
|
||||
POP DE ; Restore destination
|
||||
RET
|
||||
|
||||
SUBST3: XOR A ; Set a length index of zero
|
||||
LD (DE), A
|
||||
POP AF ; Clean off stack and set carry
|
||||
POP DE
|
||||
SCF
|
||||
RET
|
||||
ENDIF
|
||||
|
||||
; IN HL Address of string to look in, length prefixed.
|
||||
; DE Address of string to find, length prefixed.
|
||||
;
|
||||
; OUT
|
||||
; If found:
|
||||
; A Offset into look-up string where the target string was found.
|
||||
; The first byte (ignoring length prefix) is offset 1.
|
||||
; carry Reset.
|
||||
;
|
||||
; If not found:
|
||||
; A = 0
|
||||
; carry Set.
|
||||
|
||||
INDEX: IF USE_INDEX = 1
|
||||
LD A, (DE) ; Abort if string to find is too big
|
||||
CP (HL)
|
||||
INC A
|
||||
JR NC, IDXABORT
|
||||
|
||||
DEC A ; Save length of string to find
|
||||
LD IXL, A
|
||||
|
||||
LD B, 0 ; Put length of string to search in BC
|
||||
LD C, (HL)
|
||||
|
||||
INC HL ; Advance pointers
|
||||
INC DE
|
||||
PUSH HL ; Save start of search string
|
||||
|
||||
IDXRST: PUSH DE ; Save start of key string
|
||||
|
||||
LD A, IXL ; Initialize matched characters counter
|
||||
LD IXH, A
|
||||
|
||||
LD A, (DE) ; Get a character to match
|
||||
CPIR ; Look for it
|
||||
JR NZ, IDXNF ; Abort if not found
|
||||
|
||||
IDXLOOP: DEC IXH ; Update counter and see if done
|
||||
JR Z, IDXFOUND
|
||||
|
||||
INC DE ; Get next character in key string
|
||||
LD A, (DE)
|
||||
CPI ; See if it matches next char in master
|
||||
JR Z, IDXLOOP
|
||||
JP PO, IDXNF ; Abort if we ran out of characters
|
||||
|
||||
POP DE ; If a mismatch, restart from the beginning
|
||||
JR IDXRST
|
||||
|
||||
IDXNF: POP DE ; Clean stack
|
||||
POP HL
|
||||
|
||||
IDXABORT: XOR A ; Report failure
|
||||
SCF
|
||||
RET
|
||||
|
||||
IDXFOUND: POP DE
|
||||
POP BC ; BC = address of master
|
||||
|
||||
XOR A ; Put size of key string in DE
|
||||
LD D, A
|
||||
LD E, IXL
|
||||
|
||||
SBC HL, DE ; Find index
|
||||
SBC HL, BC
|
||||
LD A, L
|
||||
INC A
|
||||
RET
|
||||
ENDIF
|
||||
|
||||
; IN HL Address of string to be inserted
|
||||
; DE Address of string to receive insertion
|
||||
; C Index. Start of string is 0
|
||||
; OUT
|
||||
; If successful:
|
||||
; carry Reset
|
||||
; HL Input DE
|
||||
; If unsuccessful:
|
||||
; carry Set. If new string length is > 255.
|
||||
;
|
||||
; Notes If index > string length, string is appended.
|
||||
; Data after the string is destroyed.
|
||||
|
||||
STRINSERT: IF USE_STRINSERT = 1
|
||||
LD A, (DE)
|
||||
LD B, A
|
||||
|
||||
INC A
|
||||
CP C
|
||||
JR NC, STRINSERT1
|
||||
LD C, B
|
||||
|
||||
STRINSERT1:DEC A
|
||||
ADD A, (HL)
|
||||
RET C
|
||||
LD (DE), A ; Update length
|
||||
|
||||
PUSH DE ; Make room
|
||||
PUSH HL
|
||||
LD A, (HL)
|
||||
INC C
|
||||
|
||||
LD H, 0
|
||||
LD L, C
|
||||
ADD HL, DE
|
||||
|
||||
LD D, H
|
||||
LD E, L
|
||||
PUSH AF
|
||||
ADD A, E
|
||||
LD E, A
|
||||
ADC A, D
|
||||
SUB E
|
||||
LD D, A
|
||||
POP AF
|
||||
|
||||
LD B, 0
|
||||
LD C, A
|
||||
PUSH HL
|
||||
LDIR
|
||||
|
||||
POP DE ; Copy string over
|
||||
POP HL
|
||||
LD C, (HL)
|
||||
INC HL
|
||||
LDIR
|
||||
POP HL
|
||||
RET
|
||||
ENDIF
|
||||
|
||||
; IN HL Address of string.
|
||||
; B Index of first character to delete. First character is 0.
|
||||
; C Number of characters to kill.
|
||||
; OUT
|
||||
; If successful:
|
||||
; carry Reset
|
||||
; If unsuccessful:
|
||||
; carry Set
|
||||
;
|
||||
; Notes If B > string length, then error.
|
||||
; If B + C > string length, deletion
|
||||
; stops at end of string.
|
||||
|
||||
STRDELETE: IF USE_STRDELETE = 1
|
||||
LD A, B ; See if index is too big
|
||||
CP (HL)
|
||||
CCF ; Flip for error
|
||||
RET C
|
||||
|
||||
ADD A, C ; See if too many chars on chopping block
|
||||
CP (HL)
|
||||
JR C, STRDELETE1
|
||||
|
||||
INC B ; Set index as length
|
||||
LD (HL), B
|
||||
RET
|
||||
|
||||
STRDELETE1:PUSH HL
|
||||
LD A, (HL)
|
||||
SUB C
|
||||
LD (HL), A
|
||||
INC HL
|
||||
|
||||
LD E, C
|
||||
LD C, B
|
||||
LD B, 0
|
||||
ADD HL, BC
|
||||
|
||||
SUB C
|
||||
LD C, E
|
||||
LD D, H
|
||||
LD E, L
|
||||
ADD HL, BC
|
||||
LD C, A
|
||||
LDIR
|
||||
|
||||
POP HL
|
||||
RET
|
||||
ENDIF
|
||||
|
||||
; IN HL Address of first string.
|
||||
; DE Address of second string.
|
||||
; OUT
|
||||
; If successful:
|
||||
; carry Reset
|
||||
; If unsuccessful:
|
||||
; carry Set
|
||||
;
|
||||
; Notes If new string lenght is > 255, error.
|
||||
; HL is saved.
|
||||
|
||||
CONCAT: IF USE_CONCAT = 1
|
||||
LD A, (DE) ; Combine lengths
|
||||
ADD A, (HL)
|
||||
RET C
|
||||
LD C, (HL)
|
||||
LD (HL), A
|
||||
|
||||
LD B, 0
|
||||
INC C
|
||||
PUSH HL
|
||||
ADD HL, BC
|
||||
EX DE, HL
|
||||
LD C, (HL)
|
||||
INC HL
|
||||
LDIR
|
||||
|
||||
POP HL
|
||||
RET
|
||||
ENDIF
|
||||
|
||||
; Utility: Convert character to upper case
|
||||
; On entry: A = Character in either case
|
||||
; On exit: A = Character in upper case
|
||||
; BC DE HL IX IY I AF' BC' DE' HL' preserved
|
||||
ConvertCharToUCase: IF USE_CNVUPPER = 1
|
||||
CP 'a' ;Character less than 'a'?
|
||||
RET C ;Yes, so finished
|
||||
CP 'z'+1 ;Character greater than 'z'?
|
||||
RET NC ;Yes, so finished
|
||||
SUB 'a'-'A' ;Convert case
|
||||
RET
|
||||
ENDIF
|
||||
;
|
||||
; Utility: Convert character to numberic value
|
||||
; On entry: A = ASCII character (0-9 or A-F)
|
||||
; On exit: If character is a valid hex digit:
|
||||
; A = Numberic value (0 to 15) and Z flagged
|
||||
; If character is not a valid hex digit:
|
||||
; A = 0xFF and NZ flagged
|
||||
; BC DE HL IX IY I AF' BC' DE' HL' preserved
|
||||
; Interrupts not enabled
|
||||
ConvertCharToNumber: IF USE_CNVCHRTONUM = 1
|
||||
CALL ConvertCharToUCase
|
||||
CP '0' ;Character < '0'?
|
||||
JR C,@Bad ;Yes, so no hex character
|
||||
CP '9'+1 ;Character <= '9'?
|
||||
JR C,@OK ;Yes, got hex character
|
||||
CP 'A' ;Character < 'A'
|
||||
JR C,@Bad ;Yes, so not hex character
|
||||
CP 'F'+1 ;Character <= 'F'
|
||||
JR C,@OK ;No, not hex
|
||||
; Character is not a hex digit so return
|
||||
@Bad: LD A,0FFh ;Return status: not hex character
|
||||
OR A ; A = 0xFF and NZ flagged
|
||||
RET
|
||||
; Character is a hex digit so adjust from ASCII to number
|
||||
@OK: SUB '0' ;Subtract '0'
|
||||
CP 00Ah ;Number < 10 ?
|
||||
JR C,@Finished ;Yes, so finished
|
||||
SUB 007h ;Adjust for 'A' to 'F'
|
||||
@Finished: CP A ;Return A = number (0 to 15) and Z flagged to
|
||||
RET ; indicate character is a valid hex digital
|
||||
ENDIF
|
||||
|
||||
; Utility: Is character numeric?
|
||||
; On entry: A = ASCII character
|
||||
; On exit: Carry flag set if character is numeric (0 to 9)
|
||||
; A BC DE HL IX IY I AF' BC' DE' HL' preserved
|
||||
IsCharNumeric: IF USE_ISNUMERIC = 1
|
||||
CP '0' ;Less than '0'?
|
||||
JR C,@Not2 ;Yes, so go return NOT numeric
|
||||
CP '9'+1 ;Less than or equal to '9'?
|
||||
RET C ;Yes, so numeric (C flagged)
|
||||
@Not2: OR A ;No, so NOT numeric (NC flagged)
|
||||
RET
|
||||
ENDIF
|
||||
|
||||
; Utility: Convert hexadecimal or decimal text to number
|
||||
; On entry: DE = Pointer to start of ASCII string
|
||||
; On exit: If valid number found:
|
||||
; A = 0 and Z flagged
|
||||
; HL = Number found
|
||||
; If valid number not found:
|
||||
; A != 0 and NZ flagged
|
||||
; HL = Not specified
|
||||
; DE = Not specified
|
||||
; HL = Number
|
||||
; BC DE IX IY I AF' BC' DE' HL' preserved
|
||||
; Hexadecmal numbers can be prefixed with either "$" or "0x"
|
||||
; Decimal numbers must be prefixed with "+"
|
||||
; A number without a prefix is assumed to be hexadecimal
|
||||
; Hexadecimal number without a prefix must start with "0" to "9"
|
||||
; ... this is to stop the assembler getting confused between
|
||||
; ... register names and constants which could be fixed by
|
||||
; ... re-ordering the (dis)assebmer's instruction table
|
||||
; Numbers can be terminated with ")", space, null or control code
|
||||
; Negative numbers, preceded with "-", are not supported
|
||||
; Text must be terminated with ')', space or control char.
|
||||
ConvertStringToNumber: IF USE_CNVSTRTONUM = 1
|
||||
PUSH BC
|
||||
LD HL,0 ;Build result here
|
||||
LD A,(DE) ;Get character from string
|
||||
CP '+' ;Does string start with '+' ?
|
||||
JR Z,@Decimal ;Yes, so its decimal
|
||||
CP '$' ;Does string start with '$' ?
|
||||
JR Z,@Hdecimal ;Yes, so its hexadecimal
|
||||
CP 39 ;Does string start with apostrophe?
|
||||
JR Z,@Char ;Yes, so its a character
|
||||
CP '"' ;Does string start with '"' ?
|
||||
JR Z,@Char ;Yes, so its a character
|
||||
; CALL IsCharNumeric ;Is first character '0' to '9' ?
|
||||
; JR NC,@Failure ;No, so invalid number
|
||||
; CALL IsCharHex ;Is first character hexadecimal ?
|
||||
; JR NC,@Failure ;No, so invalid hex character
|
||||
CP '0' ;Is first character '0' ?
|
||||
; JR NZ,@HexNext ;No, so default to hexadecimal
|
||||
JR NZ,@DecNext ;No, so default to decimal
|
||||
INC DE ;Point to next character in string
|
||||
LD A,(DE) ;Get character from string
|
||||
CALL ConvertCharToUCase
|
||||
CP 'X' ;Is second character 'x' ?
|
||||
JR NZ,@HexNext ;No, so must be default format
|
||||
; JR NZ,@DecNext ;No, so must be default format
|
||||
; Hexadecimal number...
|
||||
@Hdecimal: INC DE ;Point to next character in string
|
||||
@HexNext: LD A,(DE) ;Get character from string
|
||||
CP ')' ;Terminated with a bracket?
|
||||
JR Z,@Success ;yes, so success
|
||||
CP 32+1 ;Space or control character?
|
||||
JR C,@Success ;Yes, so successld hl
|
||||
CALL ConvertCharToNumber ;Convert character to number
|
||||
JR NZ,@Failure ;Return if failure (NZ flagged)
|
||||
INC DE ;Point to next character in string
|
||||
ADD HL,HL ;Current result = 16 * current result..
|
||||
ADD HL,HL
|
||||
ADD HL,HL
|
||||
ADD HL,HL
|
||||
OR L ;Add new number (0 to 15)..
|
||||
LD L,A
|
||||
JR @HexNext
|
||||
; Decimal number...
|
||||
@Decimal: INC DE ;Point to next character in string
|
||||
@DecNext: LD A,(DE) ;Get character from string
|
||||
CP ')' ;Terminated with a bracket?
|
||||
JR Z,@Success ;yes, so success
|
||||
CP 32+1 ;Space or control character?
|
||||
JR C,@Success ;Yes, so success
|
||||
CALL IsCharNumeric ;Is first character '0' to '9' ?
|
||||
JR NC,@Failure ;No, so invalid number
|
||||
CALL ConvertCharToNumber ;Convert character to number
|
||||
JR NZ,@Failure ;Return if failure (NZ flagged)
|
||||
INC DE ;Point to next character in string
|
||||
PUSH DE
|
||||
LD B,9 ;Current result = 10 * current result..
|
||||
LD D,H
|
||||
LD E,L
|
||||
@DecLoop: ADD HL,DE ;Add result to itself 9 times
|
||||
DJNZ @DecLoop
|
||||
POP DE
|
||||
ADD A,L ;Add new number (0 to 15)..
|
||||
LD L,A
|
||||
JR NC,@DecNext
|
||||
INC H
|
||||
JR @DecNext
|
||||
; Character...
|
||||
@Char: INC DE ;Point to next character in string
|
||||
LD A,(DE) ;Get ASCII character
|
||||
LD L,A ;Store ASCII value as result
|
||||
LD H,0
|
||||
; JR @Success
|
||||
; Return result...
|
||||
@Success: POP BC
|
||||
XOR A ;Return success with A = 0 and Z flagged
|
||||
RET
|
||||
@Failure: POP BC
|
||||
LD A,0FFh ;Return failure with A != 0
|
||||
OR A ; and NZ flagged
|
||||
RET
|
||||
ENDIF
|
||||
77
software/asm/include/tzfs_variables.asm
Normal file
77
software/asm/include/tzfs_variables.asm
Normal file
@@ -0,0 +1,77 @@
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;-
|
||||
;- Name: tzfs_variales.asm
|
||||
;- Created: September 2019
|
||||
;- Author(s): Philip Smart
|
||||
;- Description: Sharp MZ series tzfs (tranZPUter Filing System).
|
||||
;- This assembly language program is a branch from the original RFS written for the
|
||||
;- MZ80A_RFS upgrade board. It is adapted to work within the similar yet different
|
||||
;- environment of the tranZPUter SW which has a large RAM capacity (512K) and an
|
||||
;- I/O processor in the K64F/ZPU.
|
||||
;-
|
||||
;- This file holds the TZFS variable definitions.
|
||||
;-
|
||||
;- Credits:
|
||||
;- Copyright: (c) 2019-21 Philip Smart <philip.smart@net2net.org>
|
||||
;-
|
||||
;- History: May 2020 - Branch taken from RFS v2.0 and adapted for the tranZPUter SW.
|
||||
;- July 2020 - Updates to accommodate v2.1 of the tranZPUter board.
|
||||
;-
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
;- 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/>.
|
||||
;--------------------------------------------------------------------------------------------------------
|
||||
|
||||
; Starting EC80H - variables used by the filing system.
|
||||
ORG TZVARMEM
|
||||
|
||||
;TZVARMEM: EQU 0EC80H
|
||||
;TZVARSIZE: EQU 00100H
|
||||
WARMSTART: DS virtual 1 ; Warm start mode, 0 = cold start, 1 = warm start.
|
||||
SCRNMODE: DS virtual 1 ; Mode of screen, [0] = 0 - 40 char, 1 - 80 char, [1] = 0 - Mainboard video, 1 - FPGA Video, [2] = 1 set VGA mode, 0 = standard, [7:4] Video mode.
|
||||
SCRNMODE2: DS virtual 1 ; Mode of screen, [3:0] - VGA mode.
|
||||
MMCFGVAL: DS virtual 1 ; Current memory model value.
|
||||
HLSAVE: DS virtual 2 ; Storage for HL during bank switch manipulation.
|
||||
AFSAVE: DS virtual 2 ; Storage for AF during bank switch manipulation.
|
||||
FNADDR: DS virtual 2 ; Function to be called address.
|
||||
TMPADR: DS virtual 2 ; TEMPORARY ADDRESS STORAGE
|
||||
TMPSIZE: DS virtual 2 ; TEMPORARY SIZE
|
||||
TMPCNT: DS virtual 2 ; TEMPORARY COUNTER
|
||||
TMPLINECNT: DS virtual 2 ; Temporary counter for displayed lines.
|
||||
TMPSTACKP: DS virtual 2 ; Temporary stack pointer save.
|
||||
DUMPADDR: DS virtual 2 ; Address used by the D(ump) command so that calls without parameters go onto the next block.
|
||||
CMTLOLOAD: DS virtual 1 ; Flag to indicate that a tape program is loaded into hi memory then shifted to low memory after ROM pageout.
|
||||
CMTCOPY: DS virtual 1 ; Flag to indicate that a CMT copy operation is taking place.
|
||||
CMTAUTOEXEC: DS virtual 1 ; Auto execution flag, run CMT program when loaded if flag clear.
|
||||
DTADRSTORE: DS virtual 2 ; Backup for load address if actual load shifts to lo memory or to 0x1200 for copy.
|
||||
SDCOPY: DS virtual 1 ; Flag to indicate an SD copy is taking place, either CMT->SD or SD->CMT.
|
||||
RESULT: DS virtual 1 ; Result variable needed for interbank calls when a result is needed.
|
||||
SDAUTOEXEC: DS virtual 1 ; Flag to indicate if a loaded file should be automatically executed.
|
||||
FDCCMD: DS virtual 1 ; Floppy disk command storage.
|
||||
MOTON: DS virtual 1 ; Motor on flag.
|
||||
TRK0FD1: DS virtual 1 ; Floppy Disk 1 track 0 indicator.
|
||||
TRK0FD2: DS virtual 1 ; Floppy Disk 2 track 0 indicator.
|
||||
TRK0FD3: DS virtual 1 ; Floppy Disk 3 track 0 indicator.
|
||||
TRK0FD4: DS virtual 1 ; Floppy Disk 4 track 0 indicator.
|
||||
RETRIES: DS virtual 1 ; Retries count for a command.
|
||||
BPARA: DS virtual 1
|
||||
CMTINACTIVE: DS virtual 1 ; Flag to indicate if the CMT is inactive (1)/SD active (0) for the CMT wrapper handlers.
|
||||
CMTFILENO: DS virtual 1 ; Sequential file access file number. Used when no filename is given, uses the directory entry number for the set wildcard,
|
||||
HWMODEL: DS virtual 1 ; Model of machine to tailor code execution
|
||||
CMTSAMPLECNT: DS virtual 1 ; Delay count for bit sampling.
|
||||
CMTDLY1CNTM: DS virtual 1 ; Short pulse delay count MARK
|
||||
CMTDLY1CNTS: DS virtual 1 ; Short pulse delay count SPACE
|
||||
CMTDLY2CNTM: DS virtual 1 ; Long pulse delay count MARK
|
||||
CMTDLY2CNTS: DS virtual 1 ; Long pulse delay count SPACE
|
||||
DS virtual (TZVARMEM + TZVARSIZE) - $ ; Top of variable area downwards is used as the working stack, SA1510 space isnt used.
|
||||
TZSTACK: EQU TZVARMEM + TZVARSIZE
|
||||
8
software/asm/monitor_1z-013a-2000.asm
Normal file
8
software/asm/monitor_1z-013a-2000.asm
Normal file
@@ -0,0 +1,8 @@
|
||||
; Configurable parameters.
|
||||
COLW: EQU 40 ; Width of the display screen (ie. columns).
|
||||
ROW: EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ: EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
MODE80C:EQU 0 ; Monitor is being built for an 80 column display.
|
||||
MODE2K: EQU 1 ; Monitor is being built for an MZ-2000 machine.
|
||||
|
||||
INCLUDE "1z-013a.asm"
|
||||
8
software/asm/monitor_1z-013a-km.asm
Normal file
8
software/asm/monitor_1z-013a-km.asm
Normal file
@@ -0,0 +1,8 @@
|
||||
; Configurable parameters.
|
||||
COLW: EQU 40 ; Width of the display screen (ie. columns).
|
||||
ROW: EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ: EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
MODE80C:EQU 0 ; Monitor is being built for an 80 column display.
|
||||
MODE2K: EQU 0 ; Monitor is being built for an MZ-2000 machine.
|
||||
|
||||
INCLUDE "1z-013a-km.asm"
|
||||
8
software/asm/monitor_1z-013a.asm
Normal file
8
software/asm/monitor_1z-013a.asm
Normal file
@@ -0,0 +1,8 @@
|
||||
; Configurable parameters.
|
||||
COLW: EQU 40 ; Width of the display screen (ie. columns).
|
||||
ROW: EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ: EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
MODE80C:EQU 0 ; Monitor is being built for an 80 column display.
|
||||
MODE2K: EQU 0 ; Monitor is being built for an MZ-2000 machine.
|
||||
|
||||
INCLUDE "1z-013a.asm"
|
||||
8
software/asm/monitor_80c_1z-013a-km.asm
Normal file
8
software/asm/monitor_80c_1z-013a-km.asm
Normal file
@@ -0,0 +1,8 @@
|
||||
; Configurable parameters.
|
||||
COLW: EQU 80 ; Width of the display screen (ie. columns).
|
||||
ROW: EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ: EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
MODE80C:EQU 1 ; Monitor is being built for an 80 column display.
|
||||
MODE2K: EQU 0 ; Monitor is being built for an MZ-2000 machine.
|
||||
|
||||
INCLUDE "1z-013a-km.asm"
|
||||
8
software/asm/monitor_80c_1z-013a.asm
Normal file
8
software/asm/monitor_80c_1z-013a.asm
Normal file
@@ -0,0 +1,8 @@
|
||||
; Configurable parameters.
|
||||
COLW: EQU 80 ; Width of the display screen (ie. columns).
|
||||
ROW: EQU 25 ; Number of rows on display screen.
|
||||
SCRNSZ: EQU COLW * ROW ; Total size, in bytes, of the screen display area.
|
||||
MODE80C:EQU 1 ; Monitor is being built for an 80 column display.
|
||||
MODE2K: EQU 0 ; Monitor is being built for an MZ-2000 machine.
|
||||
|
||||
INCLUDE "1z-013a.asm"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user