Adding MZ-1500 host

This commit is contained in:
Philip Smart
2023-05-24 09:12:39 +01:00
parent 462052140e
commit 5fa8d1fada
17 changed files with 1964 additions and 563 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,6 @@
# Select the target host.
#MODEL := MZ2000
#MODEL := MZ1500
#MODEL := MZ700
#MODEL := MZ80A
#MODEL := PCW8XXX
@@ -26,6 +27,7 @@ all:
MZ80A: MODEL_MZ80A
MZ700: MODEL_MZ700
MZ1500: MODEL_MZ1500
MZ2000: MODEL_MZ2000
PCW8XXX: MODEL_PCW8XXX
PCW9XXX: MODEL_PCW9XXX
@@ -34,6 +36,8 @@ 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:
@@ -43,6 +47,7 @@ MODEL_PCW9XXX:
BUILD_MZ80A: kmod
BUILD_MZ700: kmod
BUILD_MZ1500: kmod
BUILD_MZ2000: kmod
BUILD_PCW8XXX: kmod
BUILD_PCW9XXX: kmod

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,8 @@
// 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.
//
// Notes: See Makefile to enable/disable conditional components
//
@@ -37,36 +39,47 @@
#endif
// Build time target. Overrides if compile time definition given.
#if defined(TARGET_HOST_MZ700)
#define TARGET_HOST_MZ700 1
#define TARGET_HOST_MZ2000 0
#define TARGET_HOST_MZ80A 0
#define TARGET_HOST_PCW 0
#elif defined(TARGET_HOST_MZ2000)
#define TARGET_HOST_MZ2000 1
#define TARGET_HOST_MZ700 0
#define TARGET_HOST_MZ80A 0
#define TARGET_HOST_PCW 0
#elif defined(TARGET_HOST_MZ80A)
#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_MZ2000 0
#define TARGET_HOST_MZ700 0
#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_MZ2000 0 // MZ2000
#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)
#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.
@@ -79,12 +92,12 @@
#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)
#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 0xEF // Block cursor for CAPS 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 0x3E // Underline for lower case CAPS OFF.
#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.
@@ -96,6 +109,7 @@
// 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.
@@ -165,6 +179,20 @@
#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
@@ -332,7 +360,7 @@
display.hwVideoMode = (display.hwVideoMode & 0x3F);\
WRITE_HARDWARE_IO(0, MBADDR_PIOA, display.hwVideoMode);\
}
#define WRITE_VRAM_CHAR(__addr__,__data__) WRITE_HARDWARE(0,__addr__,__data__)
#define WRITE_VRAM_CHAR(__addr__,__data__,__xlat__) WRITE_HARDWARE(0,__addr__,__data__)
#define WRITE_VRAM_ATTRIBUTE(__addr__,__data__) {}
#define WRITE_KEYB_STROBE(__data__)\
{\
@@ -344,9 +372,9 @@
#else
#define ENABLE_VIDEO() {}
#define DISABLE_VIDEO() {}
#define WRITE_VRAM_CHAR(__addr__,__data__) WRITE_HARDWARE(0,__addr__,dispCodeMap[__data__].dispCode)
#define WRITE_VRAM_ATTRIBUTE(__addr__,__data__) WRITE_HARDWARE(0,__addr__,__data__)
#define WRITE_KEYB_STROBE(__data__) WRITE_HARDWARE(0, MBADDR_KEYPA, __data__)
#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

View File

@@ -1,4 +1,5 @@
#MODEL := MZ2000
#MODEL := MZ1500
#MODEL := MZ700
#MODEL := MZ80A
#MODEL := PCW8XXX
@@ -23,6 +24,7 @@ all:
MZ80A: MODEL_MZ80A
MZ700: MODEL_MZ700
MZ1500: MODEL_MZ1500
MZ2000: MODEL_MZ2000
PCW8XXX: MODEL_PCW8XXX
PCW9XXX: MODEL_PCW9XXX
@@ -31,6 +33,8 @@ 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:
@@ -40,6 +44,7 @@ MODEL_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

View File

@@ -20,6 +20,7 @@
// out all low level control methods.
// v1.01 - Updates to make compatible with the TZFS changes.
// Apr v1.02 - Updates to add MZ-2000 servicing.
// May v1.03 - Updates to add MZ-1500 servicing.
//
// Notes: See Makefile to enable/disable conditional components
//
@@ -2329,6 +2330,13 @@ void loadTranZPUterDefaultROMS(uint8_t cpuConfig)
}
break;
case HW_MZ1500:
#if(DEBUG_ENABLED & 0x2)
if(Z80Ctrl->debug >= 2) printf("Loading 1Z_009B\n");
#endif
result = loadTZFS(MZ_ROM_1Z_009B_40C, MZ_MROM_ADDR);
break;
case HW_MZ80B:
//result = loadBIOS(MZ_ROM_MZ80B_IPL, MZ80B, MZ_MROM_ADDR);
result = loadBIOS(MZ_ROM_MZ80B_IPL, MZ_MROM_ADDR);
@@ -2946,6 +2954,8 @@ int main(int argc, char *argv[])
z80Control.hostType = HW_MZ80A;
#elif (TARGET_HOST_MZ700 == 1)
z80Control.hostType = HW_MZ700;
#elif (TARGET_HOST_MZ1500 == 1)
z80Control.hostType = HW_MZ1500;
#elif (TARGET_HOST_MZ2000 == 1)
z80Control.hostType = HW_MZ2000;
#else

View File

@@ -21,6 +21,7 @@
//
// 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
//
@@ -338,12 +339,15 @@ int main(int argc, char *argv[])
#if(TARGET_HOST_MZ80A == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ2000 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ700 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#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);
@@ -356,10 +360,12 @@ int main(int argc, char *argv[])
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
#if(TARGET_HOST_MZ80A == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
#elif(TARGET_HOST_MZ2000 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
#elif(TARGET_HOST_MZ700 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
#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);
@@ -382,12 +388,15 @@ int main(int argc, char *argv[])
#if(TARGET_HOST_MZ80A == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ2000 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ700 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#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);
@@ -419,12 +428,15 @@ int main(int argc, char *argv[])
#if(TARGET_HOST_MZ80A == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ2000 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ700 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#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);
@@ -450,12 +462,15 @@ int main(int argc, char *argv[])
#if(TARGET_HOST_MZ80A == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ2000 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#elif(TARGET_HOST_MZ700 == 1)
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
#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);

View File

@@ -50,6 +50,8 @@
#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
@@ -203,7 +205,7 @@
// CPLD Configuration constants.
#define HWMODE_MZ80K 0x00 // Hardware mode = MZ80K
#define HWMODE_MZ80C 0x01 // Hardware mode = MZ80C
#define HWMODE_MZ1200 0x02 // Hardware mode = MZ1200
#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
@@ -421,6 +423,7 @@
#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.
@@ -481,7 +484,7 @@ enum TARGETS {
enum MACHINE_HW_TYPES {
HW_MZ80K = HWMODE_MZ80K, // Host hardware = MZ-80K.
HW_MZ80C = HWMODE_MZ80C, // Host hardware = MZ-80C.
HW_MZ1200 = HWMODE_MZ1200, // Host hardware = MZ-1200.
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.

View File

@@ -17,6 +17,7 @@
//
// 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
//
@@ -54,7 +55,7 @@
#include <Z80.h>
#include "z80driver.h"
#define VERSION "1.1"
#define VERSION "1.2"
#define AUTHOR "P.D.Smart"
#define COPYRIGHT "(c) 2018-23"
@@ -436,7 +437,7 @@ int z80load(int fdZ80, char *fileName, uint32_t memLoadAddr, long fileOffset, lo
}
else
{
#if(TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ80A)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
if(mzfHeader.loadAddr > 0x1000)
{
#endif
@@ -446,7 +447,7 @@ int z80load(int fdZ80, char *fileName, uint32_t memLoadAddr, long fileOffset, lo
// 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_MZ700 == 1 || TARGET_HOST_MZ80A)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
}
#endif
@@ -459,7 +460,7 @@ int z80load(int fdZ80, char *fileName, uint32_t memLoadAddr, long fileOffset, lo
// Set PC to 2 (NST) which switches to RUN mode and executes at 0000H
ioctlCmd.z80.pc = 2;
#endif
#if(TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ80A)
#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
@@ -601,6 +602,10 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
{
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;
@@ -638,6 +643,10 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
{
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;

View File

@@ -39,6 +39,7 @@
// if same as the target machine. This then allows the z80 driver to be
// a vanilla Z80 or customisations for hosts pulled in.
// Apr 2023 - v1.4.1 Completed MZ2000 mode to work with arbiter and ttymz.
// May 2023 - v1.5 Added MZ1500 modes.
//
//
// Notes: See Makefile to enable/disable conditional components
@@ -118,12 +119,15 @@ static DEFINE_MUTEX(Z80DRV_MUTEX);
#if(TARGET_HOST_MZ80A == 1)
#include "z80vhw_mz80a.c"
#endif
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
#include "z80vhw_rfs.c"
#endif
#if(TARGET_HOST_MZ700 == 1)
#include "z80vhw_mz700.c"
#endif
#if(TARGET_HOST_MZ1500 == 1)
#include "z80vhw_mz1500.c"
#endif
#if(TARGET_HOST_MZ2000 == 1)
#include "z80vhw_mz2000.c"
#endif
@@ -162,13 +166,19 @@ static inline void decodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t io
mz700DecodeMemoryMapSetup(address, data, ioFlag, readFlag);
} else
#endif
#if(TARGET_HOST_MZ1500 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ1500)
{
mz1500DecodeMemoryMapSetup(address, data, ioFlag, readFlag);
} else
#endif
#if(TARGET_HOST_MZ2000 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ2000)
{
mz2000DecodeMemoryMapSetup(address, data, ioFlag, readFlag);
} else
#endif
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_RFS)
{
rfsDecodeMemoryMapSetup(address, data, ioFlag, readFlag);
@@ -214,6 +224,12 @@ static inline zuint8 readVirtual(zuint16 address, uint8_t ioFlag)
data = mz700Read(address, ioFlag);
} else
#endif
#if(TARGET_HOST_MZ1500 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ1500)
{
data = mz1500Read(address, ioFlag);
} else
#endif
#if(TARGET_HOST_MZ2000 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ2000)
{
@@ -227,7 +243,7 @@ static inline zuint8 readVirtual(zuint16 address, uint8_t ioFlag)
} else
#endif
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
// RFS only has memory mapped registers.
if((Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_RFS) && ioFlag == 0)
{
@@ -268,6 +284,12 @@ static inline void writeVirtual(zuint16 address, zuint8 data, uint8_t ioFlag)
mz700Write(address, data, ioFlag);
} else
#endif
#if(TARGET_HOST_MZ1500 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ1500)
{
mz1500Write(address, data, ioFlag);
} else
#endif
#if(TARGET_HOST_MZ2000 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ2000)
{
@@ -281,7 +303,7 @@ static inline void writeVirtual(zuint16 address, zuint8 data, uint8_t ioFlag)
} else
#endif
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
// RFS only has memory mapped registers.
if((Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_RFS) && ioFlag == 0)
{
@@ -458,6 +480,10 @@ static zuint8 z80_read(void *context, zuint16 address)
// Only read if the address is in physical RAM.
#if(TARGET_HOST_PCW == 0)
if(isPhysical(address))
#elif(TARGET_HOST_MZ1500 == 1)
// MZ-1500 take into account PCG being active, always go to hardware when active. Cannot use the map because
// this can change during PCG active mode and must be reflected when PCG is deactivated.
if(isPhysicalHW(address) || (Z80Ctrl->pcgMode == 1 && address >= 0xD000))
#else
if(isPhysicalHW(address))
#endif
@@ -527,6 +553,26 @@ static zuint8 z80_read(void *context, zuint16 address)
Z80Ctrl->keyportTrigger = 0;
}
}
#elif (TARGET_HOST_MZ1500 == 1)
// Keyport data? Store.
if(isHW(address) && address == 0xE001 && (Z80Ctrl->keyportStrobe & 0x0f) == 8)
{
Z80Ctrl->keyportShiftCtrl = (data & 0x40) == 0 ? 0x01 : 0x00;
} else
if(isHW(address) && address == 0xE001 && Z80Ctrl->keyportShiftCtrl == 1)
{
if((Z80Ctrl->keyportStrobe & 0x0f) == 5 && (data & 0xF0) != 0xF0)
{
Z80Ctrl->keyportHotKey = (data & 0x80) == 0 ? HOTKEY_ORIGINAL :
(data & 0x40) == 0 ? HOTKEY_RFS40 :
(data & 0x20) == 0 ? HOTKEY_TZFS :
(data & 0x10) == 0 ? HOTKEY_LINUX : 0x00;
Z80Ctrl->keyportTrigger = Z80Ctrl->keyportHotKey;
} else
{
Z80Ctrl->keyportTrigger = 0;
}
}
#elif (TARGET_HOST_MZ2000 == 1)
#endif
@@ -548,7 +594,7 @@ static void z80_write(void *context, zuint16 address, zuint8 data)
// Locals.
Z_UNUSED(context)
#if (TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if (TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
// To detect Hotkey presses, we need to store the keyboard strobe data and on keydata read.
if(isHW(address) && address == 0xE000)
{
@@ -563,8 +609,15 @@ static void z80_write(void *context, zuint16 address, zuint8 data)
if(isPhysicalRAM(address))
writeVirtualRAM(address, data);
Z80Ctrl->ioReadAhead = 0;
}
else if(isPhysical(address))
} else
#if(TARGET_HOST_MZ1500 == 1)
// MZ-1500 take into account PCG being active, always go to hardware when active. Cannot use the map because
// this can change during PCG active mode and must be reflected when PCG is deactivated.
if(isPhysical(address) || (Z80Ctrl->pcgMode == 1 && address >= 0xD000))
#else
if(isPhysical(address))
#endif
{
// Commence cycle to write the data to real RAM.
SPI_SEND_32(address, data << 8 | CPLD_CMD_WRITE_ADDR);
@@ -1057,7 +1110,7 @@ int thread_z80(void * thread_nr)
if(Z80RunMode == Z80_RUNNING) canRun=1; else canRun=0;
mutex_unlock(&Z80RunModeMutex);
#if (TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ2000 == 1)
#if (TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1 || TARGET_HOST_MZ2000 == 1)
// Hotkey pressed? Bring up user menu.
if(Z80Ctrl->keyportTrigger != 0x00 && Z80Ctrl->keyportTriggerLast == 0)
{
@@ -1411,13 +1464,18 @@ void setupMemory(enum Z80_MEMORY_PROFILE mode)
mz700SetupMemory(mode);
else
#endif
#if(TARGET_HOST_MZ1500 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ1500)
mz1500SetupMemory(mode);
else
#endif
#if(TARGET_HOST_MZ2000 == 1)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_MZ2000)
mz2000SetupMemory(mode);
else
#endif
// RFS board only works in an MZ-80A at present.
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
// RFS board only works on an MZ-80A/MZ-700/MZ-1500 at present.
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500)
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_RFS)
rfsSetupMemory(mode);
else
@@ -1442,6 +1500,11 @@ void setupMemory(enum Z80_MEMORY_PROFILE mode)
// Inhibit mode disabled.
Z80Ctrl->inhibitMode = 0;
#if defined(TARGET_HOST_MZ1500)
// Flag to indicate PCG active, all memory accesses from D000:FFFF are sent to hardware.
Z80Ctrl->pcgMode = 0;
#endif
return;
}
@@ -1675,10 +1738,10 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
if(idx < Z80Ctrl->virtualDeviceCnt)
break;
#if(TARGET_HOST_MZ80A == 0 && TARGET_HOST_MZ700 == 0)
#if(TARGET_HOST_MZ80A == 0 && TARGET_HOST_MZ700 == 0 && TARGET_HOST_MZ1500 == 0)
if(ioctlCmd.vdev.device & VIRTUAL_DEVICE_RFS)
{
pr_info("RFS Board currently supported on MZ-80A/MZ-700 Hosts only.\n");
pr_info("RFS Board currently supported on MZ-80A/MZ-700/MZ-1500 Hosts only.\n");
break;
}
#endif
@@ -1700,7 +1763,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
#endif
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
case VIRTUAL_DEVICE_RFS40:
case VIRTUAL_DEVICE_RFS80:
Z80Ctrl->virtualDevice[Z80Ctrl->virtualDeviceCnt++] = ioctlCmd.vdev.device;
@@ -1717,6 +1780,14 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
#endif
#if(TARGET_HOST_MZ1500 == 1)
case VIRTUAL_DEVICE_MZ1500:
Z80Ctrl->virtualDevice[Z80Ctrl->virtualDeviceCnt++] = ioctlCmd.vdev.device;
Z80Ctrl->virtualDeviceBitMap |= ioctlCmd.vdev.device;
mz1500Init(0);
break;
#endif
#if(TARGET_HOST_MZ2000 == 1)
case VIRTUAL_DEVICE_MZ2000:
Z80Ctrl->virtualDevice[Z80Ctrl->virtualDeviceCnt++] = ioctlCmd.vdev.device;
@@ -1791,7 +1862,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
#endif
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if(TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1)
case VIRTUAL_DEVICE_RFS40:
case VIRTUAL_DEVICE_RFS80:
Z80Ctrl->virtualDeviceBitMap &= ~ioctlCmd.vdev.device;
@@ -1806,6 +1877,13 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
#endif
#if(TARGET_HOST_MZ1500 == 1)
case VIRTUAL_DEVICE_MZ1500:
Z80Ctrl->virtualDeviceBitMap &= ~ioctlCmd.vdev.device;
mz1500Remove();
break;
#endif
#if(TARGET_HOST_MZ2000 == 1)
case VIRTUAL_DEVICE_MZ2000:
Z80Ctrl->virtualDeviceBitMap &= ~ioctlCmd.vdev.device;
@@ -2067,7 +2145,7 @@ static int __init ModuleInit(void)
Z80Ctrl->ioReadAhead = 0;
Z80Ctrl->ioWriteAhead = 0;
#if (TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1)
#if (TARGET_HOST_MZ80A == 1 || TARGET_HOST_MZ700 == 1 || TARGET_HOST_MZ1500 == 1 || TARGET_HOST_MZ2000 == 1)
// Initialse hotkey detection variables.
Z80Ctrl->keyportStrobe = 0x00;
Z80Ctrl->keyportShiftCtrl = 0x00;

View File

@@ -16,6 +16,7 @@
// 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.
//
// Notes: See Makefile to enable/disable conditional components
//
@@ -40,26 +41,37 @@
#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
@@ -68,8 +80,8 @@
#define DRIVER_LICENSE "GPL"
#define DRIVER_AUTHOR "Philip D Smart"
#define DRIVER_DESCRIPTION "Z80 CPU Emulator and Hardware Interface Driver"
#define DRIVER_VERSION "v1.4.1"
#define DRIVER_VERSION_DATE "Apr 2023"
#define DRIVER_VERSION "v1.5"
#define DRIVER_VERSION_DATE "May 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.
@@ -173,6 +185,82 @@
#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,
@@ -612,8 +700,9 @@ enum VIRTUAL_DEVICE {
VIRTUAL_DEVICE_NONE = 0x00000000,
VIRTUAL_DEVICE_MZ80A = 0x00000001,
VIRTUAL_DEVICE_MZ700 = 0x00000002,
VIRTUAL_DEVICE_MZ2000 = 0x00000004,
VIRTUAL_DEVICE_PCW = 0x00000008,
VIRTUAL_DEVICE_MZ1500 = 0x00000004,
VIRTUAL_DEVICE_MZ2000 = 0x00000008,
VIRTUAL_DEVICE_PCW = 0x00000010,
VIRTUAL_DEVICE_RFS40 = 0x01000000,
VIRTUAL_DEVICE_RFS80 = 0x02000000,
VIRTUAL_DEVICE_RFS = 0x03000000,
@@ -674,6 +763,11 @@ typedef struct {
// 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;

View File

@@ -0,0 +1,458 @@
/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 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.
//
// Notes: See Makefile to enable/disable conditional components
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// This source file is free software: you can redistribute it and#or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/time.h>
#include "z80io.h"
#include <gpio_table.h>
#include <asm/io.h>
#include <infinity2m/gpio.h>
#include <infinity2m/registers.h>
// Device constants.
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
// PCW control.
typedef struct {
uint8_t regCtrl; // Control register.
} t_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.
uint32_t idx;
// Setup defaults.
MZ1500Ctrl.regCtrl = 0x00;
// Setup default mode according to run mode, ie. Physical run or Virtual run.
//
if(mode == USE_PHYSICAL_RAM)
{
// Initialise the page pointers and memory to use physical RAM.
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
{
if(idx >= 0 && idx < 0x1000)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
}
else if(idx >= 0x1000 && idx < 0xD000)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
}
else if(idx >= 0xD000 && idx < 0xE000)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
}
else if(idx >= 0xE000 && idx < 0xE800)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
}
else if(idx >= 0xE800 && idx < 0x10000)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
} else
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
}
}
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
{
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
}
// Cancel refresh as using physical RAM for program automatically refreshes DRAM.
Z80Ctrl->refreshDRAM = 0;
}
else if(mode == USE_VIRTUAL_RAM)
{
// Initialise the page pointers and memory to use virtual RAM.
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
{
if(idx >= 0 && idx < 0x1000)
{
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
}
else if(idx >= 0x1000 && idx < 0xD000)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
}
else if(idx >= 0xD000 && idx < 0xE000)
{
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx);
}
else if(idx >= 0xE000 && idx < 0xE800)
{
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_HW, idx);
}
else if(idx >= 0xE800 && idx < 0xF000)
{
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
}
else if(idx >= 0xF000 && idx < 0x10000)
{
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
}
}
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
{
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
}
// Enable refresh as using virtual RAM stops refresh of host DRAM.
Z80Ctrl->refreshDRAM = 2;
}
// Reset memory paging to default.
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
pr_info("MZ-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);
// 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 >= 2)
// {
// pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
// }
// #endif
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
//
// 0000 - 0FFF : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
// 1000 - CFFF : MZ80K/A/700 = RAM
// C000 - CFFF : MZ80A = Monitor ROM (MZ80A rom swap)
// D000 - D7FF : MZ80K/A/700 = VRAM
// D800 - DFFF : 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 >= 2)
// {
// pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
// }
// #endif
// Determine if this is a memory management port and update the memory page if required.
switch(address & 0x00FF)
{
// MZ1500 memory mode switch.
//
// MZ-1500
// |0000:0FFF|1000:CFFF|D000:FFFF
// ------------------------------
// OUT 0xE0 = |DRAM | |
// OUT 0xE1 = | | |DRAM
// OUT 0xE2 = |MONITOR | |
// OUT 0xE3 = | | |Memory Mapped I/O
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
// OUT 0xE5 = | | |PCG Enable
// OUT 0xE6 = | | |PCG Disable
//
// <return> = Return to the state prior to the complimentary command being invoked.
// Enable lower 4K block as DRAM
case IO_ADDR_E0:
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
}
break;
// Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM.
case IO_ADDR_E1:
if(!Z80Ctrl->inhibitMode)
{
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
{
// MZ-1500 mode we only work in first 64K block.
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
}
}
break;
// Enable MOnitor ROM in lower 4K block
case IO_ADDR_E2:
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
}
break;
// Enable Video RAM and Memory mapped peripherals in upper 12K block.
case IO_ADDR_E3:
if(!Z80Ctrl->inhibitMode)
{
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
}
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
}
}
break;
// Reset to power on condition memory map.
case IO_ADDR_E4:
// Lower 4K set to Monitor ROM.
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
}
if(!Z80Ctrl->inhibitMode)
{
// Upper 12K to hardware.
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
}
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
{
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
}
}
break;
// 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;
// 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 mz1500Read(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 mz1500Write(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;
}

View File

@@ -95,6 +95,8 @@
#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
@@ -255,9 +257,14 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
// Enable refresh as using virtual RAM stops refresh of host DRAM.
Z80Ctrl->refreshDRAM = 2;
#if (TARGET_HOST_MZ700 == 1)
#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.
@@ -312,9 +319,14 @@ void rfsInit(uint8_t mode80c)
Z80Ctrl->rom[idx+(Z80_VIRTUAL_ROM_SIZE-0x10000)] = z80io_PRL_Read8(1);
}
#if (TARGET_HOST_MZ700 == 1)
#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);