copy all local files to repo

cp/m files, sprites, circuit design
This commit is contained in:
Amber
2020-05-15 09:07:45 -04:00
parent 8353edd599
commit 783d32a495
461 changed files with 80153 additions and 0 deletions

6
emu/z80pack-1.9/cpmsim/cpm2 Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
rm -f disks/drive[ab].cpm
ln disks/library/cpm2-1.dsk disks/drivea.cpm
ln disks/library/cpm2-2.dsk disks/driveb.cpm
cpmsim

6
emu/z80pack-1.9/cpmsim/cpm3 Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
rm -f disks/drive[ab].cpm
ln disks/library/cpm3-1.dsk disks/drivea.cpm
ln disks/library/cpm3-2.dsk disks/driveb.cpm
cpmsim

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

6
emu/z80pack-1.9/cpmsim/mpm Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
rm -f disks/drive[ab].cpm
ln disks/library/mpm-1.dsk disks/drivea.cpm
ln disks/library/mpm-2.dsk disks/driveb.cpm
cpmsim -h

View File

@@ -0,0 +1,32 @@
CFLAGS= -O -s
all: format putsys bin2hex send receive bios.bin boot.bin
@echo "done"
format: format.c
cc $(CFLAGS) -o format format.c
cp format ..
putsys: putsys.c
cc $(CFLAGS) -o putsys putsys.c
bin2hex: bin2hex.c
cc $(CFLAGS) -o bin2hex bin2hex.c
cp bin2hex ..
send: send.c
cc $(CFLAGS) -o send send.c
cp send ..
receive: receive.c
cc $(CFLAGS) -o receive receive.c
cp receive ..
bios.bin: bios.asm
z80asm -vl -sn -x bios.asm
boot.bin: boot.asm
z80asm -vl -sn boot.asm
clean:
rm -f *.lis bios.bin boot.bin format putsys bin2hex receive send

View File

@@ -0,0 +1,161 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
void help(char *name)
{
printf("%s - BINARY to Intel HEX file convertor version 1.00\n"\
"(c)BCL Vysoke Myto 2001 (benedikt@lphard.cz)\n\n",name);
printf("Usage: %s [-option] binfile hexfile\n"\
" -l Bytes to read from binary file\n"\
" -i Binary file starting offset\n"\
" -o Output file offset (where HEX data starts)\n"\
" -t Exclude EOF record\n"\
" -a Append to end of existing HEX file\n"\
" -q Quiet mode (no statistics are printed)\n", name);
}
int main(int argc,char *argv[])/*Main routine*/
{
char *ifile = NULL;
char *ofile = NULL;
char c;
FILE *inp, *outp;
int ch,csum;
int ofsa = 0;
int cnt = 0;
struct stat statbuf;
long int foffset = 0;
long int fsize = 0;
long int fsub;
long int fpoint = 0;
long int adrs = 0;
unsigned char quiet = 0;
unsigned char eofrec = 0;
unsigned char append = 0;
opterr = 0; //print error message if unknown option
while ((c = getopt (argc, argv, "l:i:o:taqv")) != -1)
switch (c) {
case 'l':
fsize = atol(optarg);
break;
case 'i':
foffset = atol(optarg);
break;
case 'o':
adrs = atol(optarg);
break;
case 't':
eofrec = 1;
break;
case 'a':
append = 1;
break;
case 'q':
quiet = 1;
break;
case 'v':
printf("%s - BINARY to Intel HEX file convertor version 1.00\n"\
"(c)BCL Vysoke Myto 2001 (benedikt@lphard.cz)\n",argv[0]);
return 0;
case '?':
help (argv[0]);
return 1;
}
if ((argc - optind) != 2) {
printf("ERROR: Missing input/output file.\n");
help(argv[0]);
return 1;
}
ifile = argv[optind];
ofile = argv[optind+1];
/*Open file check*/
if((inp = fopen(ifile, "rb")) == NULL){
printf("ERROR: Cannot open input file.\n");
return 1;
}
fseek (inp, foffset, SEEK_SET);
if (append == 0) {
if((outp = fopen(ofile, "wt")) == NULL){
printf("ERROR: Cannot open output file.\n");
return 1;
}
} else {
if((outp = fopen(ofile, "at")) == NULL){
printf("ERROR: Cannot re-open output file.\n");
return 1;
}
fseek (outp, 0, SEEK_END);
}
fstat(fileno(inp), &statbuf);
if (quiet == 0) printf("Input file size=%ld\n",statbuf.st_size);
if (foffset > statbuf.st_size) {
printf("ERROR: Input offset > input file length\n");
}
if ((fsize == 0) || (fsize > (statbuf.st_size - foffset)))
fsize = statbuf.st_size - foffset;
// fprintf(outp,":020000020000FC\n");/*Start Header*/
fsub = fsize - fpoint;
if (fsub > 0x20) {
fprintf(outp,":20%04X00",adrs);/*Hex line Header*/
csum = 0x20 + (adrs>>8) + (adrs & 0xFF);
adrs += 0x20;
}
else {
fprintf(outp, ":%02X%04X00", fsub,adrs);/*Hex line Header*/
csum = fsub + (adrs>>8) + (adrs & 0xFF);
adrs += fsub;
}
while (fsub > 0){
ch = fgetc(inp);
fprintf(outp,"%02X",ch);/*Put data*/
cnt++; fpoint++;
fsub = fsize - fpoint;
csum = ch + csum;
if((fsub == 0)||(cnt == 0x20)){
cnt = 0; csum = 0xFF & (~csum + 1);
fprintf(outp,"%02X\n",csum);/*Put checksum*/
if(fsub == 0) break;
if(adrs > 0xFFFF){
ofsa = 0x1000 + ofsa;
adrs = 0;
fprintf(outp,":02000002%04X",ofsa);/*Change offset address*/
csum = 0x02 + 0x02 + (ofsa>>8) + (ofsa & 0xFF);
csum = 0xFF & (~csum + 1);
fprintf(outp,"%02X\n", csum);
}
adrs = 0xFFFF & adrs;
if (fsub > 0x20) {
fprintf(outp,":20%04X00",adrs);/*Next Hex line Header*/
csum = 0x20 + (adrs>>8) + (adrs & 0xFF);
adrs += 0x20;
}
else {
if(fsub > 0){
fprintf(outp, ":%02X%04X00", fsub,adrs);/*Next Hex line Header*/
csum = fsub + (adrs>>8) + (adrs & 0xFF);
adrs += fsub;
}
}
}
}
if (eofrec == 0) fprintf(outp,":00000001FF\n");/*End footer*/
fflush (outp);
fstat(fileno(outp), &statbuf);
if (quiet == 0) printf("Output file size=%ld\n",statbuf.st_size);
fclose(inp);
fclose(outp);
return 0;
}

View File

@@ -0,0 +1,375 @@
; CBIOS for Z80-Simulator
;
; Copyright (C) 1988-2006 by Udo Munk
;
MSIZE EQU 64 ;cp/m version memory size in kilobytes
;
; "bias" is address offset from 3400H for memory systems
; than 16K (referred to as "b" throughout the text).
;
BIAS EQU (MSIZE-20)*1024
CCP EQU 3400H+BIAS ;base of ccp
BDOS EQU CCP+806H ;base of bdos
BIOS EQU CCP+1600H ;base of bios
CDISK EQU 0004H ;current disk number 0=A,...,15=P
IOBYTE EQU 0003H ;intel i/o byte
;
; I/O ports
;
CONSTA EQU 0 ;console status port
CONDAT EQU 1 ;console data port
PRTSTA EQU 2 ;printer status port
PRTDAT EQU 3 ;printer data port
AUXDAT EQU 5 ;auxiliary data port
FDCD EQU 10 ;fdc-port: # of drive
FDCT EQU 11 ;fdc-port: # of track
FDCS EQU 12 ;fdc-port: # of sector
FDCOP EQU 13 ;fdc-port: command
FDCST EQU 14 ;fdc-port: status
DMAL EQU 15 ;dma-port: dma address low
DMAH EQU 16 ;dma-port: dma address high
;
ORG BIOS ;origin of this program
NSECTS EQU (BIOS-CCP)/128 ;warm start sector count
;
; jump vector for individual subroutines
;
JP BOOT ;cold start
WBOOTE: JP WBOOT ;warm start
JP CONST ;console status
JP CONIN ;console character in
JP CONOUT ;console character out
JP LIST ;list character out
JP PUNCH ;punch character out
JP READER ;reader character out
JP HOME ;move head to home position
JP SELDSK ;select disk
JP SETTRK ;set track number
JP SETSEC ;set sector number
JP SETDMA ;set dma address
JP READ ;read disk
JP WRITE ;write disk
JP LISTST ;return list status
JP SECTRAN ;sector translate
;
; fixed data tables for four-drive standard
; IBM-compatible 8" disks
;
; disk parameter header for disk 00
DPBASE: DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK00,ALL00
; disk parameter header for disk 01
DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK01,ALL01
; disk parameter header for disk 02
DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK02,ALL02
; disk parameter header for disk 03
DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK03,ALL03
;
; sector translate vector for the IBM 8" disks
;
TRANS: DEFB 1,7,13,19 ;sectors 1,2,3,4
DEFB 25,5,11,17 ;sectors 5,6,7,8
DEFB 23,3,9,15 ;sectors 9,10,11,12
DEFB 21,2,8,14 ;sectors 13,14,15,16
DEFB 20,26,6,12 ;sectors 17,18,19,20
DEFB 18,24,4,10 ;sectors 21,22,23,24
DEFB 16,22 ;sectors 25,26
;
; disk parameter block, common to all IBM 8" disks
;
DPBLK: DEFW 26 ;sectors per track
DEFB 3 ;block shift factor
DEFB 7 ;block mask
DEFB 0 ;extent mask
DEFW 242 ;disk size-1
DEFW 63 ;directory max
DEFB 192 ;alloc 0
DEFB 0 ;alloc 1
DEFW 16 ;check size
DEFW 2 ;track offset
;
; fixed data tables for 4MB harddisk
;
; disk parameter header
HDBASE: DEFW HDTRA,0000H
DEFW 0000H,0000H
DEFW DIRBF,HDBLK
DEFW CHKHD,ALLHD
;
; sector translate vector for the hardisk
;
HDTRA: DEFB 1,2,3,4,5,6,7,8,9,10
DEFB 11,12,13,14,15,16,17,18,19,20
DEFB 21,22,23,24,25,26,27,28,29,30
DEFB 31,32,33,34,35,36,37,38,39,40
DEFB 41,42,43,44,45,46,47,48,49,50
DEFB 51,52,53,54,55,56,57,58,59,60
DEFB 61,62,63,64,65,66,67,68,69,70
DEFB 71,72,73,74,75,76,77,78,79,80
DEFB 81,82,83,84,85,86,87,88,89,90
DEFB 91,92,93,94,95,96,97,98,99,100
DEFB 101,102,103,104,105,106,107,108,109,110
DEFB 111,112,113,114,115,116,117,118,119,120
DEFB 121,122,123,124,125,126,127,128
;
; disk parameter block for harddisk
;
HDBLK: DEFW 128 ;sectors per track
DEFB 4 ;block shift factor
DEFB 15 ;block mask
DEFB 0 ;extent mask
DEFW 2039 ;disk size-1
DEFW 1023 ;directory max
DEFB 255 ;alloc 0
DEFB 255 ;alloc 1
DEFW 0 ;check size
DEFW 0 ;track offset
;
; signon message
;
SIGNON: DEFM '64K CP/M Vers. 2.2 (CBIOS V1.1 for Z80SIM, '
DEFM 'Copyright 1988-2006 by Udo Munk)'
DEFB 13,10,0
;
; end of fixed tables
;
; individual subroutines to perform each function
; simplest case is to just perform parameter initialization
;
BOOT: LD SP,80H ;use space below buffer for stack
LD HL,SIGNON ;print message
BOOTL: LD A,(HL)
OR A
JP Z,BOOTC
LD C,A
CALL CONOUT
INC HL
JP BOOTL
BOOTC: XOR A ;zero in the accum
LD (IOBYTE),A ;clear the iobyte
LD (CDISK),A ;select disk zero
JP GOCPM ;initialize and go to cp/m
;
; simplest case is to read the disk until all sectors loaded
;
WBOOT: LD SP,80H ;use space below buffer for stack
LD C,0 ;select disk 0
CALL SELDSK
CALL HOME ;go to track 00
;
LD B,NSECTS ;b counts # of sectors to load
LD C,0 ;c has the current track number
LD D,2 ;d has the next sector to read
; note that we begin by reading track 0, sector 2 since sector 1
; contains the cold start loader, which is skipped in a warm start
LD HL,CCP ;base of cp/m (initial load point)
LOAD1: ;load one more sector
PUSH BC ;save sector count, current track
PUSH DE ;save next sector to read
PUSH HL ;save dma address
LD C,D ;get sector address to register c
CALL SETSEC ;set sector address from register c
POP BC ;recall dma address to b,c
PUSH BC ;replace on stack for later recall
CALL SETDMA ;set dma address from b,c
; drive set to 0, track set, sector set, dma address set
CALL READ
CP 00H ;any errors?
JP NZ,WBOOT ;retry the entire boot if an error occurs
; no error, move to next sector
POP HL ;recall dma address
LD DE,128 ;dma=dma+128
ADD HL,DE ;new dma address is in h,l
POP DE ;recall sector address
POP BC ;recall number of sectors remaining, and current trk
DEC B ;sectors=sectors-1
JP Z,GOCPM ;transfer to cp/m if all have been loaded
; more sectors remain to load, check for track change
INC D
LD A,D ;sector=27?, if so, change tracks
CP 27
JP C,LOAD1 ;carry generated if sector<27
; end of current track, go to next track
LD D,1 ;begin with first sector of next track
INC C ;track=track+1
; save register state, and change tracks
CALL SETTRK ;track address set from register c
JP LOAD1 ;for another sector
; end of load operation, set parameters and go to cp/m
GOCPM:
LD A,0C3H ;c3 is a jmp instruction
LD (0),A ;for jmp to wboot
LD HL,WBOOTE ;wboot entry point
LD (1),HL ;set address field for jmp at 0
;
LD (5),A ;for jmp to bdos
LD HL,BDOS ;bdos entry point
LD (6),HL ;address field of jump at 5 to bdos
;
LD BC,80H ;default dma address is 80h
CALL SETDMA
;
EI ;enable the interrupt system
LD A,(CDISK) ;get current disk number
LD C,A ;send to the ccp
JP CCP ;go to cp/m for further processing
;
;
; simple i/o handlers
;
; console status, return 0ffh if character ready, 00h if not
;
CONST: IN A,(CONSTA) ;get console status
RET
;
; console character into register a
;
CONIN: IN A,(CONDAT) ;get character from console
RET
;
; console character output from register c
;
CONOUT: LD A,C ;get to accumulator
OUT (CONDAT),A ;send character to console
RET
;
; list character from register c
;
LIST: LD A,C ;character to register a
OUT (PRTDAT),A
RET
;
; return list status (0 if not ready, 0xff if ready)
;
LISTST: IN A,(PRTSTA)
RET
;
; punch character from register c
;
PUNCH: LD A,C ;character to register a
OUT (AUXDAT),A
RET
;
; read character into register a from reader device
;
READER: IN A,(AUXDAT)
RET
;
;
; i/o drivers for the disk follow
;
; move to the track 00 position of current drive
; translate this call into a settrk call with parameter 00
;
HOME: LD C,0 ;select track 0
JP SETTRK ;we will move to 00 on first read/write
;
; select disk given by register C
;
SELDSK: LD HL,0000H ;error return code
LD A,C
CP 4 ;must be between 0 and 3
JR NC,SELHD ;no carry if 4,5,...
; disk number is in the proper range
; compute proper disk parameter header address
OUT (FDCD),A ;selekt disk drive
LD L,A ;L=disk number 0,1,2,3
ADD HL,HL ;*2
ADD HL,HL ;*4
ADD HL,HL ;*8
ADD HL,HL ;*16 (size of each header)
LD DE,DPBASE
ADD HL,DE ;HL=.dpbase(diskno*16)
RET
SELHD: CP 8 ;select the harddisk?
RET NZ ;no, error
OUT (FDCD),A ;select disk drive
LD HL,HDBASE ;HL=hdbase for harddisk
RET
;
; set track given by register c
;
SETTRK: LD A,C
OUT (FDCT),A
RET
;
; set sector given by register c
;
SETSEC: LD A,C
OUT (FDCS),A
RET
;
; translate the sector given by BC using the
; translate table given by DE
;
SECTRAN:
EX DE,HL ;HL=.trans
ADD HL,BC ;HL=.trans(sector)
LD L,(HL) ;L = trans(sector)
LD H,0 ;HL= trans(sector)
RET ;with value in HL
;
; set dma address given by registers b and c
;
SETDMA: LD A,C ;low order address
OUT (DMAL),A
LD A,B ;high order address
OUT (DMAH),A ;in dma
RET
;
; perform read operation
;
READ: XOR A ;read command -> A
JP WAITIO ;to perform the actual i/o
;
; perform a write operation
;
WRITE: LD A,1 ;write command -> A
;
; enter here from read and write to perform the actual i/o
; operation. return a 00h in register a if the operation completes
; properly, and 01h if an error occurs during the read or write
;
; in this case, we have saved the disk number in 'diskno' (0-3)
; the track number in 'track' (0-76)
; the sector number in 'sector' (1-26)
; the dma address in 'dmaad' (0-65535)
;
WAITIO: OUT (FDCOP),A ;start i/o operation
IN A,(FDCST) ;status of i/o operation -> A
RET
;
; the remainder of the CBIOS is reserved uninitialized
; data area, and does not need to be a part of the
; system memory image (the space must be available,
; however, between "begdat" and "enddat").
;
; scratch ram area for BDOS use
;
BEGDAT EQU $ ;beginning of data area
DIRBF: DEFS 128 ;scratch directory area
ALL00: DEFS 31 ;allocation vector 0
ALL01: DEFS 31 ;allocation vector 1
ALL02: DEFS 31 ;allocation vector 2
ALL03: DEFS 31 ;allocation vector 3
ALLHD: DEFS 255 ;allocation vector harddisk
CHK00: DEFS 16 ;check vector 0
CHK01: DEFS 16 ;check vector 1
CHK02: DEFS 16 ;check vector 2
CHK03: DEFS 16 ;check vector 3
CHKHD: DEFS 0 ;check vector harddisk
;
ENDDAT EQU $ ;end of data area
DATSIZ EQU $-BEGDAT ;size of data area
END ;of BIOS

View File

@@ -0,0 +1,74 @@
; CP/M 2.2 boot-loader for Z80-Simulator
;
; Copyright (C) 1988 by Udo Munk
;
ORG 0 ; mem base of boot
;
MSIZE EQU 64 ; mem size in kbytes
;
BIAS EQU (MSIZE-20)*1024 ; offset from 20k system
CCP EQU 3400H+BIAS ; base of the ccp
BIOS EQU CCP+1600H ; base of the bios
BIOSL EQU 0300H ; length of the bios
BOOT EQU BIOS
SIZE EQU BIOS+BIOSL-CCP ; size of cp/m system
SECTS EQU SIZE/128 ; # of sectors to load
;
; I/O ports
;
DRIVE EQU 10 ; fdc-port: # of drive
TRACK EQU 11 ; fdc-port: # of track
SECTOR EQU 12 ; fdc-port: # of sector
FDCOP EQU 13 ; fdc-port: command
FDCST EQU 14 ; fdc-port: status
DMAL EQU 15 ; dma-port: dma address low
DMAH EQU 16 ; dma-port: dma address high
;
; begin the load operation
;
COLD: LD BC,2 ; b=track 0, c=sector 2
LD D,SECTS ; d=# sectors to load
LD HL,CCP ; base transfer address
LD A,0 ; select drive A
OUT (DRIVE),A
;
; load the next sector
;
LSECT: LD A,B ; set track
OUT (TRACK),A
LD A,C ; set sector
OUT (SECTOR),A
LD A,L ; set dma address low
OUT (DMAL),A
LD A,H ; set dma adress high
OUT (DMAH),A
XOR A ; read sector
OUT (FDCOP),A
IN A,(FDCST) ; get status of fdc
CP 0 ; read successful ?
JP Z,CONT ; yes, continue
HALT ; no, halt cpu
CONT:
; go to next sector if load is incomplete
DEC D ; sects=sects-1
JP Z,BOOT ; head for the bios
;
; more sectors to load
;
; we aren't using a stack, so use <sp> as scratch register
; to hold the load address increment
;
LD SP,128 ; 128 bytes per sector
ADD HL,SP ; <hl> = <hl> + 128
;
INC C ; sector = sector + 1
LD A,C
CP 27 ; last sector of track ?
JP C,LSECT ; no, go read another
;
; end of track, increment to next track
;
LD C,1 ; sector = 1
INC B ; track = track + 1
JP LSECT ; for another group
END ; of boot loader

Binary file not shown.

View File

@@ -0,0 +1,69 @@
/*
* CP/M 2.2 Formats a simulated Disk Drive
*
* Copyright (C) 1988-2006 by Udo Munk
*
* History:
* 29-APR-88 Development on TARGON/35 with AT&T Unix System V.3
* 11-MAR-93 comments in english
* 01-OCT-06 modified to compile on modern POSIX OS's
* 18-NOV-06 added a second harddisk
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <fcntl.h>
#define TRACK 77
#define SECTOR 26
#define HDTRACK 255
#define HDSECTOR 128
/*
* This program is able to format the following disk formats:
*
* drive A: 8" IBM SS,SD
* drive B: 8" IBM SS,SD
* drive C: 8" IBM SS,SD
* drive D: 8" IBM SS,SD
* drive I: 4MB harddisk
* drive J: 4MB harddisk
*/
int main(int argc, char *argv[])
{
register int i;
int fd;
char drive;
static unsigned char sector[128];
static char fn[] = "disks/drive?.cpm";
static char usage[] = "usage: format a | b | c | d | i | j";
if (argc != 2) {
puts(usage);
exit(1);
}
i = *argv[1];
if (argc != 2 ||
(i != 'a' && i != 'b' && i != 'c' && i != 'd' && i != 'i'
&& i != 'j')) {
puts(usage);
exit(1);
}
fn[11] = drive = (char) i;
memset((char *) sector, 0xe5, 128);
if ((fd = creat(fn, 0644)) == -1) {
perror("disk file");
exit(1);
}
if (drive != 'i' && drive != 'j') {
for (i = 0; i < TRACK * SECTOR; i++)
write(fd, (char *) sector, 128);
} else {
for (i = 0; i < HDTRACK * HDSECTOR; i++)
write(fd, (char *) sector, 128);
}
close(fd);
return(0);
}

View File

@@ -0,0 +1,106 @@
/*
* Write the CP/M systemfiles to system tracks of drive A
*
* Copyright (C) 1988-2006 by Udo Munk
*
* History:
* 29-APR-88 Development on TARGON/35 with AT&T Unix System V.3
* 11-MAR-93 comments in english and ported to COHERENT 4.0
* 02-OCT-06 modified to compile on modern POSIX OS's
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <memory.h>
/*
* This program writes the CP/M 2.2 OS from the following files
* onto the system tracks of the boot disk (drivea.cpm):
*
* boot loader boot.bin (Mostek binary format)
* CCP cpm.bin (binary format)
* BDOS cpm.bin (binary format)
* BIOS bios.bin (Mostek binary format)
*/
int main(void)
{
unsigned char header[3];
unsigned char sector[128];
register int i;
int fd, drivea, readed;
/* open drive A for writing */
if ((drivea = open("../disks/drivea.cpm", O_WRONLY)) == -1) {
perror("file ../disks/drivea.cpm");
exit(1);
}
/* open boot loader (boot.bin) for reading */
if ((fd = open("boot.bin", O_RDONLY)) == -1) {
perror("file boot.bin");
exit(1);
}
/* read and check 3 byte header */
if ((readed = read(fd, (char *) header, 3)) != 3) {
perror("file boot.bin");
exit(1);
}
if (header[0] != 0xff || header[1] != 0 || header[2] != 0) {
puts("start adress of boot.bin <> 0");
exit(0);
}
/* read boot loader */
memset((char *) sector, 0, 128);
read(fd, (char *) sector, 128);
close(fd);
/* and write it to disk in drive A */
write(drivea, (char *) sector, 128);
/* open CP/M system file (cpm.bin) for reading */
if ((fd = open("cpm.bin", O_RDONLY)) == -1) {
perror("file cpm.bin");
exit(1);
}
/* position to CCP in cpm.bin, needed if created with SAVE or similar */
lseek(fd, (long) 17 * 128, 0);
/* read CCP and BDOS from cpm.bin and write them to disk in drive A */
for (i = 0; i < 44; i++) {
if ((readed = read(fd, (char *) sector, 128)) != 128) {
perror("file cpm.bin");
exit(1);
}
write(drivea, (char *) sector, 128);
}
close(fd);
/* open BIOS (bios.bin) for reading */
if ((fd = open("bios.bin", O_RDONLY)) == -1) {
perror("file bios.bin");
exit(1);
}
/* read and check 3 byte header */
if ((readed = read(fd, (char *) header, 3)) != 3) {
perror("file bios.bin");
exit(1);
}
if (header[0] != 0xff) {
puts("unknown format of bios.bin");
exit(0);
}
/* read BIOS from bios.bin and write it to disk in drive A */
i = 0;
while ((readed = read(fd, (char *) sector, 128)) == 128) {
write(drivea, (char *) sector, 128);
i++;
if (i == 6) {
puts("6 sectors written, can't write any more!");
goto stop;
}
}
if (readed > 0) {
write(drivea, (char *) sector, 128);
}
stop:
close(fd);
close(drivea);
return(0);
}

View File

@@ -0,0 +1,56 @@
/*
* Receive a file out of the named pipe "auxout" from CP/M simulation
*
* Copyright (C) 1988-2006 by Udo Munk
*
* History:
* 05-OKT-88 Development on TARGON/35 with AT&T Unix System V.3
* 11-MAR-93 comments in english and ported to COHERENT 4.0
* 01-OCT-06 modified to compile on modern POSIX OS's
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
int fdin, fdout;
int main(int argc, char *argv[])
{
char c;
void int_handler(void);
if (argc != 2) {
puts("usage: receive filname &");
exit(1);
}
if ((fdin = open("auxout", O_RDONLY)) == -1) {
perror("pipe auxout");
exit(1);
}
if ((fdout = creat(argv[1], 0644)) == -1) {
perror(argv[1]);
exit(1);
}
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, int_handler);
for (;;) {
if (read(fdin, &c, 1) == 1)
if (c != '\r')
write(fdout, &c, 1);
}
return(0);
}
void int_handler(void)
{
close(fdin);
close(fdout);
exit(0);
}

View File

@@ -0,0 +1,57 @@
/*
* Sends a file through named pipe "auxin" to the CP/M simulation
*
* Copyright (C) 1988-2006 by Udo Munk
*
* History:
* 05-OKT-88 Development on TARGON/35 with AT&T Unix System V.3
* 11-MAR-93 comments in english and ported to COHERENT 4.0
* 01-OCT-06 modified to compile on modern POSIX OS's
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
void sendbuf(int);
char buf[BUFSIZ];
char cr = '\r';
int fdout, fdin;
int main(int argc,char *argv[])
{
register int readed;
if (argc != 2) {
puts("usage: send filname &");
exit(1);
}
if ((fdin = open(argv[1], O_RDONLY)) == -1) {
perror(argv[1]);
exit(1);
}
if ((fdout = open("auxin", O_WRONLY)) == -1) {
perror("pipe auxin");
exit(1);
}
while ((readed = read(fdin, buf, BUFSIZ)) == BUFSIZ)
sendbuf(BUFSIZ);
if (readed)
sendbuf(readed);
close(fdin);
close(fdout);
return(0);
}
void sendbuf(int size)
{
register char *s = buf;
while (s - buf < size) {
if (*s == '\n')
write(fdout, (char *) &cr, 1);
write(fdout, s++, 1);
}
}

View File

@@ -0,0 +1,13 @@
CFLAGS= -O -s
all: putsys boot.bin
echo done
putsys: putsys.c
cc $(CFLAGS) -o putsys putsys.c
boot.bin: boot.asm
z80asm -vl -sn -fb boot.asm
clean:
rm -f *.lis putsys boot.bin

View File

@@ -0,0 +1,582 @@
; CP/M 3 BIOS for Z80-Simulator
;
; Copyright (C) 1989-2006 by Udo Munk
;
.Z80
;
; bdos functions
;
WARM EQU 0
BDOS EQU 5
PRINT EQU 9
OPEN EQU 15
READS EQU 20
DMA EQU 26
MULTI EQU 44
;
; i/o ports
;
CONSTA EQU 0 ;console status port
CONDAT EQU 1 ;console data port
PRTSTA EQU 2 ;printer status port
PRTDAT EQU 3 ;printer data port
AUXSTA EQU 4 ;auxilary status port
AUXDAT EQU 5 ;auxilary data port
FDCD EQU 10 ;fdc-port: # of drive
FDCT EQU 11 ;fdc-port: # of track
FDCS EQU 12 ;fdc-port: # of sector
FDCOP EQU 13 ;fdc-port: command
FDCST EQU 14 ;fdc-port: status
DMAL EQU 15 ;dma-port: dma address low
DMAH EQU 16 ;dma-port: dma address high
MMUINI EQU 20 ;initialize mmu
MMUSEL EQU 21 ;bank select mmu
CLKCMD EQU 25 ;clock command
CLKDAT EQU 26 ;clock data
;
; clock commands
;
GETSEC EQU 0 ;get seconds
GETMIN EQU 1 ;get minutes
GETHOU EQU 2 ;get hours
GETDAL EQU 3 ;get days low
GETDAH EQU 4 ;get days high
;
; character device mode byte fields
;
mb$input EQU 00000001B ;device may do input
mb$output EQU 00000010B ;device may do output
mb$in$out EQU mb$input+mb$output ;device may do both
baud$none EQU 0
;
; external references in scb
;
EXTRN @civec, @covec, @aovec, @aivec, @lovec, @bnkbf
EXTRN @crdma, @crdsk, @fx, @resel, @vinfo, @usrcd
EXTRN @ermde, @date, @hour, @min, @sec, @mxtpa
;
CSEG
;
; cp/m 3 jump vector for individual subroutines
;
JP BOOT ;perform cold start initialization
WBOOTE: JP WBOOT ;perform warm start initialization
JP CONST ;check for console input char ready
JP CONIN ;read console character in
JP CONOUT ;write console character out
JP LIST ;write list character out
JP AUXOUT ;write auxiliary output char
JP AUXIN ;read auxiliary input char
JP HOME ;move head to track 0 on selcted disk
JP SELDSK ;select disk drive
JP SETTRK ;set track number
JP SETSEC ;set sector number
JP SETDMA ;set dma address
JP READ ;read specified sector
JP WRITE ;write specified sector
JP LISTST ;return list status
JP SECTRAN ;translate logical to physical sector
JP CONOST ;return output status of console
JP AUXIST ;return input status of aux. port
JP AUXOST ;return output status of aux. port
JP DEVTBL ;return address of character i/o table
JP DEVINI ;initialize character i/o devices
JP DRVTBL ;return address of disk drive table
JP MULTIO ;set number of sectors to read/write
JP FLUSH ;flush deblocking buffers
JP MOVE ;memory to memory move
JP TIME ;time set/get signal
JP SELMEM ;select bank of memory
JP SETBNK ;specify bank for dma operation
JP XMOVE ;set bank for memory dma transfer
JP 0 ;reserved for system implementor
JP 0 ;reserved for future use
JP 0 ;reserved for future use
;
; drive table
;
DRIVES: DW DPH0
DW DPH1
DW DPH2
DW DPH3
DW 0
DW 0
DW 0
DW 0
DW DPH8
DW DPH9
DW 0
DW 0
DW 0
DW 0
DW 0
DW 0
;
; fixed data tables for IBM-compatible 8" disks
;
; disk parameter header
;
DPH0: DEFW TRANS ;sector translation table
DB 0,0,0,0,0,0,0,0,0 ;bdos scratch area
DB 0 ;media flag
DEFW DPB0 ;disk parameter block
DEFW 0FFFEH ;checksum vector
DEFW 0FFFEH ;allocation vector
DEFW 0FFFEH ;directory buffer control block
DEFW 0FFFFH ;dtabcb not used
DEFW 0FFFEH ;hashing
DEFB 0 ;hash bank
DPH1: DEFW TRANS ;sector translation table
DB 0,0,0,0,0,0,0,0,0 ;bdos scratch area
DB 0 ;media flag
DEFW DPB0 ;disk parameter block
DEFW 0FFFEH ;checksum vector
DEFW 0FFFEH ;allocation vector
DEFW 0FFFEH ;directory buffer control block
DEFW 0FFFFH ;dtabcb not used
DEFW 0FFFEH ;hashing
DEFB 0 ;hash bank
DPH2: DEFW TRANS ;sector translation table
DB 0,0,0,0,0,0,0,0,0 ;bdos scratch area
DB 0 ;media flag
DEFW DPB0 ;disk parameter block
DEFW 0FFFEH ;checksum vector
DEFW 0FFFEH ;allocation vector
DEFW 0FFFEH ;directory buffer control block
DEFW 0FFFFH ;dtabcb not used
DEFW 0FFFEH ;hashing
DEFB 0 ;hash bank
DPH3: DEFW TRANS ;sector translation table
DB 0,0,0,0,0,0,0,0,0 ;bdos scratch area
DB 0 ;media flag
DEFW DPB0 ;disk parameter block
DEFW 0FFFEH ;checksum vector
DEFW 0FFFEH ;allocation vector
DEFW 0FFFEH ;directory buffer control block
DEFW 0FFFFH ;dtabcb not used
DEFW 0FFFEH ;hashing
DEFB 0 ;hash bank
;
; sector translate vector for the IBM 8" disk
;
TRANS: DEFB 1,7,13,19 ;sectors 1,2,3,4
DEFB 25,5,11,17 ;sectors 5,6,7,8
DEFB 23,3,9,15 ;sectors 9,10,11,12
DEFB 21,2,8,14 ;sectors 13,14,15,16
DEFB 20,26,6,12 ;sectors 17,18,19,20
DEFB 18,24,4,10 ;sectors 21,22,23,24
DEFB 16,22 ;sectors 25,26
;
; disk parameter block for the IBM 8" disk
;
DPB0: DEFW 26 ;sectors per track
DEFB 3 ;block shift factor
DEFB 7 ;block mask
DEFB 0 ;extent mask
DEFW 242 ;disk size-1
DEFW 63 ;directory max
DEFB 192 ;alloc 0
DEFB 0 ;alloc 1
DEFW 16 ;check size
DEFW 2 ;track offset
DEFB 0,0 ;physical sector size and shift
;
; fixed data tables for 4mb harddisks
;
; disk parameter header
;
DPH8: DEFW HDTRA ;sector translation table
DB 0,0,0,0,0,0,0,0,0 ;bdos scratch area
DB 0 ;media flag
DEFW DPB1 ;disk parameter block
DEFW 0FFFEH ;checksum vector
DEFW 0FFFEH ;allocation vector
DEFW 0FFFEH ;directory buffer control block
DEFW 0FFFFH ;dtabcb not used
DEFW 0FFFEH ;hashing
DEFB 0 ;hash bank
DPH9: DEFW HDTRA ;sector translation table
DB 0,0,0,0,0,0,0,0,0 ;bdos scratch area
DB 0 ;media flag
DEFW DPB1 ;disk parameter block
DEFW 0FFFEH ;checksum vector
DEFW 0FFFEH ;allocation vector
DEFW 0FFFEH ;directory buffer control block
DEFW 0FFFFH ;dtabcb not used
DEFW 0FFFEH ;hashing
DEFB 0 ;hash bank
;
; sector translate vector for 4mb harddisk
;
HDTRA: DEFB 1,2,3,4,5,6,7,8,9,10
DEFB 11,12,13,14,15,16,17,18,19,20
DEFB 21,22,23,24,25,26,27,28,29,30
DEFB 31,32,33,34,35,36,37,38,39,40
DEFB 41,42,43,44,45,46,47,48,49,50
DEFB 51,52,53,54,55,56,57,58,59,60
DEFB 61,62,63,64,65,66,67,68,69,70
DEFB 71,72,73,74,75,76,77,78,79,80
DEFB 81,82,83,84,85,86,87,88,89,90
DEFB 91,92,93,94,95,96,97,98,99,100
DEFB 101,102,103,104,105,106,107,108,109,110
DEFB 111,112,113,114,115,116,117,118,119,120
DEFB 121,122,123,124,125,126,127,128
;
; disk parameter block for 4mb harddisk
;
DPB1: DEFW 128 ;sectors per track
DEFB 4 ;block shift factor
DEFB 15 ;block mask
DEFB 0 ;extent mask
DEFW 2039 ;disk size-1
DEFW 1023 ;directory max
DEFB 255 ;alloc 0
DEFB 255 ;alloc 1
DEFW 0 ;check size
DEFW 0 ;track offset
DEFB 0,0 ;physical sector size and shift
;
; character device table
;
CHRTBL: DEFB 'CRT '
DEFB mb$in$out
DEFB baud$none
DEFB 'LPT '
DEFB mb$output
DEFB baud$none
DEFB 'PTP '
DEFB mb$output
DEFB baud$none
DEFB 'PTR '
DEFB mb$input
DEFB baud$none
DEFB 0
;
; signon message
;
SIGNON: DEFB 13,10
DEFM 'BANKED BIOS3 V1.4 for Z80SIM, '
DEFM 'Copyright 1989-2006 by Udo Munk'
DEFB 13,10
DEFB 0
;
; small stack
;
DS 8
STACK:
;
; fcb for loading ccp
;
CCPFCB: DEFB 1,'CCP COM',0,0,0,0
DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
CCPREC: DEFB 0,0,0
;
DSEG
;
; bios error messages
;
CCPOER: DEFB 13,10,'BIOS ERROR: cannot open CCP.COM',13,10,'$'
CCPIOE: DEFB 13,10,'BIOS ERROR: reading CCP.COM',13,10,'$'
;
CSEG
;
DRIVE: DEFB 0 ;drive to select
BANK: DEFB 0 ;bank to select for dma
;
; end of fixed tables
;
; individual subroutines to perform each function
;
DSEG
;
BOOT: LD B,1 ;indicate cold boot
;
LD HL,8000H
LD (@civec),HL ;CONSOLE:=CON for input
LD (@covec),HL ;CONSOLE:=CON for output
LD HL,4000H
LD (@lovec),HL ;LST:=LPT
LD HL,2000H
LD (@aovec),HL ;AUXOUT:=PTP
LD HL,1000H
LD (@aivec),HL ;AUXIN:=PTR
;
LD A,3 ;initialize 3 memory banks
OUT (MMUINI),A
JP WBOOT1
;
CSEG
;
WBOOT: LD B,0 ;indicate warm boot
WBOOT1: LD SP,STACK
;
; initialize low memory jumps in bank 1
;
LD A,1
CALL SELMEM
;
LD A,0C3H ;jmp instruction
LD (WARM),A
LD HL,WBOOTE ;warm boot enty point
LD (WARM+1),HL
LD (BDOS),A
LD HL,(@mxtpa) ;bdos entry point
LD (BDOS+1),HL
;
; print message on cold boot
;
LD A,B
OR A
JP Z,LDCCP
LD HL,SIGNON ;print message
WBOOT2: LD A,(HL)
OR A
JP Z,LDCCP
LD C,A
CALL CONOUT
INC HL
JP WBOOT2
;
; load ccp.com into tpa
;
LDCCP: XOR A ;initialize fcb
LD (CCPFCB+15),A
LD HL,0
LD (CCPREC),HL
LD DE,CCPFCB ;open file ccp.com
LD C,OPEN
CALL BDOS
LD DE,CCPOER
INC A
JP Z,CCPERR ;print error if file not found
LD DE,0100H ;setup DMA to tpa
LD C,DMA
CALL BDOS
LD DE,128 ;read up to 16KB
LD C,MULTI
CALL BDOS
LD DE,CCPFCB ;read the ccp into memory
LD C,READS
CALL BDOS
LD DE,CCPIOE
INC A
JP NZ,0100H ;start ccp
CCPERR: LD C,PRINT ;print error message
CALL BDOS
HALT
;
; character i/o drivers
;
DEVTBL: LD HL,CHRTBL
RET
;
; character device initialization
;
DEVINI: RET
;
; console in status, return 0ffh if character ready, 00h if not
;
CONST: IN A,(CONSTA)
RET
;
; console character input from register a
;
CONIN: IN A,(CONDAT)
RET
;
; console out status, return 0ffh if ready, 00h if not
CONOST: LD A,0FFH ;console out always ready
RET
;
; console character output from register c
;
CONOUT: LD A,C ;get to accumulator
OUT (CONDAT),A ;send character to console
RET
;
; list out status, return 0ffh if ready, 00h if not
;
LISTST: LD A,0FFH ;list out always ready
RET
;
; list character output from register C
;
LIST: LD A,C
OUT (PRTDAT),A
RET
;
; auxilary input status, 0ffh if ready, 00h if not
;
AUXIST: XOR A ;never ready, hardware not available yet
RET
;
; auxilary output status, 0ffh if ready, 00h if not
;
AUXOST: XOR A ;never ready, hadware not available yet
RET
;
; auxilary input
;
AUXIN: IN A,(AUXDAT)
RET
;
; auxilary output from register c
;
AUXOUT: LD A,C
OUT (AUXDAT),A
RET
;
;
; i/o drivers for the disks
;
DRVTBL: LD HL,DRIVES
RET
;
DSEG
;
; move to the track 00 position of current drive
; translate this call into a settrk call with parameter 00
;
HOME: LD C,0 ;select track 0
JP SETTRK ;we will move to 00 on first read/write
;
; select disk given by register C
;
SELDSK: LD HL,0000H ;error return code
LD A,C
LD (DRIVE),A
CP 4 ;disk drive 1-4?
JP C,SEL1 ;go
CP 8 ;harddisk 1?
JP Z,SEL1 ;go
CP 9 ;harddisk 2?
RET NZ ;no, error
; disk number is in the proper range
; return proper disk parameter header address
SEL1: LD L,C
LD H,0
ADD HL,HL ;drive index in hl
LD BC,DRIVES
ADD HL,BC ;get pointer to dph
LD A,(HL)
INC HL
LD H,(HL)
LD L,A
LD A,(DRIVE)
OUT (FDCD),A ;selekt disk drive
RET
;
; set track given by register c
;
SETTRK: LD A,C
OUT (FDCT),A
RET
;
; set sector given by register c
;
SETSEC: LD A,C
OUT (FDCS),A
RET
;
; translate the sector given by bc using the
; translate table given by de
;
SECTRAN:
EX DE,HL ;hl=.trans
ADD HL,BC ;hl=.trans(sector)
LD L,(HL) ;l = trans(sector)
LD H,0 ;hl= trans(sector)
RET ;with value in HL
;
; set dma address given by registers b and c
;
SETDMA: LD A,C ;low order address
OUT (DMAL),A
LD A,B ;high order address
OUT (DMAH),A
RET
;
CSEG
;
; perform read operation
;
READ: LD A,(BANK) ;switch to saved bank
OUT (MMUSEL),A
XOR A ;read command -> A
JP WAITIO ;to perform the actual i/o
;
; perform write operation
;
WRITE: LD A,(BANK) ;switch to saved bank
OUT (MMUSEL),A
LD A,1 ;write command -> A
;
; enter here from read and write to perform the actual i/o
; operation. return 00h in register a if the operation completes
; properly, and 01h if an error occurs during the read or write
;
WAITIO: OUT (FDCOP),A ;start i/o operation
XOR A ;reselect bank 0
OUT (MMUSEL),A
IN A,(FDCST) ;status of i/o operation -> A
RET
;
; nothing to do
;
MULTIO: XOR A
RET
;
; nothing to do
;
FLUSH: XOR A
RET
;
; memory move
;
MOVE: EX DE,HL
LDIR
EX DE,HL
RET
;
; select memory bank
SELMEM: OUT (MMUSEL),A
RET
;
; specify memory bank for dma operation
SETBNK: LD (BANK),A
RET
;
; xmove not implemented yet, hardware missing
;
XMOVE: RET
;
; get/set time
;
TIME:
LD A,C
CP 0FFH
RET Z ;we cannot set the UNIX time from here
LD A,GETSEC ;get seconds
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (@sec),A
LD A,GETMIN ;get minutes
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (@min),A
LD A,GETHOU ;get hours
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (@hour),A
LD A,GETDAL ;get day
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (@date),A
LD A,GETDAH
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (@date+1),A
RET
;
ENDDAT EQU $ ;end
END ;of BIOS

View File

@@ -0,0 +1,67 @@
; CP/M 3 boot-loader for Z80-Simulator
;
; Copyright (C) 1989-2006 by Udo Munk
;
ORG 0 ; mem base of boot
;
BOOT EQU 0100H ; cpmldr runs at 0100H
SECTS EQU 51 ; # of sectors to load (26 * 2 - 1)
;
; I/O ports
;
DRIVE EQU 10 ; fdc-port: # of drive
TRACK EQU 11 ; fdc-port: # of track
SECTOR EQU 12 ; fdc-port: # of sector
FDCOP EQU 13 ; fdc-port: command
FDCST EQU 14 ; fdc-port: status
DMAL EQU 15 ; dma-port: dma address low
DMAH EQU 16 ; dma-port: dma address high
;
; begin the load operation
;
COLD: LD BC,2 ; b=track 0, c=sector 2
LD D,SECTS ; d=# sectors to load
LD HL,BOOT ; base transfer address
LD A,0 ; select drive A
OUT (DRIVE),A
;
; load the next sector
;
LSECT: LD A,B ; set track
OUT (TRACK),A
LD A,C ; set sector
OUT (SECTOR),A
LD A,L ; set dma address low
OUT (DMAL),A
LD A,H ; set dma adress high
OUT (DMAH),A
XOR A ; read sector
OUT (FDCOP),A
IN A,(FDCST) ; get status of fdc
CP 0 ; read successful ?
JP Z,CONT ; yes, continue
HALT ; no, halt cpu
CONT:
; go to next sector if load is incomplete
DEC D ; sects=sects-1
JP Z,BOOT ; head for the bios
;
; more sectors to load
;
; we aren't using a stack, so use <sp> as scratch register
; to hold the load address increment
;
LD SP,128 ; 128 bytes per sector
ADD HL,SP ; <hl> = <hl> + 128
;
INC C ; sector = sector + 1
LD A,C
CP 27 ; last sector of track ?
JP C,LSECT ; no, go read another
;
; end of track, increment to next track
;
LD C,1 ; sector = 1
INC B ; track = track + 1
JP LSECT ; for another group
END ; of boot loader

Binary file not shown.

View File

@@ -0,0 +1,212 @@
; CP/M 3 LDRBIOS for Z80-Simulator
;
; Copyright (C) 1989-2006 by Udo Munk
;
.Z80
;
; I/O ports
;
CONSTA EQU 0 ;console status port
CONDAT EQU 1 ;console data port
FDCD EQU 10 ;fdc-port: # of drive
FDCT EQU 11 ;fdc-port: # of track
FDCS EQU 12 ;fdc-port: # of sector
FDCOP EQU 13 ;fdc-port: command
FDCST EQU 14 ;fdc-port: status
DMAL EQU 15 ;dma-port: dma address low
DMAH EQU 16 ;dma-port: dma address high
;
CSEG
;
; jump vector for individual subroutines
; * needs to be implemented
;
JP BOOT ; * perform cold start initialization
JP WBOOT ; perform warm start initialization
JP CONST ; check for console input char ready
JP CONIN ; read console character in
JP CONOUT ; * write console character out
JP LIST ; write list character out
JP AUXOUT ; write auxiliary output char
JP AUXIN ; read auxiliary input char
JP HOME ; * move head to track 0 on selcted disk
JP SELDSK ; * select disk drive
JP SETTRK ; * set track number
JP SETSEC ; * set sector number
JP SETDMA ; * set dma address
JP READ ; * read specified sector
JP WRITE ; write specified sector
JP LISTST ; return list status
JP SECTRAN ; * translate logical to physical sector
JP CONOST ; return output status of console
JP AUXIST ; return input status of aux. port
JP AUXOST ; return output status of aux. port
JP DEVTBL ; return address of character i/o table
JP DEVINI ; initialize character i/o devices
JP DRVTBL ; return address of disk drive table
JP MULTIO ; set number of sectors to read/write
JP FLUSH ; flush deblocking buffers
JP MOVE ; * memory to memory move
JP TIME ; time set/get signal
JP SELMEM ; select bank of memory
JP SETBNK ; specify bank for dma operation
JP XMOVE ; set bank for memory dma transfer
JP 0 ; reserved for system implementor
JP 0 ; reserved for future use
JP 0 ; reserved for future use
;
; fixed data tables for a IBM-compatible 8" disk
;
; disk parameter header
;
DPH0: DEFW TRANS ;sector translation table
DB 0,0,0,0,0,0,0,0,0 ;bdos scratch area
DB 0 ;media flag
DEFW DPB0 ;disk parameter block
DEFW 0FFFEH ;checksum vector
DEFW 0FFFEH ;allocation vector
DEFW 0FFFEH ;directory buffer control block
DEFW 0FFFFH ;dtabcb not used
DEFW 0FFFFH ;hashing not used
DEFB 0 ;hash bank
;
; sector translate vector for the IBM 8" disk
;
TRANS: DEFB 1,7,13,19 ;sectors 1,2,3,4
DEFB 25,5,11,17 ;sectors 5,6,7,8
DEFB 23,3,9,15 ;sectors 9,10,11,12
DEFB 21,2,8,14 ;sectors 13,14,15,16
DEFB 20,26,6,12 ;sectors 17,18,19,20
DEFB 18,24,4,10 ;sectors 21,22,23,24
DEFB 16,22 ;sectors 25,26
;
; disk parameter block for the IBM 8" disk
;
DPB0: DEFW 26 ;sectors per track
DEFB 3 ;block shift factor
DEFB 7 ;block mask
DEFB 0 ;extent mask
DEFW 242 ;disk size-1
DEFW 63 ;directory max
DEFB 192 ;alloc 0
DEFB 0 ;alloc 1
DEFW 16 ;check size
DEFW 2 ;track offset
DEFB 0,0 ;physical sector size and shift
;
; signon message
;
SIGNON: DEFB 13,10
DEFM 'LDRBIOS3 V1.1 for Z80SIM, '
DEFM 'Copyright 1989-2006 by Udo Munk'
DEFB 13,10,0
;
; end of fixed tables
;
; individual subroutines to perform each function
;
BOOT: LD HL,SIGNON ;print message
BOOTL: LD A,(HL)
OR A
JP Z,WBOOT
LD C,A
CALL CONOUT
INC HL
JP BOOTL
;
; those are not implemented in loader bios
;
WBOOT:
CONST:
CONIN:
LIST:
AUXOUT:
AUXIN:
WRITE:
LISTST:
CONOST:
AUXIST:
AUXOST:
DEVTBL:
DEVINI:
DRVTBL:
MULTIO:
FLUSH:
TIME:
SELMEM:
SETBNK:
XMOVE: RET
;
; console character output from register c
;
CONOUT: LD A,C ;get to accumulator
OUT (CONDAT),A ;send character to console
RET
;
;
; i/o drivers for the disk follow
;
; move to the track 00 position of current drive
; translate this call into a settrk call with parameter 00
;
HOME: LD C,0 ;select track 0
JP SETTRK ;we will move to 00 on first read/write
;
; select disk given by register C
;
SELDSK: LD HL,0000H ;error return code
LD A,C
CP 0 ;we boot from drive 0 only
RET NZ ;return error
; disk number is in the proper range
; return proper disk parameter header address
OUT (FDCD),A ;selekt disk drive
LD HL,DPH0
RET
;
; set track given by register c
;
SETTRK: LD A,C
OUT (FDCT),A
RET
;
; set sector given by register c
;
SETSEC: LD A,C
OUT (FDCS),A
RET
;
; translate the sector given by BC using the
; translate table given by DE
;
SECTRAN:
EX DE,HL ;hl=.trans
ADD HL,BC ;hl=.trans(sector)
LD L,(HL) ;l = trans(sector)
LD H,0 ;hl= trans(sector)
RET ;with value in hl
;
; set dma address given by registers b and c
;
SETDMA: LD A,C ;low order address
OUT (DMAL),A
LD A,B ;high order address
OUT (DMAH),A ;in dma
RET
;
; perform read operation
;
READ: XOR A ;read command -> a
OUT (FDCOP),A ;start i/o operation
IN A,(FDCST) ;status of i/o operation -> a
RET
;
; memory move
;
MOVE: EX DE,HL
LDIR
EX DE,HL
RET
;
ENDDAT EQU $ ;end
END ;of bios

View File

@@ -0,0 +1,59 @@
/*
* Write the CP/M 3 systemfiles to system tracks of drive A
*
* Copyright (C) 1988-2006 by Udo Munk
*
* History:
* 29-APR-88 Development on TARGON/35 with AT&T Unix System V.3
* 11-MAR-93 comments in english and ported to COHERENT 4.0
* 02-OCT-06 modified to compile on modern POSIX OS's
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <memory.h>
/*
* This program writes the CP/M 3 OS from the following files
* onto the system tracks of the boot disk (drivea.cpm):
*
* boot loader boot.bin
* cpmldr cpmldr.bin
*/
int main(void)
{
unsigned char sector[128];
register int i;
int fd, drivea, readed;
/* open drive A for writing */
if ((drivea = open("../disks/drivea.cpm", O_WRONLY)) == -1) {
perror("file ../disks/drivea.cpm");
exit(1);
}
/* open boot loader (boot.bin) for reading */
if ((fd = open("boot.bin", O_RDONLY)) == -1) {
perror("file boot.bin");
exit(1);
}
/* read boot loader */
memset((char *) sector, 0, 128);
read(fd, (char *) sector, 128);
close(fd);
/* and write it to disk in drive A */
write(drivea, (char *) sector, 128);
/* open CP/M 3 cpmldr file (cpmldr.bin) for reading */
if ((fd = open("cpmldr.bin", O_RDONLY)) == -1) {
perror("file cpmldr.bin");
exit(1);
}
/* read from cpmldr.bin and write to disk in drive A */
while ((readed = read(fd, (char *) sector, 128)) == 128)
write(drivea, (char *) sector, 128);
write(drivea, (char *) sector, 128);
close(fd);
close(drivea);
return(0);
}

View File

@@ -0,0 +1,503 @@
; MP/M 2 XIOS for Z80-Simulator
;
; Copyright (C) 1989-2006 by Udo Munk
;
.Z80
CSEG
;
; i/o ports
;
CONSTA EQU 0 ;console status port
CONDAT EQU 1 ;console data port
PRTSTA EQU 2 ;printer status port
PRTDAT EQU 3 ;printer data port
AUXSTA EQU 4 ;auxilary status port
AUXDAT EQU 5 ;auxilary data port
FDCD EQU 10 ;fdc-port: # of drive
FDCT EQU 11 ;fdc-port: # of track
FDCS EQU 12 ;fdc-port: # of sector
FDCOP EQU 13 ;fdc-port: command
FDCST EQU 14 ;fdc-port: status
DMAL EQU 15 ;dma-port: dma address low
DMAH EQU 16 ;dma-port: dma address high
MMUINI EQU 20 ;initialize mmu
MMUSEL EQU 21 ;bank select mmu
CLKCMD EQU 25 ;clock command
CLKDAT EQU 26 ;clock data
TIMER EQU 27 ;interrupt timer
;
; clock commands
;
GETSEC EQU 0 ;get seconds
GETMIN EQU 1 ;get minutes
GETHOU EQU 2 ;get hours
GETDAL EQU 3 ;get days low
GETDAH EQU 4 ;get days high
;
BDOS EQU 5 ;bdos calls
SETTD EQU 104 ;bdos set time and date
;
POLL EQU 131 ;xdos poll function
PLCI0 EQU 0 ;poll console in #0
FLAGSET EQU 133 ;xdos flag set function
SYSDATA EQU 154 ;xdos syste data address
;
; jump vector for individual subroutines
;
JP COMMONBASE ;commonbase
JP WARMSTART ;warm start
JP CONST ;console status
JP CONIN ;console character in
JP CONOUT ;console character out
JP LIST ;list character out
JP PUNCH ;not used by MP/M 2
JP READER ;not used by MP/M 2
JP HOME ;move head to home
JP SELDSK ;select disk
JP SETTRK ;set track numer
JP SETSEC ;set sector number
JP SETDMA ;set dma address
JP READ ;read disk
JP WRITE ;write disk
JP LISTST ;not used by MP/M 2
JP SECTRAN ;sector translate
JP SELMEMORY ;select memory
JP POLLDEVICE ;poll device
JP STARTCLOCK ;start clock
JP STOPCLOCK ;stop clock
JP EXITREGION ;exit region
JP MAXCONSOLE ;maximum console number
JP SYSTEMINIT ;system initialization
JP IDLE ;idle prozedure
;
COMMONBASE:
JP COLDSTART
SWTUSER:
JP $-$
SWTSYS: JP $-$
PDISP: JP $-$
XDOS: JP $-$
SYSDAT: DEFW $-$
;
COLDSTART:
WARMSTART:
LD C,0
JP XDOS ;system reset, terminate prozess
;
; MP/M II V2.0 Console Bios
;
CONST:
CALL PTBLJMP ;compute and jump to handler
DW PTSTI0
;
CONIN:
CALL PTBLJMP ;compute and jump to handle
DW PTIN0
;
CONOUT:
CALL PTBLJMP ;compute and jump to handler
DW PTOUT0
;
PTSTI0: IN A,(CONSTA) ;console 0 input
RET
;
PTIN0: LD C,POLL ;poll console 0 status in
LD E,PLCI0
CALL XDOS ;poll console 0
IN A,(CONDAT) ;read character
AND 7FH ;strip parity
RET
;
PTOUT0: LD A,C ;console 0 output
OUT (CONDAT),A
RET
;
PTBLJMP: ;compute and jump to handler
LD A,D
ADD A,A ;double table index for adress offset
POP HL ;return adress of jump table
LD E,A
LD D,0
ADD HL,DE ;table index * 2 + table base
LD E,(HL) ;get handler address
INC HL
LD D,(HL)
EX DE,HL
JP (HL) ;jump to computed handler
;
LIST:
LD A,C
OUT (PRTDAT),A
RET
;
; not used by MP/M 2
PUNCH:
READER:
LISTST:
RET
;
; MP/M II V2.0 Xios
;
; select/protect memory
; BC = address of memory descriptor
SELMEMORY:
LD HL,3 ;offset memory bank in memory descriptor
ADD HL,BC
LD A,(HL) ;get bank
OUT (MMUSEL),A ;and select it
RET
;
; poll character devices
;
POLLDEVICE:
JP PTSTI0 ;poll console 0 status in
;
; start clock
;
STARTCLOCK:
LD A,0FFH
LD (TICKN),A
RET
;
; stop clock
;
STOPCLOCK:
XOR A
LD (TICKN),A
RET
;
; exit region:
; enable interrupt if not preempted or in dispatcher
;
EXITREGION:
LD A,(PREEMP)
OR A
RET NZ
EI
RET
;
; maximum console number
;
MAXCONSOLE:
LD A,1
RET
;
; system initialization
; C MP/M debugger restart #
; DE MP/M entry point for debugger
; HL BIOS jump table address
;
SYSTEMINIT:
;
;doesn't work
PUSH HL
LD C,SYSDATA ;get system data page address
CALL XDOS
CALL SETTOD ;set tod from hardware clock
POP HL
;
LD A,8 ;initialize banked memory
OUT (MMUINI),A
LD B,A
;
SYS1: DEC B
LD A,B
OUT (MMUSEL),A ;select every bank and initialize
LD A,0C3H ;jp instruction
LD (0),A
LD (38H),A
LD (1),HL
PUSH HL
LD HL,INTHND
LD (39H),HL
POP HL
JP NZ,SYS1
;
LD HL,SIGNON ;print message
SYS2: LD A,(HL)
OR A
JP Z,SYS3
OUT (CONDAT),A
INC HL
JP SYS2
;
SYS3: IM 1
LD A,1 ;enable 20ms interrupt timer
OUT (TIMER),A
EI
RET
;
; set mp/m tod from hardware clock
; hl = tod address
;
SETTOD: LD A,GETDAL
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (HL),A
INC HL
LD A,GETDAH
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (HL),A
INC HL
LD A,GETHOU
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (HL),A
INC HL
LD A,GETMIN
OUT (CLKCMD),A
IN A,(CLKDAT)
LD (HL),A
RET
;
; idle
;
IDLE: EI
HALT
RET
;
; interrupt handler
;
INTHND: LD (SVDHL),HL ;save registers
POP HL
LD (SVDRET),HL
PUSH AF
LD HL,0
ADD HL,SP
LD (SVDSP),HL
LD SP,INTSTK
PUSH DE
PUSH BC
LD A,0FFH ;set preempted flag
LD (PREEMP),A
LD A,(TICKN)
OR A ;test tick, indicates delayed process
JP Z,INTHND1
LD C,FLAGSET ;set flag #1 each tick
LD E,1
CALL XDOS
INTHND1:
LD HL,CNT50 ;decrement tick counter
DEC (HL)
JP NZ,INTDONE
LD (HL),50 ;set flag #2 each second
LD C,FLAGSET
LD E,2
CALL XDOS
INTDONE:
XOR A ;clear preempted flag
LD (PREEMP),A
POP BC ;restore registers
POP DE
LD HL,(SVDSP)
LD SP,HL
POP AF
LD HL,(SVDRET)
PUSH HL
LD HL,(PDISP+1) ;dispatch processes
PUSH HL
LD HL,(SVDHL)
RETI
;
; i/o drivers for disks
;
; move to the track 00 position of current drive
; translate this call into a settrk call with parameter 00
;
HOME: LD C,0 ;select track 0
JP SETTRK ;we will move to 00 on first read/write
;
; select disk given by register C
;
SELDSK: LD HL,0000H ;error return code
LD A,C
CP 4 ;must be between 0 and 3
JR NC,SELHD ;no carry if 4,5,...
; disk number is in the proper range
; compute proper disk parameter header address
OUT (FDCD),A ;selekt disk drive
LD L,A ;L=disk number 0,1,2,3
ADD HL,HL ;*2
ADD HL,HL ;*4
ADD HL,HL ;*8
ADD HL,HL ;*16 (size of each header)
LD DE,DPBASE
ADD HL,DE ;HL=.dpbase(diskno*16)
RET
SELHD: CP 8 ;select the harddisk?
RET NZ ;no, error
OUT (FDCD),A ;select disk drive
LD HL,HDBASE ;HL=hdbase for harddisk
RET
;
; set track given by register c
;
SETTRK: LD A,C
OUT (FDCT),A
RET
;
; set sector given by register c
;
SETSEC: LD A,C
OUT (FDCS),A
RET
;
; translate the sector given by BC using the
; translate table given by DE
;
SECTRAN:
EX DE,HL ;HL=.trans
ADD HL,BC ;HL=.trans(sector)
LD L,(HL) ;L = trans(sector)
LD H,0 ;HL= trans(sector)
RET ;with value in HL
;
; set dma address given by registers b and c
;
SETDMA: LD A,C ;low order address
OUT (DMAL),A
LD A,B ;high order address
OUT (DMAH),A ;in dma
RET
;
; perform read operation
;
READ: XOR A ;read command -> A
JP WAITIO ;to perform the actual i/o
;
; perform a write operation
;
WRITE: LD A,1 ;write command -> A
;
; enter here from read and write to perform the actual i/o
; operation. return a 00h in register a if the operation completes
; properly, and 01h if an error occurs during the read or write
;
; in this case, we have saved the disk number in 'diskno' (0-3)
; the track number in 'track' (0-76)
; the sector number in 'sector' (1-26)
; the dma address in 'dmaad' (0-65535)
;
WAITIO: OUT (FDCOP),A ;start i/o operation
IN A,(FDCST) ;status of i/o operation -> A
RET
;
; XIOS data segment
;
SIGNON: DEFB 13,10
DEFM 'MP/M 2 XIOS V1.1 for Z80SIM, '
DEFM 'Copyright 1989-2006 by Udo Munk'
DEFB 13,10,0
;
TICKN: DEFB 0 ;flag for tick
PREEMP: DEFB 0 ;preempted flag
TOD: DEFS 4 ;time of day
SVDHL: DEFS 2 ;save hl during interrupt
SVDRET: DEFS 2 ;save return address during interrupt
SVDSP: DEFS 2 ;save sp during interrupt
CNT50: DEFB 50 ;50 ticks a 20ms = 1 second
;interrupt stack
DEFW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
DEFW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
DEFW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
DEFW 0C7C7H,0C7C7H,0C7C7H,0C7C7H
INTSTK:
;
; fixed data tables for four-drive standard
; IBM-compatible 8" disks
;
; disk parameter header for disk 00
DPBASE: DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK00,ALL00
; disk parameter header for disk 01
DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK01,ALL01
; disk parameter header for disk 02
DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK02,ALL02
; disk parameter header for disk 03
DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK03,ALL03
;
; sector translate vector for the IBM 8" disks
;
TRANS: DEFB 1,7,13,19 ;sectors 1,2,3,4
DEFB 25,5,11,17 ;sectors 5,6,7,8
DEFB 23,3,9,15 ;sectors 9,10,11,12
DEFB 21,2,8,14 ;sectors 13,14,15,16
DEFB 20,26,6,12 ;sectors 17,18,19,20
DEFB 18,24,4,10 ;sectors 21,22,23,24
DEFB 16,22 ;sectors 25,26
;
; disk parameter block, common to all IBM 8" disks
;
DPBLK: DEFW 26 ;sectors per track
DEFB 3 ;block shift factor
DEFB 7 ;block mask
DEFB 0 ;extent mask
DEFW 242 ;disk size-1
DEFW 63 ;directory max
DEFB 192 ;alloc 0
DEFB 0 ;alloc 1
DEFW 16 ;check size
DEFW 2 ;track offset
;
; fixed data tables for 4MB harddisk
;
; disk parameter header
HDBASE: DEFW HDTRA,0000H
DEFW 0000H,0000H
DEFW DIRBF,HDBLK
DEFW CHKHD,ALLHD
;
; sector translate vector for the hardisk
;
HDTRA: DEFB 1,2,3,4,5,6,7,8,9,10
DEFB 11,12,13,14,15,16,17,18,19,20
DEFB 21,22,23,24,25,26,27,28,29,30
DEFB 31,32,33,34,35,36,37,38,39,40
DEFB 41,42,43,44,45,46,47,48,49,50
DEFB 51,52,53,54,55,56,57,58,59,60
DEFB 61,62,63,64,65,66,67,68,69,70
DEFB 71,72,73,74,75,76,77,78,79,80
DEFB 81,82,83,84,85,86,87,88,89,90
DEFB 91,92,93,94,95,96,97,98,99,100
DEFB 101,102,103,104,105,106,107,108,109,110
DEFB 111,112,113,114,115,116,117,118,119,120
DEFB 121,122,123,124,125,126,127,128
;
; disk parameter block for harddisk
;
HDBLK: DEFW 128 ;sectors per track
DEFB 4 ;block shift factor
DEFB 15 ;block mask
DEFB 0 ;extent mask
DEFW 2039 ;disk size-1
DEFW 1023 ;directory max
DEFB 255 ;alloc 0
DEFB 255 ;alloc 1
DEFW 0 ;check size
DEFW 0 ;track offset
;
DIRBF: DEFS 128 ;scratch directory area
ALL00: DEFS 31 ;allocation vector 0
ALL01: DEFS 31 ;allocation vector 1
ALL02: DEFS 31 ;allocation vector 2
ALL03: DEFS 31 ;allocation vector 3
ALLHD: DEFS 255 ;allocation vector harddisk
CHK00: DEFS 16 ;check vector 0
CHK01: DEFS 16 ;check vector 1
CHK02: DEFS 16 ;check vector 2
CHK03: DEFS 16 ;check vector 3
CHKHD: DEFS 0 ;check vector harddisk
;
END

View File

@@ -0,0 +1,177 @@
; MP/M 2 LDRBIOS for Z80-Simulator
;
; Copyright (C) 1989-2006 by Udo Munk
;
ORG 1700H
;
; I/O ports
;
CONSTA EQU 0 ;console status port
CONDAT EQU 1 ;console data port
FDCD EQU 10 ;fdc-port: # of drive
FDCT EQU 11 ;fdc-port: # of track
FDCS EQU 12 ;fdc-port: # of sector
FDCOP EQU 13 ;fdc-port: command
FDCST EQU 14 ;fdc-port: status
DMAL EQU 15 ;dma-port: dma address low
DMAH EQU 16 ;dma-port: dma address high
;
; jump vector for individual subroutines
;
JP BOOT ;perform cold start initialization
JP WBOOT ;perform warm start initialization
JP CONST ;check for console input char ready
JP CONIN ;read console character in
JP CONOUT ;write console character out
JP LIST ;write list character out
JP AUXOUT ;write auxiliary output char
JP AUXIN ;read auxiliary input char
JP HOME ;move head to track 0 on selcted disk
JP SELDSK ;select disk drive
JP SETTRK ;set track number
JP SETSEC ;set sector number
JP SETDMA ;set dma address
JP READ ;read specified sector
JP WRITE ;write specified sector
JP LISTST ;return list status
JP SECTRAN ;translate logical to physical sector
;
; fixed data tables for a IBM-compatible 8" disk
;
; disk parameter header
;
DPH: DEFW TRANS,0000H
DEFW 0000H,0000H
DEFW DIRBF,DPBLK
DEFW CHK00,ALL00
;
; sector translate vector for the IBM 8" disk
;
TRANS: DEFB 1,7,13,19 ;sectors 1,2,3,4
DEFB 25,5,11,17 ;sectors 5,6,7,8
DEFB 23,3,9,15 ;sectors 9,10,11,12
DEFB 21,2,8,14 ;sectors 13,14,15,16
DEFB 20,26,6,12 ;sectors 17,18,19,20
DEFB 18,24,4,10 ;sectors 21,22,23,24
DEFB 16,22 ;sectors 25,26
;
; disk parameter block for the IBM 8" disk
;
DPBLK: DEFW 26 ;sectors per track
DEFB 3 ;block shift factor
DEFB 7 ;block mask
DEFB 0 ;extent mask
DEFW 242 ;disk size-1
DEFW 63 ;directory max
DEFB 192 ;alloc 0
DEFB 0 ;alloc 1
DEFW 16 ;check size
DEFW 2 ;track offset
;
; signon message
;
SIGNON: DEFB 13,10
DEFM 'LDRBIOS V1.0 for Z80SIM, '
DEFM 'Copyright 1989-2006 by Udo Munk'
DEFB 13,10,0
;
; end of fixed tables
;
; individual subroutines to perform each function
;
BOOT: LD HL,SIGNON ;print message
BOOTL: LD A,(HL)
OR A
JP Z,WBOOT
LD C,A
CALL CONOUT
INC HL
JP BOOTL
;
; those are not implemented in loader bios
;
WBOOT:
CONST:
CONIN:
LIST:
AUXOUT:
AUXIN:
WRITE:
LISTST:
RET
;
; console character output from register c
;
CONOUT: LD A,C ;get to accumulator
OUT (CONDAT),A ;send character to console
RET
;
;
; i/o drivers for the disk follow
;
; move to the track 00 position of current drive
; translate this call into a settrk call with parameter 00
;
HOME: LD C,0 ;select track 0
JP SETTRK ;we will move to 00 on first read/write
;
; select disk given by register C
;
SELDSK: PUSH BC
CALL BOOT ;signon message
POP BC
LD HL,0000H ;error return code
LD A,C
CP 0 ;we boot from drive 0 only
RET NZ ;return error
; disk number is in the proper range
; return proper disk parameter header address
OUT (FDCD),A ;selekt disk drive
LD HL,DPH
RET
;
; set track given by register c
;
SETTRK: LD A,C
OUT (FDCT),A
RET
;
; set sector given by register c
;
SETSEC: LD A,C
OUT (FDCS),A
RET
;
; translate the sector given by BC using the
; translate table given by DE
;
SECTRAN:
EX DE,HL ;hl=.trans
ADD HL,BC ;hl=.trans(sector)
LD L,(HL) ;l = trans(sector)
LD H,0 ;hl= trans(sector)
RET ;with value in hl
;
; set dma address given by registers b and c
;
SETDMA: LD A,C ;low order address
OUT (DMAL),A
LD A,B ;high order address
OUT (DMAH),A ;in dma
RET
;
; perform read operation
;
READ: XOR A ;read command -> a
OUT (FDCOP),A ;start i/o operation
IN A,(FDCST) ;status of i/o operation -> a
RET
;
BEGDAT EQU $
DIRBF: DEFS 128 ;scratch directory area
ALL00: DEFS 31 ;allocation vector
CHK00: DEFS 16 ;check vector
;
ENDDAT EQU $ ;end
DATSIZ EQU $-BEGDAT ;size of data area
END ;of bios

View 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

View 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;
}

View 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

View 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

View 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;
}
}

View 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]

View File

@@ -0,0 +1,22 @@
Copyright (c) 1987-2006 Udo Munk
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,85 @@
Usage:
z80asm -ofile -f[b|m|h] -l[file] -s[n|a] -x -v -dsymbol ... file ...
A maximum of 512 source files is allowed. If the filename of a source
doesn't have an extension the default extension ".asm" will be
concated. Source file names may have a path, the maximum length of
a full qualified filename is 2048 characters.
For relative paths the extension must be used, because all characters
after a "." would be used as extension!
Option o:
To override the default name of the output file. Without this option
the name of the output file becomes the name of the input file,
but with the extension ".bin". The output file may have a path,
the maximum length is limited to 2048 characters.
Option f:
Format of the output file:
-fb -> binary file
-fm -> binary file with Mostek header
-fh -> Intel hex
Option l:
Without this option no list file will be generated. With -l a list
file with the name of the source file but extension ".lis" will be
generated. An optional file name with path (2048 characters maximum)
may be added to this option.
Option s:
This option writes the unsorted symbol table (-s), sorted by name (-sn)
or sorted by address (-sa) into the list file. This option only works
together with option -l.
Option x:
Don't output data in pass 2 into object file for DEFS. This only works
if unallocated data isn't followed by any code or initialized data!
Usefull for CP/M BIOS's, where unallocated data doesn't need to be
part of the system image, if the complete image won't fit on the system
tracks.
Option v:
Verbose operation of the assembler.
Option d:
This option predefines symbols with a value of 0.
The number of this option is not limited in the command line.
Pseudo Operations:
Definition of symbols and allocation of memory:
ORG <expression> - set program address
<symbol> EQU <expression> - define constant symbol
<symbol> DEFL <expression> - define variable symbol
<symbol> DEFB <exp,'char',..> - write bytes in memory
<symbol> DEFW <exp,exp..> - write words (16 bits) in memory
<symbol> DEFM <'string'> - write character string in memory
<symbol> DEFS <expression> - reserve space in memory
Conditional assembly:
IFDEF <symbol> - assemble if symbol defined
IFNDEF <symbol> - assemble if symbol not defined
IFEQ <exp1,exp2> - assemble if equal
IFNEQ <exp1,exp2> - assemble if not equal
ELSE - else for all conditionals
ENDIF - end of conditional assembly
Manipulation of list file:
PAGE <expression> - number of lines/page
EJECT - skip to new page
LIST - listing on
NOLIST - listing off
TITLE <'string'> - define title for page header
Others:
INCLUDE <filename> - include another source file
PRINT <'string'> - print string to stdout in pass one

View File

@@ -0,0 +1,54 @@
Quickstart to run CP/M and MP/M on the Z80-CPU simulation
1. Change to directory ~/z80pack/cpmsim/srcsim
make
make clean
This compiles the CPU and hardware emulation needed to run CP/M and MP/M.
2. Change to directory ~/z80pack/cpmsim/srccpm2
make
make clean
This compiles support programs (see below), installs named pipes and so on.
3. Make backup copies of your distribution disks!
cd ~/z80pack/cpmsim/disks/library
cp *.dsk ../backups
4. Change to directory ~/z80pack/cpmsim
cpm2 - run CP/M 2.2
cpm3 - run CP/M 3.0
mpm - this boots CP/M 2, run command mpm to boot MP/M 2
Usage of the support programs:
format: to create an empty disk image for the CP/M simulation.
input: format <a | b | c | d | i | j>
output: in directory disks files drivea.cpm, driveb.cpm,
drivec.cpm, drived.cpm, drivei.cpm and drivej.cpm
bin2hex:converts binary files to Intel hex.
receive:This is a process spawned by cpmsim. It reads from the named
pipe auxout and writes all input from the pipe to the file,
which is given as first argument. cpmsim spawns this process
with the output filename auxiliary.cpm. Inside the simulator
this pipe is connected to I/O-port 5, which is assigned
to the CP/M device PUN:. So everything you write from CP/M
to device PUN: goes into the file auxiliary.cpm on the
UNIX host.
send: This process is to send a file from the UNIX host to the
simulator. Type send <filename> &, and then run cpmsim.
The process writes all data from file into the named pipe
auxin, which is also connected to I/O-port 5, which is
assigned to the CP/M device RDR:. You may use this to
transfer a file from the UNIX host to the simulator.
Under CP/M type pip file=RDR: to read the data send from
the process on the UNIX host.
If you use PIP to transfer files between the UNIX host and the
simulator, you can only use ASCII files, because pip uses cntl-z
for EOF! To transfer a binary file from the UNIX host to the
simulator convert it to Intel hex format with bin2hex. This
can be converted back to a binary file under CP/M with the LOAD
command.

Binary file not shown.

View File

@@ -0,0 +1,41 @@
CFLAGS = -c -O
LFLAGS = -s
OBJ = z80amain.o \
z80atab.o \
z80anum.o \
z80aout.o \
z80arfun.o \
z80apfun.o \
z80aopc.o \
z80aglb.o
z80asm : $(OBJ)
cc $(OBJ) $(LFLAGS) -o z80asm
z80amain.o : z80amain.c z80a.h z80aglb.h
cc $(CFLAGS) z80amain.c
z80atab.o : z80atab.c z80a.h z80aglb.h
cc $(CFLAGS) z80atab.c
z80anum.o : z80anum.c z80a.h z80aglb.h
cc $(CFLAGS) z80anum.c
z80aout.o : z80aout.c z80a.h z80aglb.h
cc $(CFLAGS) z80aout.c
z80arfun.o : z80arfun.c z80a.h z80aglb.h
cc $(CFLAGS) z80arfun.c
z80apfun.o : z80apfun.c z80a.h z80aglb.h
cc $(CFLAGS) z80apfun.c
z80aopc.o : z80aopc.c z80a.h
cc $(CFLAGS) z80aopc.c
z80aglb.o : z80aglb.c z80a.h
cc $(CFLAGS) z80aglb.c
clean:
rm -f core *.o z80asm

View File

@@ -0,0 +1,144 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 21-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* OS dependant definitions
*/
#define LENFN 2048 /* max. filename length */
#define READA "r" /* file open mode read ascii */
#define WRITEA "w" /* file open mode write ascii */
#define WRITEB "w" /* file open mode write binary */
/*
* various constants
*/
#define REL "1.3"
#define COPYR "Copyright (C) 1987-2006 by Udo Munk"
#define SRCEXT ".asm" /* filenamen extension source */
#define OBJEXT ".bin" /* filenamen extension object */
#define LSTEXT ".lis" /* filenamen extension listing */
#define OUTBIN 1 /* format of object: binary */
#define OUTMOS 2 /* Mostek binaer */
#define OUTHEX 3 /* Intel hex */
#define OUTDEF OUTMOS /* default object format */
#define COMMENT ';' /* inline comment character */
#define LINCOM '*' /* comment line if in columne 1 */
#define LABSEP ':' /* label separator */
#define STRSEP '\'' /* string separator */
#define ENDFILE "END" /* end of source */
#define MAXFN 512 /* max. no. source files */
#define MAXLINE 128 /* max. line length source */
#define PLENGTH 65 /* default lines/page in listing */
#define SYMSIZE 8 /* max. symbol length */
#define INCNEST 5 /* max. INCLUDE nesting depth */
#define IFNEST 5 /* max IF.. nesting depth */
#define HASHSIZE 500 /* max. entries in symbol hash array */
#define OPCARRAY 256 /* size of object buffer */
#define SYMINC 100 /* start size of sorted symbol array */
/*
* structure opcode table
*/
struct opc {
char *op_name; /* opcode name */
int (*op_fun) (); /* function pointer code generation */
int op_c1; /* first base opcode*/
int op_c2; /* second base opcode */
};
/*
* structure operand table
*/
struct ope {
char *ope_name; /* operand name */
int ope_sym; /* symbol value operand */
};
/*
* structure symbol table entries
*/
struct sym {
char *sym_name; /* symbol name */
int sym_wert; /* symbol value */
struct sym *sym_next; /* next entry */
};
/*
* structure nested INCLUDE's
*/
struct inc {
unsigned inc_line; /* line counter for listing */
char *inc_fn; /* filename */
FILE *inc_fp; /* file pointer */
};
/*
* definition of operand symbols
* definitions for registers A, B, C, D, H, L and (HL)
* are defined as the bits used in operands and may not
* be changed!
*/
#define REGB 0 /* register B */
#define REGC 1 /* register C */
#define REGD 2 /* register D */
#define REGE 3 /* register E */
#define REGH 4 /* register H */
#define REGL 5 /* register L */
#define REGIHL 6 /* register indirect HL */
#define REGA 7 /* register A */
#define REGI 8 /* register I */
#define REGR 9 /* register R */
#define REGAF 10 /* register pair AF */
#define REGBC 11 /* register pair BC */
#define REGDE 12 /* register pair DE */
#define REGHL 13 /* register pair HL */
#define REGIX 14 /* register IX */
#define REGIY 15 /* register IY */
#define REGSP 16 /* register SP */
#define REGIBC 17 /* register indirect BC */
#define REGIDE 18 /* register indirect DE */
#define REGIIX 19 /* register indirect IX */
#define REGIIY 20 /* register indirect IY */
#define REGISP 21 /* register indirect SP */
#define FLGNC 30 /* flag no carry */
#define FLGNZ 31 /* flag not zerro */
#define FLGZ 32 /* flag zerro */
#define FLGM 33 /* flag minus */
#define FLGP 34 /* flag plus */
#define FLGPE 35 /* flag parrity even */
#define FLGPO 36 /* flag parrity odd */
#define NOOPERA 98 /* no operand */
#define NOREG 99 /* operand isn't register */
/*
* definitions of error numbers for error messages in listfile
*/
#define E_ILLOPC 0 /* illegal opcode */
#define E_ILLOPE 1 /* illegal operand */
#define E_MISOPE 2 /* missing operand */
#define E_MULSYM 3 /* multiple defined symbol */
#define E_UNDSYM 4 /* undefined symbol */
#define E_VALOUT 5 /* value out of bounds */
#define E_MISPAR 6 /* missing parren */
#define E_MISHYP 7 /* missing string separator */
#define E_MEMOVR 8 /* memory override (ORG) */
#define E_MISIFF 9 /* missing IF at ELSE or ENDIF */
#define E_IFNEST 10 /* to many IF's nested */
#define E_MISEIF 11 /* missing ENDIF */
#define E_INCNEST 12 /* to many INCLUDE's nested */
/*
* definition fatal errors
*/
#define F_OUTMEM 0 /* out of memory */
#define F_USAGE 1 /* usage: .... */
#define F_HALT 2 /* assembly halted */
#define F_FOPEN 3 /* can't open file */
#define F_INTERN 4 /* internal error */

View File

@@ -0,0 +1,67 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 21-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* this module contains all global variables other
* than CPU specific tables
*/
#include <stdio.h>
#include "z80a.h"
char *infiles[MAXFN], /* source filenames */
objfn[LENFN + 1], /* object filename */
lstfn[LENFN + 1], /* listing filename */
*srcfn, /* filename of current processed source file */
line[MAXLINE], /* buffer for one line souce */
tmp[MAXLINE], /* temporary buffer */
label[SYMSIZE+1], /* buffer for label */
opcode[MAXLINE], /* buffer for opcode */
operand[MAXLINE], /* buffer for operand */
ops[OPCARRAY], /* buffer for generated object code */
title[MAXLINE]; /* buffer for titel of souce */
int list_flag, /* flag for option -l */
sym_flag, /* flag for option -s */
ver_flag, /* flag for option -v */
dump_flag, /* flag for option -x */
pc, /* programm counter */
pass, /* processed pass */
iflevel, /* IF nesting level */
gencode = 1, /* flag for conditional object code */
errors, /* error counter */
errnum, /* error number in pass 2 */
sd_flag, /* list flag for PSEUDO opcodes */
/* = 0: address from <val>, data from <ops> */
/* = 1: address from <sd_val>, data from <ops>*/
/* = 2: no address, data from <ops> */
/* = 3: address from <sd_val>, no data */
/* = 4: suppress whole line */
sd_val, /* output value for PSEUDO opcodes */
prg_adr, /* start address of programm */
prg_flag, /* flag for prg_adr valid */
out_form = OUTDEF, /* format of object file */
symsize; /* size of symarray */
FILE *srcfp, /* file pointer for current source */
*objfp, /* file pointer for object code */
*lstfp, /* file pointer for listing */
*errfp; /* file pointer for error output */
unsigned
c_line, /* current line no. in current source */
s_line, /* line no. counter for listing */
p_line, /* no. printed lines on page */
ppl = PLENGTH, /* page length */
page; /* no. of pages for listing */
struct sym
*symtab[HASHSIZE], /* symbol table */
**symarray; /* sorted symbol table */

View File

@@ -0,0 +1,62 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 21-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* global variable declarations
*/
extern char *infiles[],
objfn[],
lstfn[],
*srcfn,
line[],
tmp[],
label[],
opcode[],
operand[],
ops[],
title[];
extern int list_flag,
sym_flag,
ver_flag,
dump_flag,
pc,
pass,
iflevel,
gencode,
errors,
errnum,
sd_flag,
sd_val,
prg_adr,
prg_flag,
out_form,
symsize,
no_opcodes,
no_operands;
extern FILE *srcfp,
*objfp,
*lstfp,
*errfp;
extern unsigned c_line,
s_line,
p_line,
ppl,
page;
extern struct sym *symtab[],
**symarray;
extern struct opc opctab[];
extern struct ope opetab[];

View File

@@ -0,0 +1,503 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 21-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* main module, handles the options and runs 2 passes over the sources
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "z80a.h"
#include "z80aglb.h"
void init(void), options(int, char *[]);
void usage(void), fatal(int, char *);
void pass1(void), p1_file(char *);
void pass2(void), p2_file(char *);
void open_o_files(char *), get_fn(char *, char *, char *);
char *get_label(char *, char *);
char *get_opcode(char *, char *);
char *get_arg(char *, char *);
extern void asmerr(int);
extern void lst_line(int, int);
extern void lst_sym(void);
extern void lst_sort_sym(int);
extern void obj_header(void);
extern void obj_end(void);
extern void obj_writeb(int);
extern struct opc *search_op(char *);
extern int put_sym(char *, int);
extern void put_label(void);
extern int copy_sym(void);
extern void n_sort_sym(int);
extern void a_sort_sym(int);
static char *errmsg[] = { /* error messages for fatal() */
"out of memory: %s", /* 0 */
"usage: z80asm -ofile -f[b|m|h] -l[file] -s[n|a] {-x} -v -dsymbol ... file ...",
"Assembly halted", /* 2 */
"can't open file %s", /* 3 */
"internal error: %s" /* 4 */
};
main(int argc, char *argv[])
{
int len;
init();
options(argc, argv);
printf("Z80 - Assembler Release %s, %s\n", REL, COPYR);
pass1();
pass2();
if (list_flag) {
switch (sym_flag) {
case 0: /* no symbol table */
break;
case 1: /* unsorted symbol table */
lst_sym();
break;
case 2: /* symbol table sorted by name */
len = copy_sym();
n_sort_sym(len);
lst_sort_sym(len);
break;
case 3: /* symbol table sorted by address */
len = copy_sym();
a_sort_sym(len);
lst_sort_sym(len);
break;
default:
break;
}
fclose(lstfp);
}
return(errors);
}
/*
* initialization
*/
void init(void)
{
errfp = stdout;
}
/*
* process options
*/
void options(int argc, char *argv[])
{
register char *s, *t;
register int i;
while (--argc > 0 && (*++argv)[0] == '-')
for (s = argv[0]+1; *s != '\0'; s++)
switch (*s) {
case 'o':
case 'O':
if (*++s == '\0') {
puts("name missing in option -o");
usage();
}
get_fn(objfn, s, OBJEXT);
s += (strlen(s) - 1);
break;
case 'l':
case 'L':
if (*(s + 1) != '\0') {
get_fn(lstfn, ++s, LSTEXT);
s += (strlen(s) - 1);
}
list_flag = 1;
break;
case 's':
case 'S':
if (*(s + 1) == '\0')
sym_flag = 1;
else if ((*(s + 1) == 'n') || (*(s + 1) == 'N'))
sym_flag = 2;
else if ((*(s + 1) == 'a') || (*(s + 1) == 'A'))
sym_flag = 3;
else {
printf("unknown option -%s\n", s);
usage();
}
s += (strlen(s) - 1);
break;
case 'x':
case 'X':
dump_flag = 1;
break;
case 'f':
case 'F':
if ((*(s + 1) == 'b') || (*(s + 1) == 'B'))
out_form = OUTBIN;
else if ((*(s + 1) == 'm') || (*(s + 1) == 'M'))
out_form = OUTMOS;
else if ((*(s + 1) == 'h') || (*(s + 1) == 'H'))
out_form = OUTHEX;
else {
printf("unknown option -%s\n", s);
usage();
}
s += (strlen(s) - 1);
break;
case 'd':
case 'D':
if (*++s == '\0') {
puts("name missing in option -d");
usage();
}
t = tmp;
while (*s)
*t++ = islower(*s) ? toupper(*s++)
: *s++;
s--;
*t = '\0';
if (put_sym(tmp, 0))
fatal(F_OUTMEM, "symbols");
break;
case 'v':
case 'V':
ver_flag = 1;
break;
default :
printf("unknown option %c\n", *s);
usage();
}
i = 0;
while ((argc--) && (i < MAXFN)) {
if ((infiles[i] = malloc(LENFN + 1)) == NULL)
fatal(F_OUTMEM, "filenames");
get_fn(infiles[i], *argv++, SRCEXT);
i++;
}
if (i == 0) {
printf("no input file given\n");
usage();
}
}
/*
* error in options, print usage
*/
void usage(void)
{
fatal(F_USAGE, NULL);
}
/*
* print error messages and abort
*/
void fatal(int i, char *arg)
{
printf(errmsg[i], arg);
putchar('\n');
exit(1);
}
/*
* Pass 1:
* - process all source files
*/
void pass1(void)
{
register int fi;
pass = 1;
pc = 0;
fi = 0;
if (!ver_flag)
puts("Pass 1");
open_o_files(infiles[fi]);
while (infiles[fi] != NULL) {
if (!ver_flag)
printf(" Read %s\n", infiles[fi]);
p1_file(infiles[fi]);
fi++;
}
if (errors) {
fclose(objfp);
unlink(objfn);
printf("%d error(s)\n", errors);
fatal(F_HALT, NULL);
}
}
/*
* Pass 1:
* - process one source file
*
* Input: name of source file
*/
void p1_file(char *fn)
{
c_line = 0;
srcfn = fn;
if ((srcfp = fopen(fn, READA)) == NULL)
fatal(F_FOPEN, fn);
while (p1_line())
;
fclose(srcfp);
if (iflevel)
asmerr(E_MISEIF);
}
/*
* Pass 1:
* - process one line of source
*
* Output: 1 line processed
* 0 EOF
*/
int p1_line(void)
{
register char *p;
register int i;
register struct opc *op;
if ((p = fgets(line, MAXLINE, srcfp)) == NULL)
return(0);
c_line++;
p = get_label(label, p);
p = get_opcode(opcode, p);
p = get_arg(operand, p);
if (strcmp(opcode, ENDFILE) == 0)
return(0);
if (*opcode) {
if ((op = search_op(opcode)) != NULL) {
i = (*op->op_fun)(op->op_c1, op->op_c2);
if (gencode)
pc += i;
} else
asmerr(E_ILLOPC);
} else
if (*label)
put_label();
return(1);
}
/*
* Pass 2:
* - process all source files
*/
void pass2(void)
{
register int fi;
pass = 2;
pc = 0;
fi = 0;
if (!ver_flag)
puts("Pass 2");
obj_header();
while (infiles[fi] != NULL) {
if (!ver_flag)
printf(" Read %s\n", infiles[fi]);
p2_file(infiles[fi]);
fi++;
}
obj_end();
fclose(objfp);
printf("%d error(s)\n", errors);
}
/*
* Pass 2:
* - process one source file
*
* Input: name of source file
*/
void p2_file(char *fn)
{
c_line = 0;
srcfn = fn;
if ((srcfp = fopen(fn, READA)) == NULL)
fatal(F_FOPEN, fn);
while (p2_line())
;
fclose(srcfp);
}
/*
* Pass 2:
* - process one line of source
*
* Output: 1 line processed
* 0 EOF
*/
int p2_line(void)
{
register char *p;
register int op_count;
register struct opc *op;
if ((p = fgets(line, MAXLINE, srcfp)) == NULL)
return(0);
c_line++;
s_line++;
p = get_label(label, p);
p = get_opcode(opcode, p);
p = get_arg(operand, p);
if (strcmp(opcode, ENDFILE) == 0) {
lst_line(pc, 0);
return(0);
}
if (*opcode) {
op = search_op(opcode);
op_count = (*op->op_fun)(op->op_c1, op->op_c2);
if (gencode) {
lst_line(pc, op_count);
obj_writeb(op_count);
pc += op_count;
} else {
sd_flag = 2;
lst_line(0, 0);
}
} else {
sd_flag = 2;
lst_line(0, 0);
}
return(1);
}
/*
* open output files:
* input is filename of source file
* list and object filenames are build from source filename if
* not given by options
*/
void open_o_files(char *source)
{
register char *p;
if (*objfn == '\0')
strcpy(objfn, source);
if ((p = strrchr(objfn, '.')) != NULL)
strcpy(p, OBJEXT);
else
strcat(objfn, OBJEXT);
if (out_form == OUTHEX)
objfp = fopen(objfn, WRITEA);
else
objfp = fopen(objfn, WRITEB);
if (objfp == NULL)
fatal(F_FOPEN, objfn);
if (list_flag) {
if (*lstfn == '\0')
strcpy(lstfn, source);
if ((p = strrchr(lstfn, '.')) != NULL)
strcpy(p, LSTEXT);
else
strcat(lstfn, LSTEXT);
if ((lstfp = fopen(lstfn, WRITEA)) == NULL)
fatal(F_FOPEN, lstfn);
errfp = lstfp;
}
}
/*
* create a filename in "dest" from "src" and "ext"
*/
void get_fn(char *dest, char *src, char *ext)
{
register int i;
register char *sp, *dp;
i = 0;
sp = src;
dp = dest;
while ((i++ < LENFN) && (*sp != '\0'))
*dp++ = *sp++;
*dp = '\0';
if ((strrchr(dest,'.') == NULL) &&
(strlen(dest) <= (LENFN - strlen(ext))))
strcat(dest, ext);
}
/*
* get labels, constants and variables from source line
* convert names to upper case and truncate length of name
*/
char *get_label(char *s, char *l)
{
register int i;
i = 0;
if (*l == LINCOM)
goto comment;
while (!isspace(*l) && *l != COMMENT && *l != LABSEP && i < SYMSIZE) {
*s++ = islower(*l) ? toupper(*l++) : *l++;
i++;
}
comment:
*s = '\0';
return(l);
}
/*
* get opcode into s from source line l
* converts to uper case
*/
char *get_opcode(char *s, char *l)
{
if (*l == LINCOM)
goto comment;
while (!isspace(*l) && *l != COMMENT && *l != LABSEP)
l++;
if (*l == LABSEP)
l++;
while (*l == ' ' || *l == '\t')
l++;
while (!isspace(*l) && *l != COMMENT)
*s++ = islower(*l) ? toupper(*l++) : *l++;
comment:
*s = '\0';
return(l);
}
/*
* get operand into s from source line l
* converts to upper case
* strings inside of 's are copied without changes
*/
char *get_arg(char *s, char *l)
{
if (*l == LINCOM)
goto comment;
while (*l == ' ' || *l == '\t')
l++;
while (*l != '\n' && *l != COMMENT) {
if (isspace(*l)) {
l++;
continue;
}
if (*l != STRSEP) {
*s++ = islower(*l) ? toupper(*l) : *l;
l++;
continue;
}
*s++ = *l++;
if (*(s - 2) == 'F') /* EX AF,AF' !!!!! */
continue;
while (*l != STRSEP) {
if (*l == '\n' || *l == '\0' || *l == COMMENT)
goto comment;
*s++ = *l++;
}
*s++ = *l++;
}
comment:
*s = '\0';
return(l);
}

View File

@@ -0,0 +1,309 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 21-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* modul with numercial computation and conversion
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "z80a.h"
#include "z80aglb.h"
#ifndef isxdigit
#define isxdigit(c) (isdigit(c) || (c>='a' && c<='f') || (c>='A' && c<='F'))
#endif
/*
* definitions of operator symbols for expression parser
*/
#define OPEDEC 1 /* decimal number */
#define OPEHEX 2 /* hexadecimal number */
#define OPEOCT 3 /* octal number */
#define OPEBIN 4 /* binary number */
#define OPESUB 5 /* arithmetical - */
#define OPEADD 6 /* arithmetical + */
#define OPEMUL 7 /* arithmetical * */
#define OPEDIV 8 /* arithmetical / */
#define OPEMOD 9 /* arithmetical modulo */
#define OPESHL 10 /* logical shift left */
#define OPESHR 11 /* logical shift right */
#define OPELOR 12 /* logical OR */
#define OPELAN 13 /* logical AND */
#define OPEXOR 14 /* logical XOR */
#define OPECOM 15 /* logical complement */
#define OPESYM 99 /* symbol */
extern struct sym *get_sym(char *);
extern void asmerr(int);
/*
* recursive expression parser
*
* Input: pointer to argument rest string
*
* Output: computed value
*/
int eval(char *s)
{
register char *p;
register int val;
char word[MAXLINE];
struct sym *sp;
val = 0;
while (*s) {
p = word;
if (*s == '(') {
s++;
while (*s != ')') {
if (*s == '\0') {
asmerr(E_MISPAR);
goto eval_break;
}
*p++ = *s++;
}
*p = '\0';
s++;
val = eval(word);
continue;
}
if (*s == STRSEP) {
s++;
while (*s != STRSEP) {
if (*s == '\n' || *s == '\0') {
asmerr(E_MISHYP);
goto hyp_error;
}
*p++ = *s++;
}
s++;
hyp_error:
*p = '\0';
val = strval(word);
continue;
}
if (isari(*s))
*p++ = *s++;
else
while (!isspace(*s) && !isari(*s) && (*s != '\0'))
*p++ = *s++;
*p = '\0';
switch (get_type(word)) {
case OPESYM: /* symbol */
if (strcmp(word, "$") == 0) {
val = pc;
break;
}
if (strlen(word) > SYMSIZE)
word[SYMSIZE] = '\0';
if ((sp = get_sym(word)) != NULL)
val = sp->sym_wert;
else
asmerr(E_UNDSYM);
break;
case OPEDEC: /* decimal number */
val = atoi(word);
break;
case OPEHEX: /* hexadecimal number */
val = axtoi(word);
break;
case OPEBIN: /* binary number */
val = abtoi(word);
break;
case OPEOCT: /* octal number */
val = aotoi(word);
break;
case OPESUB: /* arithmetical - */
val -= eval(s);
goto eval_break;
case OPEADD: /* arithmetical + */
val += eval(s);
goto eval_break;
case OPEMUL: /* arithmetical * */
val *= eval(s);
goto eval_break;
case OPEDIV: /* arithmetical / */
val /= eval(s);
goto eval_break;
case OPEMOD: /* arithmetical modulo */
val %= eval(s);
goto eval_break;
case OPESHL: /* logical shift left */
val <<= eval(s);
goto eval_break;
case OPESHR: /* logical shift right */
val >>= eval(s);
goto eval_break;
case OPELOR: /* logical OR */
val |= eval(s);
goto eval_break;
case OPELAN: /* logical AND */
val &= eval(s);
goto eval_break;
case OPEXOR: /* logical XOR */
val ^= eval(s);
goto eval_break;
case OPECOM: /* logical complement */
val = ~(eval(s));
goto eval_break;
}
}
eval_break:
return(val);
}
/*
* get typ of operand
*
* Input: pointer to string with operand
*
* Output: operand typ
*/
int get_type(char *s)
{
if (isdigit(*s)) { /* numerical operand */
if (isdigit(*(s + strlen(s) - 1))) /* decimal number */
return(OPEDEC);
else if (*(s + strlen(s) - 1) == 'H') /* hexadecimal number */
return(OPEHEX);
else if (*(s + strlen(s) - 1) == 'B') /* binary number */
return(OPEBIN);
else if (*(s + strlen(s) - 1) == 'O') /* octal number */
return(OPEOCT);
} else if (*s == '-') /* arithmetical operand - */
return(OPESUB);
else if (*s == '+') /* arithmetical operand + */
return(OPEADD);
else if (*s == '*') /* arithmetical operand * */
return(OPEMUL);
else if (*s == '/') /* arithmetical operand / */
return(OPEDIV);
else if (*s == '%') /* arithmetical modulo */
return(OPEMOD);
else if (*s == '<') /* logical shift left */
return(OPESHL);
else if (*s == '>') /* logical shift rigth */
return(OPESHR);
else if (*s == '|') /* logical OR */
return(OPELOR);
else if (*s == '&') /* logical AND */
return(OPELAN);
else if (*s == '^') /* logical XOR */
return(OPEXOR);
else if (*s == '~') /* logical complement */
return(OPECOM);
return(OPESYM); /* operand is symbol */
}
/*
* check a character for arithmetical operators
* +, -, *, /, %, <, >, |, &, ~ and ^
*/
int isari(int c)
{
return((c) == '+' || (c) == '-' || (c) == '*' ||
(c) == '/' || (c) == '%' || (c) == '<' ||
(c) == '>' || (c) == '|' || (c) == '&' ||
(c) == '~' || (c) == '^');
}
/*
* conversion of string with hexadecimal number to integer
* format: nnnnH or 0nnnnH if 1st digit > 9
*/
int axtoi(char *str)
{
register int num;
num = 0;
while (isxdigit(*str)) {
num *= 16;
num += *str - ((*str <= '9') ? '0' : '7');
str++;
}
return(num);
}
/*
* conversion of string with octal number to integer
* format: nnnnO
*/
int aotoi(char *str)
{
register int num;
num = 0;
while ('0' <= *str && *str <= '7') {
num *= 8;
num += (*str++) - '0';
}
return(num);
}
/*
* conversion of string with binary number to integer
* format: nnnnnnnnnnnnnnnnB
*/
int abtoi(char *str)
{
register int num;
num = 0;
while ('0' <= *str && *str <= '1') {
num *= 2;
num += (*str++) - '0';
}
return(num);
}
/*
* convert ASCII string to integer
*/
int strval(char *str)
{
register int num;
num = 0;
while (*str) {
num <<= 8;
num += (int) *str++;
}
return(num);
}
/*
* check value for range -256 < value < 256
* Output: value if in range, otherwise 0 and error message
*/
int chk_v1(int i)
{
if (i >= -255 && i <= 255)
return(i);
else {
asmerr(E_VALOUT);
return(0);
}
}
/*
* check value for range -128 < value < 128
* Output: value if in range, otherwise 0 and error message
*/
int chk_v2(int i)
{
if (i >= -127 && i <= 127)
return(i);
else {
asmerr(E_VALOUT);
return(0);
}
}

View File

@@ -0,0 +1,172 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 21-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* opcode tables
*/
#include <stdio.h>
#include "z80a.h"
extern int op_1b(), op_2b(), op_pupo(), op_ex(), op_ld();
extern int op_call(), op_ret(), op_jp(), op_jr(), op_djnz(), op_rst();
extern int op_add(), op_adc(), op_sub(), op_sbc(), op_cp();
extern int op_inc(), op_dec(), op_or(), op_xor(), op_and();
extern int op_rl(), op_rr(), op_sla(), op_sra(), op_srl(), op_rlc(), op_rrc();
extern int op_out(), op_in(), op_im();
extern int op_set(), op_res(), op_bit();
extern int op_org(), op_dl(), op_equ();
extern int op_ds(), op_db(), op_dw(), op_dm();
extern int op_misc();
extern int op_cond();
extern int op_glob();
/*
* opcode table:
* includes entries for all opcodes and pseudo ops other than END
* must be sorted in ascending order!
*/
struct opc opctab[] = {
{ "ADC", op_adc, 0, 0 },
{ "ADD", op_add, 0, 0 },
{ "AND", op_and, 0, 0 },
{ "BIT", op_bit, 0, 0 },
{ "CALL", op_call, 0, 0 },
{ "CCF", op_1b, 0x3f, 0 },
{ "CP", op_cp, 0, 0 },
{ "CPD", op_2b, 0xed, 0xa9 },
{ "CPDR", op_2b, 0xed, 0xb9 },
{ "CPI", op_2b, 0xed, 0xa1 },
{ "CPIR", op_2b, 0xed, 0xb1 },
{ "CPL", op_1b, 0x2f, 0 },
{ "DAA", op_1b, 0x27, 0 },
{ "DEC", op_dec, 0, 0 },
{ "DEFB", op_db, 0, 0 },
{ "DEFL", op_dl, 0, 0 },
{ "DEFM", op_dm, 0, 0 },
{ "DEFS", op_ds, 0, 0 },
{ "DEFW", op_dw, 0, 0 },
{ "DI", op_1b, 0xf3, 0 },
{ "DJNZ", op_djnz, 0, 0 },
{ "EI", op_1b, 0xfb, 0 },
{ "EJECT", op_misc, 1, 0 },
{ "ELSE", op_cond, 98, 0 },
{ "ENDIF", op_cond, 99, 0 },
{ "EQU", op_equ, 0, 0 },
{ "EX", op_ex, 0, 0 },
{ "EXTRN", op_glob, 1, 0 },
{ "EXX", op_1b, 0xd9, 0 },
{ "HALT", op_1b, 0x76, 0 },
{ "IFDEF", op_cond, 1, 0 },
{ "IFEQ", op_cond, 3, 0 },
{ "IFNDEF", op_cond, 2, 0 },
{ "IFNEQ", op_cond, 4, 0 },
{ "IM", op_im, 0, 0 },
{ "IN", op_in, 0, 0 },
{ "INC", op_inc, 0, 0 },
{ "INCLUDE", op_misc, 6, 0 },
{ "IND", op_2b, 0xed, 0xaa },
{ "INDR", op_2b, 0xed, 0xba },
{ "INI", op_2b, 0xed, 0xa2 },
{ "INIR", op_2b, 0xed, 0xb2 },
{ "JP", op_jp, 0, 0 },
{ "JR", op_jr, 0, 0 },
{ "LD", op_ld, 0, 0 },
{ "LDD", op_2b, 0xed, 0xa8 },
{ "LDDR", op_2b, 0xed, 0xb8 },
{ "LDI", op_2b, 0xed, 0xa0 },
{ "LDIR", op_2b, 0xed, 0xb0 },
{ "LIST", op_misc, 2, 0 },
{ "NEG", op_2b, 0xed, 0x44 },
{ "NOLIST", op_misc, 3, 0 },
{ "NOP", op_1b, 0, 0 },
{ "OR", op_or, 0, 0 },
{ "ORG", op_org, 0, 0 },
{ "OTDR", op_2b, 0xed, 0xbb },
{ "OTIR", op_2b, 0xed, 0xb3 },
{ "OUT", op_out, 0, 0 },
{ "OUTD", op_2b, 0xed, 0xab },
{ "OUTI", op_2b, 0xed, 0xa3 },
{ "PAGE", op_misc, 4, 0 },
{ "POP", op_pupo, 1, 0 },
{ "PRINT", op_misc, 5, 0 },
{ "PUBLIC", op_glob, 2, 0 },
{ "PUSH", op_pupo, 2, 0 },
{ "RES", op_res, 0, 0 },
{ "RET", op_ret, 0, 0 },
{ "RETI", op_2b, 0xed, 0x4d },
{ "RETN", op_2b, 0xed, 0x45 },
{ "RL", op_rl, 0, 0 },
{ "RLA", op_1b, 0x17, 0 },
{ "RLC", op_rlc, 0, 0 },
{ "RLCA", op_1b, 0x07, 0 },
{ "RLD", op_2b, 0xed, 0x6f },
{ "RR", op_rr, 0, 0 },
{ "RRA", op_1b, 0x1f, 0 },
{ "RRC", op_rrc, 0, 0 },
{ "RRCA", op_1b, 0x0f, 0 },
{ "RRD", op_2b, 0xed, 0x67 },
{ "RST", op_rst, 0, 0 },
{ "SBC", op_sbc, 0, 0 },
{ "SCF", op_1b, 0x37, 0 },
{ "SET", op_set, 0, 0 },
{ "SLA", op_sla, 0, 0 },
{ "SRA", op_sra, 0, 0 },
{ "SRL", op_srl, 0, 0 },
{ "SUB", op_sub, 0, 0 },
{ "TITLE", op_misc, 7, 0 },
{ "XOR", op_xor, 0, 0 }
};
/*
* compute no. of table entries for search_op()
*/
int no_opcodes = sizeof(opctab) / sizeof(struct opc);
/*
* table with reserverd operand words: registers and flags
* must be sorted in ascending order!
*/
struct ope opetab[] = {
{ "(BC)", REGIBC },
{ "(DE)", REGIDE },
{ "(HL)", REGIHL },
{ "(IX)", REGIIX },
{ "(IY)", REGIIY },
{ "(SP)", REGISP },
{ "A", REGA },
{ "AF", REGAF },
{ "B", REGB },
{ "BC", REGBC },
{ "C", REGC },
{ "D", REGD },
{ "DE", REGDE },
{ "E", REGE },
{ "H", REGH },
{ "HL", REGHL },
{ "I", REGI },
{ "IX", REGIX },
{ "IY", REGIY },
{ "L", REGL },
{ "M", FLGM },
{ "NC", FLGNC },
{ "NZ", FLGNZ },
{ "P", FLGP },
{ "PE", FLGPE },
{ "PO", FLGPO },
{ "R", REGR },
{ "SP", REGSP },
{ "Z", FLGZ }
};
/*
* compute no. of table entries
*/
int no_operands = sizeof(opetab) / sizeof(struct ope);

View File

@@ -0,0 +1,360 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 21-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* module for output functions to list, object and error files
*/
#include <stdio.h>
#include <string.h>
#include "z80a.h"
#include "z80aglb.h"
void flush_hex(void);
int chksum(void);
void btoh(unsigned char, char **);
extern void fatal(int, char *);
static char *errmsg[] = { /* error messages for asmerr() */
"illegal opcode", /* 0 */
"illegal operand", /* 1 */
"missing operand", /* 2 */
"multiply defined symbol", /* 3 */
"undefined symbol", /* 4 */
"value out of range", /* 5 */
"missing )", /* 6 */
"missing string separator", /* 7 */
"memory override", /* 8 */
"missing IF", /* 9 */
"IF nesting to deep", /* 10 */
"missing ENDIF", /* 11 */
"INCLUDE nesting to deep" /* 12 */
};
#define MAXHEX 32 /* max no bytes/hex record */
static unsigned short hex_adr; /* current address in hex record */
static int hex_cnt; /* current no bytes in hex buffer */
static unsigned char hex_buf[MAXHEX]; /* buffer for one hex record */
static char hex_out[MAXHEX*2+11]; /* ASCII buffer for one hex record */
/*
* print error message to listfile and increase error counter
*/
void asmerr(int i)
{
if (pass == 1) {
fprintf(errfp, "Error in file: %s Line: %d\n", srcfn, c_line);
fprintf(errfp, errmsg[i]);
fprintf(errfp, "\n\n");
} else
errnum = i;
errors++;
}
/*
* begin new page in listfile
*/
void lst_header(void)
{
fprintf(lstfp, "\fZ80-Assembler\t\tRelease %s\t\t\t\tPage %d\n", REL,
++page);
fprintf(lstfp, "Source file: %s\n", srcfn);
fprintf(lstfp, "Title: %s\n", title);
p_line = 3;
}
/*
* print header for source lines
*/
void lst_attl(void)
{
fprintf(lstfp, "\nLOC OBJECT CODE LINE STMT SOURCE CODE\n");
p_line += 2;
}
/*
* print one line into listfile, if -l option set
*/
void lst_line(int val, int opanz)
{
register int i;
if (!list_flag || sd_flag == 4) {
sd_flag = 0;
return;
}
if ((p_line >= ppl) || (c_line == 1)) {
lst_header();
lst_attl();
}
switch (sd_flag) {
case 0:
fprintf(lstfp, "%04x ", val & 0xffff);
break;
case 1:
fprintf(lstfp, "%04x ", sd_val & 0xffff);
break;
case 2:
fprintf(lstfp, " ");
break;
case 3:
fprintf(lstfp, "%04x ", sd_val & 0xffff);
goto no_data;
default:
fatal(F_INTERN, "illegal listflag for function lst_line");
break;
}
if (opanz >= 1) fprintf(lstfp, "%02x ", ops[0] & 0xff);
else fprintf(lstfp, " ");
if (opanz >= 2) fprintf(lstfp, "%02x ", ops[1] & 0xff);
else fprintf(lstfp, " ");
if (opanz >= 3) fprintf(lstfp, "%02x ", ops[2] & 0xff);
else fprintf(lstfp, " ");
if (opanz >= 4) fprintf(lstfp, "%02x ", ops[3] & 0xff);
else fprintf(lstfp, " ");
no_data:
fprintf(lstfp, "%6d %6d %s", c_line, s_line, line);
if (errnum) {
fprintf(errfp, "=> %s", errmsg[errnum]);
putc('\n', errfp);
errnum = 0;
p_line++;
}
sd_flag = 0;
p_line++;
if (opanz > 4 && sd_flag == 0) {
opanz -= 4;
i = 4;
sd_val = val;
while (opanz > 0) {
if (p_line >= ppl) {
lst_header();
lst_attl();
}
s_line++;
sd_val += 4;
fprintf(lstfp, "%04x ", sd_val & 0xffff);
if (opanz-- > 0) fprintf(lstfp, "%02x ",
ops[i++] & 0xff);
else fprintf(lstfp, " ");
if (opanz-- > 0) fprintf(lstfp, "%02x ",
ops[i++] & 0xff);
else fprintf(lstfp, " ");
if (opanz-- > 0) fprintf(lstfp, "%02x ",
ops[i++] & 0xff);
else fprintf(lstfp, " ");
if (opanz-- > 0) fprintf(lstfp, "%02x ",
ops[i++] & 0xff);
else fprintf(lstfp, " ");
fprintf(lstfp, "%6d %6d\n", c_line, s_line);
p_line++;
}
}
}
/*
* print symbol table into listfile unsorted
*/
void lst_sym(void)
{
register int i, j;
register struct sym *np;
p_line = j = 0;
strcpy(title,"Symboltable");
for (i = 0; i < HASHSIZE; i++) {
if (symtab[i] != NULL) {
for (np = symtab[i]; np != NULL; np = np->sym_next) {
if (p_line == 0) {
lst_header();
fputs("\n", lstfp);
p_line += 1;
}
fprintf(lstfp, "%-8s %04x\t", np->sym_name,
np->sym_wert & 0xffff);
if (++j == 4) {
fprintf(lstfp, "\n");
if (p_line++ >= ppl)
p_line = 0;
j = 0;
}
}
}
}
}
/*
* print sorted symbol table into listfile
*/
void lst_sort_sym(int len)
{
register int i, j;
p_line = i = j = 0;
strcpy(title, "Symboltable");
while (i < len) {
if (p_line == 0) {
lst_header();
fputs("\n", lstfp);
p_line += 1;
}
fprintf(lstfp, "%-8s %04x\t", symarray[i]->sym_name,
symarray[i]->sym_wert & 0xffff);
if (++j == 4) {
fprintf(lstfp, "\n");
if (p_line++ >= ppl)
p_line = 0;
j = 0;
}
i++;
}
}
/*
* write header record into object file
*/
void obj_header(void)
{
switch (out_form) {
case OUTBIN:
break;
case OUTMOS:
putc(0xff, objfp);
putc(prg_adr & 0xff, objfp);
putc(prg_adr >> 8, objfp);
break;
case OUTHEX:
hex_adr = prg_adr;
break;
}
}
/*
* write end record into object file
*/
void obj_end(void)
{
switch (out_form) {
case OUTBIN:
break;
case OUTMOS:
break;
case OUTHEX:
flush_hex();
fprintf(objfp, ":0000000000\n");
break;
}
}
/*
* write opcodes in ops[] into object file
*/
void obj_writeb(int opanz)
{
register int i;
switch (out_form) {
case OUTBIN:
fwrite(ops, 1, opanz, objfp);
break;
case OUTMOS:
fwrite(ops, 1, opanz, objfp);
break;
case OUTHEX:
for (i = 0; opanz; opanz--) {
if (hex_cnt >= MAXHEX)
flush_hex();
hex_buf[hex_cnt++] = ops[i++];
}
break;
}
}
/*
* write <count> bytes 0xff into object file
*/
void obj_fill(int count)
{
switch (out_form) {
case OUTBIN:
while (count--)
putc(0xff, objfp);
break;
case OUTMOS:
while (count--)
putc(0xff, objfp);
break;
case OUTHEX:
flush_hex();
hex_adr += count;
break;
}
}
/*
* create a hex record in ASCII and write into object file
*/
void flush_hex(void)
{
char *p;
register int i;
if (!hex_cnt)
return;
p = hex_out;
*p++ = ':';
btoh((unsigned char) hex_cnt, &p);
btoh((unsigned char) (hex_adr >> 8), &p);
btoh((unsigned char) (hex_adr & 0xff), &p);
*p++ = '0';
*p++ = '0';
for (i = 0; i < hex_cnt; i++)
btoh(hex_buf[i], &p);
btoh((unsigned char) chksum(), &p);
*p++ = '\n';
*p = '\0';
fwrite(hex_out, 1, strlen(hex_out), objfp);
hex_adr += hex_cnt;
hex_cnt = 0;
}
/*
* convert unsigned char into ASCII hex and copy to string at p
* increase p by 2
*/
void btoh(unsigned char byte, char **p)
{
register unsigned char c;
c = byte >> 4;
*(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A');
c = byte & 0xf;
*(*p)++ = (c < 10) ? (c + '0') : (c - 10 + 'A');
}
/*
* computer checksum for Intel hex record
*/
int chksum(void)
{
register int i, j, sum;
sum = hex_cnt;
sum += hex_adr >> 8;
sum += hex_adr & 0xff;
for (i = 0; i < hex_cnt; i++) {
j = hex_buf[i];
sum += j & 0xff;
}
return (0x100 - (sum & 0xff));
}

View File

@@ -0,0 +1,446 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 22-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* processing of all PSEUDO ops
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "z80a.h"
#include "z80aglb.h"
extern void fatal(int, char *);
extern void p1_file(char *);
extern void p2_file(char *);
extern int eval(char *);
extern void asmerr(int);
extern void lst_header(void);
extern void lst_attl(void);
extern void lst_line(int, int);
extern void obj_fill(int);
extern struct sym *get_sym(char *);
extern int put_sym(char *, int);
extern void put_label(void);
/*
* ORG
*/
int op_org(void)
{
register int i;
if (!gencode)
return(0);
i = eval(operand);
if (i < pc) {
asmerr(E_MEMOVR);
return(0);
}
if (pass == 1) { /* PASS 1 */
if (!prg_flag) {
prg_adr = i;
prg_flag++;
}
} else { /* PASS 2 */
if (++prg_flag > 2)
obj_fill(i - pc);
sd_flag = 2;
}
pc = i;
return(0);
}
/*
* EQU
*/
int op_equ(void)
{
if (!gencode)
return(0);
if (pass == 1) { /* Pass 1 */
if (get_sym(label) == NULL) {
sd_val = eval(operand);
if (put_sym(label, sd_val))
fatal(F_OUTMEM, "symbols");
} else
asmerr(E_MULSYM);
} else { /* Pass 2 */
sd_flag = 1;
sd_val = eval(operand);
}
return(0);
}
/*
* DEFL
*/
int op_dl(void)
{
if (!gencode)
return(0);
sd_flag = 1;
sd_val = eval(operand);
if (put_sym(label, sd_val))
fatal(F_OUTMEM, "symbols");
return(0);
}
/*
* DEFS
*/
int op_ds(void)
{
register int val;
if (!gencode)
return(0);
if (pass == 1)
if (*label)
put_label();
sd_val = pc;
sd_flag = 3;
val = eval(operand);
if ((pass == 2) && !dump_flag)
obj_fill(val);
pc += val;
return(0);
}
/*
* DEFB
*/
int op_db(void)
{
register int i;
register char *p;
register char *s;
if (!gencode)
return(0);
i = 0;
p = operand;
if (pass == 1)
if (*label)
put_label();
while (*p) {
if (*p == STRSEP) {
p++;
while (*p != STRSEP) {
if (*p == '\n' || *p == '\0') {
asmerr(E_MISHYP);
goto hyp_error;
}
ops[i++] = *p++;
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
p++;
} else {
s = tmp;
while (*p != ',' && *p != '\0')
*s++ = *p++;
*s = '\0';
ops[i++] = eval(tmp);
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
if (*p == ',')
p++;
}
hyp_error:
return(i);
}
/*
* DEFM
*/
int op_dm(void)
{
register int i;
register char *p;
if (!gencode)
return(0);
i = 0;
p = operand;
if (pass == 1)
if (*label)
put_label();
if (*p != STRSEP) {
asmerr(E_MISHYP);
return(0);
}
p++;
while (*p != STRSEP) {
if (*p == '\n' || *p == '\0') {
asmerr(E_MISHYP);
break;
}
ops[i++] = *p++;
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
return(i);
}
/*
* DEFW
*/
int op_dw(void)
{
register int i, len, temp;
register char *p;
register char *s;
if (!gencode)
return(0);
p = operand;
i = len = 0;
if (pass == 1)
if (*label)
put_label();
while (*p) {
s = tmp;
while (*p != ',' && *p != '\0')
*s++ = *p++;
*s = '\0';
if (pass == 2) {
temp = eval(tmp);
ops[i++] = temp & 0xff;
ops[i++] = temp >> 8;
if (i >= OPCARRAY)
fatal(F_INTERN, "Op-Code buffer overflow");
}
len += 2;
if (*p == ',')
p++;
}
return(len);
}
/*
* EJECT, LIST, NOLIST, PAGE, PRINT, TITLE, INCLUDE
*/
int op_misc(int op_code, int dummy)
{
register char *p, *d;
static char fn[LENFN];
static int incnest;
static struct inc incl[INCNEST];
if (!gencode)
return(0);
sd_flag = 2;
switch(op_code) {
case 1: /* EJECT */
if (pass == 2)
p_line = ppl;
break;
case 2: /* LIST */
if (pass == 2)
list_flag = 1;
break;
case 3: /* NOLIST */
if (pass == 2)
list_flag = 0;
break;
case 4: /* PAGE */
if (pass == 2)
ppl = eval(operand);
break;
case 5: /* PRINT */
if (pass == 1) {
p = operand;
while (*p) {
if (*p != STRSEP)
putchar(*p++);
else
p++;
}
putchar('\n');
}
break;
case 6: /* INCLUDE */
if (incnest >= INCNEST) {
asmerr(E_INCNEST);
break;
}
incl[incnest].inc_line = c_line;
incl[incnest].inc_fn = srcfn;
incl[incnest].inc_fp = srcfp;
incnest++;
p = line;
d = fn;
while(isspace(*p)) /* ignore white space until INCLUDE */
p++;
while(!isspace(*p)) /* ignore INCLUDE */
p++;
while(isspace(*p)) /* ignore white space until filename */
p++;
while(!isspace(*p) && *p != COMMENT) /* get filename */
*d++ = *p++;
*d = '\0';
if (pass == 1) { /* PASS 1 */
if (!ver_flag)
printf(" Include %s\n", fn);
p1_file(fn);
} else { /* PASS 2 */
sd_flag = 2;
lst_line(0, 0);
if (!ver_flag)
printf(" Include %s\n", fn);
p2_file(fn);
}
incnest--;
c_line = incl[incnest].inc_line;
srcfn = incl[incnest].inc_fn;
srcfp = incl[incnest].inc_fp;
printf(" Resume %s\n", srcfn);
if (list_flag && (pass == 2)) {
lst_header();
lst_attl();
}
sd_flag = 4;
break;
case 7: /* TITLE */
if (pass == 2) {
p = line;
d = title;
while (isspace(*p)) /* ignore white space until TITLE */
p++;
while (!isspace(*p)) /* ignore TITLE */
p++;
while (isspace(*p)) /* ignore white space until text */
p++;
if (*p == STRSEP)
p++;
while (*p != '\n' && *p != STRSEP && *p != COMMENT)
*d++ = *p++;
*d = '\0';
}
break;
default:
fatal(F_INTERN, "illegal opcode for function op_misc");
break;
}
return(0);
}
/*
* IFDEF, IFNDEF, IFEQ, IFNEQ, ELSE, ENDIF
*/
int op_cond(int op_code, int dummy)
{
register char *p, *p1, *p2;
static int condnest[IFNEST];
switch(op_code) {
case 1: /* IFDEF */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
if (gencode)
if (get_sym(operand) == NULL)
gencode = 0;
break;
case 2: /* IFNDEF */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
if (gencode)
if (get_sym(operand) != NULL)
gencode = 0;
break;
case 3: /* IFEQ */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
p = operand;
if (!*p || !(p1 = strchr(operand, ','))) {
asmerr(E_MISOPE);
break;
}
if (gencode) {
p2 = tmp;
while (*p != ',')
*p2++ = *p++;
*p2 = '\0';
if (eval(tmp) != eval(++p1))
gencode = 0;
}
break;
case 4: /* IFNEQ */
if (iflevel >= IFNEST) {
asmerr(E_IFNEST);
break;
}
condnest[iflevel++] = gencode;
p = operand;
if (!*p || !(p1 = strchr(operand, ','))) {
asmerr(E_MISOPE);
break;
}
if (gencode) {
p2 = tmp;
while (*p != ',')
*p2++ = *p++;
*p2 = '\0';
if (eval(tmp) == eval(++p1))
gencode = 0;
}
break;
case 98: /* ELSE */
if (!iflevel)
asmerr(E_MISIFF);
else
if ((iflevel == 0) || (condnest[iflevel - 1] == 1))
gencode = !gencode;
break;
case 99: /* ENDIF */
if (!iflevel)
asmerr(E_MISIFF);
else
gencode = condnest[--iflevel];
break;
default:
fatal(F_INTERN, "illegal opcode for function op_cond");
break;
}
sd_flag = 2;
return(0);
}
/*
* EXTRN and PUBLIC
*/
int op_glob(int op_code, int dummy)
{
if (!gencode)
return(0);
sd_flag = 2;
switch(op_code) {
case 1: /* EXTRN */
break;
case 2: /* PUBLIC */
break;
default:
fatal(F_INTERN, "illegal opcode for function op_glob");
break;
}
return(0);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,255 @@
/*
* Z80 - Assembler
* Copyright (C) 1987-2006 by Udo Munk
*
* History:
* 17-SEP-1987 Development under Digital Research CP/M 2.2
* 28-JUN-1988 Switched to Unix System V.3
* 22-OCT-2006 changed to ANSI C for modern POSIX OS's
*/
/*
* module with table oprations on opcode and symbol tables
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "z80a.h"
#include "z80aglb.h"
extern void fatal(int, char *);
extern void asmerr(int);
/*
* binary search in sorted table opctab
*
* Input: pointer to string with opcode
*
* Output: pointer to table element, or NULL if not found
*/
struct opc *search_op(char *op_name)
{
register int cond;
register struct opc *low, *high, *mid;
low = &opctab[0];
high = &opctab[no_opcodes - 1];
while (low <= high) {
mid = low + (high - low) / 2;
if ((cond = strcmp(op_name, mid->op_name)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return(mid);
}
return(NULL);
}
/*
* binary search on sorted table opetab
*
* Input: pointer to string with operand
*
* Output: symbol for operand, NOOPERA if empty operand,
* NOREG if operand not found
*/
int get_reg(char *s)
{
register int cond;
register struct ope *low, *high, *mid;
if (s == NULL || *s == '\0')
return(NOOPERA);
low = &opetab[0];
high = &opetab[no_operands - 1];
while (low <= high) {
mid = low + (high - low) / 2;
if ((cond = strcmp(s, mid->ope_name)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return(mid->ope_sym);
}
return(NOREG);
}
/*
* hash search on symbol table symtab
*
* Input: pointer to string with symbol
*
* Output: pointer to table element, or NULL if not found
*/
struct sym *get_sym(char *sym_name)
{
register struct sym *np;
for (np = symtab[hash(sym_name)]; np != NULL; np = np->sym_next)
if (strcmp(sym_name, np->sym_name) == 0)
return(np);
return(NULL);
}
/*
* add symbol to symbol table symtab, or modify existing symbol
*
* Input: sym_name pointer to string with symbol name
* sym_wert value of symbol
*
* Output: 0 symbol added/modified
* 1 out of memory
*/
int put_sym(char *sym_name, int sym_wert)
{
struct sym *get_sym();
register int hashval;
register struct sym *np;
char *strsave(char *);
if (!gencode)
return(0);
if ((np = get_sym(sym_name)) == NULL) {
np = (struct sym *) malloc(sizeof (struct sym));
if (np == NULL)
return(1);
if ((np->sym_name = strsave(sym_name)) == NULL)
return(1);
hashval = hash(sym_name);
np->sym_next = symtab[hashval];
symtab[hashval] = np;
}
np->sym_wert = sym_wert;
return(0);
}
/*
* add label to symbol table, error if symbol already exists
*/
void put_label(void)
{
struct sym *get_sym(char *);
if (get_sym(label) == NULL) {
if (put_sym(label, pc))
fatal(F_OUTMEM, "symbols");
} else
asmerr(E_MULSYM);
}
/*
* hash algorithm
*
* Input: pointer to string with name
*
* Output: hash value
*/
int hash(char *name)
{
register int hashval;
for (hashval = 0; *name;)
hashval += *name++;
return(hashval % HASHSIZE);
}
/*
* save string into allocated memory
*
* Input: pointer to string
*
* Output: pointer to allocated memory with string
*/
char *strsave(char *s)
{
register char *p;
if ((p = malloc((unsigned) strlen(s)+1)) != NULL)
strcpy(p, s);
return(p);
}
/*
* copy whole symbol hast table into allocated pointer array
* used for sorting the symbol table later
*/
int copy_sym(void)
{
register int i, j;
register struct sym *np;
symarray = (struct sym **) malloc(SYMINC * sizeof(struct sym *));
if (symarray == NULL)
fatal(F_OUTMEM, "sorting symbol table");
symsize = SYMINC;
for (i = 0, j = 0; i < HASHSIZE; i++) {
if (symtab[i] != NULL) {
for (np = symtab[i]; np != NULL; np = np->sym_next) {
symarray[j++] = np;
if (j == symsize) {
symarray = (struct sym **) realloc((char *) symarray, symsize * sizeof(struct sym *) + SYMINC * sizeof(struct sym *));
if (symarray == NULL)
fatal(F_OUTMEM, "sorting symbol table");
symsize += SYMINC;
}
}
}
}
return(j);
}
/*
* sort symbol table by name
*/
void n_sort_sym(int len)
{
register int gap, i, j;
register struct sym *temp;
for (gap = len/2; gap > 0; gap /= 2)
for (i = gap; i < len; i++)
for (j = i-gap; j >= 0; j -= gap) {
if (strcmp(symarray[j]->sym_name,
symarray[j+gap]->sym_name) <= 0)
break;
temp = symarray[j];
symarray[j] = symarray[j+gap];
symarray[j+gap] = temp;
}
}
/*
* sort symbol table by address
*/
void a_sort_sym(int len)
{
register int gap, i, j;
register struct sym *temp;
for (gap = len/2; gap > 0; gap /= 2)
for (i = gap; i < len; i++)
for (j = i-gap; j >= 0; j -= gap) {
if (numcmp(symarray[j]->sym_wert,
symarray[j+gap]->sym_wert) <= 0)
break;
temp = symarray[j];
symarray[j] = symarray[j+gap];
symarray[j+gap] = temp;
}
}
/*
* compares two 16bit values, result like strcmp()
*/
int numcmp(int n1, int n2)
{
if ((unsigned) (n1 & 0xffff) < (unsigned) (n2 & 0xffff))
return(-1);
else if ((unsigned) (n1 & 0xffff) > (unsigned) (n2 & 0xffff))
return(1);
else
return(0);
}

View File

@@ -0,0 +1,70 @@
# Makefile for Z80-CPU emulator unter UNIX System V
CFLAGS= -O -c -Wall
LFLAGS= -s
#CFLAGS= -g -c -Wall
#LFLAGS=
OBJ = sim0.o \
sim1.o \
sim2.o \
sim3.o \
sim4.o \
sim5.o \
sim6.o \
sim7.o \
simctl.o \
disas.o \
simint.o \
iosim.o \
simfun.o \
simglb.o
z80sim : $(OBJ)
cc $(OBJ) $(LFLAGS) -o z80sim
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
disas.o : disas.c
cc $(CFLAGS) disas.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 core z80sim

View File

@@ -0,0 +1,883 @@
/*
* Z80 disassembler for Z80-CPU simulator
*
* Copyright (C) 1989-2006 by Udo Munk
*
* History:
* 06-DEC-89 Development on TARGON/35 with AT&T Unix System V.3
* 07-APR-92 forget to implement Op-Codes LD A,R and LD R,A, added
* 25-JUN-92 comments in english
* 03-OCT-06 changed to ANSI C for modern POSIX OS's
*/
#include <stdio.h>
/*
* Forward declarations
*/
static int opout(char *, char **);
static int nout(char *, unsigned char **);
static int iout(char *, unsigned char **);
static int rout(char *, char **);
static int nnout(char *, unsigned char **);
static int inout(char *, unsigned char **);
static int cbop(char *, unsigned char **);
static int edop(char *, unsigned char **);
static int ddfd(char *, unsigned char **);
/*
* Op-code tables
*/
struct opt {
int (*fun) ();
char *text;
};
static struct opt optab[256] = {
{ opout, "NOP" }, /* 0x00 */
{ nnout, "LD\tBC," }, /* 0x01 */
{ opout, "LD\t(BC),A" }, /* 0x02 */
{ opout, "INC\tBC" }, /* 0x03 */
{ opout, "INC\tB" }, /* 0x04 */
{ opout, "DEC\tB" }, /* 0x05 */
{ nout, "LD\tB," }, /* 0x06 */
{ opout, "RLCA" }, /* 0x07 */
{ opout, "EX\tAF,AF'" }, /* 0x08 */
{ opout, "ADD\tHL,BC" }, /* 0x09 */
{ opout, "LD\tA,(BC)" }, /* 0x0a */
{ opout, "DEC\tBC" }, /* 0x0b */
{ opout, "INC\tC" }, /* 0x0c */
{ opout, "DEC\tC" }, /* 0x0d */
{ nout, "LD\tC," }, /* 0x0e */
{ opout, "RRCA" }, /* 0x0f */
{ rout, "DJNZ\t" }, /* 0x10 */
{ nnout, "LD\tDE," }, /* 0x11 */
{ opout, "LD\t(DE),A" }, /* 0x12 */
{ opout, "INC\tDE" }, /* 0x13 */
{ opout, "INC\tD" }, /* 0x14 */
{ opout, "DEC\tD" }, /* 0x15 */
{ nout, "LD\tD," }, /* 0x16 */
{ opout, "RLA" }, /* 0x17 */
{ rout, "JR\t" }, /* 0x18 */
{ opout, "ADD\tHL,DE" }, /* 0x19 */
{ opout, "LD\tA,(DE)" }, /* 0x1a */
{ opout, "DEC\tDE" }, /* 0x1b */
{ opout, "INC\tE" }, /* 0x1c */
{ opout, "DEC\tE" }, /* 0x1d */
{ nout, "LD\tE," }, /* 0x1e */
{ opout, "RRA" }, /* 0x1f */
{ rout, "JR\tNZ," }, /* 0x20 */
{ nnout, "LD\tHL," }, /* 0x21 */
{ inout, "LD\t(%04x),HL" }, /* 0x22 */
{ opout, "INC\tHL" }, /* 0x23 */
{ opout, "INC\tH" }, /* 0x24 */
{ opout, "DEC\tH" }, /* 0x25 */
{ nout, "LD\tH," }, /* 0x26 */
{ opout, "DAA" }, /* 0x27 */
{ rout, "JR\tZ," }, /* 0x28 */
{ opout, "ADD\tHL,HL" }, /* 0x29 */
{ inout, "LD\tHL,(%04x)" }, /* 0x2a */
{ opout, "DEC\tHL" }, /* 0x2b */
{ opout, "INC\tL" }, /* 0x2c */
{ opout, "DEC\tL" }, /* 0x2d */
{ nout, "LD\tL," }, /* 0x2e */
{ opout, "CPL" }, /* 0x2f */
{ rout, "JR\tNC," }, /* 0x30 */
{ nnout, "LD\tSP," }, /* 0x31 */
{ inout, "LD\t(%04x),A" }, /* 0x32 */
{ opout, "INC\tSP" }, /* 0x33 */
{ opout, "INC\t(HL)" }, /* 0x34 */
{ opout, "DEC\t(HL)" }, /* 0x35 */
{ nout, "LD\t(HL)," }, /* 0x36 */
{ opout, "SCF" }, /* 0x37 */
{ rout, "JR\tC," }, /* 0x38 */
{ opout, "ADD\tHL,SP" }, /* 0x39 */
{ inout, "LD\tA,(%04x)" }, /* 0x3a */
{ opout, "DEC\tSP" }, /* 0x3b */
{ opout, "INC\tA" }, /* 0x3c */
{ opout, "DEC\tA" }, /* 0x3d */
{ nout, "LD\tA," }, /* 0x3e */
{ opout, "CCF" }, /* 0x3f */
{ opout, "LD\tB,B" }, /* 0x40 */
{ opout, "LD\tB,C" }, /* 0x41 */
{ opout, "LD\tB,D" }, /* 0x42 */
{ opout, "LD\tB,E" }, /* 0x43 */
{ opout, "LD\tB,H" }, /* 0x44 */
{ opout, "LD\tB,L" }, /* 0x45 */
{ opout, "LD\tB,(HL)" }, /* 0x46 */
{ opout, "LD\tB,A" }, /* 0x47 */
{ opout, "LD\tC,B" }, /* 0x48 */
{ opout, "LD\tC,C" }, /* 0x49 */
{ opout, "LD\tC,D" }, /* 0x4a */
{ opout, "LD\tC,E" }, /* 0x4b */
{ opout, "LD\tC,H" }, /* 0x4c */
{ opout, "LD\tC,L" }, /* 0x4d */
{ opout, "LD\tC,(HL)" }, /* 0x4e */
{ opout, "LD\tC,A" }, /* 0x4f */
{ opout, "LD\tD,B" }, /* 0x50 */
{ opout, "LD\tD,C" }, /* 0x51 */
{ opout, "LD\tD,D" }, /* 0x52 */
{ opout, "LD\tD,E" }, /* 0x53 */
{ opout, "LD\tD,H" }, /* 0x54 */
{ opout, "LD\tD,L" }, /* 0x55 */
{ opout, "LD\tD,(HL)" }, /* 0x56 */
{ opout, "LD\tD,A" }, /* 0x57 */
{ opout, "LD\tE,B" }, /* 0x58 */
{ opout, "LD\tE,C" }, /* 0x59 */
{ opout, "LD\tE,D" }, /* 0x5a */
{ opout, "LD\tE,E" }, /* 0x5b */
{ opout, "LD\tE,H" }, /* 0x5c */
{ opout, "LD\tE,L" }, /* 0x5d */
{ opout, "LD\tE,(HL)" }, /* 0x5e */
{ opout, "LD\tE,A" }, /* 0x5f */
{ opout, "LD\tH,B" }, /* 0x60 */
{ opout, "LD\tH,C" }, /* 0x61 */
{ opout, "LD\tH,D" }, /* 0x62 */
{ opout, "LD\tH,E" }, /* 0x63 */
{ opout, "LD\tH,H" }, /* 0x64 */
{ opout, "LD\tH,L" }, /* 0x65 */
{ opout, "LD\tH,(HL)" }, /* 0x66 */
{ opout, "LD\tH,A" }, /* 0x67 */
{ opout, "LD\tL,B" }, /* 0x68 */
{ opout, "LD\tL,C" }, /* 0x69 */
{ opout, "LD\tL,D" }, /* 0x6a */
{ opout, "LD\tL,E" }, /* 0x6b */
{ opout, "LD\tL,H" }, /* 0x6c */
{ opout, "LD\tL,L" }, /* 0x6d */
{ opout, "LD\tL,(HL)" }, /* 0x6e */
{ opout, "LD\tL,A" }, /* 0x6f */
{ opout, "LD\t(HL),B" }, /* 0x70 */
{ opout, "LD\t(HL),C" }, /* 0x71 */
{ opout, "LD\t(HL),D" }, /* 0x72 */
{ opout, "LD\t(HL),E" }, /* 0x73 */
{ opout, "LD\t(HL),H" }, /* 0x74 */
{ opout, "LD\t(HL),L" }, /* 0x75 */
{ opout, "HALT" }, /* 0x76 */
{ opout, "LD\t(HL),A" }, /* 0x77 */
{ opout, "LD\tA,B" }, /* 0x78 */
{ opout, "LD\tA,C" }, /* 0x79 */
{ opout, "LD\tA,D" }, /* 0x7a */
{ opout, "LD\tA,E" }, /* 0x7b */
{ opout, "LD\tA,H" }, /* 0x7c */
{ opout, "LD\tA,L" }, /* 0x7d */
{ opout, "LD\tA,(HL)" }, /* 0x7e */
{ opout, "LD\tA,A" }, /* 0x7f */
{ opout, "ADD\tA,B" }, /* 0x80 */
{ opout, "ADD\tA,C" }, /* 0x81 */
{ opout, "ADD\tA,D" }, /* 0x82 */
{ opout, "ADD\tA,E" }, /* 0x83 */
{ opout, "ADD\tA,H" }, /* 0x84 */
{ opout, "ADD\tA,L" }, /* 0x85 */
{ opout, "ADD\tA,(HL)" }, /* 0x86 */
{ opout, "ADD\tA,A" }, /* 0x87 */
{ opout, "ADC\tA,B" }, /* 0x88 */
{ opout, "ADC\tA,C" }, /* 0x89 */
{ opout, "ADC\tA,D" }, /* 0x8a */
{ opout, "ADC\tA,E" }, /* 0x8b */
{ opout, "ADC\tA,H" }, /* 0x8c */
{ opout, "ADC\tA,L" }, /* 0x8d */
{ opout, "ADC\tA,(HL)" }, /* 0x8e */
{ opout, "ADC\tA,A" }, /* 0x8f */
{ opout, "SUB\tB" }, /* 0x90 */
{ opout, "SUB\tC" }, /* 0x91 */
{ opout, "SUB\tD" }, /* 0x92 */
{ opout, "SUB\tE" }, /* 0x93 */
{ opout, "SUB\tH" }, /* 0x94 */
{ opout, "SUB\tL" }, /* 0x95 */
{ opout, "SUB\t(HL)" }, /* 0x96 */
{ opout, "SUB\tA" }, /* 0x97 */
{ opout, "SBC\tA,B" }, /* 0x98 */
{ opout, "SBC\tA,C" }, /* 0x99 */
{ opout, "SBC\tA,D" }, /* 0x9a */
{ opout, "SBC\tA,E" }, /* 0x9b */
{ opout, "SBC\tA,H" }, /* 0x9c */
{ opout, "SBC\tA,L" }, /* 0x9d */
{ opout, "SBC\tA,(HL)" }, /* 0x9e */
{ opout, "SBC\tA,A" }, /* 0x9f */
{ opout, "AND\tB" }, /* 0xa0 */
{ opout, "AND\tC" }, /* 0xa1 */
{ opout, "AND\tD" }, /* 0xa2 */
{ opout, "AND\tE" }, /* 0xa3 */
{ opout, "AND\tH" }, /* 0xa4 */
{ opout, "AND\tL" }, /* 0xa5 */
{ opout, "AND\t(HL)" }, /* 0xa6 */
{ opout, "AND\tA" }, /* 0xa7 */
{ opout, "XOR\tB" }, /* 0xa8 */
{ opout, "XOR\tC" }, /* 0xa9 */
{ opout, "XOR\tD" }, /* 0xaa */
{ opout, "XOR\tE" }, /* 0xab */
{ opout, "XOR\tH" }, /* 0xac */
{ opout, "XOR\tL" }, /* 0xad */
{ opout, "XOR\t(HL)" }, /* 0xae */
{ opout, "XOR\tA" }, /* 0xaf */
{ opout, "OR\tB" }, /* 0xb0 */
{ opout, "OR\tC" }, /* 0xb1 */
{ opout, "OR\tD" }, /* 0xb2 */
{ opout, "OR\tE" }, /* 0xb3 */
{ opout, "OR\tH" }, /* 0xb4 */
{ opout, "OR\tL" }, /* 0xb5 */
{ opout, "OR\t(HL)" }, /* 0xb6 */
{ opout, "OR\tA" }, /* 0xb7 */
{ opout, "CP\tB" }, /* 0xb8 */
{ opout, "CP\tC" }, /* 0xb9 */
{ opout, "CP\tD" }, /* 0xba */
{ opout, "CP\tE" }, /* 0xbb */
{ opout, "CP\tH" }, /* 0xbc */
{ opout, "CP\tL" }, /* 0xbd */
{ opout, "CP\t(HL)" }, /* 0xbe */
{ opout, "CP\tA" }, /* 0xbf */
{ opout, "RET\tNZ" }, /* 0xc0 */
{ opout, "POP\tBC" }, /* 0xc1 */
{ nnout, "JP\tNZ," }, /* 0xc2 */
{ nnout, "JP\t" }, /* 0xc3 */
{ nnout, "CALL\tNZ," }, /* 0xc4 */
{ opout, "PUSH\tBC" }, /* 0xc5 */
{ nout, "ADD\tA," }, /* 0xc6 */
{ opout, "RST\t0" }, /* 0xc7 */
{ opout, "RET\tZ" }, /* 0xc8 */
{ opout, "RET" }, /* 0xc9 */
{ nnout, "JP\tZ," }, /* 0xca */
{ cbop, "" }, /* 0xcb */
{ nnout, "CALL\tZ," }, /* 0xcc */
{ nnout, "CALL\t" }, /* 0xcd */
{ nout, "ADC\tA," }, /* 0xce */
{ opout, "RST\t8" }, /* 0xcf */
{ opout, "RET\tNC" }, /* 0xd0 */
{ opout, "POP\tDE" }, /* 0xd1 */
{ nnout, "JP\tNC," }, /* 0xd2 */
{ iout, "OUT\t(%02x),A" }, /* 0xd3 */
{ nnout, "CALL\tNC," }, /* 0xd4 */
{ opout, "PUSH\tDE" }, /* 0xd5 */
{ nout, "SUB\t" }, /* 0xd6 */
{ opout, "RST\t10" }, /* 0xd7 */
{ opout, "RET\tC" }, /* 0xd8 */
{ opout, "EXX" }, /* 0xd9 */
{ nnout, "JP\tC," }, /* 0xda */
{ iout, "IN\tA,(%02x)" }, /* 0xdb */
{ nnout, "CALL\tC," }, /* 0xdc */
{ ddfd, "" }, /* 0xdd */
{ nout, "SBC\tA," }, /* 0xde */
{ opout, "RST\t18" }, /* 0xdf */
{ opout, "RET\tPO" }, /* 0xe0 */
{ opout, "POP\tHL" }, /* 0xe1 */
{ nnout, "JP\tPO," }, /* 0xe2 */
{ opout, "EX\t(SP),HL" }, /* 0xe3 */
{ nnout, "CALL\tPO," }, /* 0xe4 */
{ opout, "PUSH\tHL" }, /* 0xe5 */
{ nout, "AND\t" }, /* 0xe6 */
{ opout, "RST\t20" }, /* 0xe7 */
{ opout, "RET\tPE" }, /* 0xe8 */
{ opout, "JP\t(HL)" }, /* 0xe9 */
{ nnout, "JP\tPE," }, /* 0xea */
{ opout, "EX\tDE,HL" }, /* 0xeb */
{ nnout, "CALL\tPE," }, /* 0xec */
{ edop, "" }, /* 0xed */
{ nout, "XOR\t" }, /* 0xee */
{ opout, "RST\t28" }, /* 0xef */
{ opout, "RET\tP" }, /* 0xf0 */
{ opout, "POP\tAF" }, /* 0xf1 */
{ nnout, "JP\tP," }, /* 0xf2 */
{ opout, "DI" }, /* 0xf3 */
{ nnout, "CALL\tP," }, /* 0xf4 */
{ opout, "PUSH\tAF" }, /* 0xf5 */
{ nout, "OR\t" }, /* 0xf6 */
{ opout, "RST\t30" }, /* 0xf7 */
{ opout, "RET\tM" }, /* 0xf8 */
{ opout, "LD\tSP,HL" }, /* 0xf9 */
{ nnout, "JP\tM," }, /* 0xfa */
{ opout, "EI" }, /* 0xfb */
{ nnout, "CALL\tM," }, /* 0xfc */
{ ddfd, "" }, /* 0xfd */
{ nout, "CP\t" }, /* 0xfe */
{ opout, "RST\t38" } /* 0xff */
};
static int addr;
static char *unkown = "???";
static char *reg[] = { "B", "C", "D", "E", "H", "L", "(HL)", "A" };
static char *regix = "IX";
static char *regiy = "IY";
/*
* The function disass() is the only global function of
* this module. The first argument is a pointer to a
* unsigned char pointer, which points to the op-code
* to disassemble. The output of the disassembly goes
* to stdout, terminated by a newline. After the
* disassembly the pointer to the op-code will be
* increased by the size of the op-code, so that
* disass() can be called again.
* The secound argument is the (Z80) address of the
* op-code to disassemble. It is used to calculate the
* destination address of relative jumps.
*/
void disass(unsigned char **p, int adr)
{
register int len;
addr = adr;
len = (*optab[**p].fun) (optab[**p].text, p);
*p += len;
}
/*
* disassemble 1 byte op-codes
*/
static int opout(char *s, char **p)
{
puts(s);
return(1);
}
/*
* disassemble 2 byte op-codes of type "Op n"
*/
static int nout(char *s, unsigned char **p)
{
printf("%s%02x\n", s, *(*p + 1));
return(2);
}
/*
* disassemble 2 byte op-codes with indirect addressing
*/
static int iout(char *s, unsigned char **p)
{
printf(s, *(*p + 1));
putchar('\n');
return(2);
}
/*
* disassemble 2 byte op-codes with relative addressing
*/
static int rout(char *s, char **p)
{
printf("%s%04x\n", s, addr + *(*p + 1) + 2);
return(2);
}
/*
* disassemble 3 byte op-codes of type "Op nn"
*/
static int nnout(char *s, unsigned char **p)
{
register int i;
i = *(*p + 1) + (*(*p + 2) << 8);
printf("%s%04x\n", s, i);
return(3);
}
/*
* disassemble 3 byte op-codes with indirect addressing
*/
static int inout(char *s, unsigned char **p)
{
register int i;
i = *(*p + 1) + (*(*p + 2) << 8);
printf(s, i);
putchar('\n');
return(3);
}
/*
* disassemble multi byte op-codes with prefix 0xcb
*/
static int cbop(char *s, unsigned char **p)
{
register int b2;
b2 = *(*p + 1);
if (b2 >= 0x00 && b2 <= 0x07) {
printf("RLC\t");
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x08 && b2 <= 0x0f) {
printf("RRC\t");
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x10 && b2 <= 0x17) {
printf("RL\t");
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x18 && b2 <= 0x1f) {
printf("RR\t");
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x20 && b2 <= 0x27) {
printf("SLA\t");
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x28 && b2 <= 0x2f) {
printf("SRA\t");
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x38 && b2 <= 0x3f) {
printf("SRL\t");
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x40 && b2 <= 0x7f) {
printf("BIT\t");
printf("%c,", ((b2 >> 3) & 7) + '0');
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0x80 && b2 <= 0xbf) {
printf("RES\t");
printf("%c,", ((b2 >> 3) & 7) + '0');
printf("%s\n", reg[b2 & 7]);
return(2);
}
if (b2 >= 0xc0) {
printf("SET\t");
printf("%c,", ((b2 >> 3) & 7) + '0');
printf("%s\n", reg[b2 & 7]);
return(2);
}
puts(unkown);
return(2);
}
/*
* disassemble multi byte op-codes with prefix 0xed
*/
static int edop(char *s, unsigned char **p)
{
register int b2, i;
int len = 2;
b2 = *(*p + 1);
switch (b2) {
case 0x40:
puts("IN\tB,(C)");
break;
case 0x41:
puts("OUT\t(C),B");
break;
case 0x42:
puts("SBC\tHL,BC");
break;
case 0x43:
i = *(*p + 2) + (*(*p + 3) << 8);
printf("LD\t(%04x),BC\n", i);
len = 4;
break;
case 0x44:
puts("NEG");
break;
case 0x45:
puts("RETN");
break;
case 0x46:
puts("IM\t0");
break;
case 0x47:
puts("LD\tI,A");
break;
case 0x48:
puts("IN\tC,(C)");
break;
case 0x49:
puts("OUT\t(C),C");
break;
case 0x4a:
puts("ADC\tHL,BC");
break;
case 0x4b:
i = *(*p + 2) + (*(*p + 3) << 8);
printf("LD\tBC,(%04x)\n", i);
len = 4;
break;
case 0x4d:
puts("RETI");
break;
case 0x4f:
puts("LD\tR,A");
break;
case 0x50:
puts("IN\tD,(C)");
break;
case 0x51:
puts("OUT\t(C),D");
break;
case 0x52:
puts("SBC\tHL,DE");
break;
case 0x53:
i = *(*p + 2) + (*(*p + 3) << 8);
printf("LD\t(%04x),DE\n", i);
len = 4;
break;
case 0x56:
puts("IM\t1");
break;
case 0x57:
puts("LD\tA,I");
break;
case 0x58:
puts("IN\tE,(C)");
break;
case 0x59:
puts("OUT\t(C),E");
break;
case 0x5a:
puts("ADC\tHL,DE");
break;
case 0x5b:
i = *(*p + 2) + (*(*p + 3) << 8);
printf("LD\tDE,(%04x)\n", i);
len = 4;
break;
case 0x5e:
puts("IM\t2");
break;
case 0x5f:
puts("LD\tA,R");
break;
case 0x60:
puts("IN\tH,(C)");
break;
case 0x61:
puts("OUT\t(C),H");
break;
case 0x62:
puts("SBC\tHL,HL");
break;
case 0x67:
puts("RRD");
break;
case 0x68:
puts("IN\tL,(C)");
break;
case 0x69:
puts("OUT\t(C),L");
break;
case 0x6a:
puts("ADC\tHL,HL");
break;
case 0x6f:
puts("RLD");
break;
case 0x72:
puts("SBC\tHL,SP");
break;
case 0x73:
i = *(*p + 2) + (*(*p + 3) << 8);
printf("LD\t(%04x),SP\n", i);
len = 4;
break;
case 0x78:
puts("IN\tA,(C)");
break;
case 0x79:
puts("OUT\t(C),A");
break;
case 0x7a:
puts("ADC\tHL,SP");
break;
case 0x7b:
i = *(*p + 2) + (*(*p + 3) << 8);
printf("LD\tSP,(%04x)\n", i);
len = 4;
break;
case 0xa0:
puts("LDI");
break;
case 0xa1:
puts("CPI");
break;
case 0xa2:
puts("INI");
break;
case 0xa3:
puts("OUTI");
break;
case 0xa8:
puts("LDD");
break;
case 0xa9:
puts("CPD");
break;
case 0xaa:
puts("IND");
break;
case 0xab:
puts("OUTD");
break;
case 0xb0:
puts("LDIR");
break;
case 0xb1:
puts("CPIR");
break;
case 0xb2:
puts("INIR");
break;
case 0xb3:
puts("OTIR");
break;
case 0xb8:
puts("LDDR");
break;
case 0xb9:
puts("CPDR");
break;
case 0xba:
puts("INDR");
break;
case 0xbb:
puts("OTDR");
break;
default:
puts(unkown);
}
return(len);
}
/*
* disassemble multi byte op-codes with prefix 0xdd and 0xfd
*/
static int ddfd(char *s, unsigned char **p)
{
register int b2;
register char *ireg;
int len = 3;
if (**p == 0xdd)
ireg = regix;
else
ireg = regiy;
b2 = *(*p + 1);
if (b2 >= 0x70 && b2 <= 0x77) {
printf("LD\t(%s+%02x),%s\n", ireg, *(*p + 2), reg[b2 & 7]);
return(3);
}
switch (b2) {
case 0x09:
printf("ADD\t%s,BC\n", ireg);
len = 2;
break;
case 0x19:
printf("ADD\t%s,DE\n", ireg);
len = 2;
break;
case 0x21:
printf("LD\t%s,%04x\n", ireg, *(*p + 2) + (*(*p + 3) << 8));
len = 4;
break;
case 0x22:
printf("LD\t(%04x),%s\n", *(*p + 2) + (*(*p + 3) << 8), ireg);
len = 4;
break;
case 0x23:
printf("INC\t%s\n", ireg);
len = 2;
break;
case 0x29:
if (**p == 0xdd)
printf("ADD\tIX,IX\n");
else
printf("ADD\tIY,IY\n");
len = 2;
break;
case 0x2a:
printf("LD\t%s,(%04x)\n", ireg, *(*p + 2) + (*(*p + 3) << 8));
len = 4;
break;
case 0x2b:
printf("DEC\t%s\n", ireg);
len = 2;
break;
case 0x34:
printf("INC\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x35:
printf("DEC\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x36:
printf("LD\t(%s+%02x),%02x\n", ireg, *(*p + 2), *(*p + 3));
len = 4;
break;
case 0x39:
printf("ADD\t%s,SP\n", ireg);
len = 2;
break;
case 0x46:
printf("LD\tB,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x4e:
printf("LD\tC,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x56:
printf("LD\tD,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x5e:
printf("LD\tE,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x66:
printf("LD\tH,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x6e:
printf("LD\tL,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x7e:
printf("LD\tA,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x86:
printf("ADD\tA,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x8e:
printf("ADC\tA,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x96:
printf("SUB\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x9e:
printf("SBC\tA,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xa6:
printf("AND\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xae:
printf("XOR\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xb6:
printf("OR\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xbe:
printf("CP\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xcb:
switch (*(*p + 3)) {
case 0x06:
printf("RLC\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x0e:
printf("RRC\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x16:
printf("RL\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x1e:
printf("RR\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x26:
printf("SLA\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x2e:
printf("SRA\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x3e:
printf("SRL\t(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x46:
printf("BIT\t0,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x4e:
printf("BIT\t1,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x56:
printf("BIT\t2,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x5e:
printf("BIT\t3,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x66:
printf("BIT\t4,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x6e:
printf("BIT\t5,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x76:
printf("BIT\t6,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x7e:
printf("BIT\t7,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x86:
printf("RES\t0,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x8e:
printf("RES\t1,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x96:
printf("RES\t2,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0x9e:
printf("RES\t3,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xa6:
printf("RES\t4,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xae:
printf("RES\t5,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xb6:
printf("RES\t6,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xbe:
printf("RES\t7,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xc6:
printf("SET\t0,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xce:
printf("SET\t1,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xd6:
printf("SET\t2,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xde:
printf("SET\t3,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xe6:
printf("SET\t4,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xee:
printf("SET\t5,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xf6:
printf("SET\t6,(%s+%02x)\n", ireg, *(*p + 2));
break;
case 0xfe:
printf("SET\t7,(%s+%02x)\n", ireg, *(*p + 2));
break;
default:
puts(unkown);
}
len = 4;
break;
case 0xe1:
printf("POP\t%s\n", ireg);
len = 2;
break;
case 0xe3:
printf("EX\t(SP),%s\n", ireg);
len = 2;
break;
case 0xe5:
printf("PUSH\t%s\n", ireg);
len = 2;
break;
case 0xe9:
printf("JP\t(%s)\n", ireg);
len = 2;
break;
case 0xf9:
printf("LD\tSP,%s\n", ireg);
len = 2;
break;
default:
puts(unkown);
}
return(len);
}

Binary file not shown.

View File

@@ -0,0 +1,136 @@
/*
* Z80SIM - a Z80-CPU simulator
*
* Copyright (C) 1987-2006 by Udo Munk
*
* This modul of the simulator contains a simple terminal I/O
* simulation as an example.
*
* History:
* 28-SEP-87 Development 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
* 20-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
* 03-OCT-06 Release 1.8 changed to ANSI C for modern POSIX OS's
*/
/*
* Sample I/O-handler
*
* Port 0 input: reads the next byte from stdin
* Port 0 output: writes the byte to stdout
*
* All the other ports are connected to a I/O-trap handler,
* I/O to this ports stops the simulation with an I/O error.
*/
#include <stdio.h>
#include "sim.h"
#include "simglb.h"
/*
* Forward declarations of the I/O functions
* for all port addresses.
*/
static BYTE io_trap(void);
static BYTE p000_in(void);
static void p000_out(BYTE);
/*
* This two dimensional array contains function pointers
* for every I/O port (0 - 255), to do the needed I/O.
* The first entry is for input, the second for output.
*/
static BYTE (*port[256][2]) () = {
{ p000_in, p000_out } /* port 0 */
};
/*
* This function is to initiate the I/O devices.
* It will be called from the CPU simulation before
* any operation with the Z80 is possible.
*
* In this sample I/O simulation we initialize all
* unused port with an error trap handler, so that
* simulation stops at I/O on the unused ports.
*
* See the I/O simulation of CP/M for a more complex
* example.
*/
void init_io(void)
{
register int i;
for (i = 1; i <= 255; i++)
port[i][0] = port[i][1] = io_trap;
}
/*
* This function is to stop the I/O devices. It is
* called from the CPU simulation on exit.
*
* Here is just nothing to do, see the I/O simulation
* of CP/M for a more complex example.
*/
void exit_io(void)
{
}
/*
* This is the main handler for all IN op-codes,
* called by the simulator. It calls the input
* function for port adr.
*/
BYTE io_in(BYTE adr)
{
return((*port[adr][0]) ());
}
/*
* This is the main handler for all OUT op-codes,
* called by the simulator. It calls the output
* function for port adr.
*/
void io_out(BYTE adr, BYTE data)
{
(*port[adr][1]) (data);
}
/*
* I/O trap funtion
* This function should be added into all unused
* entrys of the port array. It stops the emulation
* with an I/O error.
*/
static BYTE io_trap(void)
{
if (i_flag) {
cpu_error = IOTRAP;
cpu_state = STOPPED;
}
return((BYTE) 0);
}
/*
* I/O function port 0 read:
* Read next byte from stdin.
*/
static BYTE p000_in(void)
{
return((BYTE) getchar());
}
/*
* I/O function port 0 write:
* Write byte to stdout and flush the output.
*/
static void p000_out(BYTE data)
{
putchar((int) data);
fflush(stdout);
}

Binary file not shown.

2
emu/z80pack-1.9/z80sim/run.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
./z80sim

View File

@@ -0,0 +1,104 @@
/*
* Z80SIM - a Z80-CPU simulator
*
* Copyright (C) 1987-2006 by Udo Munk
*
* This is the configuration I'm using for software testing and debugging
*
* History:
* 28-SEP-87 Development 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
* 20-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
* 03-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*/ /* activate CPU's interrupts */
#define WANT_SPC /* activate SP over-/underrun handling 0000<->FFFF */
#define WANT_PCC /* activate PC overrun handling FFFF->0000 */
#define CNTL_C /* cntl-c will stop running emulation */
#define CNTL_BS /* cntl-\ will stop running emulation */
#define CNTL_Z /* cntl-z will suspend emulator */
#define WANT_TIM /* activate runtime measurement */
#define HISIZE 100 /* number of entrys in history */
#define SBSIZE 4 /* number of software breakpoints */
/*
* The following defines may be modified and activated by
* user, to print her/his copyright for a developed system,
* which contains the Z80-CPU simulation as a part.
*/
/*
#define USR_COM "XYZ-System Simulation"
#define USR_REL "x.y"
#define USR_CPR "Copyright (C) 20xx by XYZ"
*/
/*
* 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_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

View File

@@ -0,0 +1,104 @@
/*
* Z80SIM - a Z80-CPU simulator
*
* Copyright (C) 1987-2006 by Udo Munk
*
* This is the configuration I'm using for software testing and debugging
*
* History:
* 28-SEP-87 Development 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
* 20-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
* 03-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*/ /* activate CPU's interrupts */
#define WANT_SPC /* activate SP over-/underrun handling 0000<->FFFF */
#define WANT_PCC /* activate PC overrun handling FFFF->0000 */
#define CNTL_C /* cntl-c will stop running emulation */
#define CNTL_BS /* cntl-\ will stop running emulation */
#define CNTL_Z /* cntl-z will suspend emulator */
#define WANT_TIM /* activate runtime measurement */
#define HISIZE 100 /* number of entrys in history */
#define SBSIZE 4 /* number of software breakpoints */
/*
* The following defines may be modified and activated by
* user, to print her/his copyright for a developed system,
* which contains the Z80-CPU simulation as a part.
*/
/*
#define USR_COM "XYZ-System Simulation"
#define USR_REL "x.y"
#define USR_CPR "Copyright (C) 20xx by XYZ"
*/
/*
* 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_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

View File

@@ -0,0 +1,106 @@
/*
* Z80SIM - a Z80-CPU simulator
*
* Copyright (C) 1987-2006 by Udo Munk
*
* With this configuration the simulated Z80 runs with the
* highest possible speed
*
* History:
* 28-SEP-87 Development 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
* 20-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
* 03-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*/ /* activate CPU's interrupts */
/*#define WANT_SPC*/ /* activate SP over-/underrun handling 0000<->FFFF */
/*#define WANT_PCC*/ /* activate PC overrun handling FFFF->0000 */
#define CNTL_C /* cntl-c will stop running emulation */
#define CNTL_BS /* cntl-\ will stop running emulation */
#define CNTL_Z /* cntl-z will suspend emulator */
/*#define WANT_TIM*/ /* activate runtime measurement */
/*#define HISIZE 100*/ /* number of entrys in history */
/*#define SBSIZE 4*/ /* number of software breakpoints */
/*
* The following defines may be modified and activated by
* user, to print her/his copyright for a developed system,
* which contains the Z80-CPU simulation as a part.
*/
/*
#define USR_COM "XYZ-System Simulation"
#define USR_REL "x.y"
#define USR_CPR "Copyright (C) 20xx by XYZ"
*/
/*
* 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

View File

@@ -0,0 +1,202 @@
/*
* 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
* 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
* 20-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 and ported to COHERENT 4.0
* 03-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* This modul contain the 'main()' function of the simulator,
* where the options are checked and variables are initialized.
* After initialization of the UNIX interrupts ( int_on() )
* and initialization of the I/O simulation ( init_io() )
* the user interface ( mon() ) is called.
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <memory.h>
#include "sim.h"
#include "simglb.h"
static void save_core(void), load_core(void);
extern void int_on(void), int_off(void), mon(void);
extern void init_io(void), exit_io(void);
extern int exatoi(char *);
int main(int argc, char *argv[])
{
register char *s, *p;
register char *pn = argv[0];
while (--argc > 0 && (*++argv)[0] == '-')
for (s = argv[0] + 1; *s != '\0'; s++)
switch (*s) {
case 's': /* save core and CPU on exit */
s_flag = 1;
break;
case 'l': /* load core and CPU from file */
l_flag = 1;
break;
case 'h': /* execute HALT opcode */
break_flag = 0;
break;
case 'i': /* trap I/O on unused ports */
i_flag = 1;
break;
case 'm': /* initialize Z80 memory */
m_flag = exatoi(s+1);
s += strlen(s+1);
break;
case 'f':
f_flag = atoi(s+1);
s += strlen(s+1);
freq = (float) 1 / (float) f_flag;
break;
case 'x': /* get filename with Z80 executable */
x_flag = 1;
s++;
p = xfn;
while (*s)
*p++ = *s++;
*p = '\0';
s--;
break;
case '?':
goto usage;
default:
printf("illegal option %c\n", *s);
usage: printf("usage:\t%s -s -l -i -h -mn -fn -xfilename\n", pn);
puts("\ts = save core and cpu");
puts("\tl = load core and cpu");
puts("\ti = trap on I/O to unused ports");
puts("\th = execute HALT op-code");
puts("\tm = init memory with n");
puts("\tf = CPU frequenzy n in MHz (not implemented yet)");
puts("\tx = load and execute filename");
exit(1);
}
putchar('\n');
puts("####### ##### ### ##### ### # #");
puts(" # # # # # # # # ## ##");
puts(" # # # # # # # # # # #");
puts(" # ##### # # ##### ##### # # # #");
puts(" # # # # # # # # #");
puts(" # # # # # # # # # #");
puts("####### ##### ### ##### ### # #");
printf("\nRelease %s, %s\n", RELEASE, COPYR);
#ifdef USR_COM
printf("%s Release %s, %s\n", USR_COM, USR_REL, USR_CPR);
#endif
putchar('\n');
fflush(stdout);
wrk_ram = PC = STACK = ram;
memset((char *) ram, m_flag, 32768);
memset((char *) ram + 32768, m_flag, 32768);
if (l_flag)
load_core();
int_on();
init_io();
mon();
if (s_flag)
save_core();
exit_io();
int_off();
return(0);
}
/*
* This function saves the CPU and the memory into the file core.z80
*
*/
static void save_core(void)
{
int fd;
if ((fd = open("core.z80", O_WRONLY | O_CREAT, 0600)) == -1) {
puts("can't open file core.z80");
return;
}
write(fd, (char *) &A, sizeof(A));
write(fd, (char *) &F, sizeof(F));
write(fd, (char *) &B, sizeof(B));
write(fd, (char *) &C, sizeof(C));
write(fd, (char *) &D, sizeof(D));
write(fd, (char *) &E, sizeof(E));
write(fd, (char *) &H, sizeof(H));
write(fd, (char *) &L, sizeof(L));
write(fd, (char *) &A_, sizeof(A_));
write(fd, (char *) &F_, sizeof(F_));
write(fd, (char *) &B_, sizeof(B_));
write(fd, (char *) &C_, sizeof(C_));
write(fd, (char *) &D_, sizeof(D_));
write(fd, (char *) &E_, sizeof(E_));
write(fd, (char *) &H_, sizeof(H_));
write(fd, (char *) &L_, sizeof(L_));
write(fd, (char *) &I, sizeof(I));
write(fd, (char *) &IFF, sizeof(IFF));
write(fd, (char *) &R, sizeof(R));
write(fd, (char *) &PC, sizeof(PC));
write(fd, (char *) &STACK, sizeof(STACK));
write(fd, (char *) &IX, sizeof(IX));
write(fd, (char *) &IY, sizeof(IY));
write(fd, (char *) ram, 32768);
write(fd, (char *) ram + 32768, 32768);
close(fd);
}
/*
* This function loads the CPU and memory from the file core.z80
*
*/
static void load_core(void)
{
int fd;
if ((fd = open("core.z80", O_RDONLY)) == -1) {
puts("can't open file core.z80");
return;
}
read(fd, (char *) &A, sizeof(A));
read(fd, (char *) &F, sizeof(F));
read(fd, (char *) &B, sizeof(B));
read(fd, (char *) &C, sizeof(C));
read(fd, (char *) &D, sizeof(D));
read(fd, (char *) &E, sizeof(E));
read(fd, (char *) &H, sizeof(H));
read(fd, (char *) &L, sizeof(L));
read(fd, (char *) &A_, sizeof(A_));
read(fd, (char *) &F_, sizeof(F_));
read(fd, (char *) &B_, sizeof(B_));
read(fd, (char *) &C_, sizeof(C_));
read(fd, (char *) &D_, sizeof(D_));
read(fd, (char *) &E_, sizeof(E_));
read(fd, (char *) &H_, sizeof(H_));
read(fd, (char *) &L_, sizeof(L_));
read(fd, (char *) &I, sizeof(I));
read(fd, (char *) &IFF, sizeof(IFF));
read(fd, (char *) &R, sizeof(R));
read(fd, (char *) &PC, sizeof(PC));
read(fd, (char *) &STACK, sizeof(STACK));
read(fd, (char *) &IX, sizeof(IX));
read(fd, (char *) &IY, sizeof(IY));
read(fd, (char *) ram, 32768);
read(fd, (char *) ram + 32768, 32768);
close(fd);
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,727 @@
/*
* 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
* 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
* 20-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
* 07-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* Like the function "cpu()" this one emulates multi byte opcodes
* starting with 0xdd
*/
#include "sim.h"
#include "simglb.h"
static int trap_dd(void);
static int op_popix(void), op_pusix(void);
static int op_jpix(void);
static int op_exspx(void);
static int op_ldspx(void);
static int op_ldixnn(void), op_ldixinn(void), op_ldinx(void);
static int op_adaxd(void), op_acaxd(void), op_suaxd(void), op_scaxd(void);
static int op_andxd(void), op_xorxd(void), op_orxd(void), op_cpxd(void);
static int op_decxd(void), op_incxd(void);
static int op_addxb(void), op_addxd(void), op_addxs(void), op_addxx();
static int op_incix(void), op_decix(void);
static int op_ldaxd(void), op_ldbxd(void), op_ldcxd(void);
static int op_lddxd(), op_ldexd(void);
static int op_ldhxd(void), op_ldlxd(void);
static int op_ldxda(void), op_ldxdb(void), op_ldxdc(void);
static int op_ldxdd(), op_ldxde(void);
static int op_ldxdh(void), op_ldxdl(void), op_ldxdn(void);
extern int op_ddcb_handel(void);
long op_dd_handel(void)
{
register int t;
static int (*op_dd[256]) (void) = {
trap_dd, /* 0x00 */
trap_dd, /* 0x01 */
trap_dd, /* 0x02 */
trap_dd, /* 0x03 */
trap_dd, /* 0x04 */
trap_dd, /* 0x05 */
trap_dd, /* 0x06 */
trap_dd, /* 0x07 */
trap_dd, /* 0x08 */
op_addxb, /* 0x09 */
trap_dd, /* 0x0a */
trap_dd, /* 0x0b */
trap_dd, /* 0x0c */
trap_dd, /* 0x0d */
trap_dd, /* 0x0e */
trap_dd, /* 0x0f */
trap_dd, /* 0x10 */
trap_dd, /* 0x11 */
trap_dd, /* 0x12 */
trap_dd, /* 0x13 */
trap_dd, /* 0x14 */
trap_dd, /* 0x15 */
trap_dd, /* 0x16 */
trap_dd, /* 0x17 */
trap_dd, /* 0x18 */
op_addxd, /* 0x19 */
trap_dd, /* 0x1a */
trap_dd, /* 0x1b */
trap_dd, /* 0x1c */
trap_dd, /* 0x1d */
trap_dd, /* 0x1e */
trap_dd, /* 0x1f */
trap_dd, /* 0x20 */
op_ldixnn, /* 0x21 */
op_ldinx, /* 0x22 */
op_incix, /* 0x23 */
trap_dd, /* 0x24 */
trap_dd, /* 0x25 */
trap_dd, /* 0x26 */
trap_dd, /* 0x27 */
trap_dd, /* 0x28 */
op_addxx, /* 0x29 */
op_ldixinn, /* 0x2a */
op_decix, /* 0x2b */
trap_dd, /* 0x2c */
trap_dd, /* 0x2d */
trap_dd, /* 0x2e */
trap_dd, /* 0x2f */
trap_dd, /* 0x30 */
trap_dd, /* 0x31 */
trap_dd, /* 0x32 */
trap_dd, /* 0x33 */
op_incxd, /* 0x34 */
op_decxd, /* 0x35 */
op_ldxdn, /* 0x36 */
trap_dd, /* 0x37 */
trap_dd, /* 0x38 */
op_addxs, /* 0x39 */
trap_dd, /* 0x3a */
trap_dd, /* 0x3b */
trap_dd, /* 0x3c */
trap_dd, /* 0x3d */
trap_dd, /* 0x3e */
trap_dd, /* 0x3f */
trap_dd, /* 0x40 */
trap_dd, /* 0x41 */
trap_dd, /* 0x42 */
trap_dd, /* 0x43 */
trap_dd, /* 0x44 */
trap_dd, /* 0x45 */
op_ldbxd, /* 0x46 */
trap_dd, /* 0x47 */
trap_dd, /* 0x48 */
trap_dd, /* 0x49 */
trap_dd, /* 0x4a */
trap_dd, /* 0x4b */
trap_dd, /* 0x4c */
trap_dd, /* 0x4d */
op_ldcxd, /* 0x4e */
trap_dd, /* 0x4f */
trap_dd, /* 0x50 */
trap_dd, /* 0x51 */
trap_dd, /* 0x52 */
trap_dd, /* 0x53 */
trap_dd, /* 0x54 */
trap_dd, /* 0x55 */
op_lddxd, /* 0x56 */
trap_dd, /* 0x57 */
trap_dd, /* 0x58 */
trap_dd, /* 0x59 */
trap_dd, /* 0x5a */
trap_dd, /* 0x5b */
trap_dd, /* 0x5c */
trap_dd, /* 0x5d */
op_ldexd, /* 0x5e */
trap_dd, /* 0x5f */
trap_dd, /* 0x60 */
trap_dd, /* 0x61 */
trap_dd, /* 0x62 */
trap_dd, /* 0x63 */
trap_dd, /* 0x64 */
trap_dd, /* 0x65 */
op_ldhxd, /* 0x66 */
trap_dd, /* 0x67 */
trap_dd, /* 0x68 */
trap_dd, /* 0x69 */
trap_dd, /* 0x6a */
trap_dd, /* 0x6b */
trap_dd, /* 0x6c */
trap_dd, /* 0x6d */
op_ldlxd, /* 0x6e */
trap_dd, /* 0x6f */
op_ldxdb, /* 0x70 */
op_ldxdc, /* 0x71 */
op_ldxdd, /* 0x72 */
op_ldxde, /* 0x73 */
op_ldxdh, /* 0x74 */
op_ldxdl, /* 0x75 */
trap_dd, /* 0x76 */
op_ldxda, /* 0x77 */
trap_dd, /* 0x78 */
trap_dd, /* 0x79 */
trap_dd, /* 0x7a */
trap_dd, /* 0x7b */
trap_dd, /* 0x7c */
trap_dd, /* 0x7d */
op_ldaxd, /* 0x7e */
trap_dd, /* 0x7f */
trap_dd, /* 0x80 */
trap_dd, /* 0x81 */
trap_dd, /* 0x82 */
trap_dd, /* 0x83 */
trap_dd, /* 0x84 */
trap_dd, /* 0x85 */
op_adaxd, /* 0x86 */
trap_dd, /* 0x87 */
trap_dd, /* 0x88 */
trap_dd, /* 0x89 */
trap_dd, /* 0x8a */
trap_dd, /* 0x8b */
trap_dd, /* 0x8c */
trap_dd, /* 0x8d */
op_acaxd, /* 0x8e */
trap_dd, /* 0x8f */
trap_dd, /* 0x90 */
trap_dd, /* 0x91 */
trap_dd, /* 0x92 */
trap_dd, /* 0x93 */
trap_dd, /* 0x94 */
trap_dd, /* 0x95 */
op_suaxd, /* 0x96 */
trap_dd, /* 0x97 */
trap_dd, /* 0x98 */
trap_dd, /* 0x99 */
trap_dd, /* 0x9a */
trap_dd, /* 0x9b */
trap_dd, /* 0x9c */
trap_dd, /* 0x9d */
op_scaxd, /* 0x9e */
trap_dd, /* 0x9f */
trap_dd, /* 0xa0 */
trap_dd, /* 0xa1 */
trap_dd, /* 0xa2 */
trap_dd, /* 0xa3 */
trap_dd, /* 0xa4 */
trap_dd, /* 0xa5 */
op_andxd, /* 0xa6 */
trap_dd, /* 0xa7 */
trap_dd, /* 0xa8 */
trap_dd, /* 0xa9 */
trap_dd, /* 0xaa */
trap_dd, /* 0xab */
trap_dd, /* 0xac */
trap_dd, /* 0xad */
op_xorxd, /* 0xae */
trap_dd, /* 0xaf */
trap_dd, /* 0xb0 */
trap_dd, /* 0xb1 */
trap_dd, /* 0xb2 */
trap_dd, /* 0xb3 */
trap_dd, /* 0xb4 */
trap_dd, /* 0xb5 */
op_orxd, /* 0xb6 */
trap_dd, /* 0xb7 */
trap_dd, /* 0xb8 */
trap_dd, /* 0xb9 */
trap_dd, /* 0xba */
trap_dd, /* 0xbb */
trap_dd, /* 0xbc */
trap_dd, /* 0xbd */
op_cpxd, /* 0xbe */
trap_dd, /* 0xbf */
trap_dd, /* 0xc0 */
trap_dd, /* 0xc1 */
trap_dd, /* 0xc2 */
trap_dd, /* 0xc3 */
trap_dd, /* 0xc4 */
trap_dd, /* 0xc5 */
trap_dd, /* 0xc6 */
trap_dd, /* 0xc7 */
trap_dd, /* 0xc8 */
trap_dd, /* 0xc9 */
trap_dd, /* 0xca */
op_ddcb_handel, /* 0xcb */
trap_dd, /* 0xcc */
trap_dd, /* 0xcd */
trap_dd, /* 0xce */
trap_dd, /* 0xcf */
trap_dd, /* 0xd0 */
trap_dd, /* 0xd1 */
trap_dd, /* 0xd2 */
trap_dd, /* 0xd3 */
trap_dd, /* 0xd4 */
trap_dd, /* 0xd5 */
trap_dd, /* 0xd6 */
trap_dd, /* 0xd7 */
trap_dd, /* 0xd8 */
trap_dd, /* 0xd9 */
trap_dd, /* 0xda */
trap_dd, /* 0xdb */
trap_dd, /* 0xdc */
trap_dd, /* 0xdd */
trap_dd, /* 0xde */
trap_dd, /* 0xdf */
trap_dd, /* 0xe0 */
op_popix, /* 0xe1 */
trap_dd, /* 0xe2 */
op_exspx, /* 0xe3 */
trap_dd, /* 0xe4 */
op_pusix, /* 0xe5 */
trap_dd, /* 0xe6 */
trap_dd, /* 0xe7 */
trap_dd, /* 0xe8 */
op_jpix, /* 0xe9 */
trap_dd, /* 0xea */
trap_dd, /* 0xeb */
trap_dd, /* 0xec */
trap_dd, /* 0xed */
trap_dd, /* 0xee */
trap_dd, /* 0xef */
trap_dd, /* 0xf0 */
trap_dd, /* 0xf1 */
trap_dd, /* 0xf2 */
trap_dd, /* 0xf3 */
trap_dd, /* 0xf4 */
trap_dd, /* 0xf5 */
trap_dd, /* 0xf6 */
trap_dd, /* 0xf7 */
trap_dd, /* 0xf8 */
op_ldspx, /* 0xf9 */
trap_dd, /* 0xfa */
trap_dd, /* 0xfb */
trap_dd, /* 0xfc */
trap_dd, /* 0xfd */
trap_dd, /* 0xfe */
trap_dd /* 0xff */
};
#ifdef WANT_TIM
t = (*op_dd[*PC++]) (); /* execute next opcode */
#else
(*op_dd[*PC++]) ();
#endif
#ifdef WANT_PCC
if (PC > ram + 65535) /* correct PC overrun */
PC = ram;
#endif
return(t);
}
/*
* This function traps all illegal opcodes following the
* initial 0xdd of a multi byte opcode.
*/
static int trap_dd(void)
{
cpu_error = OPTRAP2;
cpu_state = STOPPED;
return(0);
}
static int op_popix(void) /* POP IX */
{
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
IX = *STACK++;
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
IX += *STACK++ << 8;
return(14);
}
static int op_pusix(void) /* PUSH IX */
{
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
*--STACK = IX >> 8;
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
*--STACK = IX;
return(15);
}
static int op_jpix(void) /* JP (IX) */
{
PC = ram + IX;
return(8);
}
static int op_exspx(void) /* EX (SP),IX */
{
register int i;
i = *STACK + (*(STACK + 1) << 8);
*STACK = IX;
*(STACK + 1) = IX >> 8;
IX = i;
return(23);
}
static int op_ldspx(void) /* LD SP,IX */
{
STACK = ram + IX;
return(10);
}
static int op_ldixnn(void) /* LD IX,nn */
{
IX = *PC++;
IX += *PC++ << 8;
return(14);
}
static int op_ldixinn(void) /* LD IX,(nn) */
{
register BYTE *p;
p = ram + *PC++;
p += *PC++ << 8;
IX = *p++;
IX += *p << 8;
return(20);
}
static int op_ldinx(void) /* LD (nn),IX */
{
register BYTE *p;
p = ram + *PC++;
p += *PC++ << 8;
*p++ = IX;
*p = IX >> 8;
return(20);
}
static int op_adaxd(void) /* ADD A,(IX+d) */
{
register int i;
register BYTE P;
P = *(ram + IX + (char) *PC++);
((A & 0xf) + (P & 0xf) > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(A + P > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A + (char) P;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F &= ~N_FLAG;
return(19);
}
static int op_acaxd(void) /* ADC A,(IX+d) */
{
register int i, carry;
register BYTE P;
carry = (F & C_FLAG) ? 1 : 0;
P = *(ram + IX + (char) *PC++);
((A & 0xf) + (P & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(A + P + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A + (char) P + carry;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F &= ~N_FLAG;
return(19);
}
static int op_suaxd(void) /* SUB A,(IX+d) */
{
register int i;
register BYTE P;
P = *(ram + IX + (char) *PC++);
((P & 0xf) > (A & 0xf)) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(P > A) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A - (char) P;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(19);
}
static int op_scaxd(void) /* SBC A,(IX+d) */
{
register int i, carry;
register BYTE P;
carry = (F & C_FLAG) ? 1 : 0;
P = *(ram + IX + (char) *PC++);
((P & 0xf) + carry > (A & 0xf)) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(P + carry > A) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A - (char) P - carry;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(19);
}
static int op_andxd(void) /* AND (IX+d) */
{
A &= *(ram + IX + (char) *PC++);
(A & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= H_FLAG;
(parrity[A]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
F &= ~(N_FLAG | C_FLAG);
return(19);
}
static int op_xorxd(void) /* XOR (IX+d) */
{
A ^= *(ram + IX + (char) *PC++);
(A & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(parrity[A]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
F &= ~(H_FLAG | N_FLAG | C_FLAG);
return(19);
}
static int op_orxd(void) /* OR (IX+d) */
{
A |= *(ram + IX + (char) *PC++);
(A & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(parrity[A]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
F &= ~(H_FLAG | N_FLAG | C_FLAG);
return(19);
}
static int op_cpxd(void) /* CP (IX+d) */
{
register int i;
register BYTE P;
P = *(ram + IX + (char) *PC++);
((P & 0xf) > (A & 0xf)) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(P > A) ? (F |= C_FLAG) : (F &= ~C_FLAG);
i = (char) A - (char) P;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(i) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(19);
}
static int op_incxd(void) /* INC (IX+d) */
{
register BYTE *p;
p = ram + IX + (char) *PC++;
((*p & 0xf) + 1 > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(*p)++;
(*p == 128) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F &= ~N_FLAG;
return(23);
}
static int op_decxd(void) /* DEC (IX+d) */
{
register BYTE *p;
p = ram + IX + (char) *PC++;
(((*p - 1) & 0xf) == 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(*p)--;
(*p == 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(23);
}
static int op_addxb(void) /* ADD IX,BC */
{
register int carry;
BYTE ixl = IX & 0xff;
BYTE ixh = IX >> 8;
carry = (ixl + C > 255) ? 1 : 0;
ixl += C;
((ixh & 0xf) + (B & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(ixh + B + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
ixh += B + carry;
IX = (ixh << 8) + ixl;
F &= ~N_FLAG;
return(15);
}
static int op_addxd(void) /* ADD IX,DE */
{
register int carry;
BYTE ixl = IX & 0xff;
BYTE ixh = IX >> 8;
carry = (ixl + E > 255) ? 1 : 0;
ixl += E;
((ixh & 0xf) + (D & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(ixh + D + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
ixh += D + carry;
IX = (ixh << 8) + ixl;
F &= ~N_FLAG;
return(15);
}
static int op_addxs(void) /* ADD IX,SP */
{
register int carry;
BYTE ixl = IX & 0xff;
BYTE ixh = IX >> 8;
BYTE spl = (STACK - ram) & 0xff;
BYTE sph = (STACK - ram) >> 8;
carry = (ixl + spl > 255) ? 1 : 0;
ixl += spl;
((ixh & 0xf) + (sph & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(ixh + sph + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
ixh += sph + carry;
IX = (ixh << 8) + ixl;
F &= ~N_FLAG;
return(15);
}
static int op_addxx(void) /* ADD IX,IX */
{
register int carry;
BYTE ixl = IX & 0xff;
BYTE ixh = IX >> 8;
carry = (ixl << 1 > 255) ? 1 : 0;
ixl <<= 1;
((ixh & 0xf) + (ixh & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(ixh + ixh + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
ixh += ixh + carry;
IX = (ixh << 8) + ixl;
F &= ~N_FLAG;
return(15);
}
static int op_incix(void) /* INC IX */
{
IX++;
return(10);
}
static int op_decix(void) /* DEC IX */
{
IX--;
return(10);
}
static int op_ldaxd(void) /* LD A,(IX+d) */
{
A = *(IX + (char) *PC++ + ram);
return(19);
}
static int op_ldbxd(void) /* LD B,(IX+d) */
{
B = *(IX + (char) *PC++ + ram);
return(19);
}
static int op_ldcxd(void) /* LD C,(IX+d) */
{
C = *(IX + (char) *PC++ + ram);
return(19);
}
static int op_lddxd(void) /* LD D,(IX+d) */
{
D = *(IX + (char) *PC++ + ram);
return(19);
}
static int op_ldexd(void) /* LD E,(IX+d) */
{
E = *(IX + (char) *PC++ + ram);
return(19);
}
static int op_ldhxd(void) /* LD H,(IX+d) */
{
H = *(IX + (char) *PC++ + ram);
return(19);
}
static int op_ldlxd(void) /* LD L,(IX+d) */
{
L = *(IX + (char) *PC++ + ram);
return(19);
}
static int op_ldxda(void) /* LD (IX+d),A */
{
*(IX + (char) *PC++ + ram) = A;
return(19);
}
static int op_ldxdb(void) /* LD (IX+d),B */
{
*(IX + (char) *PC++ + ram) = B;
return(19);
}
static int op_ldxdc(void) /* LD (IX+d),C */
{
*(IX + (char) *PC++ + ram) = C;
return(19);
}
static int op_ldxdd(void) /* LD (IX+d),D */
{
*(IX + (char) *PC++ + ram) = D;
return(19);
}
static int op_ldxde(void) /* LD (IX+d),E */
{
*(IX + (char) *PC++ + ram) = E;
return(19);
}
static int op_ldxdh(void) /* LD (IX+d),H */
{
*(IX + (char) *PC++ + ram) = H;
return(19);
}
static int op_ldxdl(void) /* LD (IX+d),L */
{
*(IX + (char) *PC++ + ram) = L;
return(19);
}
static int op_ldxdn(void) /* LD (IX+d),n */
{
register int d;
d = (char) *PC++;
*(IX + d + ram) = *PC++;
return(19);
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,728 @@
/*
* 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
* 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
* 20-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
* 07-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* Like the function "cpu()" this one emulates multi byte opcodes
* starting with 0xfd
*/
#include "sim.h"
#include "simglb.h"
static int trap_fd(void);
static int op_popiy(void), op_pusiy(void);
static int op_jpiy(void);
static int op_exspy(void);
static int op_ldspy(void);
static int op_ldiynn(void), op_ldiyinn(void), op_ldiny(void);
static int op_adayd(void), op_acayd(void), op_suayd(void), op_scayd(void);
static int op_andyd(void), op_xoryd(void), op_oryd(void), op_cpyd(void);
static int op_decyd(void), op_incyd(void);
static int op_addyb(void), op_addyd(void), op_addys(void), op_addyy(void);
static int op_andyd(void), op_xoryd(void), op_oryd(void), op_cpyd(void);
static int op_decyd(void), op_incyd(void);
static int op_inciy(void), op_deciy(void);
static int op_ldayd(void), op_ldbyd(void), op_ldcyd(void);
static int op_lddyd(void), op_ldeyd(void);
static int op_ldhyd(void), op_ldlyd(void);
static int op_ldyda(void), op_ldydb(void), op_ldydc(void);
static int op_ldydd(void), op_ldyde(void);
static int op_ldydh(void), op_ldydl(void), op_ldydn(void);
extern int op_fdcb_handel(void);
int op_fd_handel(void)
{
register int t;
static int (*op_fd[256]) () = {
trap_fd, /* 0x00 */
trap_fd, /* 0x01 */
trap_fd, /* 0x02 */
trap_fd, /* 0x03 */
trap_fd, /* 0x04 */
trap_fd, /* 0x05 */
trap_fd, /* 0x06 */
trap_fd, /* 0x07 */
trap_fd, /* 0x08 */
op_addyb, /* 0x09 */
trap_fd, /* 0x0a */
trap_fd, /* 0x0b */
trap_fd, /* 0x0c */
trap_fd, /* 0x0d */
trap_fd, /* 0x0e */
trap_fd, /* 0x0f */
trap_fd, /* 0x10 */
trap_fd, /* 0x11 */
trap_fd, /* 0x12 */
trap_fd, /* 0x13 */
trap_fd, /* 0x14 */
trap_fd, /* 0x15 */
trap_fd, /* 0x16 */
trap_fd, /* 0x17 */
trap_fd, /* 0x18 */
op_addyd, /* 0x19 */
trap_fd, /* 0x1a */
trap_fd, /* 0x1b */
trap_fd, /* 0x1c */
trap_fd, /* 0x1d */
trap_fd, /* 0x1e */
trap_fd, /* 0x1f */
trap_fd, /* 0x20 */
op_ldiynn, /* 0x21 */
op_ldiny, /* 0x22 */
op_inciy, /* 0x23 */
trap_fd, /* 0x24 */
trap_fd, /* 0x25 */
trap_fd, /* 0x26 */
trap_fd, /* 0x27 */
trap_fd, /* 0x28 */
op_addyy, /* 0x29 */
op_ldiyinn, /* 0x2a */
op_deciy, /* 0x2b */
trap_fd, /* 0x2c */
trap_fd, /* 0x2d */
trap_fd, /* 0x2e */
trap_fd, /* 0x2f */
trap_fd, /* 0x30 */
trap_fd, /* 0x31 */
trap_fd, /* 0x32 */
trap_fd, /* 0x33 */
op_incyd, /* 0x34 */
op_decyd, /* 0x35 */
op_ldydn, /* 0x36 */
trap_fd, /* 0x37 */
trap_fd, /* 0x38 */
op_addys, /* 0x39 */
trap_fd, /* 0x3a */
trap_fd, /* 0x3b */
trap_fd, /* 0x3c */
trap_fd, /* 0x3d */
trap_fd, /* 0x3e */
trap_fd, /* 0x3f */
trap_fd, /* 0x40 */
trap_fd, /* 0x41 */
trap_fd, /* 0x42 */
trap_fd, /* 0x43 */
trap_fd, /* 0x44 */
trap_fd, /* 0x45 */
op_ldbyd, /* 0x46 */
trap_fd, /* 0x47 */
trap_fd, /* 0x48 */
trap_fd, /* 0x49 */
trap_fd, /* 0x4a */
trap_fd, /* 0x4b */
trap_fd, /* 0x4c */
trap_fd, /* 0x4d */
op_ldcyd, /* 0x4e */
trap_fd, /* 0x4f */
trap_fd, /* 0x50 */
trap_fd, /* 0x51 */
trap_fd, /* 0x52 */
trap_fd, /* 0x53 */
trap_fd, /* 0x54 */
trap_fd, /* 0x55 */
op_lddyd, /* 0x56 */
trap_fd, /* 0x57 */
trap_fd, /* 0x58 */
trap_fd, /* 0x59 */
trap_fd, /* 0x5a */
trap_fd, /* 0x5b */
trap_fd, /* 0x5c */
trap_fd, /* 0x5d */
op_ldeyd, /* 0x5e */
trap_fd, /* 0x5f */
trap_fd, /* 0x60 */
trap_fd, /* 0x61 */
trap_fd, /* 0x62 */
trap_fd, /* 0x63 */
trap_fd, /* 0x64 */
trap_fd, /* 0x65 */
op_ldhyd, /* 0x66 */
trap_fd, /* 0x67 */
trap_fd, /* 0x68 */
trap_fd, /* 0x69 */
trap_fd, /* 0x6a */
trap_fd, /* 0x6b */
trap_fd, /* 0x6c */
trap_fd, /* 0x6d */
op_ldlyd, /* 0x6e */
trap_fd, /* 0x6f */
op_ldydb, /* 0x70 */
op_ldydc, /* 0x71 */
op_ldydd, /* 0x72 */
op_ldyde, /* 0x73 */
op_ldydh, /* 0x74 */
op_ldydl, /* 0x75 */
trap_fd, /* 0x76 */
op_ldyda, /* 0x77 */
trap_fd, /* 0x78 */
trap_fd, /* 0x79 */
trap_fd, /* 0x7a */
trap_fd, /* 0x7b */
trap_fd, /* 0x7c */
trap_fd, /* 0x7d */
op_ldayd, /* 0x7e */
trap_fd, /* 0x7f */
trap_fd, /* 0x80 */
trap_fd, /* 0x81 */
trap_fd, /* 0x82 */
trap_fd, /* 0x83 */
trap_fd, /* 0x84 */
trap_fd, /* 0x85 */
op_adayd, /* 0x86 */
trap_fd, /* 0x87 */
trap_fd, /* 0x88 */
trap_fd, /* 0x89 */
trap_fd, /* 0x8a */
trap_fd, /* 0x8b */
trap_fd, /* 0x8c */
trap_fd, /* 0x8d */
op_acayd, /* 0x8e */
trap_fd, /* 0x8f */
trap_fd, /* 0x90 */
trap_fd, /* 0x91 */
trap_fd, /* 0x92 */
trap_fd, /* 0x93 */
trap_fd, /* 0x94 */
trap_fd, /* 0x95 */
op_suayd, /* 0x96 */
trap_fd, /* 0x97 */
trap_fd, /* 0x98 */
trap_fd, /* 0x99 */
trap_fd, /* 0x9a */
trap_fd, /* 0x9b */
trap_fd, /* 0x9c */
trap_fd, /* 0x9d */
op_scayd, /* 0x9e */
trap_fd, /* 0x9f */
trap_fd, /* 0xa0 */
trap_fd, /* 0xa1 */
trap_fd, /* 0xa2 */
trap_fd, /* 0xa3 */
trap_fd, /* 0xa4 */
trap_fd, /* 0xa5 */
op_andyd, /* 0xa6 */
trap_fd, /* 0xa7 */
trap_fd, /* 0xa8 */
trap_fd, /* 0xa9 */
trap_fd, /* 0xaa */
trap_fd, /* 0xab */
trap_fd, /* 0xac */
trap_fd, /* 0xad */
op_xoryd, /* 0xae */
trap_fd, /* 0xaf */
trap_fd, /* 0xb0 */
trap_fd, /* 0xb1 */
trap_fd, /* 0xb2 */
trap_fd, /* 0xb3 */
trap_fd, /* 0xb4 */
trap_fd, /* 0xb5 */
op_oryd, /* 0xb6 */
trap_fd, /* 0xb7 */
trap_fd, /* 0xb8 */
trap_fd, /* 0xb9 */
trap_fd, /* 0xba */
trap_fd, /* 0xbb */
trap_fd, /* 0xbc */
trap_fd, /* 0xbd */
op_cpyd, /* 0xbe */
trap_fd, /* 0xbf */
trap_fd, /* 0xc0 */
trap_fd, /* 0xc1 */
trap_fd, /* 0xc2 */
trap_fd, /* 0xc3 */
trap_fd, /* 0xc4 */
trap_fd, /* 0xc5 */
trap_fd, /* 0xc6 */
trap_fd, /* 0xc7 */
trap_fd, /* 0xc8 */
trap_fd, /* 0xc9 */
trap_fd, /* 0xca */
op_fdcb_handel, /* 0xcb */
trap_fd, /* 0xcc */
trap_fd, /* 0xcd */
trap_fd, /* 0xce */
trap_fd, /* 0xcf */
trap_fd, /* 0xd0 */
trap_fd, /* 0xd1 */
trap_fd, /* 0xd2 */
trap_fd, /* 0xd3 */
trap_fd, /* 0xd4 */
trap_fd, /* 0xd5 */
trap_fd, /* 0xd6 */
trap_fd, /* 0xd7 */
trap_fd, /* 0xd8 */
trap_fd, /* 0xd9 */
trap_fd, /* 0xda */
trap_fd, /* 0xdb */
trap_fd, /* 0xdc */
trap_fd, /* 0xdd */
trap_fd, /* 0xde */
trap_fd, /* 0xdf */
trap_fd, /* 0xe0 */
op_popiy, /* 0xe1 */
trap_fd, /* 0xe2 */
op_exspy, /* 0xe3 */
trap_fd, /* 0xe4 */
op_pusiy, /* 0xe5 */
trap_fd, /* 0xe6 */
trap_fd, /* 0xe7 */
trap_fd, /* 0xe8 */
op_jpiy, /* 0xe9 */
trap_fd, /* 0xea */
trap_fd, /* 0xeb */
trap_fd, /* 0xec */
trap_fd, /* 0xed */
trap_fd, /* 0xee */
trap_fd, /* 0xef */
trap_fd, /* 0xf0 */
trap_fd, /* 0xf1 */
trap_fd, /* 0xf2 */
trap_fd, /* 0xf3 */
trap_fd, /* 0xf4 */
trap_fd, /* 0xf5 */
trap_fd, /* 0xf6 */
trap_fd, /* 0xf7 */
trap_fd, /* 0xf8 */
op_ldspy, /* 0xf9 */
trap_fd, /* 0xfa */
trap_fd, /* 0xfb */
trap_fd, /* 0xfc */
trap_fd, /* 0xfd */
trap_fd, /* 0xfe */
trap_fd /* 0xff */
};
#ifdef WANT_TIM
t = (*op_fd[*PC++]) (); /* execute next opcode */
#else
(*op_fd[*PC++]) ();
#endif
#ifdef WANT_PCC
if (PC > ram + 65535) /* correct PC overrun */
PC = ram;
#endif
return(t);
}
/*
* This function traps all illegal opcodes following the
* initial 0xfd of a multi byte opcode.
*/
static int trap_fd(void)
{
cpu_error = OPTRAP2;
cpu_state = STOPPED;
return(0);
}
static int op_popiy(void) /* POP IY */
{
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
IY = *STACK++;
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
IY += *STACK++ << 8;
return(14);
}
static int op_pusiy(void) /* PUSH IY */
{
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
*--STACK = IY >> 8;
#ifdef WANT_SPC
if (STACK <= ram)
STACK = ram + 65536L;
#endif
*--STACK = IY;
return(15);
}
static int op_jpiy(void) /* JP (IY) */
{
PC = ram + IY;
return(8);
}
static int op_exspy(void) /* EX (SP),IY */
{
register int i;
i = *STACK + (*(STACK + 1) << 8);
*STACK = IY;
*(STACK + 1) = IY >> 8;
IY = i;
return(23);
}
static int op_ldspy(void) /* LD SP,IY */
{
STACK = ram + IY;
return(10);
}
static int op_ldiynn(void) /* LD IY,nn */
{
IY = *PC++;
IY += *PC++ << 8;
return(14);
}
static int op_ldiyinn(void) /* LD IY,(nn) */
{
register BYTE *p;
p = ram + *PC++;
p += *PC++ << 8;
IY = *p++;
IY += *p << 8;
return(20);
}
static int op_ldiny(void) /* LD (nn),IY */
{
register BYTE *p;
p = ram + *PC++;
p += *PC++ << 8;
*p++ = IY;
*p = IY >> 8;
return(20);
}
static int op_adayd(void) /* ADD A,(IY+d) */
{
register int i;
register BYTE P;
P = *(ram + IY + (char) *PC++);
((A & 0xf) + (P & 0xf) > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(A + P > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A + (char) P;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F &= ~N_FLAG;
return(19);
}
static int op_acayd(void) /* ADC A,(IY+d) */
{
register int i, carry;
register BYTE P;
carry = (F & C_FLAG) ? 1 : 0;
P = *(ram + IY + (char) *PC++);
((A & 0xf) + (P & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(A + P + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A + (char) P + carry;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F &= ~N_FLAG;
return(19);
}
static int op_suayd(void) /* SUB A,(IY+d) */
{
register int i;
register BYTE P;
P = *(ram + IY + (char) *PC++);
((P & 0xf) > (A & 0xf)) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(P > A) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A - (char) P;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(19);
}
static int op_scayd(void) /* SBC A,(IY+d) */
{
register int i, carry;
register BYTE P;
carry = (F & C_FLAG) ? 1 : 0;
P = *(ram + IY + (char) *PC++);
((P & 0xf) + carry > (A & 0xf)) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(P + carry > A) ? (F |= C_FLAG) : (F &= ~C_FLAG);
A = i = (char) A - (char) P - carry;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(19);
}
static int op_andyd(void) /* AND (IY+d) */
{
A &= *(ram + IY + (char) *PC++);
(A & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= H_FLAG;
(parrity[A]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
F &= ~(N_FLAG | C_FLAG);
return(19);
}
static int op_xoryd(void) /* XOR (IY+d) */
{
A ^= *(ram + IY + (char) *PC++);
(A & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(parrity[A]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
F &= ~(H_FLAG | N_FLAG | C_FLAG);
return(19);
}
static int op_oryd(void) /* OR (IY+d) */
{
A |= *(ram + IY + (char) *PC++);
(A & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(A) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(parrity[A]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
F &= ~(H_FLAG | N_FLAG | C_FLAG);
return(19);
}
static int op_cpyd(void) /* CP (IY+d) */
{
register int i;
register BYTE P;
P = *(ram + IY + (char) *PC++);
((P & 0xf) > (A & 0xf)) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(P > A) ? (F |= C_FLAG) : (F &= ~C_FLAG);
i = (char) A - (char) P;
(i < -128 || i > 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(i & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(i) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(19);
}
static int op_incyd(void) /* INC (IY+d) */
{
register BYTE *p;
p = ram + IY + (char) *PC++;
((*p & 0xf) + 1 > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(*p)++;
(*p == 128) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F &= ~N_FLAG;
return(23);
}
static int op_decyd(void) /* DEC (IY+d) */
{
register BYTE *p;
p = ram + IY + (char) *PC++;
(((*p - 1) & 0xf) == 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(*p)--;
(*p == 127) ? (F |= P_FLAG) : (F &= ~P_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
F |= N_FLAG;
return(23);
}
static int op_addyb(void) /* ADD IY,BC */
{
register int carry;
BYTE iyl = IY & 0xff;
BYTE iyh = IY >> 8;
carry = (iyl + C > 255) ? 1 : 0;
iyl += C;
((iyh & 0xf) + (B & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(iyh + B + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
iyh += B + carry;
IY = (iyh << 8) + iyl;
F &= ~N_FLAG;
return(15);
}
static int op_addyd(void) /* ADD IY,DE */
{
register int carry;
BYTE iyl = IY & 0xff;
BYTE iyh = IY >> 8;
carry = (iyl + E > 255) ? 1 : 0;
iyl += E;
((iyh & 0xf) + (D & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(iyh + D + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
iyh += D + carry;
IY = (iyh << 8) + iyl;
F &= ~N_FLAG;
return(15);
}
static int op_addys(void) /* ADD IY,SP */
{
register int carry;
BYTE iyl = IY & 0xff;
BYTE iyh = IY >> 8;
BYTE spl = (STACK - ram) & 0xff;
BYTE sph = (STACK - ram) >> 8;
carry = (iyl + spl > 255) ? 1 : 0;
iyl += spl;
((iyh & 0xf) + (sph & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(iyh + sph + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
iyh += sph + carry;
IY = (iyh << 8) + iyl;
F &= ~N_FLAG;
return(15);
}
static int op_addyy(void) /* ADD IY,IY */
{
register int carry;
BYTE iyl = IY & 0xff;
BYTE iyh = IY >> 8;
carry = (iyl << 1 > 255) ? 1 : 0;
iyl <<= 1;
((iyh & 0xf) + (iyh & 0xf) + carry > 0xf) ? (F |= H_FLAG) : (F &= ~H_FLAG);
(iyh + iyh + carry > 255) ? (F |= C_FLAG) : (F &= ~C_FLAG);
iyh += iyh + carry;
IY = (iyh << 8) + iyl;
F &= ~N_FLAG;
return(15);
}
static int op_inciy(void) /* INC IY */
{
IY++;
return(10);
}
static int op_deciy(void) /* DEC IY */
{
IY--;
return(10);
}
static int op_ldayd(void) /* LD A,(IY+d) */
{
A = *(IY + (char) *PC++ + ram);
return(19);
}
static int op_ldbyd(void) /* LD B,(IY+d) */
{
B = *(IY + (char) *PC++ + ram);
return(19);
}
static int op_ldcyd(void) /* LD C,(IY+d) */
{
C = *(IY + (char) *PC++ + ram);
return(19);
}
static int op_lddyd(void) /* LD D,(IY+d) */
{
D = *(IY + (char) *PC++ + ram);
return(19);
}
static int op_ldeyd(void) /* LD E,(IY+d) */
{
E = *(IY + (char) *PC++ + ram);
return(19);
}
static int op_ldhyd(void) /* LD H,(IY+d) */
{
H = *(IY + (char) *PC++ + ram);
return(19);
}
static int op_ldlyd(void) /* LD L,(IY+d) */
{
L = *(IY + (char) *PC++ + ram);
return(19);
}
static int op_ldyda(void) /* LD (IY+d),A */
{
*(IY + (char) *PC++ + ram) = A;
return(19);
}
static int op_ldydb(void) /* LD (IY+d),B */
{
*(IY + (char) *PC++ + ram) = B;
return(19);
}
static int op_ldydc(void) /* LD (IY+d),C */
{
*(IY + (char) *PC++ + ram) = C;
return(19);
}
static int op_ldydd(void) /* LD (IY+d),D */
{
*(IY + (char) *PC++ + ram) = D;
return(19);
}
static int op_ldyde(void) /* LD (IY+d),E */
{
*(IY + (char) *PC++ + ram) = E;
return(19);
}
static int op_ldydh(void) /* LD (IY+d),H */
{
*(IY + (char) *PC++ + ram) = H;
return(19);
}
static int op_ldydl(void) /* LD (IY+d),L */
{
*(IY + (char) *PC++ + ram) = L;
return(19);
}
static int op_ldydn(void) /* LD (IY+d),n */
{
register int d;
d = (char) *PC++;
*(IY + d + ram) = *PC++;
return(19);
}

Binary file not shown.

View File

@@ -0,0 +1,617 @@
/*
* 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
* 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
* 20-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
* 07-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* Like the function "cpu()" this one emulates 4 byte opcodes
* starting with 0xdd 0xcb
*/
#include "sim.h"
#include "simglb.h"
static int trap_ddcb(void);
static int op_tb0ixd(int), op_tb1ixd(int), op_tb2ixd(int), op_tb3ixd(int);
static int op_tb4ixd(int), op_tb5ixd(int), op_tb6ixd(int), op_tb7ixd(int);
static int op_rb0ixd(int), op_rb1ixd(int), op_rb2ixd(int), op_rb3ixd(int);
static int op_rb4ixd(int), op_rb5ixd(int), op_rb6ixd(int), op_rb7ixd(int);
static int op_sb0ixd(int), op_sb1ixd(int), op_sb2ixd(int), op_sb3ixd(int);
static int op_sb4ixd(int), op_sb5ixd(int), op_sb6ixd(int), op_sb7ixd(int);
static int op_rlcixd(int), op_rrcixd(int), op_rlixd(int), op_rrixd(int);
static int op_slaixd(int), op_sraixd(int), op_srlixd(int);
int op_ddcb_handel(void)
{
static int (*op_ddcb[256]) () = {
trap_ddcb, /* 0x00 */
trap_ddcb, /* 0x01 */
trap_ddcb, /* 0x02 */
trap_ddcb, /* 0x03 */
trap_ddcb, /* 0x04 */
trap_ddcb, /* 0x05 */
op_rlcixd, /* 0x06 */
trap_ddcb, /* 0x07 */
trap_ddcb, /* 0x08 */
trap_ddcb, /* 0x09 */
trap_ddcb, /* 0x0a */
trap_ddcb, /* 0x0b */
trap_ddcb, /* 0x0c */
trap_ddcb, /* 0x0d */
op_rrcixd, /* 0x0e */
trap_ddcb, /* 0x0f */
trap_ddcb, /* 0x10 */
trap_ddcb, /* 0x11 */
trap_ddcb, /* 0x12 */
trap_ddcb, /* 0x13 */
trap_ddcb, /* 0x14 */
trap_ddcb, /* 0x15 */
op_rlixd, /* 0x16 */
trap_ddcb, /* 0x17 */
trap_ddcb, /* 0x18 */
trap_ddcb, /* 0x19 */
trap_ddcb, /* 0x1a */
trap_ddcb, /* 0x1b */
trap_ddcb, /* 0x1c */
trap_ddcb, /* 0x1d */
op_rrixd, /* 0x1e */
trap_ddcb, /* 0x1f */
trap_ddcb, /* 0x20 */
trap_ddcb, /* 0x21 */
trap_ddcb, /* 0x22 */
trap_ddcb, /* 0x23 */
trap_ddcb, /* 0x24 */
trap_ddcb, /* 0x25 */
op_slaixd, /* 0x26 */
trap_ddcb, /* 0x27 */
trap_ddcb, /* 0x28 */
trap_ddcb, /* 0x29 */
trap_ddcb, /* 0x2a */
trap_ddcb, /* 0x2b */
trap_ddcb, /* 0x2c */
trap_ddcb, /* 0x2d */
op_sraixd, /* 0x2e */
trap_ddcb, /* 0x2f */
trap_ddcb, /* 0x30 */
trap_ddcb, /* 0x31 */
trap_ddcb, /* 0x32 */
trap_ddcb, /* 0x33 */
trap_ddcb, /* 0x34 */
trap_ddcb, /* 0x35 */
trap_ddcb, /* 0x36 */
trap_ddcb, /* 0x37 */
trap_ddcb, /* 0x38 */
trap_ddcb, /* 0x39 */
trap_ddcb, /* 0x3a */
trap_ddcb, /* 0x3b */
trap_ddcb, /* 0x3c */
trap_ddcb, /* 0x3d */
op_srlixd, /* 0x3e */
trap_ddcb, /* 0x3f */
trap_ddcb, /* 0x40 */
trap_ddcb, /* 0x41 */
trap_ddcb, /* 0x42 */
trap_ddcb, /* 0x43 */
trap_ddcb, /* 0x44 */
trap_ddcb, /* 0x45 */
op_tb0ixd, /* 0x46 */
trap_ddcb, /* 0x47 */
trap_ddcb, /* 0x48 */
trap_ddcb, /* 0x49 */
trap_ddcb, /* 0x4a */
trap_ddcb, /* 0x4b */
trap_ddcb, /* 0x4c */
trap_ddcb, /* 0x4d */
op_tb1ixd, /* 0x4e */
trap_ddcb, /* 0x4f */
trap_ddcb, /* 0x50 */
trap_ddcb, /* 0x51 */
trap_ddcb, /* 0x52 */
trap_ddcb, /* 0x53 */
trap_ddcb, /* 0x54 */
trap_ddcb, /* 0x55 */
op_tb2ixd, /* 0x56 */
trap_ddcb, /* 0x57 */
trap_ddcb, /* 0x58 */
trap_ddcb, /* 0x59 */
trap_ddcb, /* 0x5a */
trap_ddcb, /* 0x5b */
trap_ddcb, /* 0x5c */
trap_ddcb, /* 0x5d */
op_tb3ixd, /* 0x5e */
trap_ddcb, /* 0x5f */
trap_ddcb, /* 0x60 */
trap_ddcb, /* 0x61 */
trap_ddcb, /* 0x62 */
trap_ddcb, /* 0x63 */
trap_ddcb, /* 0x64 */
trap_ddcb, /* 0x65 */
op_tb4ixd, /* 0x66 */
trap_ddcb, /* 0x67 */
trap_ddcb, /* 0x68 */
trap_ddcb, /* 0x69 */
trap_ddcb, /* 0x6a */
trap_ddcb, /* 0x6b */
trap_ddcb, /* 0x6c */
trap_ddcb, /* 0x6d */
op_tb5ixd, /* 0x6e */
trap_ddcb, /* 0x6f */
trap_ddcb, /* 0x70 */
trap_ddcb, /* 0x71 */
trap_ddcb, /* 0x72 */
trap_ddcb, /* 0x73 */
trap_ddcb, /* 0x74 */
trap_ddcb, /* 0x75 */
op_tb6ixd, /* 0x76 */
trap_ddcb, /* 0x77 */
trap_ddcb, /* 0x78 */
trap_ddcb, /* 0x79 */
trap_ddcb, /* 0x7a */
trap_ddcb, /* 0x7b */
trap_ddcb, /* 0x7c */
trap_ddcb, /* 0x7d */
op_tb7ixd, /* 0x7e */
trap_ddcb, /* 0x7f */
trap_ddcb, /* 0x80 */
trap_ddcb, /* 0x81 */
trap_ddcb, /* 0x82 */
trap_ddcb, /* 0x83 */
trap_ddcb, /* 0x84 */
trap_ddcb, /* 0x85 */
op_rb0ixd, /* 0x86 */
trap_ddcb, /* 0x87 */
trap_ddcb, /* 0x88 */
trap_ddcb, /* 0x89 */
trap_ddcb, /* 0x8a */
trap_ddcb, /* 0x8b */
trap_ddcb, /* 0x8c */
trap_ddcb, /* 0x8d */
op_rb1ixd, /* 0x8e */
trap_ddcb, /* 0x8f */
trap_ddcb, /* 0x90 */
trap_ddcb, /* 0x91 */
trap_ddcb, /* 0x92 */
trap_ddcb, /* 0x93 */
trap_ddcb, /* 0x94 */
trap_ddcb, /* 0x95 */
op_rb2ixd, /* 0x96 */
trap_ddcb, /* 0x97 */
trap_ddcb, /* 0x98 */
trap_ddcb, /* 0x99 */
trap_ddcb, /* 0x9a */
trap_ddcb, /* 0x9b */
trap_ddcb, /* 0x9c */
trap_ddcb, /* 0x9d */
op_rb3ixd, /* 0x9e */
trap_ddcb, /* 0x9f */
trap_ddcb, /* 0xa0 */
trap_ddcb, /* 0xa1 */
trap_ddcb, /* 0xa2 */
trap_ddcb, /* 0xa3 */
trap_ddcb, /* 0xa4 */
trap_ddcb, /* 0xa5 */
op_rb4ixd, /* 0xa6 */
trap_ddcb, /* 0xa7 */
trap_ddcb, /* 0xa8 */
trap_ddcb, /* 0xa9 */
trap_ddcb, /* 0xaa */
trap_ddcb, /* 0xab */
trap_ddcb, /* 0xac */
trap_ddcb, /* 0xad */
op_rb5ixd, /* 0xae */
trap_ddcb, /* 0xaf */
trap_ddcb, /* 0xb0 */
trap_ddcb, /* 0xb1 */
trap_ddcb, /* 0xb2 */
trap_ddcb, /* 0xb3 */
trap_ddcb, /* 0xb4 */
trap_ddcb, /* 0xb5 */
op_rb6ixd, /* 0xb6 */
trap_ddcb, /* 0xb7 */
trap_ddcb, /* 0xb8 */
trap_ddcb, /* 0xb9 */
trap_ddcb, /* 0xba */
trap_ddcb, /* 0xbb */
trap_ddcb, /* 0xbc */
trap_ddcb, /* 0xbd */
op_rb7ixd, /* 0xbe */
trap_ddcb, /* 0xbf */
trap_ddcb, /* 0xc0 */
trap_ddcb, /* 0xc1 */
trap_ddcb, /* 0xc2 */
trap_ddcb, /* 0xc3 */
trap_ddcb, /* 0xc4 */
trap_ddcb, /* 0xc5 */
op_sb0ixd, /* 0xc6 */
trap_ddcb, /* 0xc7 */
trap_ddcb, /* 0xc8 */
trap_ddcb, /* 0xc9 */
trap_ddcb, /* 0xca */
trap_ddcb, /* 0xcb */
trap_ddcb, /* 0xcc */
trap_ddcb, /* 0xcd */
op_sb1ixd, /* 0xce */
trap_ddcb, /* 0xcf */
trap_ddcb, /* 0xd0 */
trap_ddcb, /* 0xd1 */
trap_ddcb, /* 0xd2 */
trap_ddcb, /* 0xd3 */
trap_ddcb, /* 0xd4 */
trap_ddcb, /* 0xd5 */
op_sb2ixd, /* 0xd6 */
trap_ddcb, /* 0xd7 */
trap_ddcb, /* 0xd8 */
trap_ddcb, /* 0xd9 */
trap_ddcb, /* 0xda */
trap_ddcb, /* 0xdb */
trap_ddcb, /* 0xdc */
trap_ddcb, /* 0xdd */
op_sb3ixd, /* 0xde */
trap_ddcb, /* 0xdf */
trap_ddcb, /* 0xe0 */
trap_ddcb, /* 0xe1 */
trap_ddcb, /* 0xe2 */
trap_ddcb, /* 0xe3 */
trap_ddcb, /* 0xe4 */
trap_ddcb, /* 0xe5 */
op_sb4ixd, /* 0xe6 */
trap_ddcb, /* 0xe7 */
trap_ddcb, /* 0xe8 */
trap_ddcb, /* 0xe9 */
trap_ddcb, /* 0xea */
trap_ddcb, /* 0xeb */
trap_ddcb, /* 0xec */
trap_ddcb, /* 0xed */
op_sb5ixd, /* 0xee */
trap_ddcb, /* 0xef */
trap_ddcb, /* 0xf0 */
trap_ddcb, /* 0xf1 */
trap_ddcb, /* 0xf2 */
trap_ddcb, /* 0xf3 */
trap_ddcb, /* 0xf4 */
trap_ddcb, /* 0xf5 */
op_sb6ixd, /* 0xf6 */
trap_ddcb, /* 0xf7 */
trap_ddcb, /* 0xf8 */
trap_ddcb, /* 0xf9 */
trap_ddcb, /* 0xfa */
trap_ddcb, /* 0xfb */
trap_ddcb, /* 0xfc */
trap_ddcb, /* 0xfd */
op_sb7ixd, /* 0xfe */
trap_ddcb /* 0xff */
};
register int d;
register int t;
d = (char) *PC++;
#ifdef WANT_PCC
if (PC > ram + 65535) /* correct PC overrun */
PC = ram;
#endif
#ifdef WANT_TIM
t = (*op_ddcb[*PC++]) (d); /* execute next opcode */
#else
(*op_ddcb[*PC++]) (d);
#endif
#ifdef WANT_PCC
if (PC > ram + 65535) /* again correct PC overrun */
PC = ram;
#endif
return(t);
}
/*
* This function traps all illegal opcodes following the
* initial 0xdd 0xcb of a 4 byte opcode.
*/
static int trap_ddcb(void)
{
cpu_error = OPTRAP4;
cpu_state = STOPPED;
return(0);
}
static int op_tb0ixd(int data) /* BIT 0,(IX+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IX + data) & 1) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb1ixd(int data) /* BIT 1,(IX+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IX + data) & 2) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb2ixd(int data) /* BIT 2,(IX+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IX + data) & 4) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb3ixd(int data) /* BIT 3,(IX+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IX + data) & 8) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb4ixd(int data) /* BIT 4,(IX+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IX + data) & 16) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb5ixd(int data) /* BIT 5,(IX+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IX + data) & 32) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb6ixd(int data) /* BIT 6,(IX+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IX + data) & 64) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb7ixd(int data) /* BIT 7,(IX+d) */
{
F &= ~N_FLAG;
F |= H_FLAG;
if (*(ram + IX + data) & 128) {
F &= ~(Z_FLAG | P_FLAG);
F |= S_FLAG;
} else {
F |= (Z_FLAG | P_FLAG);
F &= ~S_FLAG;
}
return(20);
}
static int op_rb0ixd(int data) /* RES 0,(IX+d) */
{
*(ram + IX + data) &= ~1;
return(23);
}
static int op_rb1ixd(int data) /* RES 1,(IX+d) */
{
*(ram + IX + data) &= ~2;
return(23);
}
static int op_rb2ixd(int data) /* RES 2,(IX+d) */
{
*(ram + IX + data) &= ~4;
return(23);
}
static int op_rb3ixd(int data) /* RES 3,(IX+d) */
{
*(ram + IX + data) &= ~8;
return(23);
}
static int op_rb4ixd(int data) /* RES 4,(IX+d) */
{
*(ram + IX + data) &= ~16;
return(23);
}
static int op_rb5ixd(int data) /* RES 5,(IX+d) */
{
*(ram + IX + data) &= ~32;
return(23);
}
static int op_rb6ixd(int data) /* RES 6,(IX+d) */
{
*(ram + IX + data) &= ~64;
return(23);
}
static int op_rb7ixd(int data) /* RES 7,(IX+d) */
{
*(ram + IX + data) &= ~128;
return(23);
}
static int op_sb0ixd(int data) /* SET 0,(IX+d) */
{
*(ram + IX + data) |= 1;
return(23);
}
static int op_sb1ixd(int data) /* SET 1,(IX+d) */
{
*(ram + IX + data) |= 2;
return(23);
}
static int op_sb2ixd(int data) /* SET 2,(IX+d) */
{
*(ram + IX + data) |= 4;
return(23);
}
static int op_sb3ixd(int data) /* SET 3,(IX+d) */
{
*(ram + IX + data) |= 8;
return(23);
}
static int op_sb4ixd(int data) /* SET 4,(IX+d) */
{
*(ram + IX + data) |= 16;
return(23);
}
static int op_sb5ixd(int data) /* SET 5,(IX+d) */
{
*(ram + IX + data) |= 32;
return(23);
}
static int op_sb6ixd(int data) /* SET 6,(IX+d) */
{
*(ram + IX + data) |= 64;
return(23);
}
static int op_sb7ixd(int data) /* SET 7,(IX+d) */
{
*(ram + IX + data) |= 128;
return(23);
}
static int op_rlcixd(int data) /* RLC (IX+d) */
{
register int i;
register BYTE *p;
p = ram + IX + data;
i = *p & 128;
(i) ? (F |= C_FLAG) : (F &= ~C_FLAG);
F &= ~(H_FLAG | N_FLAG);
*p <<= 1;
if (i) *p |= 1;
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_rrcixd(int data) /* RRC (IX+d) */
{
register int i;
register BYTE *p;
p = ram + IX + data;
i = *p & 1;
(i) ? (F |= C_FLAG) : (F &= ~C_FLAG);
F &= ~(H_FLAG | N_FLAG);
*p >>= 1;
if (i) *p |= 128;
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_rlixd(int data) /* RL (IX+d) */
{
register int old_c_flag;
register BYTE *p;
p = ram + IX + data;
old_c_flag = F & C_FLAG;
(*p & 128) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p <<= 1;
if (old_c_flag) *p |= 1;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_rrixd(int data) /* RR (IX+d) */
{
register int old_c_flag;
register BYTE *p;
old_c_flag = F & C_FLAG;
p = ram + IX + data;
(*p & 1) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p >>= 1;
if (old_c_flag) *p |= 128;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_slaixd(int data) /* SLA (IX+d) */
{
register BYTE *p;
p = ram + IX + data;
(*p & 128) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p <<= 1;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_sraixd(int data) /* SRA (IX+d) */
{
register int i;
register BYTE *p;
p = ram + IX + data;
i = *p & 128;
(*p & 1) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p >>= 1;
*p |= i;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_srlixd(int data) /* SRL (IX+d) */
{
register BYTE *p;
p = ram + IX + data;
(*p & 1) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p >>= 1;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}

Binary file not shown.

View File

@@ -0,0 +1,617 @@
/*
* 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.1)
* 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
* 20-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
* 07-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* Like the function "cpu()" this one emulates 4 byte opcodes
* starting with 0xfd 0xcb
*/
#include "sim.h"
#include "simglb.h"
static int trap_fdcb(void);
static int op_tb0iyd(int), op_tb1iyd(int), op_tb2iyd(int), op_tb3iyd(int);
static int op_tb4iyd(int), op_tb5iyd(int), op_tb6iyd(int), op_tb7iyd(int);
static int op_rb0iyd(int), op_rb1iyd(int), op_rb2iyd(int), op_rb3iyd(int);
static int op_rb4iyd(int), op_rb5iyd(int), op_rb6iyd(int), op_rb7iyd(int);
static int op_sb0iyd(int), op_sb1iyd(int), op_sb2iyd(int), op_sb3iyd(int);
static int op_sb4iyd(int), op_sb5iyd(int), op_sb6iyd(int), op_sb7iyd(int);
static int op_rlciyd(int), op_rrciyd(int), op_rliyd(int), op_rriyd(int);
static int op_slaiyd(int), op_sraiyd(int), op_srliyd(int);
int op_fdcb_handel(void)
{
static int (*op_fdcb[256]) () = {
trap_fdcb, /* 0x00 */
trap_fdcb, /* 0x01 */
trap_fdcb, /* 0x02 */
trap_fdcb, /* 0x03 */
trap_fdcb, /* 0x04 */
trap_fdcb, /* 0x05 */
op_rlciyd, /* 0x06 */
trap_fdcb, /* 0x07 */
trap_fdcb, /* 0x08 */
trap_fdcb, /* 0x09 */
trap_fdcb, /* 0x0a */
trap_fdcb, /* 0x0b */
trap_fdcb, /* 0x0c */
trap_fdcb, /* 0x0d */
op_rrciyd, /* 0x0e */
trap_fdcb, /* 0x0f */
trap_fdcb, /* 0x10 */
trap_fdcb, /* 0x11 */
trap_fdcb, /* 0x12 */
trap_fdcb, /* 0x13 */
trap_fdcb, /* 0x14 */
trap_fdcb, /* 0x15 */
op_rliyd, /* 0x16 */
trap_fdcb, /* 0x17 */
trap_fdcb, /* 0x18 */
trap_fdcb, /* 0x19 */
trap_fdcb, /* 0x1a */
trap_fdcb, /* 0x1b */
trap_fdcb, /* 0x1c */
trap_fdcb, /* 0x1d */
op_rriyd, /* 0x1e */
trap_fdcb, /* 0x1f */
trap_fdcb, /* 0x20 */
trap_fdcb, /* 0x21 */
trap_fdcb, /* 0x22 */
trap_fdcb, /* 0x23 */
trap_fdcb, /* 0x24 */
trap_fdcb, /* 0x25 */
op_slaiyd, /* 0x26 */
trap_fdcb, /* 0x27 */
trap_fdcb, /* 0x28 */
trap_fdcb, /* 0x29 */
trap_fdcb, /* 0x2a */
trap_fdcb, /* 0x2b */
trap_fdcb, /* 0x2c */
trap_fdcb, /* 0x2d */
op_sraiyd, /* 0x2e */
trap_fdcb, /* 0x2f */
trap_fdcb, /* 0x30 */
trap_fdcb, /* 0x31 */
trap_fdcb, /* 0x32 */
trap_fdcb, /* 0x33 */
trap_fdcb, /* 0x34 */
trap_fdcb, /* 0x35 */
trap_fdcb, /* 0x36 */
trap_fdcb, /* 0x37 */
trap_fdcb, /* 0x38 */
trap_fdcb, /* 0x39 */
trap_fdcb, /* 0x3a */
trap_fdcb, /* 0x3b */
trap_fdcb, /* 0x3c */
trap_fdcb, /* 0x3d */
op_srliyd, /* 0x3e */
trap_fdcb, /* 0x3f */
trap_fdcb, /* 0x40 */
trap_fdcb, /* 0x41 */
trap_fdcb, /* 0x42 */
trap_fdcb, /* 0x43 */
trap_fdcb, /* 0x44 */
trap_fdcb, /* 0x45 */
op_tb0iyd, /* 0x46 */
trap_fdcb, /* 0x47 */
trap_fdcb, /* 0x48 */
trap_fdcb, /* 0x49 */
trap_fdcb, /* 0x4a */
trap_fdcb, /* 0x4b */
trap_fdcb, /* 0x4c */
trap_fdcb, /* 0x4d */
op_tb1iyd, /* 0x4e */
trap_fdcb, /* 0x4f */
trap_fdcb, /* 0x50 */
trap_fdcb, /* 0x51 */
trap_fdcb, /* 0x52 */
trap_fdcb, /* 0x53 */
trap_fdcb, /* 0x54 */
trap_fdcb, /* 0x55 */
op_tb2iyd, /* 0x56 */
trap_fdcb, /* 0x57 */
trap_fdcb, /* 0x58 */
trap_fdcb, /* 0x59 */
trap_fdcb, /* 0x5a */
trap_fdcb, /* 0x5b */
trap_fdcb, /* 0x5c */
trap_fdcb, /* 0x5d */
op_tb3iyd, /* 0x5e */
trap_fdcb, /* 0x5f */
trap_fdcb, /* 0x60 */
trap_fdcb, /* 0x61 */
trap_fdcb, /* 0x62 */
trap_fdcb, /* 0x63 */
trap_fdcb, /* 0x64 */
trap_fdcb, /* 0x65 */
op_tb4iyd, /* 0x66 */
trap_fdcb, /* 0x67 */
trap_fdcb, /* 0x68 */
trap_fdcb, /* 0x69 */
trap_fdcb, /* 0x6a */
trap_fdcb, /* 0x6b */
trap_fdcb, /* 0x6c */
trap_fdcb, /* 0x6d */
op_tb5iyd, /* 0x6e */
trap_fdcb, /* 0x6f */
trap_fdcb, /* 0x70 */
trap_fdcb, /* 0x71 */
trap_fdcb, /* 0x72 */
trap_fdcb, /* 0x73 */
trap_fdcb, /* 0x74 */
trap_fdcb, /* 0x75 */
op_tb6iyd, /* 0x76 */
trap_fdcb, /* 0x77 */
trap_fdcb, /* 0x78 */
trap_fdcb, /* 0x79 */
trap_fdcb, /* 0x7a */
trap_fdcb, /* 0x7b */
trap_fdcb, /* 0x7c */
trap_fdcb, /* 0x7d */
op_tb7iyd, /* 0x7e */
trap_fdcb, /* 0x7f */
trap_fdcb, /* 0x80 */
trap_fdcb, /* 0x81 */
trap_fdcb, /* 0x82 */
trap_fdcb, /* 0x83 */
trap_fdcb, /* 0x84 */
trap_fdcb, /* 0x85 */
op_rb0iyd, /* 0x86 */
trap_fdcb, /* 0x87 */
trap_fdcb, /* 0x88 */
trap_fdcb, /* 0x89 */
trap_fdcb, /* 0x8a */
trap_fdcb, /* 0x8b */
trap_fdcb, /* 0x8c */
trap_fdcb, /* 0x8d */
op_rb1iyd, /* 0x8e */
trap_fdcb, /* 0x8f */
trap_fdcb, /* 0x90 */
trap_fdcb, /* 0x91 */
trap_fdcb, /* 0x92 */
trap_fdcb, /* 0x93 */
trap_fdcb, /* 0x94 */
trap_fdcb, /* 0x95 */
op_rb2iyd, /* 0x96 */
trap_fdcb, /* 0x97 */
trap_fdcb, /* 0x98 */
trap_fdcb, /* 0x99 */
trap_fdcb, /* 0x9a */
trap_fdcb, /* 0x9b */
trap_fdcb, /* 0x9c */
trap_fdcb, /* 0x9d */
op_rb3iyd, /* 0x9e */
trap_fdcb, /* 0x9f */
trap_fdcb, /* 0xa0 */
trap_fdcb, /* 0xa1 */
trap_fdcb, /* 0xa2 */
trap_fdcb, /* 0xa3 */
trap_fdcb, /* 0xa4 */
trap_fdcb, /* 0xa5 */
op_rb4iyd, /* 0xa6 */
trap_fdcb, /* 0xa7 */
trap_fdcb, /* 0xa8 */
trap_fdcb, /* 0xa9 */
trap_fdcb, /* 0xaa */
trap_fdcb, /* 0xab */
trap_fdcb, /* 0xac */
trap_fdcb, /* 0xad */
op_rb5iyd, /* 0xae */
trap_fdcb, /* 0xaf */
trap_fdcb, /* 0xb0 */
trap_fdcb, /* 0xb1 */
trap_fdcb, /* 0xb2 */
trap_fdcb, /* 0xb3 */
trap_fdcb, /* 0xb4 */
trap_fdcb, /* 0xb5 */
op_rb6iyd, /* 0xb6 */
trap_fdcb, /* 0xb7 */
trap_fdcb, /* 0xb8 */
trap_fdcb, /* 0xb9 */
trap_fdcb, /* 0xba */
trap_fdcb, /* 0xbb */
trap_fdcb, /* 0xbc */
trap_fdcb, /* 0xbd */
op_rb7iyd, /* 0xbe */
trap_fdcb, /* 0xbf */
trap_fdcb, /* 0xc0 */
trap_fdcb, /* 0xc1 */
trap_fdcb, /* 0xc2 */
trap_fdcb, /* 0xc3 */
trap_fdcb, /* 0xc4 */
trap_fdcb, /* 0xc5 */
op_sb0iyd, /* 0xc6 */
trap_fdcb, /* 0xc7 */
trap_fdcb, /* 0xc8 */
trap_fdcb, /* 0xc9 */
trap_fdcb, /* 0xca */
trap_fdcb, /* 0xcb */
trap_fdcb, /* 0xcc */
trap_fdcb, /* 0xcd */
op_sb1iyd, /* 0xce */
trap_fdcb, /* 0xcf */
trap_fdcb, /* 0xd0 */
trap_fdcb, /* 0xd1 */
trap_fdcb, /* 0xd2 */
trap_fdcb, /* 0xd3 */
trap_fdcb, /* 0xd4 */
trap_fdcb, /* 0xd5 */
op_sb2iyd, /* 0xd6 */
trap_fdcb, /* 0xd7 */
trap_fdcb, /* 0xd8 */
trap_fdcb, /* 0xd9 */
trap_fdcb, /* 0xda */
trap_fdcb, /* 0xdb */
trap_fdcb, /* 0xdc */
trap_fdcb, /* 0xdd */
op_sb3iyd, /* 0xde */
trap_fdcb, /* 0xdf */
trap_fdcb, /* 0xe0 */
trap_fdcb, /* 0xe1 */
trap_fdcb, /* 0xe2 */
trap_fdcb, /* 0xe3 */
trap_fdcb, /* 0xe4 */
trap_fdcb, /* 0xe5 */
op_sb4iyd, /* 0xe6 */
trap_fdcb, /* 0xe7 */
trap_fdcb, /* 0xe8 */
trap_fdcb, /* 0xe9 */
trap_fdcb, /* 0xea */
trap_fdcb, /* 0xeb */
trap_fdcb, /* 0xec */
trap_fdcb, /* 0xed */
op_sb5iyd, /* 0xee */
trap_fdcb, /* 0xef */
trap_fdcb, /* 0xf0 */
trap_fdcb, /* 0xf1 */
trap_fdcb, /* 0xf2 */
trap_fdcb, /* 0xf3 */
trap_fdcb, /* 0xf4 */
trap_fdcb, /* 0xf5 */
op_sb6iyd, /* 0xf6 */
trap_fdcb, /* 0xf7 */
trap_fdcb, /* 0xf8 */
trap_fdcb, /* 0xf9 */
trap_fdcb, /* 0xfa */
trap_fdcb, /* 0xfb */
trap_fdcb, /* 0xfc */
trap_fdcb, /* 0xfd */
op_sb7iyd, /* 0xfe */
trap_fdcb /* 0xff */
};
register int d;
register int t;
d = (char) *PC++;
#ifdef WANT_PCC
if (PC > ram + 65535) /* correct PC overrun */
PC = ram;
#endif
#ifdef WANT_TIM
t = (*op_fdcb[*PC++]) (d); /* execute next opcode */
#else
(*op_fdcb[*PC++]) (d);
#endif
#ifdef WANT_PCC
if (PC > ram + 65535) /* again correct PC overrun */
PC = ram;
#endif
return(t);
}
/*
* This function traps all illegal opcodes following the
* initial 0xfd 0xcb of a 4 byte opcode.
*/
static int trap_fdcb(void)
{
cpu_error = OPTRAP4;
cpu_state = STOPPED;
return(0L);
}
static int op_tb0iyd(int data) /* BIT 0,(IY+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IY + data) & 1) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb1iyd(int data) /* BIT 1,(IY+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IY + data) & 2) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb2iyd(int data) /* BIT 2,(IY+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IY + data) & 4) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb3iyd(int data) /* BIT 3,(IY+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IY + data) & 8) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb4iyd(int data) /* BIT 4,(IY+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IY + data) & 16) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb5iyd(int data) /* BIT 5,(IY+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IY + data) & 32) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb6iyd(int data) /* BIT 6,(IY+d) */
{
F &= ~(N_FLAG | S_FLAG);
F |= H_FLAG;
(*(ram + IY + data) & 64) ? (F &= ~(Z_FLAG | P_FLAG))
: (F |= (Z_FLAG | P_FLAG));
return(20);
}
static int op_tb7iyd(int data) /* BIT 7,(IY+d) */
{
F &= ~N_FLAG;
F |= H_FLAG;
if (*(ram + IY + data) & 128) {
F &= ~(Z_FLAG | P_FLAG);
F |= S_FLAG;
} else {
F |= (Z_FLAG | P_FLAG);
F &= ~S_FLAG;
}
return(20);
}
static int op_rb0iyd(int data) /* RES 0,(IY+d) */
{
*(ram + IY + data) &= ~1;
return(23);
}
static int op_rb1iyd(int data) /* RES 1,(IY+d) */
{
*(ram + IY + data) &= ~2;
return(23);
}
static int op_rb2iyd(int data) /* RES 2,(IY+d) */
{
*(ram + IY + data) &= ~4;
return(23);
}
static int op_rb3iyd(int data) /* RES 3,(IY+d) */
{
*(ram + IY + data) &= ~8;
return(23);
}
static int op_rb4iyd(int data) /* RES 4,(IY+d) */
{
*(ram + IY + data) &= ~16;
return(23);
}
static int op_rb5iyd(int data) /* RES 5,(IY+d) */
{
*(ram + IY + data) &= ~32;
return(23);
}
static int op_rb6iyd(int data) /* RES 6,(IY+d) */
{
*(ram + IY + data) &= ~64;
return(23);
}
static int op_rb7iyd(int data) /* RES 7,(IY+d) */
{
*(ram + IY + data) &= ~128;
return(23);
}
static int op_sb0iyd(int data) /* SET 0,(IY+d) */
{
*(ram + IY + data) |= 1;
return(23);
}
static int op_sb1iyd(int data) /* SET 1,(IY+d) */
{
*(ram + IY + data) |= 2;
return(23);
}
static int op_sb2iyd(int data) /* SET 2,(IY+d) */
{
*(ram + IY + data) |= 4;
return(23);
}
static int op_sb3iyd(int data) /* SET 3,(IY+d) */
{
*(ram + IY + data) |= 8;
return(23);
}
static int op_sb4iyd(int data) /* SET 4,(IY+d) */
{
*(ram + IY + data) |= 16;
return(23);
}
static int op_sb5iyd(int data) /* SET 5,(IY+d) */
{
*(ram + IY + data) |= 32;
return(23);
}
static int op_sb6iyd(int data) /* SET 6,(IY+d) */
{
*(ram + IY + data) |= 64;
return(23);
}
static int op_sb7iyd(int data) /* SET 7,(IY+d) */
{
*(ram + IY + data) |= 128;
return(23);
}
static int op_rlciyd(int data) /* RLC (IY+d) */
{
register int i;
register BYTE *p;
p = ram + IY + data;
i = *p & 128;
(i) ? (F |= C_FLAG) : (F &= ~C_FLAG);
F &= ~(H_FLAG | N_FLAG);
*p <<= 1;
if (i) *p |= 1;
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_rrciyd(int data) /* RRC (IY+d) */
{
register int i;
register BYTE *p;
p = ram + IY + data;
i = *p & 1;
(i) ? (F |= C_FLAG) : (F &= ~C_FLAG);
F &= ~(H_FLAG | N_FLAG);
*p >>= 1;
if (i) *p |= 128;
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_rliyd(int data) /* RL (IY+d) */
{
register int old_c_flag;
register BYTE *p;
p = ram + IY + data;
old_c_flag = F & C_FLAG;
(*p & 128) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p <<= 1;
if (old_c_flag) *p |= 1;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_rriyd(int data) /* RR (IY+d) */
{
register int old_c_flag;
register BYTE *p;
old_c_flag = F & C_FLAG;
p = ram + IY + data;
(*p & 1) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p >>= 1;
if (old_c_flag) *p |= 128;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_slaiyd(int data) /* SLA (IY+d) */
{
register BYTE *p;
p = ram + IY + data;
(*p & 128) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p <<= 1;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_sraiyd(int data) /* SRA (IY+d) */
{
register int i;
register BYTE *p;
p = ram + IY + data;
i = *p & 128;
(*p & 1) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p >>= 1;
*p |= i;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}
static int op_srliyd(int data) /* SRL (IY+d) */
{
register BYTE *p;
p = ram + IY + data;
(*p & 1) ? (F |= C_FLAG) : (F &= ~C_FLAG);
*p >>= 1;
F &= ~(H_FLAG | N_FLAG);
(*p) ? (F &= ~Z_FLAG) : (F |= Z_FLAG);
(*p & 128) ? (F |= S_FLAG) : (F &= ~S_FLAG);
(parrity[*p]) ? (F &= ~P_FLAG) : (F |= P_FLAG);
return(23);
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,63 @@
/*
* 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
* 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
* 20-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 and ported to COHERENT 4.0
* 04-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* This modul contains some commonly used functions
*/
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <termios.h>
#include "sim.h"
/*
* atoi for hexadecimal numbers
*/
int exatoi(char *str)
{
register int num = 0;
while (isxdigit(*str)) {
num *= 16;
if (*str <= '9')
num += *str - '0';
else
num += toupper(*str) - '7';
str++;
}
return(num);
}
/*
* Wait for a single keystroke without echo
*/
int getkey(void)
{
register int c;
struct termios old_term, new_term;
tcgetattr(0, &old_term);
new_term = old_term;
new_term.c_lflag &= ~(ICANON | ECHO);
new_term.c_cc[VMIN] = 1;
tcsetattr(0, TCSADRAIN, &new_term);
c = getchar();
tcsetattr(0, TCSADRAIN, &old_term);
return(c);
}

Binary file not shown.

View File

@@ -0,0 +1,184 @@
/*
* 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
* 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
* 20-DEC-90 Release 1.5 Ported to COHERENT
* 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 and ported to COHERENT 4.0
* 04-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* This modul contains all the global variables
*/
#include "sim.h"
/*
* CPU-Register
*/
BYTE A,B,C,D,E,H,L; /* Z80 primary registers */
int F; /* normaly 8-Bit, but int is faster */
WORD IX, IY;
BYTE A_,B_,C_,D_,E_,H_,L_; /* Z80 secoundary registers */
int F_;
BYTE *PC; /* Z80 programm counter */
BYTE *STACK; /* Z80 stackpointer */
BYTE I; /* Z80 interrupt register */
BYTE IFF; /* Z80 interrupt flags */
long R; /* Z80 refresh register */
/* is normaly a 8 bit register */
/* the 32 bits are used to measure the */
/* clock frequency */
/*
* Variables for memory of the emulated CPU
*/
BYTE ram[65536L]; /* 64KB RAM */
BYTE *wrk_ram; /* workpointer into memory for dump etc. */
/*
* Variables for history memory
*/
#ifdef HISIZE
struct history his[HISIZE]; /* memory to hold trace informations */
int h_next; /* index into trace memory */
int h_flag; /* flag for trace memory overrun */
#endif
/*
* Variables for breakpoint memory
*/
#ifdef SBSIZE
struct softbreak soft[SBSIZE]; /* memory to hold breakpoint informations */
int sb_next; /* index into breakpoint memory */
#endif
/*
* Variables for runtime measurement
*/
#ifdef WANT_TIM
long t_states; /* number of counted T states */
int t_flag; /* flag, 1 = on, 0 = off */
BYTE *t_start = ram + 65535; /* start address for measurement */
BYTE *t_end = ram + 65535; /* end address for measurement */
#endif
/*
* Flag to controll operation of simulation
*/
int s_flag; /* flag for -s option */
int l_flag; /* flag for -l option */
int m_flag; /* flag for -m option */
int x_flag; /* flag for -x option */
int i_flag; /* flag for -i option */
int f_flag; /* flag for -f option */
char xfn[LENCMD]; /* buffer for filename (option -x) */
int break_flag = 1; /* 1 = break at HALT, 0 = execute HALT */
int cpu_state; /* status of CPU emulation */
int cpu_error; /* error status of CPU emulation */
int int_type; /* type of interrupt */
float freq; /* CPU clock in usec */
int int_mode; /* CPU interrupt mode (IM 0, IM 1, IM 2) */
int cntl_c; /* flag for cntl-c entered */
int cntl_bs; /* flag for cntl-\ entered */
/*
* Table to get parrity as fast as possible
*/
int parrity[256] = {
0 /* 00000000 */, 1 /* 00000001 */, 1 /* 00000010 */,
0 /* 00000011 */, 1 /* 00000100 */, 0 /* 00000101 */,
0 /* 00000110 */, 1 /* 00000111 */, 1 /* 00001000 */,
0 /* 00001001 */, 0 /* 00001010 */, 1 /* 00001011 */,
0 /* 00001100 */, 1 /* 00001101 */, 1 /* 00001110 */,
0 /* 00001111 */, 1 /* 00010000 */, 0 /* 00010001 */,
0 /* 00010010 */, 1 /* 00010011 */, 0 /* 00010100 */,
1 /* 00010101 */, 1 /* 00010110 */, 0 /* 00010111 */,
0 /* 00011000 */, 1 /* 00011001 */, 1 /* 00011010 */,
0 /* 00011011 */, 1 /* 00011100 */, 0 /* 00011101 */,
0 /* 00011110 */, 1 /* 00011111 */, 1 /* 00100000 */,
0 /* 00100001 */, 0 /* 00100010 */, 1 /* 00100011 */,
0 /* 00100100 */, 1 /* 00100101 */, 1 /* 00100110 */,
0 /* 00100111 */, 0 /* 00101000 */, 1 /* 00101001 */,
1 /* 00101010 */, 0 /* 00101011 */, 1 /* 00101100 */,
0 /* 00101101 */, 0 /* 00101110 */, 1 /* 00101111 */,
0 /* 00110000 */, 1 /* 00110001 */, 1 /* 00110010 */,
0 /* 00110011 */, 1 /* 00110100 */, 0 /* 00110101 */,
0 /* 00110110 */, 1 /* 00110111 */, 1 /* 00111000 */,
0 /* 00111001 */, 0 /* 00111010 */, 1 /* 00111011 */,
0 /* 00111100 */, 1 /* 00111101 */, 1 /* 00111110 */,
0 /* 00111111 */, 1 /* 01000000 */, 0 /* 01000001 */,
0 /* 01000010 */, 1 /* 01000011 */, 0 /* 01000100 */,
1 /* 01000101 */, 1 /* 01000110 */, 0 /* 01000111 */,
0 /* 01001000 */, 1 /* 01001001 */, 1 /* 01001010 */,
0 /* 01001011 */, 1 /* 01001100 */, 0 /* 01001101 */,
0 /* 01001110 */, 1 /* 01001111 */, 0 /* 01010000 */,
1 /* 01010001 */, 1 /* 01010010 */, 0 /* 01010011 */,
1 /* 01010100 */, 0 /* 01010101 */, 0 /* 01010110 */,
1 /* 01010111 */, 1 /* 01011000 */, 0 /* 01011001 */,
0 /* 01011010 */, 1 /* 01011011 */, 0 /* 01011100 */,
1 /* 01011101 */, 1 /* 01011110 */, 0 /* 01011111 */,
0 /* 01100000 */, 1 /* 01100001 */, 1 /* 01100010 */,
0 /* 01100011 */, 1 /* 01100100 */, 0 /* 01100101 */,
0 /* 01100110 */, 1 /* 01100111 */, 1 /* 01101000 */,
0 /* 01101001 */, 0 /* 01101010 */, 1 /* 01101011 */,
0 /* 01101100 */, 1 /* 01101101 */, 1 /* 01101110 */,
0 /* 01101111 */, 1 /* 01110000 */, 0 /* 01110001 */,
0 /* 01110010 */, 1 /* 01110011 */, 0 /* 01110100 */,
1 /* 01110101 */, 1 /* 01110110 */, 0 /* 01110111 */,
0 /* 01111000 */, 1 /* 01111001 */, 1 /* 01111010 */,
0 /* 01111011 */, 1 /* 01111100 */, 0 /* 01111101 */,
0 /* 01111110 */, 1 /* 01111111 */,
1 /* 10000000 */, 0 /* 10000001 */, 0 /* 10000010 */,
1 /* 10000011 */, 0 /* 10000100 */, 1 /* 10000101 */,
1 /* 10000110 */, 0 /* 10000111 */, 0 /* 10001000 */,
1 /* 10001001 */, 1 /* 10001010 */, 0 /* 10001011 */,
1 /* 10001100 */, 0 /* 10001101 */, 0 /* 10001110 */,
1 /* 10001111 */, 0 /* 10010000 */, 1 /* 10010001 */,
1 /* 10010010 */, 0 /* 10010011 */, 1 /* 10010100 */,
0 /* 10010101 */, 0 /* 10010110 */, 1 /* 10010111 */,
1 /* 10011000 */, 0 /* 10011001 */, 0 /* 10011010 */,
1 /* 10011011 */, 0 /* 10011100 */, 1 /* 10011101 */,
1 /* 10011110 */, 0 /* 10011111 */, 0 /* 10100000 */,
1 /* 10100001 */, 1 /* 10100010 */, 0 /* 10100011 */,
1 /* 10100100 */, 0 /* 10100101 */, 0 /* 10100110 */,
1 /* 10100111 */, 1 /* 10101000 */, 0 /* 10101001 */,
0 /* 10101010 */, 1 /* 10101011 */, 0 /* 10101100 */,
1 /* 10101101 */, 1 /* 10101110 */, 0 /* 10101111 */,
1 /* 10110000 */, 0 /* 10110001 */, 0 /* 10110010 */,
1 /* 10110011 */, 0 /* 10110100 */, 1 /* 10110101 */,
1 /* 10110110 */, 0 /* 10110111 */, 0 /* 10111000 */,
1 /* 10111001 */, 1 /* 10111010 */, 0 /* 10111011 */,
1 /* 10111100 */, 0 /* 10111101 */, 0 /* 10111110 */,
1 /* 10111111 */, 0 /* 11000000 */, 1 /* 11000001 */,
1 /* 11000010 */, 0 /* 11000011 */, 1 /* 11000100 */,
0 /* 11000101 */, 0 /* 11000110 */, 1 /* 11000111 */,
1 /* 11001000 */, 0 /* 11001001 */, 0 /* 11001010 */,
1 /* 11001011 */, 0 /* 11001100 */, 1 /* 11001101 */,
1 /* 11001110 */, 0 /* 11001111 */, 1 /* 11010000 */,
0 /* 11010001 */, 0 /* 11010010 */, 1 /* 11010011 */,
0 /* 11010100 */, 1 /* 11010101 */, 1 /* 11010110 */,
0 /* 11010111 */, 0 /* 11011000 */, 1 /* 11011001 */,
1 /* 11011010 */, 0 /* 11011011 */, 1 /* 11011100 */,
0 /* 11011101 */, 0 /* 11011110 */, 1 /* 11011111 */,
1 /* 11100000 */, 0 /* 11100001 */, 0 /* 11100010 */,
1 /* 11100011 */, 0 /* 11100100 */, 1 /* 11100101 */,
1 /* 11100110 */, 0 /* 11100111 */, 0 /* 11101000 */,
1 /* 11101001 */, 1 /* 11101010 */, 0 /* 11101011 */,
1 /* 11101100 */, 0 /* 11101101 */, 0 /* 11101110 */,
1 /* 11101111 */, 0 /* 11110000 */, 1 /* 11110001 */,
1 /* 11110010 */, 0 /* 11110011 */, 1 /* 11110100 */,
0 /* 11110101 */, 0 /* 11110110 */, 1 /* 11110111 */,
1 /* 11111000 */, 0 /* 11111001 */, 0 /* 11111010 */,
1 /* 11111011 */, 0 /* 11111100 */, 1 /* 11111101 */,
1 /* 11111110 */, 0 /* 11111111 */
};

View File

@@ -0,0 +1,50 @@
/*
* 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
* 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
* 20-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 and ported to COHERENT 4.0
* 03-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* Declaration of variables in simglb.c
*/
extern BYTE A,B,C,D,E,H,L,A_,B_,C_,D_,E_,H_,L_,*PC,*STACK,I,IFF;
extern WORD IX,IY;
extern int F,F_;
extern long R;
extern BYTE ram[],*wrk_ram;
extern int s_flag,l_flag,m_flag,x_flag,break_flag,i_flag,f_flag,
cpu_state, cpu_error,int_type,int_mode,cntl_c,cntl_bs,
parrity[],sb_next;
extern float freq;
extern char xfn[];
#ifdef HISIZE
extern struct history his[];
extern int h_next, h_flag;
#endif
#ifdef SBSIZE
extern struct softbreak soft[];
#endif
#ifdef WANT_TIM
extern long t_states;
extern int t_flag;
extern BYTE *t_start, *t_end;
#endif

Binary file not shown.

View File

@@ -0,0 +1,90 @@
/*
* 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
* 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
* 20-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
* 04-OCT-06 Release 1.8 modified to compile on modern POSIX OS's
*/
/*
* This module contain the interrupt handlers for the OS:
*
* int_on() : initialize interrupt handlers
* int_off() : reset interrupts to default
* user_int() : handler for user interrupt (CNTL-C)
* quit_int() : handler for signal "quit" (CNTL-\)
* term_int() : handler for signal SIGTERM when process is killed
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include "sim.h"
#include "simglb.h"
static void user_int(int), quit_int(int), term_int(int);
extern void exit_io(void), int_off();
extern struct termios old_term;
void int_on(void)
{
static struct sigaction newact;
newact.sa_handler = user_int;
sigaction(SIGINT, &newact, NULL);
newact.sa_handler = quit_int;
sigaction(SIGQUIT, &newact, NULL);
newact.sa_handler = term_int;
sigaction(SIGTERM, &newact, NULL);
}
void int_off(void)
{
static struct sigaction newact;
newact.sa_handler = SIG_DFL;
sigaction(SIGINT, &newact, NULL);
sigaction(SIGQUIT, &newact, NULL);
sigaction(SIGTERM, &newact, NULL);
}
static void user_int(int sig)
{
#ifdef CNTL_C
cpu_error = USERINT;
cpu_state = STOPPED;
#else
cntl_c++;
#endif
}
static void quit_int(int sig)
{
#ifdef CNTL_BS
cpu_error = USERINT;
cpu_state = STOPPED;
#else
cntl_bs++;
#endif
}
static void term_int(int sig)
{
exit_io();
int_off();
tcsetattr(0, TCSADRAIN, &old_term);
puts("\nKilled by user");
exit(0);
}

Binary file not shown.

BIN
emu/z80pack-1.9/z80sim/z80sim Executable file

Binary file not shown.

View File

@@ -0,0 +1,837 @@
;
; this is a Z80 floating point package from an ancient german computer magazine
; I'm not going to translate this into english
; assemble this source with z80asm and run it under z80sim, if everything
; is working it should print the numbers below
;
; *******************************
; * Fliesskomma-Arithmetik fuer *
; * den Z80-Mikroprozessor *
; * (mc 12/88, Seite 100 *
; *******************************
; ********************************************************
; * Die folgende Testroutine liefert die Ausgabe:
; * 40400000
; * 00700000
; * 7F800000
; * 35BFFFFF
; * 00400000
; * 7F7FFFFF
; * 7F800000
; * 406DB6DB
; * 15400001
START:
LD SP,STACK
LD BC,3F80H ; Aufruf der Additionsroutine
LD DE,0000H ; mit verschiedenen Parametern
PUSH BC ; entspricht 1 + 2
PUSH DE
LD BC,4000H
LD DE,0000H
PUSH BC
PUSH DE
CALL F_ADD
CALL HEXOUT ; anschliessend Ausgabe
LD BC,00F0H ; eine kleine, gerade noch normalisierte
LD DE,0000H ; Zahl, dazu die kleinste normalisierte
PUSH BC ; Zahl mit negativem Vorzeichen addieren
PUSH DE
LD BC,8080H
LD DE,0000H
PUSH BC
PUSH DE
CALL F_ADD
CALL HEXOUT
LD BC,7F00H ; die Summe dieser beiden Zahlen
LD DE,0000H ; ergibt unendlich. Setzt man
PUSH BC ; fuer die zweite Zahl den Wert
PUSH DE ; 7EFFFFFE, so ist das Ergebnis
LD BC,7EFFH ; gerade MAXFLOAT
LD DE,0FFFFH
PUSH BC
PUSH DE
CALL F_ADD
CALL HEXOUT
LD BC,0000H ; Multiplikation testen
LD DE,0003H ; MAXFLOAT * <denormalisierte Zahl>
PUSH BC
PUSH DE
LD BC,7F7FH
LD DE,0FFFFH
PUSH BC
PUSH DE
CALL F_MUL
CALL HEXOUT
LD BC,0080H ; die kleinste normalisierte Zahl
LD DE,0000H ; mit 0.5 multiplizieren
PUSH BC ; (ergibt eine denormalisierte Zahl)
PUSH DE
LD BC,3F00H
LD DE,0000H
PUSH BC
PUSH DE
CALL F_MUL
CALL HEXOUT
LD BC,4000H ; eine sehr grosse Zahl mit zwei
LD DE,0000H ; multiplizieren. Das Ergebnis
PUSH BC ; ist genau MAXFLOAT
PUSH DE
LD BC,7EFFH
LD DE,0FFFFH
PUSH BC
PUSH DE
CALL F_MUL
CALL HEXOUT
LD BC,0000H ; Test der Divisionsroutine
LD DE,0000H ; hier 1 / 0 (ergibt unendlich)
PUSH BC
PUSH DE
LD BC,3F80H
LD DE,0000H
PUSH BC
PUSH DE
CALL F_DIV
CALL HEXOUT
LD BC,40E0H ; jetzt 26 / 7 berechnen
LD DE,0000H
PUSH BC
PUSH DE
LD BC,41D0H
LD DE,0000H
PUSH BC
PUSH DE
CALL F_DIV
CALL HEXOUT
LD BC,1FFFH ; jetzt eine sehr kleine
LD DE,0FFFFH ; denormalisierte Zahl durch
PUSH BC ; eine kleine normalisierte
PUSH DE ; Zahl dividieren
LD BC,0000H
LD DE,0003H
PUSH BC
PUSH DE
CALL F_DIV
CALL HEXOUT
HALT ; Ende des Tests
DEFS 100
STACK:
; ************************************************
; * Zahl in BC-DE in 8 Hexadezimalziffern drucken.
; * Dazu werden nacheinander die Nibble-Paare in
; * B, C, D und E ausgedruckt.
; *
HEXOUT:
LD A,B ; Nacheinander die einzelnen
CALL DIG2 ; Nibble-Paare in A laden
LD A,C ; und ausdrucken
CALL DIG2
LD A,D
CALL DIG2
LD A,E
CALL DIG2
LD A,10
CALL OUTCHAR
LD A,13
CALL OUTCHAR
RET
DIG2:
PUSH AF ; Nibble-Paar ausdrucken
RRCA ; unterstes Nibble retten
RRCA ; oberes Nibble rechtsbuendig
RRCA ; positionieren
RRCA
AND 00001111B
ADD A,90H ; binaer in ASCII (hex)
DAA
ADC A,40H
DAA
CALL OUTCHAR ; Zeichen ausgeben
POP AF ; jetzt unteres Nibble verarbeiten
AND 00001111B ; Nibble maskieren
ADD A,90H ; binaer in ASCII (hex)
DAA
ADC A,40H
DAA
CALL OUTCHAR
RET
OUTCHAR: ; Zeichen auf Console ausgeben
OUT (0),A
RET
; **********************************
; * Globale Konstanten-Definitionen
; * fuer das Fliesskommapaket
; *
MAXEXPO EQU 255 ; Maximal zulaessiger Exponent
BIAS EQU 127 ; Bias des Exponenten
; *************************************************
; * Fliesskomma-Addition in Single-Precision
; * Parameter: Operand 1 und Operand 2 ueber Stack
; * Ergebnis: in BC-DE: MSB in B, LSB in E
; *
; * Es folgen Offset-Definitionen fuer Stack-relativen Zugriff
FHL_ALT EQU 0 ; Top of Stack liegt HL
FADR EQU 2 ; dann die Ruecksprungadresse
OP1 EQU 4 ; jetzt Offset-Definitionen fuer
OP2 EQU 8 ; Parameter-Uebergabe
OPSIZE EQU 4 ; Groesse eines Operanden
F_ADD:
PUSH HL ; alten Basepointer retten
LD (F_STACK),SP ; aktuellen Stackpointer abspeichern
LD HL,(F_STACK) ; und in HL laden (= Basepointer)
PUSH AF ; benoetigte Register retten
PUSH IX
PUSH IY
LD BC,OP1 ; jeztz die Zeiger auf die
ADD HL,BC ; Operanden initialisieren
PUSH HL
POP IX ; IX zeigt auf Operand 1
LD BC,OPSIZE
ADD HL,BC
PUSH HL
POP IY ; IY zeigt auf Operand 2
F_ADSUB:
ADD HL,BC ; HL zeigt jetzt hinter die Operanden!
LD (F_STACK),HL ; diese Adresse fuer's Ende merken
LD A,(IX+3) ; Vorzeichen von Operand 1 laden
LD E,A ; Ergebnisvorzeichen in E, Bit 7
XOR (IY+3) ; mit Vorzeichen von OP2 verknuepfen
LD D,A ; Subtraktionsflag in D, Bit 7
RES 7,(IX+3) ; Vorzeichen in Mantisse 1 loeschen
RES 7,(IY+3) ; Vorzeichen in Mantisse 2 loeschen
; Die Operanden sind jetzt in der Form: 0EEE EEEE EFFF ... FFFF
LD A,(IX+0) ; Differenz OP1 - OP2 bilden
SUB (IY+0)
LD A,(IX+1)
SBC A,(IY+1)
LD A,(IX+2)
SBC A,(IY+2)
LD A,(IX+3)
SBC A,(IY+3)
JR NC,FAD_1 ; Sprung falls OP1 groesser als OP2
PUSH IX ; ansonsten Operanden vertauschen
EX (SP),IY ; (eigentlich nur die Pointer), so
POP IX ; dass IY den Kleineren adressiert
LD A,E ; Ergebnisvorzeichen neu berechnen
XOR D
LD E,A
FAD_1:
LD A,(IX+2)
LD C,(IX+3) ; Exponent der groesseren Zahl laden
SLA A
RL C
JR Z,AD_DN1
SET 7,(IX+2) ; implizite Eins erzeugen
AD_DN1:
LD A,(IY+2)
LD B,(IY+3) ; Exponent der kleineren Zahl laden
SLA A
RL B
JR Z,AD_DN2
SET 7,(IY+2) ; implizite Eins erzeugen
AD_DN2:
PUSH BC ; Jetzt die Register fuer den
PUSH DE ; Blocktransferbefehl retten
LD BC,(OPSIZE*2)-1 ; beide Operanden verschieben
DEC HL ; HL zeigt auf letztes Byte
PUSH HL ; HL nach DE kopieren
POP DE
DEC HL ; HL zeigt auf vorletztes Byte
LDDR ; Verschiebung beider Mantissen
POP DE ; um 8 Bit nach links
POP BC
XOR A
LD (IX+0),A ; Form: FFFF ... FFFF 0000 0000
LD (IY+0),A
LD A,C ; Differenz der Exponenten berechnen
SUB B
LD B,A ; Differenz nach B fuer Loop-Befehl
JR Z,AD_NAP ; falls Null, dann keine Anpassung
CP 25 ; mehr als 24? (Abfrage mit Carry
JP NC,AD_RND ; erfordert Vergleich mit 25)
AD_ANP:
SRL (IY+3) ; Anpassung der zweiten Mantisse
RR (IY+2) ; durch Verschiebung nach rechts
RR (IY+1)
RR (IY+0)
DJNZ AD_ANP ; Loop-Befehl bis B = 0
AD_NAP:
BIT 7,D ; Subtraktion oder Addition?
JR NZ,SUBTR ; ggf. zur Subtraktion springen
LD A,(IX+0) ; jetzt werden die beiden Mantissen
ADD A,(IY+0) ; zueinander addiert
LD (IX+0),A
LD A,(IX+1)
ADC A,(IY+1)
LD (IX+1),A
LD A,(IX+2)
ADC A,(IY+2)
LD (IX+2),A
LD A,(IX+3)
ADC A,(IY+3)
LD (IX+3),A
JR NC,AD_RND ; kein Ueberlauf --> zum Runden
RR (IX+3) ; Ueberlauf einschieben
RR (IX+2) ; und Exponent erhoehen
RR (IX+1) ; durch die Vorgeschichte ist
RR (IX+0) ; gesichert, dass B Null ist; BC
INC BC ; enthaelt den 16-Bit-Exponent
JR AD_RND ; und zum Runden
SUBTR:
LD A,(IX+0) ; Die beiden Mantissen werden
SUB (IY+0) ; voneinander subtrahiert
LD (IX+0),A
LD A,(IX+1)
SBC A,(IY+1)
LD (IX+1),A
LD A,(IX+2)
SBC A,(IY+2)
LD (IX+2),A
LD A,(IX+3)
SBC A,(IY+3)
LD (IX+3),A
JP M,AD_RND ; bei fuehrender Eins zum Runden
JR NZ,AD_NRM ; ungleich Null: Normalisieren
CP (IX+2) ; Rest der Mantisse auch Null?
JR NZ,AD_NRM
CP (IX+1)
JR NZ,AD_NRM
CP (IX+0)
JR Z,AD_ZERO ; alles Null --> Ergebnis ist Null
AD_NRM:
XOR A ; A = 0
AD_NR1:
CP C ; Exponent ist Null?
JR NZ,AD_NR2 ; nein, Normierung moeglich
CP B ; oberes Byte auch Null?
JR Z,AD_RND ; dann ist Ergebnis denormalisiert
AD_NR2:
DEC BC ; Exponent erniedrigen
SLA (IX+0) ; Mantisse normalisieren bis
RL (IX+1) ; fuehrende Eins auftaucht
RL (IX+2)
RL (IX+3)
JP P,AD_NR1 ; weiter bis fuehrende Eins auftaucht
AD_RND:
LD A,(IX+0) ; jetzt Runden auf Bit hinter
ADD A,80H ; Mantisse
JR NC,AD_NOV ; kein Uebertrag?
INC (IX+1) ; doch, naechstes Mantissenbyte
JR NZ,AD_NOV ; behandeln, jetzt auf Null pruefen,
INC (IX+2) ; da der INC-Befehl kein Carry liefert
JR NZ,AD_NOV
INC (IX+3)
JR NZ,AD_NOV
SCF ; Eins erzeugen
RR (IX+3) ; bei Ueberlauf Mantisse durch
RR (IX+2) ; Rechtsschieben wieder normalisieren
RR (IX+1) ; (nur noch 24 Bit noetig)
INC BC ; und Exponent korrigieren
AD_NOV:
XOR A ; A = 0
CP (IX+3) ; Mantisse auf Null pruefen
JR NZ,AD_NOZ
CP (IX+2)
JR NZ,AD_NOZ
CP (IX+1) ; alle Mantissenbytes Null?
JR NZ,AD_NOZ ; dann ist auch das Ergebnis Null
AD_ZERO: ; Null Ergebnis aufbauen
LD B,A
LD C,A
LD D,A
LD E,A
JR AD_EXIT ; dann Routine verlassen
AD_NOZ:
CP B ; A ist 0
LD A,MAXEXPO ; Exponent oberstes Byte ungleich Null?
JR NZ,AD_OVR ; dann ist Ueberlauf eingetreten
CP C ; oder genau maxexpo erreicht?
JR NZ,AD_NUE ; nein, --> kein Ueberlauf
AD_OVR:
LD C,A ; Exponent auf maxexpo setzen
XOR A ; und Mantisse auf Null
LD (IX+3),A ; fuer unendlich
LD (IX+2),A
LD (IX+1),A
JR AD_DEN
AD_NUE:
XOR A ; A = 0
CP C ; Exponent Null (Zahl denormalisiert)?
JR Z,AD_DEN ; ja, -->
SLA (IX+1) ; fuehrendes Bit wird nicht gespeichert
RL (IX+2) ; daher Mantisse um 1 Bit nach links
RL (IX+3)
AD_DEN:
LD B,C ; Ergebnis aufbauen: Exponent in B
LD C,(IX+3) ; Mantisse oberstes Byte
LD D,(IX+2)
SLA E ; Vorzeichen aus E in Carry schieben
LD E,(IX+1)
RR B ; Vorzeichen in Ergebnis einschieben
RR C
RR D
RR E
AD_EXIT:
POP IY ; Register restaurieren
POP IX
POP AF
POP HL
LD (F_HL),HL ; HL zwischenspeichern
EX (SP),HL ; alte Ruecksprungadresse in HL
LD SP,(F_STACK) ; Stack zuruecksetzen
PUSH HL ; Ruecksprungadresse ablegen
LD HL,(F_HL) ; HL wieder laden
RET ; Ende des Unterprogramms
; *************************************************
; * Fliesskomma-Subtraktion in Single-Precision
; * Parameter: Operand 1 und Operand 2 ueber Stack
; * Ergebnis: in BC-DE: MSB in B, LSB in E
; *
F_SUB:
PUSH HL ; alten Basepointer retten
LD (F_STACK),SP ; aktuellen Stackpointer abspeichern
LD HL,(F_STACK) ; und in HL laden (= Basepointer)
PUSH AF ; benoetigte Register retten
PUSH IX
PUSH IY
LD BC,OP1
ADD HL,BC
PUSH HL
POP IX ; IX zeigt auf Operand 1
LD BC,OPSIZE
ADD HL,BC
PUSH HL
POP IY ; IY zeigt auf Operand 2
LD A,80H
XOR (IY+3) ; Vorzeichenbit von Operand 2 umdrehen
LD (IY+3),A ; wieder abspeichern
JP F_ADSUB ; jetzt weiter bei Additionsroutine
; *************************************************
; * Fliesskomma-Multiplikation in Single-Precision
; * Parameter: Operand 1 und Operand 2 ueber Stack
; * Ergebnis: in BC-DE: MSB in B, LSB in E
; *
TEMP EQU -10 ; Offset lokale Variable (6 Byte)
F_MUL:
PUSH HL ; alten Basepointer retten
LD (F_STACK),SP ; aktuellen Stackpointer abspeichern
LD HL,(F_STACK) ; und in HL laden (= Basepointer)
PUSH AF ; benoetigte Register retten
PUSH IX
PUSH IY
LD BC,OP1
ADD HL,BC
PUSH HL
EX (SP),IX ; IX zeigt auf Operand 1
; 2 Dummy-Byte auf Stack fuer lokale
LD BC,OPSIZE ; Variable bleiben stehen
ADD HL,BC
PUSH HL
EX (SP),IY ; IY zeigt auf Operand 2
PUSH HL ; insgesamt 6 Byte fuer lokale Variable
ADD HL,BC ; HL zeigt jetzt hinter die Operanden!
LD (F_STACK),HL
LD A,(IX+3) ; Ergebnisvorzeichen bestimmen
XOR (IY+3)
LD C,A ; Vorzeichen in C Bit 7 merken
LD D,0 ; Exponent 1 laden
LD E,(IX+3)
LD A,(IX+2) ; Operand um 8 Bit nach links schieben
LD (IX+3),A
RES 7,(IX+3) ; implizite Null vorbesetzen
SLA A ; Exponent unterstes Bit in Carry
RL E ; und in E einschieben
JR Z,MU_DN1 ; falls Null, dann OP1 denormalisieren
SET 7,(IX+3) ; implizite Eins erzeugen
DEC DE ; Bias kompensieren
MU_DN1:
LD A,(IX+1) ; jetzt restliche Bytes verschieben
LD (IX+2),A
LD A,(IX+0)
LD (IX+1),A
XOR A ; unterste Mantissenbits loeschen
LD (IX+0),A ; Form: FFFF ... FFFF 0000 0000
LD (IX+TEMP+5),A ; lokale Variable mit Null vorbesetzen
LD (IX+TEMP+4),A
LD (IX+TEMP+3),A
LD (IX+TEMP+2),A
LD (IX+TEMP+1),A
LD (IX+TEMP+0),A
LD H,A ; Exponent 2 in HL aufbauen
LD L,(IY+3)
LD A,(IY+2)
RES 7,(IY+2) ; implizite Null vorbesetzen
SLA A
RL L
JR Z,MU_DN2 ; gleich Null, dann Op2 denormalisieren
SET 7,(IY+2) ; implizite Eins erzeugen
DEC HL ; Bias kompensieren
MU_DN2:
ADD HL,DE ; Exponenten aufaddieren
LD DE,3-BIAS ; Bias-3 subtrahieren
ADD HL,DE ; bzw. 3-Bias addieren
JP P,MU_NOZ
LD A,L ; Exponent kleiner als -24?
CP -24
JR NC,MU_NOZ
JP MU_ZERO ; ja, dann ist das Ergebnis Null
MU_NOZ:
LD B,24 ; Multiplikationsschleifenzaehler
LD DE,0 ; Hilfsregister fuer Multiplikand
MU_MUL:
SRL (IX+3) ; Multiplikand nach rechts schieben
RR (IX+2)
RR (IX+1)
RR (IX+0)
RR D ; DE als Verlaengerung von Operand 1
RR E
SLA (IY+0) ; Multiplikator nach links schieben
RL (IY+1)
RL (IY+2) ; falls fuehrendes Bit Null ist, dann
JR NC,MU_NAD ; muss nicht addiert werden
LD A,(IX+TEMP+0) ; sonst Multiplikand aufaddieren
ADD A,E
LD (IX+TEMP+0),A
LD A,(IX+TEMP+1)
ADC A,D
LD (IX+TEMP+1),A
LD A,(IX+TEMP+2)
ADC A,(IX+0)
LD (IX+TEMP+2),A
LD A,(IX+TEMP+3)
ADC A,(IX+1)
LD (IX+TEMP+3),A
LD A,(IX+TEMP+4)
ADC A,(IX+2)
LD (IX+TEMP+4),A
LD A,(IX+TEMP+5)
ADC A,(IX+3)
LD (IX+TEMP+5),A
MU_NAD:
DJNZ MU_MUL ; Schleife durchlaufen
LD A,(IX+TEMP+5)
OR A ; Flags setzen
JP M,MU_RND ; bei fuerender Eins zum Runden
JR NZ,MU_NOR ; ungleich Null --> normalisieren
CP (IX+TEMP+4)
JR NZ,MU_NOR
CP (IX+TEMP+3)
JR NZ,MU_NOR
CP (IX+TEMP+2)
JR NZ,MU_NOR
JP MU_ZERO ; Mantisse komplett Null --> Null
MU_NOR:
XOR A ; A = 0
OR H ; Exponent ist negativ?
JP M,MU_UNT ; ggf. Unterlauf behandeln
MU_NR1:
XOR A ; A = 0
CP L ; Exponent = Null?
JR NZ,MU_NR2
CP H ; bei Null zum Runden
JR Z,MU_RND
MU_NR2:
DEC HL ; Exponent erniedrigen
SLA (IX+TEMP+0)
RL (IX+TEMP+1)
RL (IX+TEMP+2) ; Mantisse solange nach links
RL (IX+TEMP+3) ; verschieben bis fuerende Eins
RL (IX+TEMP+4) ; auftaucht
RL (IX+TEMP+5)
JP P,MU_NR1
MU_RND:
LD A,(IX+TEMP+2) ; jetzt Runden auf Bit hinter
ADD A,80H ; Mantisse
JR NC,MU_NOV ; kein Uebertrag?
INC (IX+TEMP+3) ; doch, naechstes Mantissenbyte
JR NZ,MU_NOV ; behandeln, jetzt auf Null pruefen
INC (IX+TEMP+4) ; da der INC-Befehl kein Carry liefert
JR NZ,MU_NOV
INC (IX+TEMP+5)
JR NZ,MU_NOV
SCF ; Eins erzeugen
RR (IX+TEMP+5) ; bei Ueberlauf Mantisse durch
RR (IX+TEMP+4) ; Rechtsschieben wieder normalisieren
RR (IX+TEMP+3)
INC HL ; und Eponent korrigieren
MU_NOV:
XOR A ; A = 0
CP H ; Exponent pruefen
LD A,MAXEXPO ; A vorbesetzen
JR NZ,MU_OVR ; groesser Null: Ueberlauf behandeln
CP L ; oder genau maxexpo erreicht?
JR NZ,MU_NUE ; nein, kein Ueberlauf
MU_OVR:
LD L,MAXEXPO ; Ueberlauf: Exponent = maxexpo
XOR A ; Mantisse = Null
LD (IX+TEMP+5),A
LD (IX+TEMP+4),A
LD (IX+TEMP+3),A
JR MU_DEN
MU_NUE:
XOR A ; A = 0
CP L ; Exponent ist Null?
JR Z,MU_DEN ; ja, Ergebnis ist denormalisiert
SLA (IX+TEMP+3) ; nein, fuehrendes Mantissenbit
RL (IX+TEMP+4) ; rausschieben
RL (IX+TEMP+5)
MU_DEN:
SLA C ; Vorzeichen in Carry schieben
LD B,L ; Exponent einsetzen
LD C,(IX+TEMP+5)
LD D,(IX+TEMP+4)
LD E,(IX+TEMP+3)
RR B ; und Vorzeichen einschieben
RR C
RR D ; Form: SEEE EEEE EFFF FFFF ... FFFF
RR E
MU_RES:
POP HL ; lokale Variable deallozieren
POP HL
POP HL
POP IY ; Register restaurieren
POP IX
POP AF
POP HL
LD (F_HL),HL ; Parameter vom Stack deallozieren
EX (SP),HL
LD SP,(F_STACK)
PUSH HL
LD HL,(F_HL)
RET ; und return
MU_ZERO:
XOR A ; Ergebnis ist Null
LD B,A
LD C,A
LD D,A
LD E,A
JR MU_RES
MU_UNT:
LD A,L ; Exponent in A
NEG ; negieren fuer Schleifenzaehler
CP 24 ; totaler Ueberlauf?
JR NC,MU_ZERO ; ja, dann ist Ergebnis Null
LD B,A ; in B fuer Loop
MU_SHR:
SRL (IX+TEMP+5) ; Mantisse denormalisieren
RR (IX+TEMP+4) ; bis Exponent Null ist
RR (IX+TEMP+3)
DJNZ MU_SHR
LD L,B ; Exponent in Register L = B = 0
JP MU_DEN ; denormalisiertes Ergebnis erzeugen
; *************************************************
; * Fliesskomma-Division in Single-Precision
; * Parameter: Operand 1 und Operand 2 ueber Stack
; * Ergebnis: in BC-DE: MSB in B, LSB in E
; *
F_DIV:
PUSH HL ; alten Basepointer retten
LD (F_STACK),SP ; aktuellen Stackpointer abspeichern
LD HL,(F_STACK) ; und in HL laden (= Basepointer)
PUSH AF ; benoetigte Register retten
PUSH IX
PUSH IY
LD BC,OP1
ADD HL,BC
PUSH HL
EX (SP),IX ; IX zeigt auf Operand 1
; 2 Dummy-Byte auf Stack fuer lokale
LD BC,OPSIZE ; Variable bleiben stehen
ADD HL,BC
PUSH HL
EX (SP),IY ; IY zeigt auf Operand 2
PUSH HL ; insgesamt 6 Byte fuer lokale Variable
ADD HL,BC ; HL zeigt jetzt hinter die Operanden!
LD (F_STACK),HL
LD A,(IX+3) ; Ergebnisvorzeichen bestimmen
XOR (IY+3)
LD C,A ; Vorzeichen in C Bit 7 merken
LD H,0 ; Exponent 1 laden
LD L,(IX+3)
LD A,(IX+2)
RES 7,(IX+2) ; implizite Null vorbesetzen
SLA A ; Exponent unterstes Bit in Carry
RL L ; und in E einschieben
JR Z,DV_DN1 ; falls Null, dann Op1 denormalisieren
SET 7,(IX+2) ; implizite Eins erzeugen
DEC HL ; Bias kompensieren
DV_DN1:
LD D,0 ; Exponent 2 in DE aufbauen
LD E,(IY+3)
LD A,(IY+2)
LD (IY+3),A ; Mantisse um 8 Bit verschieben
RES 7,(IY+3) ; implizite Null vorbesetzen
SLA A
RL E
JR Z,DV_DN2 ; gleich Null, dann Op2 denormalisieren
SET 7,(IY+3) ; implizite Eins erzeugen
DEC DE ; Bias kompensieren
DV_DN2:
LD A,(IY+1) ; jetzt restliche Bytes verschieben
LD (IY+2),A
LD A,(IY+0)
LD (IY+1),A
XOR A ; A = 0
LD (IY+0),A ; Form: FFFF ... FFFF 0000 0000
SRL (IY+3)
RR (IY+2)
RR (IY+1)
RR (IY+0) ; Form: 0FFF ... FFFF F000 0000
JR NZ,DV_NZ1 ; Mantisse 2 auf Null pruefen
CP (IY+1)
JR NZ,DV_NZ1
CP (IY+2)
JR NZ,DV_NZ1
CP (IY+3)
JR NZ,DV_NZ1
JP MU_OVR ; Bei Division durch Null: unendlich
DV_NZ1:
XOR A ; Carry-Flag loeschen
SBC HL,DE ; Exponenten subtrahieren
LD DE,BIAS ; Bias addieren
ADD HL,DE
BIT 7,H ; Exponent positiv?
JR Z,DV_NOZ
LD A,L ; Exponent kleiner als -24?
JR NC,DV_NOZ
JP MU_ZERO ; ja, dann ist das Ergebnis Null
DV_NOZ:
PUSH BC ; Vorzeichen retten
LD DE,25 ; Exponent um 25 erhoehen
ADD HL,DE ; jetzt ist er sicher groesser als Null
XOR A ; A = 0
LD B,(IX+2) ; Divident in Register kopieren
LD C,(IX+1)
LD D,(IX+0)
LD E,A ; die untersten Bits sind Null
CP D ; ist Dividend Null?
JR NZ,DV_NZ2
CP C
JR NZ,DV_NZ2
CP B
JR NZ,DV_NZ2
POP BC ; Stack bereinigen (Vorzeichen laden)
JP MU_ZERO ; und Null als Ergebnis ausgeben
DV_NZ2:
LD (IX+TEMP+5),A ; Ergebnis vorbesetzen
LD (IX+TEMP+4),A
LD (IX+TEMP+3),A
LD (IX+TEMP+2),A
DV_NLP:
BIT 6,(IY+3) ; ist der Divisor normalisiert
JR NZ,DV_NOR ; ja, -->
INC HL ; nein, Exponent erhoehen
SLA (IY+0) ; Divisor verschieben bis in
RL (IY+1) ; Form 01FF ...
RL (IY+2)
RL (IY+3)
JR DV_NLP
DV_NOR:
SRL B
RR C
RR D
RR E ; Form: 0FFF ... FFFF F000 0000
DV_LOP:
LD (IX+3),B ; Dividend zwischenspeichern
LD (IX+2),C ; die Speicherplaetze von Op1
LD (IX+1),D ; stehen zur Verfuegung, da wir OP1
LD (IX+0),E ; in die Register BC-DE kopiert haben
LD A,E ; jetzt Divisor abziehen
SUB (IY+0)
LD E,A
LD A,D
SBC A,(IY+1)
LD D,A
LD A,C
SBC A,(IY+2)
LD C,A
LD A,B
SBC A,(IY+3)
LD B,A
JR NC,DV_ONE ; kein Carry: Divisor passt
LD E,(IX+0) ; zurueckkopieren
LD D,(IX+1) ; Carry bleibt dabei erhalten
LD C,(IX+2)
LD B,(IX+3)
DV_ONE:
CCF ; Carry-Flag umkehren
RL (IX+TEMP+2) ; Ergebnis aufbauen
RL (IX+TEMP+3)
RL (IX+TEMP+4)
RL (IX+TEMP+5)
SLA E ; Dividend verschieben
RL D
RL C
RL B
DEC HL ; Exponent erniedrigen
XOR A ; A = 0
CP L ; Exponent = Null ?
JR NZ,DV_DIV
CP H
JR Z,DV_DEN ; falls Null, dann denormalisiert
DV_DIV:
BIT 0,(IX+TEMP+5) ; fuerende Eins in Ergebnis-Mantisse?
JR Z,DV_LOP ; nein, weiter rechnen
DV_DEN:
LD B,(IX+TEMP+5) ; hoechstes Bit merken
LD A,(IX+TEMP+4)
LD (IX+TEMP+5),A ; Mantisse in Form
LD A,(IX+TEMP+3) ; FFFF ... FFFF 0000 0000
LD (IX+TEMP+4),A
LD A,(IX+TEMP+2)
LD (IX+TEMP+3),A
RR B ; hoechstes Bit einschieben
RR (IX+TEMP+5)
RR (IX+TEMP+4)
RR (IX+TEMP+3) ; Form: FFFF ... FFFF F000 0000
RR (IX+TEMP+2)
POP BC ; Vorzeichen wieder laden
XOR A ; A = 0
CP (IX+TEMP+5) ; Mantisse ist Null?
JR NZ,DV_NZ3
CP (IX+TEMP+4)
JR NZ,DV_NZ3
CP (IX+TEMP+3)
JR NZ,DV_NZ3
CP (IX+TEMP+2)
JP Z,MU_ZERO ; dann ist Ergebnis auch Null
DV_NZ3:
JP MU_RND ; sonst weiter wie bei Multiplikation
F_STACK:
DEFS 2 ; Hilfsspeicher fuer Stackpointer
F_HL:
DEFS 2 ; Hilfsspeicher fuer Basepointer HL
END

View File

@@ -0,0 +1,638 @@
TITLE 'Z80-Disassembler'
; Hardware-unabhaengiger, ROM-faehiger Z80-Disassembler
;
; Die Adresse, ab der disassembliert serden soll, ist in der
; 16-Bit Speicherzelle DADR abzulegen. Danach kann eines der
; Entrys DISSCR (Ausgabe eines Bildschirms) oder DISLIN
; (Ausgabe einer Zeile) aufgerufen werden. Da die Folgeadressen
; durch das Programm ebenfalls wieder in der Speicherzelle
; DADR abgelegt werden, ist mehrfacher Aufruf ohne Laden
; von neuen Adressen moeglich.
; Zur Ausgabe muss ein Unterprogramm mit dem Namen PRTSTR
; erstellt werden, dem in HL die Adresse eines Null-terminierten
; Strings uebergeben wird.
;
; 27-JUN-89 Udo Munk
LPP EQU 15 ; Anzahl Zeilen/Bildschirm Ausgabe
MNEPOS EQU 11H ; Offset des Mnemonics in Ausgabe-Workspace
; Disassembliere einen Bildschirm voll
DISSCR: LD B,LPP ; einen Bildschirm mit LPP Zeilen
$DLP1: PUSH BC ; disassemblieren
CALL DISLIN
POP BC
DJNZ $DLP1
RET
; Disassembliere eine Zeile
DISLIN: CALL CLWO ; Workspace fuer eine Zeile Ausgabe loeschen
LD HL,WRKS ; Adresse der Ausgabe-Workspace -> HL
LD DE,(DADR) ; Disassemblier-Adresse -> DE
CALL PRBY ; Adresse in DE ausgeben
INC HL ; Blank ausgeben
LD (PRTMP),HL ; vordere Printposition retten
LD C,0 ; Steuerflag loeschen
DEC DE ; laufende Adr.-1 -> DE
$DL13: CALL PRNB ; laufendes Byte ausgeben
LD A,(DE) ; laufendes Byte -> A
LD B,A ; und in B retten
CP 0EDH ; Preafix ED ?
JR NZ,$DL14
SET 4,C ; ja, ED-Flag setzen
JR $DL13 ; und naechstes Byte bearbeiten
$DL14: CP 0FDH ; Preafix FD ?
JR NZ,$DL15
SET 6,C ; ja, FD-Flag setzen
JR $DL16 ; und Index-Flag setzen
$DL15: CP 0DDH ; Preafix DD ?
JR NZ,$DL17
$DL16: SET 5,C ; Index-Flag fuer IX/IY-Adressierung setzen
LD HL,(PRTMP) ; vordere Printposition -> HL
JR $DL13 ; naechstes Byte bearbeiten
$DL17: LD HL,WRKS+MNEPOS ; HL auf Operator Position setzen
; nach Praefix CB
CB: LD A,B ; Befehlsbyte aus B holen
CP 0CBH ; Preafix CB ?
JP NZ,OHNE
INC DE ; ja, Pointer auf naechstes Byte setzen
BIT 5,C ; IX/IY-Flag ?
JR Z,$DL18
INC DE ; ja, Pointer auf naechstes Byte setzen
$DL18: LD A,(DE) ; naechstes Byte -> A
LD B,A ; und in B retten
PUSH DE ; Disassemblieradr. retten
LD D,MNETAB > 8 ; High-Byte Operatorentabelle -> D
LD E,0E8H ; DE = Pointer auf "SET"
CP 0C0H ; SET ?
JR NC,$DL19
LD E,0E4H ; nein, DE = Pointer auf "RES"
CP 80H ; RES ?
JR NC,$DL19
LD E,0E0H ; nein, DE = Pointer auf "BIT"
CP 40H ; BIT ?
JR NC,$DL19
AND 38H ; loesche Bits 0..2 und 6..7
RRCA ; Division durch 2
ADD A,CBMTAB & 0FFH ; zur Basis der CB-Mnemonics addieren
LD E,A
LD D,CBMTAB > 8 ; DE = Pointer auf CB-Mnemonic
$DL19: CALL TRBY ; Mnemonic ausgeben
POP DE ; akt. Disassemblieradr. wieder -> DE
LD A,B ; Byte wieder -> A
BIT 5,C ; IX/IY-Flag ?
JR Z,$DL20
DEC DE ; eins zurueck bei IX/IY-Adressierung
$DL20: DEC DE ; Pointer wieder auf CB-Preafix
CP 40H ; CB-Befehl < 40H ?
JR C,$DL21
AND 38H ; nein, Bits 0..2 und 6..7 loeschen
RRCA ; Division durch 8 -> 1. Operanden
RRCA
RRCA
CALL PRO1 ; 1. Operanden ausgeben
LD A,B ; Byte wieder -> A
SET 7,C ; Komma-Flag setzen
$DL21: AND 7 ; Bits 3..7 loeschen -> 2. Operanden
SET 4,A ; Buchstaben-Flag setzen
CALL PRO1 ; 2. Operanden ausgeben
CALL PRNB ; Befehlsbyte vorne ausgeben
JP INAD ; fertig, Adresse merken und Workspace ausgeben
; ohne Preafix CB/ED
OHNE: PUSH DE ; Disassemblieradr. retten
BIT 4,C ; ED-Flag ?
JP NZ,ED
CP 40H ; nein, < 40H ?
JR C,$DL25
CP 80H ; nein, > 80H ?
JR NC,$DL23
LD E,50H ; nein, DE = Pointer auf "LD"
CP 76H ; HALT ?
JR NZ,$DL22
LD E,5CH ; nein, DE = Pointer auf "HALT"
$DL22: JR $DL26 ; Mnemonic ausgeben
$DL23: CP 0C0H ; > C0H ?
JR NC,$DL24
AND 38H ; ja, Bits 0..2 und 6..7 loeschen
RRCA ; Division durch 2 -> Operator
LD E,A ; Operator -> E
JR $DL26 ; Mnemonic ausgeben
$DL24: SUB 80H ; wenn > C0H, -80 -> Tabellenoperator
$DL25: LD E,A ; Operator -> E
LD D,CODTAB > 8 ; High-Byte Operatortabelle -> D
LD A,(DE) ; LSB Mnemonic-Adresse -> A
LD E,A ; und nach E
$DL26: LD D,MNETAB > 8 ; MSB Mnemonic-Adresse -> D
CALL TRBY ; Mnemonic ausgeben
POP DE ; akt. Disassemblieradr. wieder -> DE
LD A,B ; Befehlsbyte wieder -> A
PUSH DE ; Disassemblieradr. retten
CP 40H ; Byte < 40 ?
JR C,$DL30
CP 80H ; nein, > 80 ?
JR NC,$DL28
CP 76H ; nein, HALT ?
JR NZ,$DL27
LD A,0FFH ; ja, leeren Operanden -> A
JR $DL31 ; Operanden ausgeben
$DL27: AND 38H ; loesche Bits 0..2 und 6..7
RRCA ; Division durch 8 -> 1. Operanden
RRCA
RRCA
SET 4,A ; Buchstabenflag setzen
JR $DL31 ; Operanden ausgeben
$DL28: CP 0C0H ; > C0 ?
JR NC,$DL29
CP 90H ; > 90 ?
JR C,$DL51
AND 0F8H ; ja, Register-Bits loeschen
CP 98H ; "SBC" ?
JR Z,$DL51
LD A,B ; Byte wieder -> A
AND 7 ; nur Register Bits uebrig lassen
SET 4,A ; Buchstaben-Flag setzen
JR $DL52
$DL51: LD A,17H ; ja, 17 = Register A ausgeben
JR $DL31 ; Operanden ausgeben
$DL29: SUB 80H ; wenn > C0, -80 -> Operandentabelle
$DL30: LD E,A ; LSB Operandentabelle -> E
LD D,OPETAB > 8 ; MSB Operandentabelle -> D
LD A,(DE) ; 1. Operanden -> A
$DL31: POP DE ; akt. Disassemblieradr. wieder -> DE
CALL PRO1 ; 1. Operanden ausgeben
LD A,B ; Befehlsbyte wieder -> A
PUSH DE ; akt. Disassemblieradr. retten
CP 40H ; < 40 ?
JR C,$DL34
CP 0C0H ; nein, < C0 ?
JR NC,$DL33
CP 76H ; ja, HALT ?
JR NZ,$DL32
LD A,0FFH ; ja, wieder leeren Operanden -> A
JR $DL35 ; Operanden ausgeben
$DL32: AND 7 ; loesche Bits 3..7, -> 2. Operanden
SET 4,A ; Buchstabenflag setzen
JR $DL35 ; Operanden ausgeben
$DL33: SUB 80H ; wenn > C0 : 80 abziehen
$DL34: ADD A,80H ; LSB Operandentabelle -> A
LD E,A ; und -> E
LD D,OPETAB > 8 ; MSB Operandentabelle -> D
LD A,(DE) ; 2. Operanden -> A
$DL35: POP DE ; akt. Disassemblieradr. wieder -> DE
SET 7,C ; Komma-Flag setzen
CALL PRO1 ; 2. Operanden ausgeben
JP INAD ; fertig, Adresse merken und Workspace ausgeben
; nach Preafix ED
ED: SUB 40H ; 40 vom 2. Byte subtrahieren
JP C,ERRO ; Fehler wenn carry
CP 60H ; 2. Byte < A0 ?
JR NC,$DL36
CP 40H ; ja, >= 60 ?
JP NC,ERRO ; ja, Fehler
JR $DL37 ; nein, weiter
$DL36: SUB 20H ; aus 60..7F wird 00..20
$DL37: ADD A,80H ; LSB Operatortabelle -> A
LD E,A ; und -> E
LD D,CODTAB > 8 ; MSB Operatortabelle -> D
LD A,(DE) ; LSB Mnemonic-Adresse -> A
CP 0FFH ; leer ?
JP Z,ERRO ; ja, Fehler
LD E,A ; nein, -> E
LD D,MNETAB > 8 ; MSB Mnemonic-Adresse -> D
CALL TRBY ; Mnemonic ausgeben
POP DE ; Disassemblieradr. wieder -> DE
LD A,B ; Befehlsbyte wieder -> A
CP 80H ; < 80 ?
JP NC,INAD ; nein, Workspace ausgeben und fertig
PUSH DE ; Disassemblieradr. retten
SUB 40H ; LSB 1. Operanden in A
LD E,A ; und -> E
LD D,OP2TAB > 8 ; MSB 2. Operanden -> D
LD A,(DE) ; 1. Operanden -> A
POP DE ; akt. Disassemblieradr. wieder -> DE
CALL PRO1 ; 1. Operanden ausgeben
LD A,B ; Befehlsbyte wieder -> A
CP 80H ; < 80 ?
JP NC,INAD ; ja, Workspace ausgeben und fertig
PUSH DE ; akt. Disassemblieradr. retten
LD E,A ; LSB Operandentabelle -> E
LD D,OP2TAB > 8 ; MSB Operandentabelle -> D
LD A,(DE) ; 2. Operanden -> A
SET 7,C ; Buchstabenflag setzen
$DL52: POP DE ; akt. Disassemblieradr. retten
CALL PRO1 ; 2. Operanden ausgeben
JP INAD ; fertig, Adresse merken und Workspace ausgeben
; Operand 1 ausgeben
PRO1: CP 0FFH ; leere Operand ?
RET Z ; ja, fertig
CP 17H ; nein, Register "A" ausgeben ?
JR NZ,$DL01
LD A,18H ; ja, umkodieren
$DL01: CP 16H ; Register "(HL)" ausgeben ?
JR NZ,$DL02
LD A,0B4H ; ja, umkodieren
$DL02: BIT 7,C ; 2. Operand ?
JR Z,$DL03
LD (HL),',' ; ja, "," ausgeben
INC HL ; naechste Printposition -> HL
$DL03: BIT 7,A ; "(...)" ?
JR Z,$DL04
LD (HL),'(' ; ja, "(" ausgeben
INC HL ; naechste Printposition -> HL
$DL04: BIT 4,A ; Buchstabe ?
JR NZ,PRBU ; ja, Buchstaben ausgeben
BIT 6,A ; nein, Bitnummer/RST-Adresse ?
JR NZ,DIST ; ja, Distanz ausgeben
BIT 5,A ; nein, Bitnummer ?
JR NZ,PRO2 ; ja, RST ausgeben
AND 7 ; nein, Bits 3..7 loeschen
CALL PRCH ; Hexbyte ausgeben
RET
; RST ausgeben
PRO2: PUSH AF ; A retten
AND 6 ; loesche Bits 0 und 4..7
RRCA ; Division durch 2
CALL PRCH ; oberes Nibble ausgeben
POP AF ; A wieder herstellen
BIT 0,A ; RST x8 ?
LD A,'0' ; nein, "0" -> A
JR Z,$DL05
LD A,'8' ; ja, "8" -> A
$DL05: LD (HL),A ; "0" oder "8" ausgeben
INC HL ; naechste Printposition -> HL
RET
; Distanz ausgeben
DIST: BIT 0,A ; relative Distanz ?
JR Z,PR_N ; nein, N ausgeben
CALL PRNB ; Byte vorne ausgeben
PUSH DE ; akt. Disassemblieradr. retten
LD A,(DE) ; Distanzbyte -> A
INC DE ; Disassemblieradr. erhoehen
RLCA ; Bit 7 Distanzbyte -> carry
RRCA
JR NC,$DL06 ; Vorwaertsprung
SET 0,C ; Flag fuer Rueckwaertssprung setzen
$DL06: ADD A,E ; Distanz zu PC addieren
LD E,A
BIT 0,C ; Flag testen
JR NC,$DL07 ; kein Ueberlauf
JR NZ,$DL08 ; Rueckwaertssprung
INC D ; MSB PC erhoehen
JR $DL08 ; Zieladresse ausgeben
$DL07: JR Z,$DL08 ; bei Vorwaertssprung Zieladresse ausgeben
DEC D ; sonst MSB PC erniedrigen
$DL08: CALL PRBY ; Zieladresse in DE ausgeben
POP DE ; akt. Disassemblieradresse wieder -> DE
RET
; N ausgeben
PR_N: PUSH AF ; A retten
BIT 1,A ; N ?
JR Z,PRNN ; nein, NN ausgeben
CALL PRVH ; ja, Byte vorne und hinten ausgeben
JR $DL12 ; ")" bearbeiten
; NN ausgeben
PRNN: CALL PRNB ; Byte vorne ausgeben
CALL PRVH ; Byte vorne und hinten ausgeben
DEC DE ; DE -> LSB von NN
CALL PRBH ; Byte hinten ausgeben
INC DE ; akt. Disassemblieradr. wieder -> DE
JR $DL12 ; ")" bearbeiten
; Buchstaben ausgeben
PRBU: PUSH AF ; A retten
PUSH BC ; Flags in C retten
PUSH DE ; akt. Disassemblieradr. retten
LD B,1 ; Anzahl = 1
LD DE,REGTAB ; DE zeigt auf die Register-Namen
BIT 5,A ; 2 Buchstaben ?
JR Z,$DL09
INC B ; ja, Anzahl erhoehen
$DL09: BIT 6,A ; Sprungbedingung ?
JR Z,$DL10
LD DE,SPRTAB ; ja, DE zeigt auf Condition-Namen
$DL10: RES 7,A ; Klammer-Bit loeschen
CP 34H ; "(HL)" ?
JR NZ,$DL11
BIT 5,C ; ja, Indexregister ?
JR Z,$DL11
LD A,0AH ; ja, A -> IX-Register
BIT 6,C ; IY-Register ?
JR Z,$DL11
LD A,0CH ; ja, A -> IY-Register
$DL11: AND 0FH ; loesche oberes Nibble
ADD A,E ; und addiere zur Basis in DE
LD E,A
$DL50: LD A,(DE) ; Zeichen -> A
LD (HL),A ; Zeichen ausgeben
INC DE ; Tabellen-Adresse erhoehen
INC HL ; naechste Printposition
DJNZ $DL50 ; naechstes Zeichen
POP DE ; Register wieder herstellen
POP BC
POP AF
PUSH AF ; A retten
CP 0B4H ; "(HL)" ?
JR NZ,$DL12
BIT 5,C ; nein, Indexregister ?
JR Z,$DL12
LD A,(DE) ; ja, Befehlsbyte nach DD/FD -> A
CP 0E9H ; "JP (IX/IY)" ?
JR Z,$DL12
LD (HL),'+' ; nein, "+" ausgeben
INC HL ; naechste Printposition
CALL PRVH ; Offset ausgeben
$DL12: POP AF ; A wieder herstellen
BIT 7,A ; "()" ?
RET Z ; nein, fertig
LD (HL),')' ; ja, ")" ausgeben
INC HL ; naechste Printposition
RET
; Error
ERRO: LD DE,CBMTAB+24 ; Pointer auf "????" -> DE
CALL TRBY ; als Mnemonic ausgeben
POP DE ; akt. Disassemblieradr. vom Stack holen
; Disassemblier-Adresse erhoehen und merken
INAD: INC DE
LD (DADR),DE
; Workspace ausgeben
PRWO: PUSH AF ; Register retten
PUSH BC
PUSH DE
PUSH HL
LD HL,WRKS ; Adresse Workspace -> HL
CALL PRTSTR ; Workspace aufs Terminal ausgeben
LD HL,NL ; Adresse Newline-String -> HL
CALL PRTSTR ; Newline ausgeben
POP HL ; Register wieder herstellen
POP DE
POP BC
POP AF
RET
; Workspace loeschen
CLWO: LD HL,WRKS ; Workspace mit Space fuellen
LD DE,WRKS+1 ; und mit Null terminieren
LD (HL),32
LD BC,32
LDIR
XOR A
LD (DE),A
RET
; 4 Bytes transferieren
TRBY: PUSH BC ; BC retten
LD BC,4 ; 4 Bytes
EX DE,HL ; DE=Printposition, HL=Mnemonic
LDIR ; Bytes transferieren
EX DE,HL ; HL ist wieder Printposition
POP BC ; BC wieder herstellen
INC HL ; Leerzeichen
RET
; Byte vorne und hinten ausgeben
PRVH: CALL PRNB ; Byte vorne ausgeben
; Byte hinten ausgeben
PRBH: PUSH AF ; A retten
LD A,(DE) ; Byte -> A
CALL PRAK ; A ausgeben
POP AF ; A wieder herstellen
RET
; Byte vorne ausgeben
PRNB: PUSH AF ; A retten
INC DE ; DE auf naechstes Byte setzen
PUSH HL ; akt. Printposition retten
LD HL,(PRTMP) ; vordere Printposition -> HL
LD A,(DE) ; Byte -> A
CALL PRAK ; A ausgeben
INC HL ; Leerzeichen
LD (PRTMP),HL ; vordere Printposition retten
POP HL ; akt. Printposition wieder -> HL
POP AF ; A wieder herstellen
RET
; DE ausgeben
PRBY: LD A,D ; MSB -> A
CALL PRAK ; A ausgeben
LD A,E ; LSB -> A
; A ausgeben
PRAK: PUSH AF ; A retten
RRCA ; oberes Nibble ins untere schieben
RRCA
RRCA
RRCA
CALL PRCH ; oberes Nibble ausgeben
POP AF ; A wieder herstellen
CALL PRCH ; unteres Nibble ausgeben
RET
; unteres Nibble in ASCII-Hex umwandeln und in Workspace schreiben
PRCH: AND 0FH
ADD A,90H
DAA
ADC A,40H
DAA
LD (HL),A ; ASCII-Ziffer in Workspace schreiben
INC HL ; Printposition erhoehen
RET
; Die hier folgenden Tabellen muessen am Anfang einer Page
; beginnen, und die Reihenfolge der Tabellen darf auf keinen
; Fall geaendert werden, weil das LSB der Tabellenadressen
; durch arithmetische Operationen mit den Op-Codes berechnet
; wird !!!
DEFS 256 - ($ & 0FFH)
MNETAB: ; Tabelle mit den Z80-Mnemonics
DEFM 'ADD ADC '
DEFM 'SUB SBC '
DEFM 'AND XOR '
DEFM 'OR CP '
DEFM 'JR NOP '
DEFM 'DJNZEX '
DEFM 'RLCARLA '
DEFM 'DAA SCF '
DEFM 'RRCARRA '
DEFM 'CPL CCF '
DEFM 'LD INC '
DEFM 'DEC HALT'
DEFM 'RET POP '
DEFM 'JP OUT '
DEFM 'EX DI '
DEFM 'CALLPUSH'
DEFM 'RST EXX '
DEFM 'IN EX '
DEFM 'EI LDI '
DEFM 'LDIRINI '
DEFM 'INIROUTI'
DEFM 'OTIRNEG '
DEFM 'RETNRRD '
DEFM 'LDD LDDR'
DEFM 'CPD CPDR'
DEFM 'IND INDR'
DEFM 'OTDROUTD'
DEFM 'RETIRLD '
DEFM 'BIT RES '
DEFM 'SET ????'
DEFM 'CPI CPIR'
DEFM 'IM ----'
CODTAB: ; LSB-Adressen der Mnemonics in MNETAB fuer
; Befehle 00..3F ohne Preafix ED/CB
DEFB 024H,050H,050H,054H,054H,058H,050H,030H ; NOP LD LD INC INC DEC LD RLCA
DEFB 070H,000H,050H,058H,054H,058H,050H,040H ; EX ADD LD DEC INC DEC LD RRCA
DEFB 028H,050H,050H,054H,054H,058H,050H,034H ; DJNZ LD LD INC INC DEC LD RLA
DEFB 020H,000H,050H,058H,054H,058H,050H,044H ; JR ADD LD DEC INC DEC LD RRA
DEFB 020H,050H,050H,054H,054H,058H,050H,038H ; JR LD LD INC INC DEC LD DAA
DEFB 020H,000H,050H,058H,054H,058H,050H,048H ; JR ADD LD DEC INC DEC LD CPL
DEFB 020H,050H,050H,054H,054H,058H,050H,03CH ; JR LD LD INC INC DEC LD SCF
DEFB 020H,000H,050H,058H,054H,058H,050H,04CH ; JR ADD LD DEC INC DEC LD CCF
; LSB-Adressen der Mnemonics in MNETAB fuer
; Befehle C0..FF ohne Preafix ED/CB
DEFB 060H,064H,068H,068H,078H,07CH,000H,080H ; RET POP JP JP CALL PUSH ADD RET
DEFB 060H,060H,068H,0F1H,078H,078H,004H,080H ; RET RET JP (CB) CALL CALL ADC RST
DEFB 060H,064H,068H,06CH,078H,07CH,008H,080H ; RET POP JP OUT CALL PUSH SUB RST
DEFB 060H,084H,068H,088H,078H,0F0H,00CH,080H ; RET EXX JP IN CALL (DD) SBC RST
DEFB 060H,064H,068H,070H,078H,07CH,010H,080H ; RET POP JP EX CALL PUSH AND RST
DEFB 060H,068H,068H,02CH,078H,0F2H,014H,080H ; RET JP JP EX CALL (ED) XOR RST
DEFB 060H,064H,068H,074H,078H,07CH,018H,080H ; RET POP JP DI CALL PUSH OR RST
DEFB 060H,050H,068H,090H,078H,0F8H,01CH,080H ; RET LD JP EI CALL (FD) CP RST
; LSB-Adressen der Mnemonics in MNETAB fuer
; Befehle 40..7F mit Preafix ED
DEFB 088H,06CH,00CH,050H,0ACH,0B0H,0F8H,050H ; IN OUT SBC LD NEG RETN IM LD
DEFB 088H,06CH,004H,050H,0FFH,0D8H,0FFH,050H ; IN OUT ADC LD RETI LD
DEFB 088H,06CH,00CH,050H,0FFH,0FFH,0F8H,050H ; IN OUT SBC LD IM LD
DEFB 088H,06CH,004H,050H,0FFH,0FFH,0F8H,050H ; IN OUT ADC LD IM LD
DEFB 088H,06CH,00CH,0FFH,0FFH,0FFH,0FFH,0B4H ; IN OUT SBC RRD
DEFB 088H,06CH,004H,0FFH,0FFH,0FFH,0FFH,0DCH ; IN OUT ADC RLD
DEFB 0FFH,0FFH,00CH,050H,0FFH,0FFH,0FFH,0FFH ; SBC LD
DEFB 088H,06CH,004H,050H,0FFH,0FFH,0FFH,0FFH ; IN OUT ADC LD
; LSB-Adressen der Mnemonics in MNETAB fuer
; Befehle A0..BF mit Praefix ED
DEFB 094H,0F0H,09CH,0A4H,0FFH,0FFH,0FFH,0FFH ; LDI CPI INI OUTI
DEFB 0B8H,0C0H,0C8H,0D4H,0FFH,0FFH,0FFH,0FFH ; LDD CPD IND OUTD
DEFB 098H,0F4H,0A0H,0A8H,0FFH,0FFH,0FFH,0FFH ; LDIR CPIR INIR OTIR
DEFB 0BCH,0C4H,0CCH,0D0H,0FFH,0FFH,0FFH,0FFH ; LDDR CPDR INDR OTDR
SPRTAB: ; Tabelle der Sprungbedingungen
DEFM 'NZNCPOPEPM'
DEFB 0FFH,0FFH,0FFH,0FFH,0FFH,0FFH
REGTAB: ; Tabelle der Register
DEFM 'BCDEHLSPAFIXIYIR'
OPETAB: ; Tabelle der Operanden:
; Bit 7: Zahl/Buchstabe
; Bit 6: einfach/doppelt
; Bit 5: Register/Sprungbedingung
; Bit 4: ohne/mit Klammer
; Bit 0..3: Offset in der Tabelle der Registernamen
; Befehle 00..3F ohne Preafix ED/CB
; 1. Operand
DEFB 0FFH,030H,0B0H,030H,010H,010H,010H,0FFH ; - BC (BC) BC B B B -
DEFB 038H,034H,017H,030H,011H,011H,011H,0FFH ; AF HL A BC C C C -
DEFB 041H,032H,0B2H,032H,012H,012H,012H,0FFH ; DIS DE (DE) DE D D D -
DEFB 041H,034H,017H,032H,013H,013H,013H,0FFH ; DIS HL A DE E E E -
DEFB 070H,034H,0C4H,034H,014H,014H,014H,0FFH ; NZ HL (NN) HL H H H -
DEFB 051H,034H,034H,034H,015H,015H,015H,0FFH ; Z HL HL HL L L L -
DEFB 072H,036H,0C4H,036H,016H,016H,016H,0FFH ; NC SP (NN) SP (HL) (HL) (HL) -
DEFB 011H,034H,017H,036H,017H,017H,017H,0FFH ; C HL A SP A A A -
; Befehle C0..FF ohne Preafix ED/CB
; 1. Operand
DEFB 070H,030H,070H,044H,070H,030H,017H,020H ; NZ BC NZ NN NZ BC A 00
DEFB 051H,0FFH,051H,0F1H,051H,044H,017H,021H ; Z - Z *CB Z NN A 08
DEFB 072H,032H,072H,0C2H,072H,032H,042H,022H ; NC DE NC (N) NC DE N 10
DEFB 053H,0FFH,053H,017H,053H,0F2H,017H,023H ; C - C A C *DD A 18
DEFB 074H,034H,074H,0B6H,074H,034H,042H,024H ; PO HL PO (SP) PO HL N 20
DEFB 076H,016H,076H,032H,076H,0F4H,042H,025H ; PE (HL) PE DE PE *ED N 28
DEFB 058H,038H,058H,0FFH,058H,038H,042H,026H ; P AF P - P AF N 30
DEFB 059H,036H,059H,0FFH,059H,0F8H,042H,027H ; M SP M - M *FD N 38
; Befehle 00..3F ohne Preafix ED/CB
; 2. Operand
DEFB 0FFH,044H,017H,0FFH,0FFH,0FFH,042H,0FFH ; - NN A - - - N -
DEFB 038H,030H,0B0H,0FFH,0FFH,0FFH,042H,0FFH ; AF BC (BC) - - - N -
DEFB 0FFH,044H,017H,0FFH,0FFH,0FFH,042H,0FFH ; - NN A - - - N -
DEFB 0FFH,032H,0B2H,0FFH,0FFH,0FFH,042H,0FFH ; - DE (DE) - - - N -
DEFB 041H,044H,034H,0FFH,0FFH,0FFH,042H,0FFH ; DIS NN HL - - - N -
DEFB 041H,034H,0C4H,0FFH,0FFH,0FFH,042H,0FFH ; DIS HL (NN) - - - N -
DEFB 041H,044H,017H,0FFH,0FFH,0FFH,042H,0FFH ; DIS NN A - - - N -
DEFB 041H,036H,0C4H,0FFH,0FFH,0FFH,042H,0FFH ; DIS SP (NN) - - - N -
; Befehle C0..FF ohne Praefix ED/CB
; 2. Operand
DEFB 0FFH,0FFH,044H,0FFH,044H,0FFH,042H,0FFH ; - - NN - NN - N -
DEFB 0FFH,0FFH,044H,0FFH,044H,0FFH,042H,0FFH ; - - NN *CB NN - N -
DEFB 0FFH,0FFH,044H,017H,044H,0FFH,0FFH,0FFH ; - - NN A NN - - -
DEFB 0FFH,0FFH,044H,0C2H,044H,0FFH,042H,0FFH ; - - NN (N) NN *DD N -
DEFB 0FFH,0FFH,044H,034H,044H,0FFH,0FFH,0FFH ; - - NN HL NN - - -
DEFB 0FFH,0FFH,044H,034H,044H,0FFH,0FFH,0FFH ; - - NN HL NN *ED - -
DEFB 0FFH,0FFH,044H,0FFH,044H,0FFH,0FFH,0FFH ; - - NN - NN - - -
DEFB 0FFH,034H,044H,0FFH,044H,0FFH,0FFH,0FFH ; - HL NN - NN *FD - -
OP2TAB: ; Befehle 40..7F mit Praefix ED
; 1. Operand
DEFB 010H,091H,034H,0C4H,0FFH,0FFH,000H,01EH ; B (C) HL (NN) - - 0 I
DEFB 011H,091H,034H,030H,0FFH,0FFH,0FFH,01FH ; C (C) HL BC - - - R
DEFB 012H,091H,034H,0C4H,0FFH,0FFH,001H,017H ; D (C) HL (NN) - - 1 A
DEFB 013H,091H,034H,032H,0FFH,0FFH,002H,017H ; E (C) HL DE - - 2 A
DEFB 014H,091H,034H,0C4H,0FFH,0FFH,076H,0FFH ; H (C) HL - - - - -
DEFB 015H,091H,034H,0FFH,0FFH,0FFH,0FFH,0FFH ; L (C) HL - - - - -
DEFB 0FFH,0FFH,034H,0C4H,0FFH,0FFH,0FFH,0FFH ; - - HL (NN) - - - -
DEFB 017H,091H,034H,036H,0FFH,0FFH,0FFH,0FFH ; A (C) HL SP - - - -
; Befehle 40..7F mit Preafix ED
; 2. Operand
DEFB 091H,010H,030H,030H,0FFH,0FFH,0FFH,017H ; (C) B BC BC - - - A
DEFB 091H,011H,030H,0C4H,0FFH,0FFH,0FFH,017H ; (C) C BC (NN) - - - A
DEFB 091H,012H,032H,032H,0FFH,0FFH,0FFH,01EH ; (C) D DE DE - - - I
DEFB 091H,013H,032H,0C4H,0FFH,0FFH,0FFH,01FH ; (C) E DE (NN) - - - R
DEFB 091H,014H,034H,034H,0FFH,0FFH,0FFH,0FFH ; (C) H HL - - - - -
DEFB 091H,015H,034H,0FFH,0FFH,0FFH,0FFH,0FFH ; (C) L HL - - - - -
DEFB 0FFH,0FFH,036H,036H,0FFH,0FFH,0FFH,0FFH ; - - SP SP - - - -
DEFB 091H,017H,036H,0C4H,0FFH,0FFH,0FFH,0FFH ; (C) A SP (NN) - - - -
CBMTAB: ; Tabelle der Mnemonics mit Praefix CB
DEFM 'RLC RRC '
DEFM 'RL RR '
DEFM 'SLA SRA '
DEFM '????SRL '
NL: ; Null-terminiertes Newline fuers Terminal
DEFB 10,13,0
WRKS: DEFS 34 ; Workspace zur Aufbereitung einer Ausgabezeile
PRTMP: DEFS 2 ; temoraerer Speicher fuer Printposition
DADR: DEFS 2 ; Disassemblier-Adresse

View File

@@ -0,0 +1,28 @@
TITLE 'Test programm for Z80-Disassembler'
;==========================================================================
; Test programm for Z80-Disassembler
;==========================================================================
LD SP,STACK ; initialize stack for simulator
LD HL,Z80OPS ; start address for disassembler
LD (DADR),HL
LOOP:
CALL DISSCR ; disassemble one screen full
HALT ; stop simulation
JP LOOP ; next run
PRTSTR: ; print 0 terminated string
LD A,(HL) ; next char -> A
OR A ; 0 ?
RET Z ; yes, done
OUT (0),A ; no, print it
INC HL ; increase pointer to string
JP PRTSTR ; process next char
INCLUDE z80dis.asm
INCLUDE z80ops.asm
DEFS 100H
STACK:
END

View File

@@ -0,0 +1,704 @@
TITLE 'Z80 Instruction Set in alphabetical Order'
IND EQU 5
M EQU 10H
N EQU 20H
DIS EQU 30H
Z80OPS:
ADC A,(HL)
ADC A,(IX+IND)
ADC A,(IY+IND)
ADC A,A
ADC A,B
ADC A,C
ADC A,D
ADC A,E
ADC A,H
ADC A,L
ADC A,N
ADC HL,BC
ADC HL,DE
ADC HL,HL
ADC HL,SP
ADD A,(HL)
ADD A,(IX+IND)
ADD A,(IY+IND)
ADD A,A
ADD A,B
ADD A,C
ADD A,D
ADD A,E
ADD A,H
ADD A,L
ADD A,N
ADD HL,BC
ADD HL,DE
ADD HL,HL
ADD HL,SP
ADD IX,BC
ADD IX,DE
ADD IX,IX
ADD IX,SP
ADD IY,BC
ADD IY,DE
ADD IY,IY
ADD IY,SP
AND (HL)
AND (IX+IND)
AND (IY+IND)
AND A
AND B
AND C
AND D
AND E
AND H
AND L
AND N
BIT 0,(HL)
BIT 0,(IX+IND)
BIT 0,(IY+IND)
BIT 0,A
BIT 0,B
BIT 0,C
BIT 0,D
BIT 0,E
BIT 0,H
BIT 0,L
BIT 1,(HL)
BIT 1,(IX+IND)
BIT 1,(IY+IND)
BIT 1,A
BIT 1,B
BIT 1,C
BIT 1,D
BIT 1,E
BIT 1,H
BIT 1,L
BIT 2,(HL)
BIT 2,(IX+IND)
BIT 2,(IY+IND)
BIT 2,A
BIT 2,B
BIT 2,C
BIT 2,D
BIT 2,E
BIT 2,H
BIT 2,L
BIT 3,(HL)
BIT 3,(IX+IND)
BIT 3,(IY+IND)
BIT 3,A
BIT 3,B
BIT 3,C
BIT 3,D
BIT 3,E
BIT 3,H
BIT 3,L
BIT 4,(HL)
BIT 4,(IX+IND)
BIT 4,(IY+IND)
BIT 4,A
BIT 4,B
BIT 4,C
BIT 4,D
BIT 4,E
BIT 4,H
BIT 4,L
BIT 5,(HL)
BIT 5,(IX+IND)
BIT 5,(IY+IND)
BIT 5,A
BIT 5,B
BIT 5,C
BIT 5,D
BIT 5,E
BIT 5,H
BIT 5,L
BIT 6,(HL)
BIT 6,(IX+IND)
BIT 6,(IY+IND)
BIT 6,A
BIT 6,B
BIT 6,C
BIT 6,D
BIT 6,E
BIT 6,H
BIT 6,L
BIT 7,(HL)
BIT 7,(IX+IND)
BIT 7,(IY+IND)
BIT 7,A
BIT 7,B
BIT 7,C
BIT 7,D
BIT 7,E
BIT 7,H
BIT 7,L
CALL C,NN
CALL M,NN
CALL NC,NN
CALL NN
CALL NZ,NN
CALL P,NN
CALL PE,NN
CALL PO,NN
CALL Z,NN
CCF
CP (HL)
CP (IX+IND)
CP (IY+IND)
CP A
CP B
CP C
CP D
CP E
CP H
CP L
CP N
CPD
CPDR
CPI
CPIR
CPL
DAA
DEC (HL)
DEC (IX+IND)
DEC (IY+IND)
DEC A
DEC B
DEC BC
DEC C
DEC D
DEC DE
DEC E
DEC H
DEC HL
DEC IX
DEC IY
DEC L
DEC SP
DI
DJNZ $+DIS
EI
EX (SP),HL
EX (SP),IX
EX (SP),IY
EX AF,AF'
EX DE,HL
EXX
HALT
IM 0
IM 1
IM 2
IN A,(C)
IN A,(N)
IN B,(C)
IN C,(C)
IN D,(C)
IN E,(C)
IN H,(C)
IN L,(C)
INC (HL)
INC (IX+IND)
INC (IY+IND)
INC A
INC B
INC BC
INC C
INC D
INC DE
INC E
INC H
INC HL
INC IX
INC IY
INC L
INC SP
IND
INDR
INI
INIR
JP (HL)
JP (IX)
JP (IY)
JP C,NN
JP M,NN
JP NC,NN
JP NN
JP NZ,NN
JP P,NN
JP PE,NN
JP PO,NN
JP Z,NN
JR C,$+DIS
JR $+DIS
JR NC,$+DIS
JR NZ,$+DIS
JR Z,$+DIS
LD (BC),A
LD (DE),A
LD (HL),A
LD (HL),B
LD (HL),C
LD (HL),D
LD (HL),E
LD (HL),H
LD (HL),L
LD (HL),N
LD (IX+IND),A
LD (IX+IND),B
LD (IX+IND),C
LD (IX+IND),D
LD (IX+IND),E
LD (IX+IND),H
LD (IX+IND),L
LD (IX+IND),N
LD (IY+IND),A
LD (IY+IND),B
LD (IY+IND),C
LD (IY+IND),D
LD (IY+IND),E
LD (IY+IND),H
LD (IY+IND),L
LD (IY+IND),N
LD (NN),A
LD (NN),BC
LD (NN),DE
LD (NN),HL
LD (NN),IX
LD (NN),IY
LD (NN),SP
LD A,(BC)
LD A,(DE)
LD A,(HL)
LD A,(IX+IND)
LD A,(IY+IND)
LD A,(NN)
LD A,A
LD A,B
LD A,C
LD A,D
LD A,E
LD A,H
LD A,I
LD A,L
LD A,N
LD B,(HL)
LD B,(IX+IND)
LD B,(IY+IND)
LD B,A
LD B,B
LD B,C
LD B,D
LD B,E
LD B,H
LD B,L
LD B,N
LD BC,(NN)
LD BC,NN
LD C,(HL)
LD C,(IX+IND)
LD C,(IY+IND)
LD C,A
LD C,B
LD C,C
LD C,D
LD C,E
LD C,H
LD C,L
LD C,N
LD D,(HL)
LD D,(IX+IND)
LD D,(IY+IND)
LD D,A
LD D,B
LD D,C
LD D,D
LD D,E
LD D,H
LD D,L
LD D,N
LD DE,(NN)
LD DE,NN
LD E,(HL)
LD E,(IX+IND)
LD E,(IY+IND)
LD E,A
LD E,B
LD E,C
LD E,D
LD E,E
LD E,H
LD E,L
LD E,N
LD H,(HL)
LD H,(IX+IND)
LD H,(IY+IND)
LD H,A
LD H,B
LD H,C
LD H,D
LD H,E
LD H,H
LD H,L
LD H,N
LD HL,(NN)
LD HL,NN
LD I,A
LD IX,(NN)
LD IX,NN
LD IY,(NN)
LD IY,NN
LD L,(HL)
LD L,(IX+IND)
LD L,(IY+IND)
LD L,A
LD L,B
LD L,C
LD L,D
LD L,E
LD L,H
LD L,L
LD L,N
LD SP,(NN)
LD SP,HL
LD SP,IX
LD SP,IY
LD SP,NN
LDD
LDDR
LDI
LDIR
NEG
NOP
OR (HL)
OR (IX+IND)
OR (IY+IND)
OR A
OR B
OR C
OR D
OR E
OR H
OR L
OR N
OTDR
OTIR
OUT (C),A
OUT (C),B
OUT (C),C
OUT (C),D
OUT (C),E
OUT (C),H
OUT (C),L
OUT (N),A
OUTD
OUTI
POP AF
POP BC
POP DE
POP HL
POP IX
POP IY
PUSH AF
PUSH BC
PUSH DE
PUSH HL
PUSH IX
PUSH IY
RES 0,(HL)
RES 0,(IX+IND)
RES 0,(IY+IND)
RES 0,A
RES 0,B
RES 0,C
RES 0,D
RES 0,E
RES 0,H
RES 0,L
RES 1,(HL)
RES 1,(IX+IND)
RES 1,(IY+IND)
RES 1,A
RES 1,B
RES 1,C
RES 1,D
RES 1,E
RES 1,H
RES 1,L
RES 2,(HL)
RES 2,(IX+IND)
RES 2,(IY+IND)
RES 2,A
RES 2,B
RES 2,C
RES 2,D
RES 2,E
RES 2,H
RES 2,L
RES 3,(HL)
RES 3,(IX+IND)
RES 3,(IY+IND)
RES 3,A
RES 3,B
RES 3,C
RES 3,D
RES 3,E
RES 3,H
RES 3,L
RES 4,(HL)
RES 4,(IX+IND)
RES 4,(IY+IND)
RES 4,A
RES 4,B
RES 4,C
RES 4,D
RES 4,E
RES 4,H
RES 4,L
RES 5,(HL)
RES 5,(IX+IND)
RES 5,(IY+IND)
RES 5,A
RES 5,B
RES 5,C
RES 5,D
RES 5,E
RES 5,H
RES 5,L
RES 6,(HL)
RES 6,(IX+IND)
RES 6,(IY+IND)
RES 6,A
RES 6,B
RES 6,C
RES 6,D
RES 6,E
RES 6,H
RES 6,L
RES 7,(HL)
RES 7,(IX+IND)
RES 7,(IY+IND)
RES 7,A
RES 7,B
RES 7,C
RES 7,D
RES 7,E
RES 7,H
RES 7,L
RET
RET C
RET M
RET NC
RET NZ
RET P
RET PE
RET PO
RET Z
RETI
RETN
RL (HL)
RL (IX+IND)
RL (IY+IND)
RL A
RL B
RL C
RL D
RL E
RL H
RL L
RLA
RLC (HL)
RLC (IX+IND)
RLC (IY+IND)
RLC A
RLC B
RLC C
RLC D
RLC E
RLC H
RLC L
RLCA
RLD
RR (HL)
RR (IX+IND)
RR (IY+IND)
RR A
RR B
RR C
RR D
RR E
RR H
RR L
RRA
RRC (HL)
RRC (IX+IND)
RRC (IY+IND)
RRC A
RRC B
RRC C
RRC D
RRC E
RRC H
RRC L
RRCA
RRD
RST 0
RST 10H
RST 18H
RST 20H
RST 28H
RST 30H
RST 38H
RST 8
SBC A,(HL)
SBC A,(IX+IND)
SBC A,(IY+IND)
SBC A,A
SBC A,B
SBC A,C
SBC A,D
SBC A,E
SBC A,H
SBC A,L
SBC A,N
SBC HL,BC
SBC HL,DE
SBC HL,HL
SBC HL,SP
SCF
SET 0,(HL)
SET 0,(IX+IND)
SET 0,(IY+IND)
SET 0,A
SET 0,B
SET 0,C
SET 0,D
SET 0,E
SET 0,H
SET 0,L
SET 1,(HL)
SET 1,(IX+IND)
SET 1,(IY+IND)
SET 1,A
SET 1,B
SET 1,C
SET 1,D
SET 1,E
SET 1,H
SET 1,L
SET 2,(HL)
SET 2,(IX+IND)
SET 2,(IY+IND)
SET 2,A
SET 2,B
SET 2,C
SET 2,D
SET 2,E
SET 2,H
SET 2,L
SET 3,(HL)
SET 3,(IX+IND)
SET 3,(IY+IND)
SET 3,A
SET 3,B
SET 3,C
SET 3,D
SET 3,E
SET 3,H
SET 3,L
SET 4,(HL)
SET 4,(IX+IND)
SET 4,(IY+IND)
SET 4,A
SET 4,B
SET 4,C
SET 4,D
SET 4,E
SET 4,H
SET 4,L
SET 5,(HL)
SET 5,(IX+IND)
SET 5,(IY+IND)
SET 5,A
SET 5,B
SET 5,C
SET 5,D
SET 5,E
SET 5,H
SET 5,L
SET 6,(HL)
SET 6,(IX+IND)
SET 6,(IY+IND)
SET 6,A
SET 6,B
SET 6,C
SET 6,D
SET 6,E
SET 6,H
SET 6,L
SET 7,(HL)
SET 7,(IX+IND)
SET 7,(IY+IND)
SET 7,A
SET 7,B
SET 7,C
SET 7,D
SET 7,E
SET 7,H
SET 7,L
SLA (HL)
SLA (IX+IND)
SLA (IY+IND)
SLA A
SLA B
SLA C
SLA D
SLA E
SLA H
SLA L
SRA (HL)
SRA (IX+IND)
SRA (IY+IND)
SRA A
SRA B
SRA C
SRA D
SRA E
SRA H
SRA L
SRL (HL)
SRL (IX+IND)
SRL (IY+IND)
SRL A
SRL B
SRL C
SRL D
SRL E
SRL H
SRL L
SUB (HL)
SUB (IX+IND)
SUB (IY+IND)
SUB A
SUB B
SUB C
SUB D
SUB E
SUB H
SUB L
SUB N
XOR (HL)
XOR (IX+IND)
XOR (IY+IND)
XOR A
XOR B
XOR C
XOR D
XOR E
XOR H
XOR L
XOR N
NN: DEFS 2