copy all local files to repo
cp/m files, sprites, circuit design
This commit is contained in:
74
emu/z80pack-1.9/cpmsim/srcsim/Makefile
Normal file
74
emu/z80pack-1.9/cpmsim/srcsim/Makefile
Normal file
@@ -0,0 +1,74 @@
|
||||
CFLAGS= -O -c -Wall
|
||||
LFLAGS= -s
|
||||
|
||||
OBJ = sim0.o \
|
||||
sim1.o \
|
||||
sim2.o \
|
||||
sim3.o \
|
||||
sim4.o \
|
||||
sim5.o \
|
||||
sim6.o \
|
||||
sim7.o \
|
||||
simctl.o \
|
||||
simint.o \
|
||||
iosim.o \
|
||||
simfun.o \
|
||||
simglb.o
|
||||
|
||||
all: ../auxin ../auxout ../cpmsim
|
||||
@echo "done."
|
||||
|
||||
../auxin:
|
||||
test -f ../auxin || mknod ../auxin p
|
||||
|
||||
../auxout:
|
||||
test -f ../auxout || mknod ../auxout p
|
||||
|
||||
../cpmsim : $(OBJ)
|
||||
cc $(OBJ) $(LFLAGS) -o ../cpmsim
|
||||
|
||||
sim0.c:
|
||||
lnsrc
|
||||
|
||||
sim0.o : sim0.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim0.c
|
||||
|
||||
sim1.o : sim1.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim1.c
|
||||
|
||||
sim2.o : sim2.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim2.c
|
||||
|
||||
sim3.o : sim3.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim3.c
|
||||
|
||||
sim4.o : sim4.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim4.c
|
||||
|
||||
sim5.o : sim5.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim5.c
|
||||
|
||||
sim6.o : sim6.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim6.c
|
||||
|
||||
sim7.o : sim7.c sim.h simglb.h
|
||||
cc $(CFLAGS) sim7.c
|
||||
|
||||
simctl.o : simctl.c sim.h simglb.h
|
||||
cc $(CFLAGS) simctl.c
|
||||
|
||||
simint.o : simint.c sim.h simglb.h
|
||||
cc $(CFLAGS) simint.c
|
||||
|
||||
iosim.o : iosim.c sim.h simglb.h
|
||||
cc $(CFLAGS) iosim.c
|
||||
|
||||
simfun.o : simfun.c sim.h
|
||||
cc $(CFLAGS) simfun.c
|
||||
|
||||
simglb.o : simglb.c sim.h
|
||||
cc $(CFLAGS) simglb.c
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
ulnsrc
|
868
emu/z80pack-1.9/cpmsim/srcsim/iosim.c
Normal file
868
emu/z80pack-1.9/cpmsim/srcsim/iosim.c
Normal file
@@ -0,0 +1,868 @@
|
||||
/*
|
||||
* Z80SIM - a Z80-CPU simulator
|
||||
*
|
||||
* Copyright (C) 1987-2006 by Udo Munk
|
||||
*
|
||||
* This modul contains a complex I/O-simulation for running
|
||||
* CP/M 2, CP/M 3, MP/M...
|
||||
* Please note this this doesn't emulate any hardware which
|
||||
* ever existed, we've got all virtual circuits in here!
|
||||
*
|
||||
* History:
|
||||
* 28-SEP-87 Development on TARGON/35 with AT&T Unix System V.3
|
||||
* 19-MAY-89 Additions for CP/M 3.0 und MP/M
|
||||
* 23-DEC-90 Ported to COHERENT 3.0
|
||||
* 10-JUN-92 Some optimization done
|
||||
* 25-JUN-92 Flush output of stdout only at every OUT to port 0
|
||||
* 25-JUN-92 Comments in english and ported to COHERENT 4.0
|
||||
* 05-OCT-06 modified to compile on modern POSIX OS's
|
||||
* 18-NOV-06 added a second harddisk
|
||||
*/
|
||||
|
||||
/*
|
||||
* This module contains the I/O handlers for a simulation
|
||||
* of the hardware required for a CP/M system.
|
||||
*
|
||||
* Used I/O ports:
|
||||
*
|
||||
* 0 - console status
|
||||
* 1 - console data
|
||||
*
|
||||
* 2 - printer status
|
||||
* 3 - printer data
|
||||
*
|
||||
* 4 - auxilary status
|
||||
* 5 - auxilary data
|
||||
*
|
||||
* 10 - FDC drive
|
||||
* 11 - FDC track
|
||||
* 12 - FDC sector
|
||||
* 13 - FDC command
|
||||
* 14 - FDC status
|
||||
*
|
||||
* 15 - DMA destination address low
|
||||
* 16 - DMA destination address high
|
||||
*
|
||||
* 20 - MMU initialization
|
||||
* 21 - MMU bank select
|
||||
*
|
||||
* 25 - clock command
|
||||
* 26 - clock data
|
||||
* 27 - 20ms timer causing INT, only usable in IM 1
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "sim.h"
|
||||
#include "simglb.h"
|
||||
|
||||
/*
|
||||
* Structure to describe a emulated floppy disk drive:
|
||||
* pointer to filename
|
||||
* pointer to file descriptor
|
||||
* number of tracks
|
||||
* number of sectors
|
||||
*/
|
||||
struct dskdef {
|
||||
char *fn;
|
||||
int *fd;
|
||||
unsigned int tracks;
|
||||
unsigned int sectors;
|
||||
};
|
||||
|
||||
static BYTE drive; /* current drive A..P (0..15) */
|
||||
static BYTE track; /* current track (0..255) */
|
||||
static BYTE sector; /* current sektor (0..255) */
|
||||
static BYTE status; /* status of last I/O operation on FDC */
|
||||
static BYTE dmadl; /* current DMA adresse destination low */
|
||||
static BYTE dmadh; /* current DMA adresse destination high */
|
||||
static BYTE clkcmd; /* clock command */
|
||||
static BYTE timer; /* 20ms timer */
|
||||
static int drivea; /* fd for file "drivea.cpm" */
|
||||
static int driveb; /* fd for file "driveb.cpm" */
|
||||
static int drivec; /* fd for file "drivec.cpm" */
|
||||
static int drived; /* fd for file "drived.cpm" */
|
||||
static int drivee; /* fd for file "drivee.cpm" */
|
||||
static int drivef; /* fd for file "drivef.cpm" */
|
||||
static int driveg; /* fd for file "driveg.cpm" */
|
||||
static int driveh; /* fd for file "driveh.cpm" */
|
||||
static int drivei; /* fd for file "drivei.cpm" */
|
||||
static int drivej; /* fd for file "drivej.cpm" */
|
||||
static int drivek; /* fd for file "drivek.cpm" */
|
||||
static int drivel; /* fd for file "drivel.cpm" */
|
||||
static int drivem; /* fd for file "drivem.cpm" */
|
||||
static int driven; /* fd for file "driven.cpm" */
|
||||
static int driveo; /* fd for file "driveo.cpm" */
|
||||
static int drivep; /* fd for file "drivep.cpm" */
|
||||
static int printer; /* fd for file "printer.cpm" */
|
||||
static int auxin; /* fd for pipe "auxin" */
|
||||
static int auxout; /* fd for pipe "auxout" */
|
||||
static int aux_in_eof; /* status of pipe "auxin" (<>0 means EOF) */
|
||||
static int pid_rec; /* PID of the receiving process for auxiliary */
|
||||
static char last_char; /* buffer for 1 character (console status) */
|
||||
|
||||
static struct dskdef disks[16] = {
|
||||
{ "disks/drivea.cpm", &drivea, 77, 26 },
|
||||
{ "disks/driveb.cpm", &driveb, 77, 26 },
|
||||
{ "disks/drivec.cpm", &drivec, 77, 26 },
|
||||
{ "disks/drived.cpm", &drived, 77, 26 },
|
||||
{ "disks/drivee.cpm", &drivee, -1, -1 },
|
||||
{ "disks/drivef.cpm", &drivef, -1, -1 },
|
||||
{ "disks/driveg.cpm", &driveg, -1, -1 },
|
||||
{ "disks/driveh.cpm", &driveh, -1, -1 },
|
||||
{ "disks/drivei.cpm", &drivei, 255, 128 },
|
||||
{ "disks/drivej.cpm", &drivej, 255, 128 },
|
||||
{ "disks/drivek.cpm", &drivek, -1, -1 },
|
||||
{ "disks/drivel.cpm", &drivel, -1, -1 },
|
||||
{ "disks/drivem.cpm", &drivem, -1, -1 },
|
||||
{ "disks/driven.cpm", &driven, -1, -1 },
|
||||
{ "disks/driveo.cpm", &driveo, -1, -1 },
|
||||
{ "disks/drivep.cpm", &drivep, -1, -1 }
|
||||
};
|
||||
|
||||
/*
|
||||
* MMU:
|
||||
* ===
|
||||
*
|
||||
* +--------+
|
||||
* 16KB | common |
|
||||
* +--------+
|
||||
* +--------+ +--------+ .......... +--------+
|
||||
* | | | | | |
|
||||
* 48KB | | | | .......... | |
|
||||
* | bank 0 | | bank 1 | | bank n |
|
||||
* +--------+ +--------+ .......... +--------+
|
||||
*/
|
||||
#define MAXSEG 16 /* max. number of memory banks */
|
||||
#define SEGSIZ 49152 /* size of one bank = 48KBytes */
|
||||
static char *mmu[MAXSEG]; /* MMU with pointers to the banks */
|
||||
static int selbnk; /* current bank */
|
||||
static int maxbnk; /* number of initialized banks */
|
||||
|
||||
/*
|
||||
* Forward declaration of the I/O handlers for all used ports
|
||||
*/
|
||||
static BYTE io_trap(void);
|
||||
static BYTE cond_in(void), cond_out(BYTE), cons_in(void), cons_out(BYTE);
|
||||
static BYTE prtd_in(void), prtd_out(BYTE), prts_in(void), prts_out(BYTE);
|
||||
static BYTE auxd_in(void), auxd_out(BYTE), auxs_in(void), auxs_out(BYTE);
|
||||
static BYTE fdcd_in(void), fdcd_out(BYTE);
|
||||
static BYTE fdct_in(void), fdct_out(BYTE);
|
||||
static BYTE fdcs_in(void), fdcs_out(BYTE);
|
||||
static BYTE fdco_in(void), fdco_out(BYTE);
|
||||
static BYTE fdcx_in(void), fdcx_out(BYTE);
|
||||
static BYTE dmal_in(void), dmal_out(BYTE);
|
||||
static BYTE dmah_in(void), dmah_out(BYTE);
|
||||
static BYTE mmui_in(void), mmui_out(BYTE), mmus_in(void), mmus_out(BYTE);
|
||||
static BYTE clkc_in(void), clkc_out(BYTE), clkd_in(void), clkd_out(BYTE);
|
||||
static BYTE time_in(void), time_out(BYTE);
|
||||
static void int_timer(int);
|
||||
|
||||
static int to_bcd(int), get_date(struct tm *);
|
||||
|
||||
/*
|
||||
* This array contains two function pointer for every
|
||||
* active port, one for input and one for output.
|
||||
*/
|
||||
static BYTE (*port[256][2]) () = {
|
||||
{ cons_in, cons_out }, /* port 0 */
|
||||
{ cond_in, cond_out }, /* port 1 */
|
||||
{ prts_in, prts_out }, /* port 2 */
|
||||
{ prtd_in, prtd_out }, /* port 3 */
|
||||
{ auxs_in, auxs_out }, /* port 4 */
|
||||
{ auxd_in, auxd_out }, /* port 5 */
|
||||
{ io_trap, io_trap }, /* port 6 */
|
||||
{ io_trap, io_trap }, /* port 7 */
|
||||
{ io_trap, io_trap }, /* port 8 */
|
||||
{ io_trap, io_trap }, /* port 9 */
|
||||
{ fdcd_in, fdcd_out }, /* port 10 */
|
||||
{ fdct_in, fdct_out }, /* port 11 */
|
||||
{ fdcs_in, fdcs_out }, /* port 12 */
|
||||
{ fdco_in, fdco_out }, /* port 13 */
|
||||
{ fdcx_in, fdcx_out }, /* port 14 */
|
||||
{ dmal_in, dmal_out }, /* port 15 */
|
||||
{ dmah_in, dmah_out }, /* port 16 */
|
||||
{ io_trap, io_trap }, /* port 17 */
|
||||
{ io_trap, io_trap }, /* port 18 */
|
||||
{ io_trap, io_trap }, /* port 19 */
|
||||
{ mmui_in, mmui_out }, /* port 20 */
|
||||
{ mmus_in, mmus_out }, /* port 21 */
|
||||
{ io_trap, io_trap }, /* port 22 */
|
||||
{ io_trap, io_trap }, /* port 23 */
|
||||
{ io_trap, io_trap }, /* port 24 */
|
||||
{ clkc_in, clkc_out }, /* port 25 */
|
||||
{ clkd_in, clkd_out }, /* port 26 */
|
||||
{ time_in, time_out } /* port 27 */
|
||||
};
|
||||
|
||||
/*
|
||||
* This function initializes the I/O handlers:
|
||||
* 1. Initialize all unused ports with the I/O trap handler.
|
||||
* 2. Initialize the MMU with NULL pointers.
|
||||
* 3. Open the files which emulates the disk drives. The file
|
||||
* for drive A must be opened, or CP/M can't be booted.
|
||||
* Errors for opening one of the other 15 drives results
|
||||
* in a NULL pointer for fd in the dskdef structure,
|
||||
* so that this drive can't be used.
|
||||
* 4. Create and open the file "printer.cpm" for emulation
|
||||
* of a printer.
|
||||
* 5. Fork the process for receiving from the serial port.
|
||||
* 6. Open the named pipes "auxin" and "auxout" for simulation
|
||||
* of a serial port.
|
||||
*/
|
||||
void init_io(void)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 28; i <= 255; i++) {
|
||||
port[i][0] = io_trap;
|
||||
port[i][1] = io_trap;
|
||||
}
|
||||
for (i = 0; i < MAXSEG; i++)
|
||||
mmu[i] = NULL;
|
||||
if ((*disks[0].fd = open(disks[0].fn, O_RDWR)) == -1) {
|
||||
perror("file disks/drivea.cpm");
|
||||
exit(1);
|
||||
}
|
||||
for (i = 1; i <= 15; i++)
|
||||
if ((*disks[i].fd = open(disks[i].fn, O_RDWR)) == -1)
|
||||
disks[i].fd = NULL;
|
||||
if ((printer = creat("printer.cpm", 0644)) == -1) {
|
||||
perror("file printer.cpm");
|
||||
exit(1);
|
||||
}
|
||||
pid_rec = fork();
|
||||
switch (pid_rec) {
|
||||
case -1:
|
||||
puts("can't fork");
|
||||
exit(1);
|
||||
case 0:
|
||||
execlp("./receive", "receive", "auxiliary.cpm", (char *) NULL);
|
||||
puts("can't exec receive process");
|
||||
exit(1);
|
||||
}
|
||||
if ((auxin = open("auxin", O_RDONLY | O_NDELAY)) == -1) {
|
||||
perror("pipe auxin");
|
||||
exit(1);
|
||||
}
|
||||
if ((auxout = open("auxout", O_WRONLY)) == -1) {
|
||||
perror("pipe auxout");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function stops the I/O handlers:
|
||||
*
|
||||
* 1. The files emulating the disk drives are closed.
|
||||
* 2. The file "printer.com" emulating a printer is closed.
|
||||
* 3. The named pipes "auxin" and "auxout" are closed.
|
||||
* 4. The receiving process for the serial port is stopped.
|
||||
*/
|
||||
void exit_io(void)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i <= 15; i++)
|
||||
if (disks[i].fd != NULL)
|
||||
close(*disks[i].fd);
|
||||
close(printer);
|
||||
close(auxin);
|
||||
close(auxout);
|
||||
kill(pid_rec, SIGHUP);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called for every IN opcode from the
|
||||
* CPU emulation. It calls the right handler for the
|
||||
* port, from which input is wanted.
|
||||
*/
|
||||
BYTE io_in(BYTE adr)
|
||||
{
|
||||
return((*port[adr][0]) ());
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called for every OUT opcode from the
|
||||
* CPU emulation. It calls the right handler for the port,
|
||||
* to which output is wanted.
|
||||
*/
|
||||
BYTE io_out(BYTE adr, BYTE data)
|
||||
{
|
||||
(*port[adr][1]) (data);
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O trap handler
|
||||
*/
|
||||
static BYTE io_trap(void)
|
||||
{
|
||||
if (i_flag) {
|
||||
cpu_error = IOTRAP;
|
||||
cpu_state = STOPPED;
|
||||
}
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read console status:
|
||||
* 0xff : input available
|
||||
* 0x00 : no input available
|
||||
*/
|
||||
static BYTE cons_in(void)
|
||||
{
|
||||
register int flags, readed;
|
||||
|
||||
if (last_char)
|
||||
return((BYTE) 0xff);
|
||||
if (cntl_c)
|
||||
return((BYTE) 0xff);
|
||||
if (cntl_bs)
|
||||
return((BYTE) 0xff);
|
||||
else {
|
||||
flags = fcntl(0, F_GETFL, 0);
|
||||
fcntl(0, F_SETFL, flags | O_NDELAY);
|
||||
readed = read(0, &last_char, 1);
|
||||
fcntl(0, F_SETFL, flags);
|
||||
if (readed == 1)
|
||||
return((BYTE) 0xff);
|
||||
}
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write console status:
|
||||
* no reaction
|
||||
*/
|
||||
static BYTE cons_out(BYTE data)
|
||||
{
|
||||
data = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read console data:
|
||||
* read one character from the terminal without echo
|
||||
* and character transformations
|
||||
*/
|
||||
static BYTE cond_in(void)
|
||||
{
|
||||
char c;
|
||||
|
||||
aborted:
|
||||
if (last_char) {
|
||||
c = last_char;
|
||||
last_char = '\0';
|
||||
} else if (cntl_c) {
|
||||
cntl_c--;
|
||||
c = 0x03;
|
||||
} else if (cntl_bs) {
|
||||
cntl_bs--;
|
||||
c = 0x1c;
|
||||
} else if (read(0, &c, 1) != 1) {
|
||||
goto aborted;
|
||||
}
|
||||
return((BYTE) c);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write console data:
|
||||
* the output is written to the terminal
|
||||
*/
|
||||
static BYTE cond_out(BYTE data)
|
||||
{
|
||||
while ((write(fileno(stdout), (char *) &data, 1)) != 1)
|
||||
;
|
||||
fflush(stdout);
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read printer status:
|
||||
* the printer is ready all the time
|
||||
*/
|
||||
static BYTE prts_in(void)
|
||||
{
|
||||
return((BYTE) 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write printer status:
|
||||
* no reaction
|
||||
*/
|
||||
static BYTE prts_out(BYTE data)
|
||||
{
|
||||
data = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read printer data:
|
||||
* always read a 0 from the printer
|
||||
*/
|
||||
static BYTE prtd_in(void)
|
||||
{
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write printer data:
|
||||
* the output is written to file "printer.cpm"
|
||||
*/
|
||||
static BYTE prtd_out(BYTE data)
|
||||
{
|
||||
if (data != '\r')
|
||||
while ((write(printer, (char *) &data, 1)) != 1)
|
||||
;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read aux status:
|
||||
* return EOF status of the aux device
|
||||
*/
|
||||
static BYTE auxs_in(void)
|
||||
{
|
||||
return((BYTE) aux_in_eof);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write aux status:
|
||||
* change EOF status of the aux device
|
||||
*/
|
||||
static BYTE auxs_out(BYTE data)
|
||||
{
|
||||
aux_in_eof = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read aux data:
|
||||
* read next byte from pipe "auxin"
|
||||
*/
|
||||
static BYTE auxd_in(void)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (read(auxin, &c, 1) == 1)
|
||||
return((BYTE) c);
|
||||
else {
|
||||
aux_in_eof = 0xff;
|
||||
return((BYTE) 0x1a); /* CP/M EOF */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write aux data:
|
||||
* write output to pipe "auxout"
|
||||
*/
|
||||
static BYTE auxd_out(BYTE data)
|
||||
{
|
||||
if (data != '\r')
|
||||
write(auxout, (char *) &data, 1);
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read FDC drive:
|
||||
* return the current drive
|
||||
*/
|
||||
static BYTE fdcd_in(void)
|
||||
{
|
||||
return((BYTE) drive);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write FDC drive:
|
||||
* set the current drive
|
||||
*/
|
||||
static BYTE fdcd_out(BYTE data)
|
||||
{
|
||||
drive = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read FDC track:
|
||||
* return the current track
|
||||
*/
|
||||
static BYTE fdct_in(void)
|
||||
{
|
||||
return((BYTE) track);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write FDC track:
|
||||
* set the current track
|
||||
*/
|
||||
static BYTE fdct_out(BYTE data)
|
||||
{
|
||||
track = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read FDC sector
|
||||
* return the current sector
|
||||
*/
|
||||
static BYTE fdcs_in(void)
|
||||
{
|
||||
return((BYTE) sector);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write FDC sector:
|
||||
* set the current sector
|
||||
*/
|
||||
static BYTE fdcs_out(BYTE data)
|
||||
{
|
||||
sector = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read FDC command:
|
||||
* always returns 0
|
||||
*/
|
||||
static BYTE fdco_in(void)
|
||||
{
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write FDC command:
|
||||
* transfer one sector in the wanted direction,
|
||||
* 0 = read, 1 = write
|
||||
*
|
||||
* The status byte of the FDC is set as follows:
|
||||
* 0 - ok
|
||||
* 1 - illegal drive
|
||||
* 2 - illegal track
|
||||
* 3 - illegal sector
|
||||
* 4 - seek error
|
||||
* 5 - read error
|
||||
* 6 - write error
|
||||
* 7 - illegal command to FDC
|
||||
*/
|
||||
static BYTE fdco_out(BYTE data)
|
||||
{
|
||||
register long pos;
|
||||
if (disks[drive].fd == NULL) {
|
||||
status = 1;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
if (track > disks[drive].tracks) {
|
||||
status = 2;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
if (sector > disks[drive].sectors) {
|
||||
status = 3;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
pos = (((long)track) * ((long)disks[drive].sectors) + sector - 1) << 7;
|
||||
if (lseek(*disks[drive].fd, pos, 0) == -1L) {
|
||||
status = 4;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
switch (data) {
|
||||
case 0: /* read */
|
||||
if (read(*disks[drive].fd, (char *) ram + (dmadh << 8) +
|
||||
dmadl, 128) != 128)
|
||||
status = 5;
|
||||
else
|
||||
status = 0;
|
||||
break;
|
||||
case 1: /* write */
|
||||
if (write(*disks[drive].fd, (char *) ram + (dmadh << 8) +
|
||||
dmadl, 128) != 128)
|
||||
status = 6;
|
||||
else
|
||||
status = 0;
|
||||
break;
|
||||
default: /* illegal command */
|
||||
status = 7;
|
||||
break;
|
||||
}
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read FDC status:
|
||||
* returns status of last FDC operation,
|
||||
* 0 = ok, else some error
|
||||
*/
|
||||
static BYTE fdcx_in(void)
|
||||
{
|
||||
return((BYTE) status);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write FDC status:
|
||||
* no reaction
|
||||
*/
|
||||
static BYTE fdcx_out(BYTE data)
|
||||
{
|
||||
data = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read lower byte of DMA address:
|
||||
* return lower byte of current DMA address
|
||||
*/
|
||||
static BYTE dmal_in(void)
|
||||
{
|
||||
return((BYTE) dmadl);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write lower byte of DMA address:
|
||||
* set lower byte of DMA address
|
||||
*/
|
||||
static BYTE dmal_out(BYTE data)
|
||||
{
|
||||
dmadl = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read higher byte of DMA address:
|
||||
* return higher byte of current DMA address
|
||||
*/
|
||||
static BYTE dmah_in(void)
|
||||
{
|
||||
return((BYTE) dmadh);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write higher byte of DMA address:
|
||||
* set higher byte of the DMA address
|
||||
*/
|
||||
static BYTE dmah_out(BYTE data)
|
||||
{
|
||||
dmadh = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read MMU initialization:
|
||||
* return number of initialized MMU banks
|
||||
*/
|
||||
static BYTE mmui_in(void)
|
||||
{
|
||||
return((BYTE) maxbnk);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write MMU initialization:
|
||||
* for the FIRST call the memory for the wanted number of banks
|
||||
* is allocated and pointers to the memory is stored in the MMU array
|
||||
*/
|
||||
static BYTE mmui_out(BYTE data)
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (mmu[0] != NULL)
|
||||
return((BYTE) 0);
|
||||
if (data > MAXSEG) {
|
||||
printf("Try to init %d banks, available %d banks\n",
|
||||
data, MAXSEG);
|
||||
exit(1);
|
||||
}
|
||||
for (i = 0; i < data; i++) {
|
||||
if ((mmu[i] = malloc(SEGSIZ)) == NULL) {
|
||||
printf("can't allocate memory for bank %d\n", i+1);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
maxbnk = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read MMU bank select:
|
||||
* return current selected MMU bank
|
||||
*/
|
||||
static BYTE mmus_in(void)
|
||||
{
|
||||
return((BYTE) selbnk);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write MMU bank select:
|
||||
* if the current selected bank is not equal the wanted bank,
|
||||
* the current bank is saved. Then the memory of the wanted
|
||||
* bank is copied into the CPU address space and this bank is
|
||||
* set to be the current one now.
|
||||
*/
|
||||
static BYTE mmus_out(BYTE data)
|
||||
{
|
||||
if (data > maxbnk) {
|
||||
printf("Try to select unallocated bank %d\n", data);
|
||||
exit(1);
|
||||
}
|
||||
if (data == selbnk)
|
||||
return((BYTE) 0);
|
||||
memcpy(mmu[selbnk], (char *) ram, SEGSIZ);
|
||||
memcpy((char *) ram, mmu[data], SEGSIZ);
|
||||
selbnk = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read clock command:
|
||||
* return last clock command
|
||||
*/
|
||||
static BYTE clkc_in(void)
|
||||
{
|
||||
return(clkcmd);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write clock command:
|
||||
* set the wanted clock command
|
||||
*/
|
||||
static BYTE clkc_out(BYTE data)
|
||||
{
|
||||
clkcmd = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read clock data:
|
||||
* dependent from the last clock command the following
|
||||
* informations are given from the system clock:
|
||||
* 0 - seconds in BCD
|
||||
* 1 - minutes in BCD
|
||||
* 2 - hours in BCD
|
||||
* 3 - low byte number of days since 1.1.1978
|
||||
* 4 - high byte number of days since 1.1.1978
|
||||
* for every other clock command a 0 is returned
|
||||
*/
|
||||
static BYTE clkd_in(void)
|
||||
{
|
||||
register struct tm *t;
|
||||
register int val;
|
||||
time_t Time;
|
||||
|
||||
time(&Time);
|
||||
t = localtime(&Time);
|
||||
switch(clkcmd) {
|
||||
case 0: /* seconds in BCD */
|
||||
val = to_bcd(t->tm_sec);
|
||||
break;
|
||||
case 1: /* minutes in BCD */
|
||||
val = to_bcd(t->tm_min);
|
||||
break;
|
||||
case 2: /* hours in BCD */
|
||||
val = to_bcd(t->tm_hour);
|
||||
break;
|
||||
case 3: /* low byte days */
|
||||
val = get_date(t) & 255;
|
||||
break;
|
||||
case 4: /* high byte days */
|
||||
val = get_date(t) >> 8;
|
||||
break;
|
||||
default:
|
||||
val = 0;
|
||||
break;
|
||||
}
|
||||
return((BYTE) val);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write clock data:
|
||||
* under UNIX the system clock only can be set by the
|
||||
* super user, so we do nothing here
|
||||
*/
|
||||
static BYTE clkd_out(BYTE data)
|
||||
{
|
||||
data = data;
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an integer to BCD
|
||||
*/
|
||||
static int to_bcd(int val)
|
||||
{
|
||||
register int i = 0;
|
||||
|
||||
while (val >= 10) {
|
||||
i += val / 10;
|
||||
i <<= 4;
|
||||
val %= 10;
|
||||
}
|
||||
i += val;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate number of days since 1.1.1978
|
||||
* The Y2K bug here is intentional, CP/M 3 has a Y2K bug fix
|
||||
*/
|
||||
static int get_date(struct tm *t)
|
||||
{
|
||||
register int i;
|
||||
register int val = 0;
|
||||
|
||||
for (i = 1978; i < 1900 + t->tm_year; i++) {
|
||||
val += 365;
|
||||
if (i % 4 == 0)
|
||||
val++;
|
||||
}
|
||||
val += t->tm_yday + 1;
|
||||
return(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for write timer
|
||||
*/
|
||||
static BYTE time_out(BYTE data)
|
||||
{
|
||||
static struct itimerval tim;
|
||||
static struct sigaction newact;
|
||||
|
||||
if (data == 1) {
|
||||
timer = 1;
|
||||
newact.sa_handler = int_timer;
|
||||
sigaction(SIGALRM, &newact, NULL);
|
||||
tim.it_value.tv_sec = 0;
|
||||
tim.it_value.tv_usec = 20000;
|
||||
tim.it_interval.tv_sec = 0;
|
||||
tim.it_interval.tv_usec = 20000;
|
||||
setitimer(ITIMER_REAL, &tim, NULL);
|
||||
} else {
|
||||
timer = 0;
|
||||
newact.sa_handler = SIG_IGN;
|
||||
sigaction(SIGALRM, &newact, NULL);
|
||||
tim.it_value.tv_sec = 0;
|
||||
tim.it_value.tv_usec = 0;
|
||||
setitimer(ITIMER_REAL, &tim, NULL);
|
||||
}
|
||||
return((BYTE) 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* I/O handler for read timer
|
||||
*/
|
||||
static BYTE time_in(void)
|
||||
{
|
||||
return(timer);
|
||||
}
|
||||
|
||||
/*
|
||||
* timer interrupt causes maskerable CPU interrupt
|
||||
*/
|
||||
static void int_timer(int sig)
|
||||
{
|
||||
int_type = INT_INT;
|
||||
}
|
14
emu/z80pack-1.9/cpmsim/srcsim/lnsrc
Executable file
14
emu/z80pack-1.9/cpmsim/srcsim/lnsrc
Executable file
@@ -0,0 +1,14 @@
|
||||
# use this to link the common parts of Z80 simulation
|
||||
|
||||
ln ../../z80sim/sim0.c sim0.c
|
||||
ln ../../z80sim/sim1.c sim1.c
|
||||
ln ../../z80sim/sim2.c sim2.c
|
||||
ln ../../z80sim/sim3.c sim3.c
|
||||
ln ../../z80sim/sim4.c sim4.c
|
||||
ln ../../z80sim/sim5.c sim5.c
|
||||
ln ../../z80sim/sim6.c sim6.c
|
||||
ln ../../z80sim/sim7.c sim7.c
|
||||
ln ../../z80sim/simfun.c simfun.c
|
||||
ln ../../z80sim/simint.c simint.c
|
||||
ln ../../z80sim/simglb.c simglb.c
|
||||
ln ../../z80sim/simglb.h simglb.h
|
96
emu/z80pack-1.9/cpmsim/srcsim/sim.h
Normal file
96
emu/z80pack-1.9/cpmsim/srcsim/sim.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Z80SIM - a Z80-CPU simulator
|
||||
*
|
||||
* Copyright (C) 1987-2006 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 28-SEP-87 Develoment on TARGON/35 with AT&T Unix System V.3
|
||||
* 11-JAN-89 Release 1.1
|
||||
* 08-FEB-89 Release 1.2
|
||||
* 13-MAR-89 Release 1.3
|
||||
* 09-FEB-90 Release 1.4 Ported to TARGON/31 M10/30
|
||||
* 23-DEC-90 Release 1.5 Ported to COHERENT 3.0
|
||||
* 10-JUN-92 Release 1.6 long casting problem solved with COHERENT 3.2
|
||||
* and some optimization
|
||||
* 25-JUN-92 Release 1.7 comments in english
|
||||
* 02-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following defines may be activated, commented or modified
|
||||
* by user for her/his own purpose.
|
||||
*/
|
||||
#define WANT_INT /* interrupt for MP/M */
|
||||
/*#define WANT_SPC*/ /* CP/M doesn't work with SP over-/underrun */
|
||||
/*#define WANT_PCC*/ /* CP/M doesn't work with PC overrun */
|
||||
/*#define CNTL_C*/ /* don't abort simulation with cntl-c */
|
||||
#define CNTL_BS /* emergency exit with cntl-\ :-) */
|
||||
/*#define CNTL_Z*/ /* don't suspend simulation with cntl-z */
|
||||
#define WANT_TIM /* run length measurement needed to adjust CPU speed */
|
||||
/*#define HISIZE 1000*//* no history */
|
||||
/*#define SBSIZE 10*/ /* no breakpoints */
|
||||
|
||||
/*
|
||||
* The following lines of this file should not be modified by user
|
||||
*/
|
||||
#define COPYR "Copyright (C) 1987-2006 by Udo Munk"
|
||||
#define RELEASE "1.9"
|
||||
|
||||
#define LENCMD 80 /* length of command buffers etc */
|
||||
|
||||
#define S_FLAG 128 /* bit definitions of CPU flags */
|
||||
#define Z_FLAG 64
|
||||
#define N2_FLAG 32
|
||||
#define H_FLAG 16
|
||||
#define N1_FLAG 8
|
||||
#define P_FLAG 4
|
||||
#define N_FLAG 2
|
||||
#define C_FLAG 1
|
||||
|
||||
/* operation of simulated CPU */
|
||||
#define SINGLE_STEP 0 /* single step */
|
||||
#define CONTIN_RUN 1 /* continual run */
|
||||
#define STOPPED 0 /* stop CPU because of error */
|
||||
|
||||
/* causes of error */
|
||||
#define NONE 0 /* no error */
|
||||
#define OPHALT 1 /* HALT op-code trap */
|
||||
#define IOTRAP 2 /* IN/OUT trap */
|
||||
#define OPTRAP1 3 /* illegal 1 byte op-code trap */
|
||||
#define OPTRAP2 4 /* illegal 2 byte op-code trap */
|
||||
#define OPTRAP4 5 /* illegal 4 byte op-code trap */
|
||||
#define USERINT 6 /* user interrupt */
|
||||
|
||||
/* type of CPU interrupt */
|
||||
#define INT_NONE 0
|
||||
#define INT_NMI 1 /* non maskable interrupt */
|
||||
#define INT_INT 2 /* maskable interrupt */
|
||||
|
||||
typedef unsigned short WORD; /* 16 bit unsigned */
|
||||
typedef unsigned char BYTE; /* 8 bit unsigned */
|
||||
|
||||
#ifdef HISIZE
|
||||
struct history { /* structure of a history entry */
|
||||
WORD h_adr; /* address of execution */
|
||||
WORD h_af; /* register AF */
|
||||
WORD h_bc; /* register BC */
|
||||
WORD h_de; /* register DE */
|
||||
WORD h_hl; /* register HL */
|
||||
WORD h_ix; /* register IX */
|
||||
WORD h_iy; /* register IY */
|
||||
WORD h_sp; /* register SP */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef SBSIZE
|
||||
struct softbreak { /* structure of a breakpoint */
|
||||
WORD sb_adr; /* address of breakpoint */
|
||||
BYTE sb_oldopc; /* op-code at address of breakpoint */
|
||||
int sb_passcount; /* pass counter of breakpoint */
|
||||
int sb_pass; /* no. of pass to break */
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef isxdigit
|
||||
#define isxdigit(c) ((c<='f'&&c>='a')||(c<='F'&&c>='A')||(c<='9'&&c>='0'))
|
||||
#endif
|
92
emu/z80pack-1.9/cpmsim/srcsim/simctl.c
Normal file
92
emu/z80pack-1.9/cpmsim/srcsim/simctl.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Z80SIM - a Z80-CPU simulator
|
||||
*
|
||||
* Copyright (C) 1987-2006 by Udo Munk
|
||||
*
|
||||
* History:
|
||||
* 28-SEP-87 Development on TARGON/35 with AT&T Unix System V.3
|
||||
* 14-MAR-89 new option -l
|
||||
* 23-DEC-90 Ported to COHERENT 3.0
|
||||
* 06-OCT-06 modified to compile on modern POSIX OS's
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include "sim.h"
|
||||
#include "simglb.h"
|
||||
|
||||
extern void cpu(void);
|
||||
|
||||
struct termios old_term, new_term;
|
||||
|
||||
/*
|
||||
* This function gets the CP/M boot sector from first track/sector
|
||||
* of disk drive A (file drivea.cpm) into memory started at 0.
|
||||
* Then the Z80 CPU emulation is started and the system should boot.
|
||||
*/
|
||||
void mon(void)
|
||||
{
|
||||
register int fd;
|
||||
|
||||
if (!l_flag) {
|
||||
if ((fd = open("disks/drivea.cpm", O_RDONLY)) == -1) {
|
||||
perror("file disks/drivea.cpm");
|
||||
return;
|
||||
}
|
||||
if (read(fd, (char *) ram, 128) != 128) {
|
||||
perror("file disks/drivea.cpm");
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
tcgetattr(0, &old_term);
|
||||
new_term = old_term;
|
||||
new_term.c_lflag &= ~(ICANON | ECHO);
|
||||
new_term.c_iflag &= ~(IXON | IXANY | IXOFF);
|
||||
new_term.c_iflag &= ~(IGNCR | ICRNL | INLCR);
|
||||
new_term.c_cc[VMIN] = 1;
|
||||
#ifndef CNTL_Z
|
||||
new_term.c_cc[VSUSP] = 0;
|
||||
#endif
|
||||
tcsetattr(0, TCSADRAIN, &new_term);
|
||||
|
||||
cpu_state = CONTIN_RUN;
|
||||
cpu_error = NONE;
|
||||
cpu();
|
||||
|
||||
tcsetattr(0, TCSADRAIN, &old_term);
|
||||
|
||||
switch (cpu_error) {
|
||||
case NONE:
|
||||
break;
|
||||
case OPHALT:
|
||||
printf("\nHALT Op-Code reached at %04x\n",
|
||||
(unsigned int)(PC - ram - 1));
|
||||
break;
|
||||
case IOTRAP:
|
||||
printf("\nI/O Trap at %04x\n", (unsigned int)(PC - ram));
|
||||
break;
|
||||
case OPTRAP1:
|
||||
printf("\nOp-code trap at %04x %02x\n",
|
||||
(unsigned int)(PC - 1 - ram), *(PC - 1));
|
||||
break;
|
||||
case OPTRAP2:
|
||||
printf("\nOp-code trap at %04x %02x %02x\n",
|
||||
(unsigned int)(PC - 2 - ram), *(PC - 2), *(PC - 1));
|
||||
break;
|
||||
case OPTRAP4:
|
||||
printf("\nOp-code trap at %04x %02x %02x %02x %02x\n",
|
||||
(unsigned int)(PC - 4 - ram), *(PC - 4), *(PC - 3),
|
||||
*(PC - 2), *(PC - 1));
|
||||
break;
|
||||
case USERINT:
|
||||
puts("\nUser Interrupt");
|
||||
break;
|
||||
default:
|
||||
printf("\nUnknown error %d\n", cpu_error);
|
||||
break;
|
||||
}
|
||||
}
|
6
emu/z80pack-1.9/cpmsim/srcsim/ulnsrc
Executable file
6
emu/z80pack-1.9/cpmsim/srcsim/ulnsrc
Executable file
@@ -0,0 +1,6 @@
|
||||
# use this to unlink the common parts of Z80 simulation
|
||||
|
||||
rm sim[0-7].c
|
||||
rm simfun.c
|
||||
rm simint.c
|
||||
rm simglb.[hc]
|
Reference in New Issue
Block a user