Added arbiter and bug fixes
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1717,4 +1717,6 @@ 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
|
||||
|
||||
|
||||
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.
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.
@@ -1038,23 +1038,23 @@ static t_scanCodeMap scanCodeMap[] = {
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
// S8 40 - 47 - Keypad keys.
|
||||
'8' , // Keypad 8
|
||||
'7' , // 7
|
||||
'5' , // 5
|
||||
'4' , // 4
|
||||
'2' , // 2
|
||||
'1' , // 1
|
||||
DBLZERO , // 00
|
||||
'0' , // 0
|
||||
NOKEY , // Keypad 8
|
||||
NOKEY , // 7
|
||||
NOKEY , // 5
|
||||
HOTKEY_LINUX, // 4 - Hotkey to invoke Linux mode.
|
||||
HOTKEY_RFS40, // 2 - Hotkey to invoke RFS 40 mode.
|
||||
HOTKEY_RFS80, // 1 - Hotkey to invoke RFS 80 mode.
|
||||
NOKEY , // 00
|
||||
HOTKEY_ORIGINAL, // 0 - Hotkey to invoke original mode.
|
||||
// S9 48 - 4F - Keypad keys.
|
||||
'+' , // +
|
||||
'0' , // 9
|
||||
'-' , // -
|
||||
'6' , // 6
|
||||
NOKEY , // +
|
||||
NOKEY , // 9
|
||||
NOKEY , // -
|
||||
NOKEY , // 6
|
||||
NOKEY , //
|
||||
'3' , // 3
|
||||
HOTKEY_TZFS, // 3 - Hotkey to invoke TZFS mode.
|
||||
NOKEY ,
|
||||
'.' // .
|
||||
NOKEY // .
|
||||
}},
|
||||
// MZ_80A KANA
|
||||
{{
|
||||
@@ -1268,6 +1268,12 @@ uint8_t mzInitMBHardware(void)
|
||||
// Set timer timer to run.
|
||||
WRITE_HARDWARE(1, MBADDR_CONTF, 0x80);
|
||||
|
||||
// Reset display.
|
||||
READ_HARDWARE_INIT(1, MBADDR_NRMDSP); // Restore screen to non-inverted.
|
||||
READ_HARDWARE_INIT(1, MBADDR_SCLDSP); // Hardware scroll needs to be reset.
|
||||
|
||||
// Disable the hardware sound output.
|
||||
WRITE_HARDWARE(0, MBADDR_SUNDG, 0x00); // Sound could be enabled on start, disable it.
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
9
software/FusionX/src/ttymz/sharpmz.h
vendored
9
software/FusionX/src/ttymz/sharpmz.h
vendored
@@ -122,8 +122,8 @@
|
||||
#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_INVDSP 0xE014 // Invert display.
|
||||
#define MBADDR_NRMDSP 0xE015 // Return display to normal.
|
||||
#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)
|
||||
@@ -192,6 +192,11 @@
|
||||
#define PAGEDOWN 0xE1
|
||||
#define CURHOMEKEY 0xE2
|
||||
#define ALPHAGRAPHKEY 0xE3
|
||||
#define HOTKEY_ORIGINAL 0xE8
|
||||
#define HOTKEY_RFS80 0xE9
|
||||
#define HOTKEY_RFS40 0xEA
|
||||
#define HOTKEY_TZFS 0xEB
|
||||
#define HOTKEY_LINUX 0xEC
|
||||
#define NOKEY 0xF0
|
||||
#define CURSRIGHT 0xF1
|
||||
#define CURSLEFT 0xF2
|
||||
|
||||
@@ -80,8 +80,7 @@ MODULE_INFO(copyright, DRIVER_COPYRIGHT);
|
||||
|
||||
// Device control variables.
|
||||
static t_TTYMZ *ttymzConnections[SHARPMZ_TTY_MINORS]; // Initially all NULL, no devices connected.
|
||||
static struct tty_port ttymzPort[SHARPMZ_TTY_MINORS];
|
||||
static struct tty_driver *ttymzDriver;
|
||||
static t_TTYMZCtrl ttymzCtrl;
|
||||
|
||||
// Read method. Keys entered on the host keyboard are sent to the user process via this method.
|
||||
//
|
||||
@@ -194,8 +193,24 @@ static void ttymz_keyboardTimer(unsigned long timerAddr)
|
||||
// Scan the Sharp MZ host keyboard, push any character received. Mode 2 = Ansi scan without wait.
|
||||
if((key = mzGetKey(2)) != -1)
|
||||
{
|
||||
//pr_info("%d ", key);
|
||||
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.
|
||||
@@ -240,6 +255,7 @@ static int ttymz_open(struct tty_struct *tty, struct file *file)
|
||||
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;
|
||||
@@ -247,6 +263,7 @@ static int ttymz_open(struct tty_struct *tty, struct file *file)
|
||||
// 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
|
||||
@@ -265,6 +282,7 @@ static int ttymz_open(struct tty_struct *tty, struct file *file)
|
||||
// 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;
|
||||
@@ -273,7 +291,8 @@ static int ttymz_open(struct tty_struct *tty, struct file *file)
|
||||
|
||||
// Port opened, perform initialisation.
|
||||
//
|
||||
if(++ttymz->open_count == 1)
|
||||
++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)
|
||||
@@ -301,11 +320,27 @@ static int ttymz_open(struct tty_struct *tty, struct file *file)
|
||||
ttymz->timerDisplay.expires = jiffies + 1;
|
||||
add_timer(&ttymz->timerDisplay);
|
||||
} else
|
||||
// SSD202 Framebuffer?
|
||||
if(ttymz->open_count == 1 && tty->index == 1)
|
||||
{
|
||||
// Not allowed to open the port more than once.
|
||||
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);
|
||||
}
|
||||
@@ -315,6 +350,8 @@ static int ttymz_open(struct tty_struct *tty, struct file *file)
|
||||
static void do_close(t_TTYMZ *ttymz)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
struct task_struct *task = get_current();
|
||||
|
||||
mutex_lock(&ttymz->mutex);
|
||||
|
||||
@@ -324,13 +361,36 @@ static void do_close(t_TTYMZ *ttymz)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Shutdown hardware tasks to exit.
|
||||
if(--ttymz->open_count <= 0)
|
||||
// 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);
|
||||
}
|
||||
@@ -368,70 +428,90 @@ static void ttymz_set_termios(struct tty_struct *tty, struct ktermios *old_termi
|
||||
}
|
||||
}
|
||||
|
||||
// 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:
|
||||
pr_info(" - data bits = 5\n");
|
||||
break;
|
||||
case CS6:
|
||||
pr_info(" - data bits = 6\n");
|
||||
break;
|
||||
case CS7:
|
||||
pr_info(" - data bits = 7\n");
|
||||
break;
|
||||
default:
|
||||
case CS8:
|
||||
pr_info(" - data bits = 8\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// Determine the parity
|
||||
if (cflag & PARENB)
|
||||
if (cflag & PARODD)
|
||||
pr_info(" - parity = odd\n");
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
pr_info(" - parity = even\n");
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
pr_info(" - parity = none\n");
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// Figure out the stop bits requested
|
||||
if (cflag & CSTOPB)
|
||||
pr_info(" - stop bits = 2\n");
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
pr_info(" - stop bits = 1\n");
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// Figure out the hardware flow control settings
|
||||
if (cflag & CRTSCTS)
|
||||
pr_info(" - RTS/CTS is enabled\n");
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
pr_info(" - RTS/CTS is disabled\n");
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// 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);
|
||||
//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))
|
||||
pr_info(" - INBOUND XON/XOFF is enabled, "
|
||||
"XON = %2x, XOFF = %2x", start_char, stop_char);
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
pr_info(" - INBOUND XON/XOFF is disabled");
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
// if we are implementing OUTBOUND XON/XOFF
|
||||
if(I_IXON(tty))
|
||||
pr_info(" - OUTBOUND XON/XOFF is enabled, "
|
||||
"XON = %2x, XOFF = %2x", start_char, stop_char);
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
pr_info(" - OUTBOUND XON/XOFF is disabled");
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the baud rate wanted
|
||||
pr_info(" - baud rate = %d", tty_get_baud_rate(tty));
|
||||
// baud = tty_get_baud_rate(tty));
|
||||
return;
|
||||
}
|
||||
|
||||
static int ttymz_tiocmget(struct tty_struct *tty)
|
||||
@@ -608,6 +688,14 @@ static int ttymz_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long a
|
||||
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.
|
||||
@@ -734,39 +822,39 @@ static int __init ttymz_init(void)
|
||||
char buf[80];
|
||||
|
||||
// Allocate the tty driver handles, one per potential device.
|
||||
ttymzDriver = alloc_tty_driver(SHARPMZ_TTY_MINORS);
|
||||
if(!ttymzDriver)
|
||||
ttymzCtrl.ttymzDriver = alloc_tty_driver(SHARPMZ_TTY_MINORS);
|
||||
if(!ttymzCtrl.ttymzDriver)
|
||||
return -ENOMEM;
|
||||
|
||||
// Initialize the tty driver
|
||||
ttymzDriver->owner = THIS_MODULE;
|
||||
ttymzDriver->driver_name = DRIVER_NAME;
|
||||
ttymzDriver->name = DEVICE_NAME;
|
||||
ttymzDriver->major = SHARPMZ_TTY_MAJOR,
|
||||
ttymzDriver->type = TTY_DRIVER_TYPE_SERIAL,
|
||||
ttymzDriver->subtype = SERIAL_TYPE_NORMAL,
|
||||
ttymzDriver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV,
|
||||
ttymzDriver->init_termios = tty_std_termios;
|
||||
ttymzDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
||||
tty_set_operations(ttymzDriver, &serial_ops);
|
||||
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(ttymzPort + i);
|
||||
tty_port_link_device(ttymzPort + i, ttymzDriver, 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(ttymzDriver);
|
||||
retval = tty_register_driver(ttymzCtrl.ttymzDriver);
|
||||
if(retval)
|
||||
{
|
||||
pr_err("Failed to register SharpMZ tty driver");
|
||||
put_tty_driver(ttymzDriver);
|
||||
put_tty_driver(ttymzCtrl.ttymzDriver);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Register the devices.
|
||||
for (i = 0; i < SHARPMZ_TTY_MINORS; ++i)
|
||||
tty_register_device(ttymzDriver, i, NULL);
|
||||
tty_register_device(ttymzCtrl.ttymzDriver, i, NULL);
|
||||
|
||||
// Initialise the hardware to host interface.
|
||||
z80io_init();
|
||||
@@ -796,10 +884,10 @@ static void __exit ttymz_exit(void)
|
||||
// De-register the devices and driver.
|
||||
for(idx = 0; idx < SHARPMZ_TTY_MINORS; ++idx)
|
||||
{
|
||||
tty_unregister_device(ttymzDriver, idx);
|
||||
tty_port_destroy(ttymzPort + idx);
|
||||
tty_unregister_device(ttymzCtrl.ttymzDriver, idx);
|
||||
tty_port_destroy(ttymzCtrl.ttymzPort + idx);
|
||||
}
|
||||
tty_unregister_driver(ttymzDriver);
|
||||
tty_unregister_driver(ttymzCtrl.ttymzDriver);
|
||||
|
||||
// Shut down all of the timers and free the memory.
|
||||
for(idx = 0; idx < SHARPMZ_TTY_MINORS; ++idx)
|
||||
|
||||
35
software/FusionX/src/ttymz/ttymz.h
vendored
35
software/FusionX/src/ttymz/ttymz.h
vendored
@@ -41,6 +41,7 @@
|
||||
#define DEVICE_NAME "ttymz"
|
||||
#define DRIVER_NAME "SharpMZ_tty"
|
||||
#define DEBUG_ENABLED 0 // 0 = disabled, 1 .. debug level.
|
||||
#define ARBITER_NAME "sharpbiter"
|
||||
|
||||
// Fake UART values
|
||||
#define MCR_DTR 0x01
|
||||
@@ -52,17 +53,37 @@
|
||||
#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 2 // Assign 2 devices, Sharp VRAM and SigmaStar SSD202 Framebuffer.
|
||||
#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
|
||||
@@ -70,16 +91,24 @@ typedef struct {
|
||||
struct timer_list timerKeyboard; // Keyboard sweep timer.
|
||||
struct timer_list timerDisplay; // Display service timer.
|
||||
|
||||
/* for tiocmget and tiocmset functions */
|
||||
// for tiocmget and tiocmset functions
|
||||
int msr; // MSR shadow
|
||||
int mcr; // MCR shadow
|
||||
|
||||
/* for ioctl fun */
|
||||
// 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;
|
||||
|
||||
@@ -12,10 +12,9 @@
|
||||
// The primary code base is take from tranzputer.c/.h which is part of the zSoft OS
|
||||
// package. It is customised for this application.
|
||||
//
|
||||
// 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.
|
||||
// Credits:
|
||||
//
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
// (c) 1999-2023 Manuel Sainz de Baranda y Goñi
|
||||
//
|
||||
// History: Feb 2023 v1.0 - Source copied from zSoft and modified to run as a daemon, stripping
|
||||
// out all low level control methods.
|
||||
@@ -2825,6 +2824,7 @@ 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("%*c --startz80 # Start Z80 and reset host.\n", strlen(progName), ' ');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2843,6 +2843,7 @@ int main(int argc, char *argv[])
|
||||
long fileOffset = -1;
|
||||
long fileLen = -1;
|
||||
int helpFlag = 0;
|
||||
int startFlag = 0;
|
||||
int verboseFlag = 0;
|
||||
uint8_t memoryType = 0;
|
||||
struct ioctlCmd ioctlCmd;
|
||||
@@ -2851,6 +2852,7 @@ int main(int argc, char *argv[])
|
||||
struct optparse options;
|
||||
static struct optparse_long long_options[] =
|
||||
{
|
||||
{"startz80", 's', OPTPARSE_NONE},
|
||||
{"help", 'h', OPTPARSE_NONE},
|
||||
{"verbose", 'v', OPTPARSE_NONE},
|
||||
{0}
|
||||
@@ -2869,6 +2871,11 @@ int main(int argc, char *argv[])
|
||||
printf("Hex data:%08x\n", hexData);
|
||||
break;
|
||||
|
||||
// Start the Z80 processor, default is to wait for a service command or signal.
|
||||
case 's':
|
||||
startFlag = 1;
|
||||
break;
|
||||
|
||||
// Verbose mode.
|
||||
case 'v':
|
||||
verboseFlag = 1;
|
||||
@@ -2932,7 +2939,10 @@ int main(int argc, char *argv[])
|
||||
signal(SIGTERM, shutdownRequest);
|
||||
|
||||
// Initiate a reset which loads the default roms and caches SD directory.
|
||||
if(startFlag == 1)
|
||||
{
|
||||
z80ResetRequest(0);
|
||||
}
|
||||
|
||||
// Enter a loop, process requests as the come in and terminate if requested by signals.
|
||||
runControl = 1;
|
||||
|
||||
445
software/FusionX/src/z80drv/MZ80A/sharpbiter.c
Normal file
445
software/FusionX/src/z80drv/MZ80A/sharpbiter.c
Normal file
@@ -0,0 +1,445 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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;
|
||||
|
||||
// Method to reset the Z80 CPU.
|
||||
//
|
||||
void reqResetZ80(uint8_t memoryMode)
|
||||
{
|
||||
// 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(uint8_t memoryMode)
|
||||
{
|
||||
// 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(uint8_t memoryMode)
|
||||
{
|
||||
// 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.
|
||||
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;
|
||||
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);
|
||||
|
||||
// Reset and start the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
|
||||
case HOTKEY_RFS80:
|
||||
case HOTKEY_RFS40:
|
||||
// Disable TTY I/O.
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// 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;
|
||||
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.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
|
||||
case HOTKEY_TZFS:
|
||||
// Disable TTY I/O.
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// 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;
|
||||
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);
|
||||
|
||||
// Reset and start the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
// ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
// ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
|
||||
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;
|
||||
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
|
||||
2
software/FusionX/src/z80drv/MZ80A/tzpu.h
vendored
2
software/FusionX/src/z80drv/MZ80A/tzpu.h
vendored
@@ -46,7 +46,7 @@
|
||||
#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.
|
||||
#define OS_BASE_DIR "/apps/FusionX/disk/MZ-80A/" // Linux base directory where all the files are stored. On a real tranZPUter this would be the SD card root dir.
|
||||
#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.
|
||||
#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.
|
||||
|
||||
|
||||
@@ -544,14 +544,31 @@ static zuint8 z80_read(void *context, zuint16 address)
|
||||
}
|
||||
|
||||
// Keyport data? Store.
|
||||
if(isHW(address) && address == 0xE001 && (Z80Ctrl->keyportStrobe & 0x0f) == 8 && (data & 0x41) == 0)
|
||||
if(isHW(address) && address == 0xE001 && (Z80Ctrl->keyportStrobe & 0x0f) == 0)
|
||||
{
|
||||
Z80Ctrl->keyportShiftCtrl = 0x01;
|
||||
Z80Ctrl->keyportShiftCtrl = (data & 0x80) == 0 ? 0x01 : 0x00;
|
||||
} else
|
||||
if(isHW(address) && address == 0xE001 && (Z80Ctrl->keyportStrobe & 0x0f) == 0 && (data & 0x80) == 0)
|
||||
// If CTRL key pressed followed by a key on Row 8/9 (Keypad), set Hotkey for later processing.
|
||||
if(isHW(address) && address == 0xE001 && Z80Ctrl->keyportShiftCtrl == 1)
|
||||
{
|
||||
Z80Ctrl->keyportHotKey = 0x01;
|
||||
if((Z80Ctrl->keyportStrobe & 0x0f) == 8 && (data & 0x1D) != 0x1D)
|
||||
{
|
||||
Z80Ctrl->keyportHotKey = (data & 0x01) == 0 ? HOTKEY_ORIGINAL :
|
||||
(data & 0x04) == 0 ? HOTKEY_RFS80 :
|
||||
(data & 0x08) == 0 ? HOTKEY_RFS40 :
|
||||
(data & 0x10) == 0 ? HOTKEY_LINUX : 0x00;
|
||||
Z80Ctrl->keyportTrigger = Z80Ctrl->keyportHotKey;
|
||||
} else
|
||||
if((Z80Ctrl->keyportStrobe & 0x09) == 9 && (data & 0x04) != 0x04)
|
||||
{
|
||||
Z80Ctrl->keyportHotKey = HOTKEY_TZFS;
|
||||
Z80Ctrl->keyportTrigger = 1;
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->keyportTrigger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if(DEBUG_ENABLED & 1)
|
||||
if(Z80Ctrl->debug >= 3)
|
||||
{
|
||||
@@ -943,12 +960,13 @@ int thread_z80(void * thread_nr)
|
||||
mutex_unlock(&Z80RunModeMutex);
|
||||
|
||||
// Hotkey pressed? Bring up user menu.
|
||||
if(Z80Ctrl->keyportShiftCtrl && Z80Ctrl->keyportHotKey)
|
||||
if(Z80Ctrl->keyportTrigger != 0x00 && Z80Ctrl->keyportTriggerLast == 0)
|
||||
{
|
||||
z80menu();
|
||||
sendSignal(Z80Ctrl->arbTask, SIGUSR1);
|
||||
Z80Ctrl->keyportShiftCtrl = 0;
|
||||
Z80Ctrl->keyportHotKey = 0;
|
||||
}
|
||||
Z80Ctrl->keyportTriggerLast = Z80Ctrl->keyportTrigger;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -981,6 +999,12 @@ static int z80drv_release(struct inode *inodep, struct file *filep)
|
||||
Z80Ctrl->ioTask = NULL;
|
||||
pr_info("I/O processor stopped.\n");
|
||||
} else
|
||||
// Is this the Arbiter de-registering?
|
||||
if(Z80Ctrl->arbTask == task)
|
||||
{
|
||||
Z80Ctrl->arbTask = NULL;
|
||||
pr_info("Arbiter stopped.\n");
|
||||
} else
|
||||
{
|
||||
// Free up the mutex preventing more than one control process taking control at the same time.
|
||||
mutex_unlock(&Z80DRV_MUTEX);
|
||||
@@ -1012,6 +1036,18 @@ static int z80drv_open(struct inode *inodep, struct file *filep)
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
} else
|
||||
// Arbiter?
|
||||
if(Z80Ctrl->arbTask == NULL && strcmp(task->comm, ARBITER_NAME) == 0)
|
||||
{
|
||||
Z80Ctrl->arbTask = task;
|
||||
pr_info("Registering Aribter:%s\n", Z80Ctrl->arbTask->comm);
|
||||
} else
|
||||
if(Z80Ctrl->arbTask != NULL && strcmp(task->comm, ARBITER_NAME) == 0)
|
||||
{
|
||||
pr_info("Arbiter already registered, PID:%d\n", Z80Ctrl->arbTask->pid);
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
} else
|
||||
if(!mutex_trylock(&Z80DRV_MUTEX))
|
||||
{
|
||||
pr_alert("z80drv: Device busy!\n");
|
||||
@@ -1388,9 +1424,36 @@ void setupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_RFS)
|
||||
rfsSetupMemory(mode);
|
||||
else
|
||||
#endif
|
||||
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_TZPU)
|
||||
tzpuSetupMemory(mode);
|
||||
else
|
||||
{
|
||||
// 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(TARGET_HOST_MZ700 == 1)
|
||||
if(idx >= 0x0000 && idx < 0x1000)
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
if((idx >= 0x0000 && idx < 0x1000) || (idx >= 0xF000 && idx < 0x10000))
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
if(idx >= 0x0000 && idx < 0x8000)
|
||||
#endif
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enable autorefresh if refreshDRAM is set.
|
||||
SPI_SEND8(Z80Ctrl->refreshDRAM == 1 ? CPLD_CMD_SET_AUTO_REFRESH : CPLD_CMD_CLEAR_AUTO_REFRESH);
|
||||
@@ -1623,7 +1686,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
{
|
||||
if(Z80Ctrl->virtualDevice[idx] == ioctlCmd.vdev.device)
|
||||
{
|
||||
pr_info("Virtual Device already installed.\n");
|
||||
//pr_info("Virtual Device already installed.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1670,7 +1733,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
|
||||
// Z80 can continue.
|
||||
mutex_lock(&Z80RunModeMutex); Z80RunMode = currentRunMode; mutex_unlock(&Z80RunModeMutex);
|
||||
pr_info("Virtual device added.\n");
|
||||
//pr_info("Virtual device added.\n");
|
||||
break;
|
||||
|
||||
// Command to remove a device from the Z80 configuration.
|
||||
@@ -1683,7 +1746,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
}
|
||||
if(idx == Z80Ctrl->virtualDeviceCnt)
|
||||
{
|
||||
pr_info("Virtual Device not found.\n");
|
||||
//pr_info("Virtual Device not found.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1701,13 +1764,17 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
// Delete the device, removing hooks etc as required.
|
||||
switch(ioctlCmd.vdev.device)
|
||||
{
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
case VIRTUAL_DEVICE_RFS40:
|
||||
case VIRTUAL_DEVICE_RFS80:
|
||||
Z80Ctrl->virtualDeviceBitMap &= ~ioctlCmd.vdev.device;
|
||||
rfsRemove();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case VIRTUAL_DEVICE_TZPU:
|
||||
Z80Ctrl->virtualDeviceBitMap &= ~VIRTUAL_DEVICE_TZPU;
|
||||
tzpuRemove();
|
||||
break;
|
||||
|
||||
case VIRTUAL_DEVICE_NONE:
|
||||
@@ -1720,7 +1787,7 @@ static long int z80drv_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
|
||||
// Z80 can continue.
|
||||
mutex_lock(&Z80RunModeMutex); Z80RunMode = currentRunMode; mutex_unlock(&Z80RunModeMutex);
|
||||
pr_info("Device removed\n");
|
||||
//pr_info("Device removed\n");
|
||||
break;
|
||||
|
||||
// Method to send adhoc commands to the CPLD, ie for switching active display etc.
|
||||
@@ -1981,29 +2048,6 @@ static int __init ModuleInit(void)
|
||||
Z80Ctrl->ram[0x120f] = 0x00;
|
||||
#endif
|
||||
|
||||
// Copy the host BIOS into the Virtual ROM and initialise remainder of ROM.
|
||||
pr_info("Sync Host BIOS to virtual ROM.\n");
|
||||
for(idx=0; idx < Z80_VIRTUAL_ROM_SIZE; idx++)
|
||||
{
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
if(idx >= 0x0000 && idx < 0x1000)
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
if((idx >= 0x0000 && idx < 0x1000) || (idx >= 0xE800 && idx < 0x10000))
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
if(idx >= 0x0000 && idx < 0x8000)
|
||||
#endif
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
Z80Ctrl->lowMemorySwap = 1;
|
||||
#endif
|
||||
@@ -2036,6 +2080,7 @@ static int __init ModuleInit(void)
|
||||
|
||||
// Initialise control handles.
|
||||
Z80Ctrl->ioTask = NULL;
|
||||
Z80Ctrl->arbTask = NULL;
|
||||
|
||||
// Initialse run control.
|
||||
mutex_init(&Z80RunModeMutex);
|
||||
@@ -2049,6 +2094,8 @@ static int __init ModuleInit(void)
|
||||
Z80Ctrl->keyportStrobe = 0x00;
|
||||
Z80Ctrl->keyportShiftCtrl = 0x00;
|
||||
Z80Ctrl->keyportHotKey = 0x00;
|
||||
Z80Ctrl->keyportTrigger = 0x00;
|
||||
Z80Ctrl->keyportTriggerLast = 0x00;
|
||||
|
||||
// PC to start and power on the CPU
|
||||
Z80_PC(Z80CPU) = 0;
|
||||
|
||||
24
software/FusionX/src/z80drv/MZ80A/z80driver.h
vendored
24
software/FusionX/src/z80drv/MZ80A/z80driver.h
vendored
@@ -53,6 +53,7 @@
|
||||
#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.
|
||||
@@ -71,6 +72,13 @@
|
||||
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
||||
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
||||
|
||||
// Hotkeys handled.
|
||||
#define HOTKEY_ORIGINAL 0xE8
|
||||
#define HOTKEY_RFS80 0xE9
|
||||
#define HOTKEY_RFS40 0xEA
|
||||
#define HOTKEY_TZFS 0xEB
|
||||
#define HOTKEY_LINUX 0xEC
|
||||
|
||||
//*********************************************************************************************
|
||||
// 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
|
||||
@@ -404,21 +412,22 @@ enum Z80_INSTRUCTION_DELAY {
|
||||
#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(_signal_) { struct siginfo sigInfo;\
|
||||
if(Z80Ctrl->ioTask != NULL)\
|
||||
#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, Z80Ctrl->ioTask) < 0)\
|
||||
if(send_sig_info(_signal_, &sigInfo, __task__) < 0)\
|
||||
{\
|
||||
pr_info("Error: Failed to send Request to I/O Processor:%d, %s\n", _signal_, Z80Ctrl->ioTask->comm);\
|
||||
pr_info("Error: Failed to send signal:%02x to:%s\n", _signal_, __task__->comm);\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
#define resetZ80() {\
|
||||
sendSignal(SIGUSR1); \
|
||||
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_TZPU)\
|
||||
sendSignal(Z80Ctrl->ioTask, SIGUSR1); \
|
||||
setupMemory(Z80Ctrl->defaultPageMode);\
|
||||
z80_instant_reset(&Z80CPU);\
|
||||
}
|
||||
@@ -527,6 +536,8 @@ typedef struct {
|
||||
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,
|
||||
@@ -539,6 +550,9 @@ typedef struct {
|
||||
// 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;
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
#define BNKCTRLDEF BBMOSI+SDCS+BBCLK // Default on startup for the Bank Control register.
|
||||
|
||||
// RFS Board ROM rom filename definitions.
|
||||
#define ROM_DIR "/apps/FusionX/roms/"
|
||||
#define ROM_DIR "/apps/FusionX/host/MZ-80A/RFS/"
|
||||
#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"
|
||||
@@ -108,7 +108,7 @@
|
||||
#define ROM_USER_III_SIZE 0x80000
|
||||
|
||||
// SD Drive constants.
|
||||
#define SD_DIR "/apps/FusionX/SD/"
|
||||
#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)
|
||||
@@ -219,6 +219,10 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
// 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)));
|
||||
}
|
||||
}
|
||||
|
||||
// No I/O Ports on the RFS board.
|
||||
@@ -257,6 +261,7 @@ uint8_t loadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
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.
|
||||
loadROM(mode80c == 0 ? ROM_MROM_40C_FILENAME : ROM_MROM_80C_FILENAME, ROM_MROM_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
@@ -264,7 +269,22 @@ void rfsInit(uint8_t mode80c)
|
||||
loadROM(mode80c == 0 ? ROM_USER_II_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_II_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
loadROM(mode80c == 0 ? ROM_USER_III_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_III_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
|
||||
// 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);
|
||||
}
|
||||
pr_info("Enabling RFS driver.\n");
|
||||
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.
|
||||
|
||||
@@ -121,6 +121,13 @@ void tzpuInit(void)
|
||||
pr_info("Enabling TZPU driver.\n");
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void tzpuRemove(void)
|
||||
{
|
||||
pr_info("Removing TZPU driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to decode an address and make any system memory map changes as required.
|
||||
//
|
||||
static inline void tzpuDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||
@@ -683,7 +690,7 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
#endif
|
||||
|
||||
// If a k64f process has registered, send it a service request signal.
|
||||
sendSignal(SIGIO);
|
||||
sendSignal(Z80Ctrl->ioTask, SIGIO);
|
||||
|
||||
// A strange race state exists with CP/M and interrupts during disk requests. If no delay is
|
||||
// given for read/write requests, the interrupt line will eventually lockup active and the Z80
|
||||
|
||||
3
software/FusionX/src/z80drv/Makefile
vendored
3
software/FusionX/src/z80drv/Makefile
vendored
@@ -16,6 +16,9 @@ z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables
|
||||
|
||||
|
||||
all:
|
||||
@echo ""
|
||||
@echo "Build Sharp MZ Arbiter for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/sharpbiter.c -o sharpbiter
|
||||
@echo ""
|
||||
@echo "Build K64F Daemon for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/k64fcpu.c -o k64fcpu
|
||||
|
||||
81
software/FusionX/start_FusionX.sh
Normal file → Executable file
81
software/FusionX/start_FusionX.sh
Normal file → Executable file
@@ -1,10 +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/>.
|
||||
#########################################################################################################
|
||||
|
||||
# Constants.
|
||||
FUSIONXDIR=/apps/FusionX
|
||||
|
||||
cd ${FUSIONXDIR}
|
||||
|
||||
# Choose one of the initial options below.
|
||||
#
|
||||
# Host installs a virtual RFS board and initialises host.
|
||||
${FUSIONXDIR}/etc/startZ80_RFS.sh
|
||||
# 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."
|
||||
|
||||
Reference in New Issue
Block a user