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]