2013-05-20 18:20:14 +00:00
|
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* paravirt.c */
|
|
|
|
/* */
|
|
|
|
/* Paravirtualization for the sim65 6502 simulator */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* (C) 2013-2013 Ullrich von Bassewitz */
|
2021-04-19 14:06:10 +00:00
|
|
|
/* Roemerstrasse 52 */
|
2013-05-20 18:20:14 +00:00
|
|
|
/* D-70794 Filderstadt */
|
|
|
|
/* EMail: uz@cc65.org */
|
|
|
|
/* */
|
|
|
|
/* */
|
|
|
|
/* This software is provided 'as-is', without any expressed or implied */
|
|
|
|
/* warranty. In no event will the authors be held liable for any damages */
|
|
|
|
/* arising from the use of this software. */
|
|
|
|
/* */
|
|
|
|
/* Permission is granted to anyone to use this software for any purpose, */
|
|
|
|
/* including commercial applications, and to alter it and redistribute it */
|
|
|
|
/* freely, subject to the following restrictions: */
|
|
|
|
/* */
|
|
|
|
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
|
|
/* claim that you wrote the original software. If you use this software */
|
|
|
|
/* in a product, an acknowledgment in the product documentation would be */
|
|
|
|
/* appreciated but is not required. */
|
|
|
|
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
|
|
/* be misrepresented as being the original software. */
|
|
|
|
/* 3. This notice may not be removed or altered from any source */
|
|
|
|
/* distribution. */
|
|
|
|
/* */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
#include <string.h>
|
2013-05-20 18:20:14 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
2018-08-17 19:09:20 +00:00
|
|
|
#include <sys/stat.h>
|
2014-03-03 21:12:14 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
# define O_INITIAL O_BINARY
|
|
|
|
#else
|
|
|
|
# define O_INITIAL 0
|
|
|
|
#endif
|
2013-05-20 18:20:14 +00:00
|
|
|
#if defined(_MSC_VER)
|
|
|
|
/* Microsoft compiler */
|
|
|
|
# include <io.h>
|
|
|
|
#else
|
|
|
|
/* Anyone else */
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
2018-08-17 18:20:34 +00:00
|
|
|
#ifndef S_IREAD
|
2018-08-18 22:01:40 +00:00
|
|
|
# define S_IREAD S_IRUSR
|
2018-08-17 18:20:34 +00:00
|
|
|
#endif
|
|
|
|
#ifndef S_IWRITE
|
2018-08-18 22:01:40 +00:00
|
|
|
# define S_IWRITE S_IWUSR
|
2018-08-17 18:20:34 +00:00
|
|
|
#endif
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
/* common */
|
2013-05-24 16:36:30 +00:00
|
|
|
#include "cmdline.h"
|
2013-05-20 18:20:14 +00:00
|
|
|
#include "print.h"
|
|
|
|
#include "xmalloc.h"
|
|
|
|
|
|
|
|
/* sim65 */
|
|
|
|
#include "6502.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "paravirt.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Data */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef void (*PVFunc) (CPURegs* Regs);
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
static unsigned ArgStart;
|
2019-05-28 19:29:55 +00:00
|
|
|
static unsigned char SPAddr;
|
2013-05-24 16:36:30 +00:00
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
/* Code */
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
static unsigned GetAX (CPURegs* Regs)
|
|
|
|
{
|
|
|
|
return Regs->AC + (Regs->XR << 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void SetAX (CPURegs* Regs, unsigned Val)
|
|
|
|
{
|
|
|
|
Regs->AC = Val & 0xFF;
|
|
|
|
Val >>= 8;
|
|
|
|
Regs->XR = Val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
static unsigned char Pop (CPURegs* Regs)
|
|
|
|
{
|
2022-01-07 14:56:46 +00:00
|
|
|
return MemReadByte (0x0100 + (++Regs->SP & 0xFF));
|
2013-05-20 18:20:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned PopParam (unsigned char Incr)
|
|
|
|
{
|
2019-05-28 19:29:55 +00:00
|
|
|
unsigned SP = MemReadZPWord (SPAddr);
|
2013-05-20 18:20:14 +00:00
|
|
|
unsigned Val = MemReadWord (SP);
|
2019-05-28 19:29:55 +00:00
|
|
|
MemWriteWord (SPAddr, SP + Incr);
|
2013-05-20 18:20:14 +00:00
|
|
|
return Val;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-05-29 22:10:17 +00:00
|
|
|
static void PVExit (CPURegs* Regs)
|
|
|
|
{
|
|
|
|
Print (stderr, 1, "PVExit ($%02X)\n", Regs->AC);
|
|
|
|
if (PrintCycles) {
|
|
|
|
Print (stdout, 0, "%lu cycles\n", GetCycles ());
|
|
|
|
}
|
|
|
|
|
|
|
|
exit (Regs->AC);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
static void PVArgs (CPURegs* Regs)
|
|
|
|
{
|
|
|
|
unsigned ArgC = ArgCount - ArgStart;
|
|
|
|
unsigned ArgV = GetAX (Regs);
|
2019-05-28 19:29:55 +00:00
|
|
|
unsigned SP = MemReadZPWord (SPAddr);
|
2013-05-24 16:36:30 +00:00
|
|
|
unsigned Args = SP - (ArgC + 1) * 2;
|
|
|
|
|
2016-01-05 16:45:18 +00:00
|
|
|
Print (stderr, 2, "PVArgs ($%04X)\n", ArgV);
|
2013-05-24 16:36:30 +00:00
|
|
|
|
|
|
|
MemWriteWord (ArgV, Args);
|
|
|
|
|
|
|
|
SP = Args;
|
|
|
|
while (ArgStart < ArgCount) {
|
|
|
|
unsigned I = 0;
|
|
|
|
const char* Arg = ArgVec[ArgStart++];
|
|
|
|
SP -= strlen (Arg) + 1;
|
|
|
|
do {
|
|
|
|
MemWriteByte (SP + I, Arg[I]);
|
|
|
|
}
|
|
|
|
while (Arg[I++]);
|
|
|
|
|
|
|
|
MemWriteWord (Args, SP);
|
|
|
|
Args += 2;
|
|
|
|
}
|
2019-05-28 19:29:55 +00:00
|
|
|
MemWriteWord (Args, SPAddr);
|
2013-05-24 16:36:30 +00:00
|
|
|
|
2019-05-28 19:29:55 +00:00
|
|
|
MemWriteWord (SPAddr, SP);
|
2013-05-24 16:36:30 +00:00
|
|
|
SetAX (Regs, ArgC);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
static void PVOpen (CPURegs* Regs)
|
|
|
|
{
|
|
|
|
char Path[1024];
|
|
|
|
int OFlag = O_INITIAL;
|
2018-08-18 22:01:40 +00:00
|
|
|
int OMode = 0;
|
2018-08-17 20:17:38 +00:00
|
|
|
unsigned RetVal, I = 0;
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
unsigned Mode = PopParam (Regs->YR - 4);
|
|
|
|
unsigned Flags = PopParam (2);
|
|
|
|
unsigned Name = PopParam (2);
|
|
|
|
|
2018-08-17 17:50:16 +00:00
|
|
|
if (Regs->YR - 4 < 2) {
|
2018-08-18 22:01:40 +00:00
|
|
|
/* If the caller didn't supply the mode
|
|
|
|
** argument, use a reasonable default.
|
2018-08-17 17:50:16 +00:00
|
|
|
*/
|
2018-08-18 22:01:40 +00:00
|
|
|
Mode = 0x01 | 0x02;
|
2018-08-17 17:50:16 +00:00
|
|
|
}
|
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
do {
|
|
|
|
Path[I] = MemReadByte (Name++);
|
|
|
|
}
|
|
|
|
while (Path[I++]);
|
|
|
|
|
2016-01-05 16:45:18 +00:00
|
|
|
Print (stderr, 2, "PVOpen (\"%s\", $%04X)\n", Path, Flags);
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
switch (Flags & 0x03) {
|
|
|
|
case 0x01:
|
|
|
|
OFlag |= O_RDONLY;
|
|
|
|
break;
|
|
|
|
case 0x02:
|
|
|
|
OFlag |= O_WRONLY;
|
|
|
|
break;
|
|
|
|
case 0x03:
|
|
|
|
OFlag |= O_RDWR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Flags & 0x10) {
|
|
|
|
OFlag |= O_CREAT;
|
|
|
|
}
|
|
|
|
if (Flags & 0x20) {
|
|
|
|
OFlag |= O_TRUNC;
|
|
|
|
}
|
|
|
|
if (Flags & 0x40) {
|
|
|
|
OFlag |= O_APPEND;
|
|
|
|
}
|
|
|
|
if (Flags & 0x80) {
|
|
|
|
OFlag |= O_EXCL;
|
|
|
|
}
|
|
|
|
|
2018-08-18 22:01:40 +00:00
|
|
|
if (Mode & 0x01) {
|
2018-08-17 17:43:14 +00:00
|
|
|
OMode |= S_IREAD;
|
|
|
|
}
|
2018-08-18 22:01:40 +00:00
|
|
|
if (Mode & 0x02) {
|
2018-08-17 17:43:14 +00:00
|
|
|
OMode |= S_IWRITE;
|
|
|
|
}
|
2013-05-20 18:20:14 +00:00
|
|
|
|
2018-08-17 17:43:14 +00:00
|
|
|
RetVal = open (Path, OFlag, OMode);
|
2013-05-20 18:20:14 +00:00
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
SetAX (Regs, RetVal);
|
2013-05-20 18:20:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void PVClose (CPURegs* Regs)
|
|
|
|
{
|
|
|
|
unsigned RetVal;
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
unsigned FD = GetAX (Regs);
|
2013-05-20 18:20:14 +00:00
|
|
|
|
2016-01-05 16:45:18 +00:00
|
|
|
Print (stderr, 2, "PVClose ($%04X)\n", FD);
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
RetVal = close (FD);
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
SetAX (Regs, RetVal);
|
2013-05-20 18:20:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void PVRead (CPURegs* Regs)
|
|
|
|
{
|
|
|
|
unsigned char* Data;
|
|
|
|
unsigned RetVal, I = 0;
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
unsigned Count = GetAX (Regs);
|
2013-05-20 18:20:14 +00:00
|
|
|
unsigned Buf = PopParam (2);
|
|
|
|
unsigned FD = PopParam (2);
|
|
|
|
|
2016-01-05 16:45:18 +00:00
|
|
|
Print (stderr, 2, "PVRead ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
Data = xmalloc (Count);
|
|
|
|
|
|
|
|
RetVal = read (FD, Data, Count);
|
|
|
|
|
|
|
|
if (RetVal != (unsigned) -1) {
|
|
|
|
while (I < RetVal) {
|
|
|
|
MemWriteByte (Buf++, Data[I++]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
xfree (Data);
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
SetAX (Regs, RetVal);
|
2013-05-20 18:20:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void PVWrite (CPURegs* Regs)
|
|
|
|
{
|
|
|
|
unsigned char* Data;
|
|
|
|
unsigned RetVal, I = 0;
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
unsigned Count = GetAX (Regs);
|
2013-05-20 18:20:14 +00:00
|
|
|
unsigned Buf = PopParam (2);
|
|
|
|
unsigned FD = PopParam (2);
|
|
|
|
|
2016-01-05 16:45:18 +00:00
|
|
|
Print (stderr, 2, "PVWrite ($%04X, $%04X, $%04X)\n", FD, Buf, Count);
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
Data = xmalloc (Count);
|
|
|
|
while (I < Count) {
|
|
|
|
Data[I++] = MemReadByte (Buf++);
|
|
|
|
}
|
|
|
|
|
|
|
|
RetVal = write (FD, Data, Count);
|
|
|
|
|
|
|
|
xfree (Data);
|
|
|
|
|
2013-05-24 16:36:30 +00:00
|
|
|
SetAX (Regs, RetVal);
|
2013-05-20 18:20:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const PVFunc Hooks[] = {
|
|
|
|
PVOpen,
|
|
|
|
PVClose,
|
|
|
|
PVRead,
|
|
|
|
PVWrite,
|
2019-05-29 22:10:17 +00:00
|
|
|
PVArgs,
|
|
|
|
PVExit,
|
2013-05-20 18:20:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-05-28 19:29:55 +00:00
|
|
|
void ParaVirtInit (unsigned aArgStart, unsigned char aSPAddr)
|
2013-05-24 16:36:30 +00:00
|
|
|
/* Initialize the paravirtualization subsystem */
|
|
|
|
{
|
|
|
|
ArgStart = aArgStart;
|
2019-05-28 19:29:55 +00:00
|
|
|
SPAddr = aSPAddr;
|
2013-05-24 16:36:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void ParaVirtHooks (CPURegs* Regs)
|
|
|
|
/* Potentially execute paravirtualization hooks */
|
2013-05-20 18:20:14 +00:00
|
|
|
{
|
2022-01-08 21:29:42 +00:00
|
|
|
unsigned lo;
|
|
|
|
|
2013-05-20 18:20:14 +00:00
|
|
|
/* Check for paravirtualization address range */
|
2019-05-30 19:34:05 +00:00
|
|
|
if (Regs->PC < PARAVIRT_BASE ||
|
|
|
|
Regs->PC >= PARAVIRT_BASE + sizeof (Hooks) / sizeof (Hooks[0])) {
|
2013-05-20 18:20:14 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call paravirtualization hook */
|
2019-05-30 19:34:05 +00:00
|
|
|
Hooks[Regs->PC - PARAVIRT_BASE] (Regs);
|
2013-05-20 18:20:14 +00:00
|
|
|
|
|
|
|
/* Simulate RTS */
|
2022-01-08 21:39:30 +00:00
|
|
|
lo = Pop (Regs);
|
|
|
|
Regs->PC = lo + (Pop (Regs) << 8) + 1;
|
2013-05-20 18:20:14 +00:00
|
|
|
}
|