realized the emulators were not mine, cant be in the repo
This commit is contained in:
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
The two files in this ZIP file are disassembled CP/M 2.2.
|
||||
|
||||
CPM22.ASM : CP/M 2.2 in 8080 mnemonics
|
||||
CPM22.Z80 : CP/M 2.2 in Z80 mnemonics
|
||||
|
||||
Both files claim to implement a fix that affects operation in a sector
|
||||
deblocking environment. The Z80 version does not look to have been optimized
|
||||
for the Z80, it just uses Z80 mnemonics.
|
||||
|
4190
cpm/pcpm/BDOS.MAC
4190
cpm/pcpm/BDOS.MAC
File diff suppressed because it is too large
Load Diff
1660
cpm/pcpm/CCP.MAC
1660
cpm/pcpm/CCP.MAC
File diff suppressed because it is too large
Load Diff
1630
cpm/pcpm/ED.PLM
1630
cpm/pcpm/ED.PLM
File diff suppressed because it is too large
Load Diff
1509
cpm/pcpm/PIP.PLM
1509
cpm/pcpm/PIP.PLM
File diff suppressed because it is too large
Load Diff
@@ -1,39 +0,0 @@
|
||||
The following list of corrections should be made to the Personal CP/M 8-bit
|
||||
version 1.0 documentation.
|
||||
|
||||
Programmer's Guide
|
||||
|
||||
page 2-10
|
||||
BDOS function 2
|
||||
text says 'CONSOLE INPUT'
|
||||
should be 'CONSOLE OUTPUT'
|
||||
|
||||
page 2-45
|
||||
BDOS function 33
|
||||
'Entry Parameters' add after Register C line:
|
||||
'Register DE: FCB Address'
|
||||
|
||||
page 2-49
|
||||
BDOS function 35
|
||||
replace information about values returned in registers with:
|
||||
'Random record field of FCB set'
|
||||
|
||||
System Guide
|
||||
|
||||
Section 2
|
||||
References to the BDOS size being 1100h bytes are incorrect.
|
||||
The BDOS code segment is 1000h bytes, and the BDOS data
|
||||
segment is 00BFh bytes. With the standard distibution,
|
||||
BDOSH.REL and BDOSL.REL will link these in a separate area
|
||||
from the BDOS code segment. OEMs that purchase the source
|
||||
can set an assembly-time switch that will make the data areas
|
||||
part of the code segment so that it will all be linked as one
|
||||
segment of 1100h bytes if the BDOS will execute in RAM.
|
||||
|
||||
page 4-15
|
||||
BIOS function WRITE
|
||||
Entry Parameters: Register C = 0: normal sector write
|
||||
1: write to directory sector
|
||||
2: write to the first sector
|
||||
of a new data block
|
||||
|
@@ -1,15 +0,0 @@
|
||||
Please note: line 2528 in BDOS.MAC is corrupted. It should read
|
||||
|
||||
jp z,COPY$DIRLOC ;stop at end of dir
|
||||
|
||||
--------------------------
|
||||
|
||||
This zip file contains the original source for Personal CP/M 1.0.
|
||||
If anybody figures out anything about this code, please drop an
|
||||
email message to me at :
|
||||
|
||||
gaby@gaby.de
|
||||
|
||||
and I'll pass it on.
|
||||
|
||||
tnx
|
@@ -1,834 +0,0 @@
|
||||
stat:
|
||||
do;
|
||||
declare
|
||||
cpmversion literally '20h'; /* requires 2.0 cp/m */
|
||||
/* c p / m s t a t u s c o m m a n d (s t a t) */
|
||||
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
/* status status status status status status */
|
||||
|
||||
/*
|
||||
copyright(c) 1975, 1976, 1977, 1978, 1979, 1984
|
||||
digital research
|
||||
box 579
|
||||
pacific grove, ca
|
||||
93950
|
||||
*/
|
||||
|
||||
/* modified 10/30/78 to fix the space computation */
|
||||
/* modified 01/28/79 to remove despool dependencies */
|
||||
/* modified 07/26/79 to operate under cp/m 2.0 */
|
||||
/* modified 03/14/84 to remove iobyte modification for Personal CP/M */
|
||||
|
||||
declare jump byte data(0c3h),
|
||||
jadr address data (.status);
|
||||
/* jump to status */
|
||||
|
||||
/* function call 32 returns the address of the disk parameter
|
||||
block for the currently selected disk, which consists of:
|
||||
scptrk (2 by) number of sectors per track
|
||||
blkshf (1 by) log2 of blocksize (2**blkshf=blksize)
|
||||
blkmsk (1 by) 2**blkshf-1
|
||||
extmsk (1 by) logical/physical extents
|
||||
maxall (2 by) max alloc number
|
||||
dirmax (2 by) size of directory-1
|
||||
dirblk (2 by) reservation bits for directory
|
||||
chksiz (2 by) size of checksum vector
|
||||
offset (2 by) offset for operating system
|
||||
*/
|
||||
|
||||
declare
|
||||
/* fixed locations for cp/m */
|
||||
bdosa literally '0006h', /* bdos base */
|
||||
buffa literally '0080h', /* default buffer */
|
||||
fcba literally '005ch', /* default file control block */
|
||||
dolla literally '006dh', /* dollar sign position */
|
||||
parma literally '006eh', /* parameter, if sent */
|
||||
rreca literally '007dh', /* random record 7d,7e,7f */
|
||||
rreco literally '007fh', /* high byte of random overflow */
|
||||
sectorlen literally '128', /* sector length */
|
||||
memsize address at(bdosa), /* end of memory */
|
||||
rrec address at(rreca), /* random record address */
|
||||
rovf byte at(rreco), /* overflow on getfile */
|
||||
doll byte at(dolla), /* dollar parameter */
|
||||
parm byte at(parma), /* parameter */
|
||||
sizeset byte, /* true if displaying size field */
|
||||
dpba address, /* disk parameter block address */
|
||||
dpb based dpba structure
|
||||
(spt address, bls byte, bms byte, exm byte, mxa address,
|
||||
dmx address, dbl address, cks address, ofs address),
|
||||
scptrk literally 'dpb.spt',
|
||||
blkshf literally 'dpb.bls',
|
||||
blkmsk literally 'dpb.bms',
|
||||
extmsk literally 'dpb.exm',
|
||||
maxall literally 'dpb.mxa',
|
||||
dirmax literally 'dpb.dmx',
|
||||
dirblk literally 'dpb.dbl',
|
||||
chksiz literally 'dpb.cks',
|
||||
offset literally 'dpb.ofs';
|
||||
|
||||
|
||||
boot: procedure external;
|
||||
/* reboot */
|
||||
end boot;
|
||||
|
||||
mon1: procedure(f,a) external;
|
||||
declare f byte, a address;
|
||||
end mon1;
|
||||
|
||||
mon2: procedure(f,a) byte external;
|
||||
declare f byte, a address;
|
||||
end mon2;
|
||||
|
||||
mon3: procedure(f,a) address external;
|
||||
declare f byte, a address;
|
||||
end mon3;
|
||||
|
||||
|
||||
status: procedure;
|
||||
declare copyright(*) byte data (
|
||||
' Copyright (c) 1984, Digital Research');
|
||||
/* dummy outer procedure 'status' will start at 100h */
|
||||
/* determine status of currently selected disk */
|
||||
|
||||
declare alloca address,
|
||||
/* alloca is the address of the disk allocation vector */
|
||||
alloc based alloca (1024) byte; /* allocation vector */
|
||||
|
||||
declare
|
||||
true literally '1',
|
||||
false literally '0',
|
||||
forever literally 'while true',
|
||||
cr literally '13',
|
||||
lf literally '10';
|
||||
|
||||
printchar: procedure(char);
|
||||
declare char byte;
|
||||
call mon1(2,char);
|
||||
end printchar;
|
||||
|
||||
crlf: procedure;
|
||||
call printchar(cr);
|
||||
call printchar(lf);
|
||||
end crlf;
|
||||
|
||||
printb: procedure;
|
||||
/* print blank character */
|
||||
call printchar(' ');
|
||||
end printb;
|
||||
|
||||
printx: procedure(a);
|
||||
declare a address;
|
||||
declare s based a byte;
|
||||
do while s <> 0;
|
||||
call printchar(s);
|
||||
a = a + 1;
|
||||
end;
|
||||
end printx;
|
||||
|
||||
print: procedure(a);
|
||||
declare a address;
|
||||
/* print the string starting at address a until the
|
||||
next 0 is encountered */
|
||||
call crlf;
|
||||
call printx(a);
|
||||
end print;
|
||||
|
||||
break: procedure byte;
|
||||
return mon2(11,0); /* console ready */
|
||||
end break;
|
||||
|
||||
declare dcnt byte;
|
||||
|
||||
version: procedure byte;
|
||||
/* returns current cp/m version # */
|
||||
return mon2(12,0);
|
||||
end version;
|
||||
|
||||
select: procedure(d);
|
||||
declare d byte;
|
||||
call mon1(14,d);
|
||||
end select;
|
||||
|
||||
open: procedure(fcb);
|
||||
declare fcb address;
|
||||
dcnt = mon2(15,fcb);
|
||||
end open;
|
||||
|
||||
search: procedure(fcb);
|
||||
declare fcb address;
|
||||
dcnt = mon2(17,fcb);
|
||||
end search;
|
||||
|
||||
searchn: procedure;
|
||||
dcnt = mon2(18,0);
|
||||
end searchn;
|
||||
|
||||
cselect: procedure byte;
|
||||
/* return current disk number */
|
||||
return mon2(25,0);
|
||||
end cselect;
|
||||
|
||||
setdma: procedure(dma);
|
||||
declare dma address;
|
||||
call mon1(26,dma);
|
||||
end setdma;
|
||||
|
||||
getalloca: procedure address;
|
||||
/* get base address of alloc vector */
|
||||
return mon3(27,0);
|
||||
end getalloca;
|
||||
|
||||
getlogin: procedure address;
|
||||
/* get the login vector */
|
||||
return mon3(24,0);
|
||||
end getlogin;
|
||||
|
||||
writeprot: procedure;
|
||||
/* write protect the current disk */
|
||||
call mon1(28,0);
|
||||
end writeprot;
|
||||
|
||||
getrodisk: procedure address;
|
||||
/* get the read-only disk vector */
|
||||
return mon3(29,0);
|
||||
end getrodisk;
|
||||
|
||||
setind: procedure;
|
||||
/* set file indicators for current fcb */
|
||||
call mon1(30,fcba);
|
||||
end setind;
|
||||
|
||||
set$dpb: procedure;
|
||||
/* set disk parameter block values */
|
||||
dpba = mon3(31,0); /* base of dpb */
|
||||
end set$dpb;
|
||||
|
||||
getuser: procedure byte;
|
||||
/* return current user number */
|
||||
return mon2(32,0ffh);
|
||||
end getuser;
|
||||
|
||||
setuser: procedure(user);
|
||||
declare user byte;
|
||||
call mon1(32,user);
|
||||
end setuser;
|
||||
|
||||
getfilesize: procedure(fcb);
|
||||
declare fcb address;
|
||||
call mon1(35,fcb);
|
||||
end getfilesize;
|
||||
|
||||
declare oldsp address, /* sp on entry */
|
||||
stack(16) address; /* this program's stack */
|
||||
|
||||
declare
|
||||
fcbmax literally '512', /* max fcb count */
|
||||
fcbs literally 'memory',/* remainder of memory */
|
||||
fcb(33) byte at (fcba), /* default file control block */
|
||||
buff(128) byte at (buffa); /* default buffer */
|
||||
|
||||
declare bpb address; /* bytes per block */
|
||||
|
||||
set$bpb: procedure;
|
||||
call set$dpb; /* disk parameters set */
|
||||
bpb = shl(double(1),blkshf) * sectorlen;
|
||||
end set$bpb;
|
||||
|
||||
select$disk: procedure(d);
|
||||
declare d byte;
|
||||
/* select disk and set bpb */
|
||||
call select(d);
|
||||
call set$bpb; /* bytes per block */
|
||||
end select$disk;
|
||||
|
||||
getalloc: procedure(i) byte;
|
||||
/* return the ith bit of the alloc vector */
|
||||
declare i address;
|
||||
return
|
||||
rol(alloc(shr(i,3)), (i and 111b) + 1);
|
||||
end getalloc;
|
||||
|
||||
declare
|
||||
accum(4) byte, /* accumulator */
|
||||
ibp byte; /* input buffer pointer */
|
||||
|
||||
compare: procedure(a) byte;
|
||||
/* compare accumulator with four bytes addressed by a */
|
||||
declare a address;
|
||||
declare (s based a) (4) byte;
|
||||
declare i byte;
|
||||
do i = 0 to 3;
|
||||
if s(i) <> accum(i) then return false;
|
||||
end;
|
||||
return true;
|
||||
end compare;
|
||||
|
||||
scan: procedure;
|
||||
/* fill accum with next input value */
|
||||
declare (i,b) byte;
|
||||
setacc: procedure(b);
|
||||
declare b byte;
|
||||
accum(i) = b; i = i + 1;
|
||||
end setacc;
|
||||
/* deblank input */
|
||||
do while buff(ibp) = ' '; ibp=ibp+1;
|
||||
end;
|
||||
/* initialize accum length */
|
||||
i = 0;
|
||||
do while i < 4;
|
||||
if (b := buff(ibp)) > 1 then /* valid */
|
||||
call setacc(b); else /* blank fill */
|
||||
call setacc(' ');
|
||||
if b <= 1 or b = ',' or b = ':' or
|
||||
b = '*' or b = '.' or b = '>' or
|
||||
b = '<' or b = '=' then buff(ibp) = 1;
|
||||
else
|
||||
ibp = ibp + 1;
|
||||
end;
|
||||
ibp = ibp + 1;
|
||||
end scan;
|
||||
|
||||
pdecimal: procedure(v,prec);
|
||||
/* print value v with precision prec (10,100,1000)
|
||||
with leading zero suppression */
|
||||
declare
|
||||
v address, /* value to print */
|
||||
prec address, /* precision */
|
||||
zerosup byte, /* zero suppression flag */
|
||||
d byte; /* current decimal digit */
|
||||
zerosup = true;
|
||||
do while prec <> 0;
|
||||
d = v / prec ; /* get next digit */
|
||||
v = v mod prec;/* get remainder back to v */
|
||||
prec = prec / 10; /* ready for next digit */
|
||||
if prec <> 0 and zerosup and d = 0 then call printb; else
|
||||
do; zerosup = false; call printchar('0'+d);
|
||||
end;
|
||||
end;
|
||||
end pdecimal;
|
||||
|
||||
add$block: procedure(ak,ab);
|
||||
declare (ak, ab) address;
|
||||
/* add one block to the kilobyte accumulator */
|
||||
declare kaccum based ak address; /* kilobyte accum */
|
||||
declare baccum based ab address; /* byte accum */
|
||||
baccum = baccum + bpb;
|
||||
do while baccum >= 1024;
|
||||
baccum = baccum - 1024;
|
||||
kaccum = kaccum + 1;
|
||||
end;
|
||||
end add$block;
|
||||
|
||||
count: procedure(mode) address;
|
||||
declare mode byte; /* true if counting 0's */
|
||||
/* count kb remaining, kaccum set upon exit */
|
||||
declare
|
||||
ka address, /* kb accumulator */
|
||||
ba address, /* byte accumulator */
|
||||
i address, /* local index */
|
||||
bit byte; /* always 1 if mode = false */
|
||||
ka, ba = 0;
|
||||
bit = 0;
|
||||
do i = 0 to maxall;
|
||||
if mode then bit = getalloc(i);
|
||||
if not bit then call add$block(.ka,.ba);
|
||||
end;
|
||||
return ka;
|
||||
end count;
|
||||
|
||||
abortmsg: procedure;
|
||||
call print(.('** Aborted **',0));
|
||||
end abortmsg;
|
||||
|
||||
userstatus: procedure;
|
||||
/* display active user numbers */
|
||||
declare i byte;
|
||||
declare user(32) byte;
|
||||
declare ufcb(*) byte data ('????????????',0,0,0);
|
||||
call print(.('Active User :',0));
|
||||
call pdecimal(getuser,10);
|
||||
call print(.('Active Files:',0));
|
||||
do i = 0 to last(user);
|
||||
user(i) = false;
|
||||
end;
|
||||
call setdma(.fcbs);
|
||||
call search(.ufcb);
|
||||
do while dcnt <> 255;
|
||||
if (i := fcbs(shl(dcnt and 11b,5))) <> 0e5h then
|
||||
user(i and 1fh) = true;
|
||||
call searchn;
|
||||
end;
|
||||
do i = 0 to last(user);
|
||||
if user(i) then call pdecimal(i,10);
|
||||
end;
|
||||
end userstatus;
|
||||
|
||||
drivestatus: procedure;
|
||||
declare
|
||||
rpb address,
|
||||
rpd address;
|
||||
pv: procedure(v);
|
||||
declare v address;
|
||||
call crlf;
|
||||
call pdecimal(v,10000);
|
||||
call printchar(':');
|
||||
call printb;
|
||||
end pv;
|
||||
/* print the characteristics of the currently selected drive */
|
||||
call print(.(' ',0));
|
||||
call printchar(cselect+'A');
|
||||
call printchar(':');
|
||||
call printx(.(' Drive Characteristics',0));
|
||||
rpb = shl(double(1),blkshf); /* records/block=2**blkshf */
|
||||
if (rpd := (maxall+1) * rpb) = 0 and (rpb <> 0) then
|
||||
call print(.('65536: ',0)); else
|
||||
call pv(rpd);
|
||||
call printx(.('128 Byte Record Capacity',0));
|
||||
call pv(count(false));
|
||||
call printx(.('Kilobyte Drive Capacity',0));
|
||||
call pv(dirmax+1);
|
||||
call printx(.('32 Byte Directory Entries',0));
|
||||
call pv(shl(chksiz,2));
|
||||
call printx(.('Checked Directory Entries',0));
|
||||
call pv((extmsk+1) * 128);
|
||||
call printx(.('Records/ Extent',0));
|
||||
call pv(rpb);
|
||||
call printx(.('Records/ Block',0));
|
||||
call pv(scptrk);
|
||||
call printx(.('Sectors/ Track',0));
|
||||
call pv(offset);
|
||||
call printx(.('Reserved Tracks',0));
|
||||
call crlf;
|
||||
end drivestatus;
|
||||
|
||||
diskstatus: procedure;
|
||||
/* display disk status */
|
||||
declare login address, d byte;
|
||||
login = getlogin; /* login vector set */
|
||||
d = 0;
|
||||
do while login <> 0;
|
||||
if low(login) then
|
||||
do; call select$disk(d);
|
||||
call drivestatus;
|
||||
end;
|
||||
login = shr(login,1);
|
||||
d = d + 1;
|
||||
end;
|
||||
end diskstatus;
|
||||
|
||||
match: procedure(va,vl) byte;
|
||||
/* return index+1 to vector at va if match */
|
||||
declare va address,
|
||||
v based va (16) byte,
|
||||
vl byte;
|
||||
declare (i,j,match,sync) byte;
|
||||
j,sync = 0;
|
||||
do sync = 1 to vl;
|
||||
match = true;
|
||||
do i = 0 to 3;
|
||||
if v(j) <> accum(i) then match=false;
|
||||
j = j + 1;
|
||||
end;
|
||||
if match then return sync;
|
||||
end;
|
||||
return 0; /* no match */
|
||||
end match;
|
||||
|
||||
declare devl(*) byte data
|
||||
('VAL:USR:DSK:');
|
||||
|
||||
devreq: procedure byte;
|
||||
/* process device request, return true if found */
|
||||
|
||||
declare
|
||||
(i,j,items) byte;
|
||||
|
||||
|
||||
items = 0;
|
||||
do forever;
|
||||
call scan;
|
||||
if (i:=match(.devl,8)) = 0 then return items<>0;
|
||||
items = items+1; /* found first/next item */
|
||||
if i = 1 then /* list possible assignment */
|
||||
do;
|
||||
call print(.('Temp R/O Disk: d:=R/O',0));
|
||||
call print(.('Set Indicator: d:filename.typ ',
|
||||
'$R/O $R/W $SYS $DIR',0));
|
||||
call print(.('Disk Status : DSK: d:DSK:',0));
|
||||
call print(.('User Status : USR:',0));
|
||||
end; else
|
||||
if i = 2 then /* list user status values */
|
||||
call userstatus;
|
||||
else
|
||||
if i = 3 then /* show the disk device status */
|
||||
call diskstatus;
|
||||
/* end of current item, look for more */
|
||||
call scan;
|
||||
if accum(0) = ' ' then return true;
|
||||
if accum(0) <> ',' then
|
||||
do; call print(.('Bad Delimiter',0));
|
||||
return true;
|
||||
end;
|
||||
end; /* of do forever */
|
||||
end devreq;
|
||||
|
||||
pvalue: procedure(v);
|
||||
declare (d,zero) byte,
|
||||
(k,v) address;
|
||||
k = 10000;
|
||||
zero = false;
|
||||
do while k <> 0;
|
||||
d = low(v/k); v = v mod k;
|
||||
k = k / 10;
|
||||
if zero or k = 0 or d <> 0 then
|
||||
do; zero = true; call printchar('0'+d);
|
||||
end;
|
||||
end;
|
||||
call printchar('k');
|
||||
call crlf;
|
||||
end pvalue;
|
||||
|
||||
comp$alloc: procedure;
|
||||
alloca = getalloca;
|
||||
call printchar(cselect+'A');
|
||||
call printx(.(': ',0));
|
||||
end comp$alloc;
|
||||
|
||||
prcount: procedure;
|
||||
/* print the actual byte count */
|
||||
call pvalue(count(true));
|
||||
end prcount;
|
||||
|
||||
pralloc: procedure;
|
||||
/* print allocation for current disk */
|
||||
call print (.('Bytes Remaining On ',0));
|
||||
call comp$alloc;
|
||||
call prcount;
|
||||
end pralloc;
|
||||
|
||||
prstatus: procedure;
|
||||
/* print the status of the disk system */
|
||||
declare (login, rodisk) address;
|
||||
declare d byte;
|
||||
login = getlogin; /* login vector set */
|
||||
rodisk = getrodisk; /* read only disk vector set */
|
||||
d = 0;
|
||||
do while login <> 0;
|
||||
if low(login) then
|
||||
do; call select$disk(d);
|
||||
call comp$alloc;
|
||||
call printx(.('R/',0));
|
||||
if low(rodisk) then
|
||||
call printchar('O'); else
|
||||
call printchar('W');
|
||||
call printx(.(', Space: ',0));
|
||||
call prcount;
|
||||
end;
|
||||
login = shr(login,1); rodisk = shr(rodisk,1);
|
||||
d = d + 1;
|
||||
end;
|
||||
call crlf;
|
||||
end prstatus;
|
||||
|
||||
setdisk: procedure;
|
||||
if fcb(0) <> 0 then call select$disk(fcb(0)-1);
|
||||
end setdisk;
|
||||
|
||||
getfile: procedure;
|
||||
/* process file request */
|
||||
|
||||
declare
|
||||
fnam literally '11', fext literally '12',
|
||||
fmod literally '14',
|
||||
frc literally '15', fln literally '15',
|
||||
fdm literally '16', fdl literally '31',
|
||||
ftyp literally '9',
|
||||
rofile literally '9', /* read/only file */
|
||||
infile literally '10'; /* invisible file */
|
||||
declare
|
||||
fcbn address, /* number of fcb's collected so far */
|
||||
finx(fcbmax) address, /* index vector used during sort */
|
||||
fcbe(fcbmax) address, /* extent counts */
|
||||
fcbb(fcbmax) address, /* byte count (mod kb) */
|
||||
fcbk(fcbmax) address, /* kilobyte count */
|
||||
fcbr(fcbmax) address, /* record count */
|
||||
bfcba address, /* index into directory buffer */
|
||||
fcbsa address, /* index into fcbs */
|
||||
bfcb based bfcba (32) byte, /* template over directory */
|
||||
fcbv based fcbsa (16) byte; /* template over fcbs entry */
|
||||
declare
|
||||
i address, /* fcb counter during collection and display */
|
||||
l address, /* used during sort and display */
|
||||
k address, /* " */
|
||||
m address, /* " */
|
||||
kb byte, /* byte counter */
|
||||
lb byte, /* byte counter */
|
||||
mb byte, /* byte counter */
|
||||
(b,f) byte, /* counters */
|
||||
matched byte; /* used during fcbs search */
|
||||
|
||||
multi16: procedure;
|
||||
/* utility to compute fcbs address from i */
|
||||
fcbsa = shl(i,4) + .fcbs;
|
||||
end multi16;
|
||||
|
||||
declare
|
||||
scase byte; /* status case # */
|
||||
|
||||
declare
|
||||
fstatlist(*) byte data('R/O',0,'R/W',0,'SYS',0,'DIR',0);
|
||||
|
||||
setfilestatus: procedure byte;
|
||||
/* eventually, scase set r/o=0,r/w=1,dat=2,sys=3 */
|
||||
declare
|
||||
fstat(*) byte data('R/O R/W SYS DIR ');
|
||||
if doll = ' ' then return false;
|
||||
call move(4,.parm,.accum); /* $???? */
|
||||
if accum(0) = 'S' and accum(1) = ' ' then
|
||||
return not (sizeset := true);
|
||||
/* must be a parameter */
|
||||
if (scase := match(.fstat,4)) = 0 then
|
||||
call print(.('Invalid File Indicator',0));
|
||||
return true;
|
||||
end setfilestatus;
|
||||
|
||||
printfn: procedure;
|
||||
declare (k, lb) byte;
|
||||
/* print file name */
|
||||
do k = 1 to fnam;
|
||||
if (lb := fcbv(k) and 7fh) <> ' ' then
|
||||
do; if k = ftyp then call printchar('.');
|
||||
call printchar(lb);
|
||||
end;
|
||||
end;
|
||||
end printfn;
|
||||
|
||||
call set$bpb; /* in case default disk */
|
||||
call setdisk;
|
||||
sizeset = false;
|
||||
scase = 255;
|
||||
if setfilestatus then
|
||||
do; if scase = 0 then return;
|
||||
scase = scase - 1;
|
||||
end; else
|
||||
if fcb(1) = ' ' then /* no file named */
|
||||
do; call pralloc;
|
||||
return;
|
||||
end;
|
||||
/* read the directory, collect all common file names */
|
||||
fcbn,fcb(0) = 0;
|
||||
fcb(fext),fcb(fmod) = '?'; /* question mark matches all */
|
||||
call search(fcba); /* fill directory buffer */
|
||||
collect: /* label for debug */
|
||||
do while dcnt <> 255;
|
||||
/* another item found, compare it for common entry */
|
||||
bfcba = shl(dcnt and 11b,5)+buffa; /* dcnt mod 4 * 32 */
|
||||
matched = false; i = 0;
|
||||
do while not matched and i < fcbn;
|
||||
/* compare current entry */
|
||||
call multi16;
|
||||
do kb = 1 to fnam;
|
||||
if bfcb(kb) <> fcbv(kb) then kb = fnam; else
|
||||
/* complete match if at end */
|
||||
matched = kb = fnam;
|
||||
end;
|
||||
i = i + 1;
|
||||
end;
|
||||
checkmatched: /* label for debug */
|
||||
if matched then i = i - 1; else
|
||||
do; /* copy to new position in fcbs */
|
||||
fcbn = (i := fcbn) + 1;
|
||||
call multi16;
|
||||
/* fcbsa set to next to fill */
|
||||
if (fcbn > fcbmax) or (fcbsa + 16) >= memsize then
|
||||
do; call print(.('** Too Many Files **',0));
|
||||
i = 0; fcbn = 1;
|
||||
call multi16;
|
||||
end;
|
||||
/* save index to element for later sort */
|
||||
finx(i) = i;
|
||||
do kb = 0 to fnam;
|
||||
fcbv(kb) = bfcb(kb);
|
||||
end;
|
||||
fcbe(i),fcbb(i),fcbk(i),fcbr(i) = 0;
|
||||
end;
|
||||
/* entry is at, or was placed at location i in fcbs */
|
||||
fcbe(i) = fcbe(i) + 1; /* extent incremented */
|
||||
/* record count */
|
||||
fcbr(i) = fcbr(i) + bfcb(frc)
|
||||
+ (bfcb(fext) and extmsk) * 128;
|
||||
/* count kilobytes */
|
||||
countbytes: /* label for debug */
|
||||
lb = 1;
|
||||
if maxall > 255 then lb = 2; /* double precision inx */
|
||||
do kb = fdm to fdl by lb;
|
||||
mb = bfcb(kb);
|
||||
if lb = 2 then /* double precision inx */
|
||||
mb = mb or bfcb(kb+1);
|
||||
if mb <> 0 then /* allocated */
|
||||
call add$block(.fcbk(i),.fcbb(i));
|
||||
end;
|
||||
call searchn; /* to next entry in directory */
|
||||
end; /* of do while dcnt <> 255 */
|
||||
|
||||
display: /* label for debug */
|
||||
/* now display the collected data */
|
||||
if fcbn = 0 then call print(.('File Not Found',0)); else
|
||||
if scase = 255 then /* display collected data */
|
||||
do;
|
||||
/* sort the file names in ascending order */
|
||||
if fcbn > 1 then /* requires at least two to sort */
|
||||
do; l = 1;
|
||||
do while l > 0; /* bubble sort */
|
||||
l = 0;
|
||||
do m = 0 to fcbn - 2;
|
||||
i = finx(m+1); call multi16; bfcba = fcbsa; i = finx(m);
|
||||
call multi16; /* sets fcbsa, basing fcbv */
|
||||
do kb = 1 to fnam; /* compare for less or equal */
|
||||
if (b:=bfcb(kb)) < (f:=fcbv(kb)) then /* switch */
|
||||
do; k = finx(m); finx(m) = finx(m + 1);
|
||||
finx(m + 1) = k; l = l + 1; kb = fnam;
|
||||
end;
|
||||
else if b > f then kb = fnam; /* stop compare */
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
if sizeset then
|
||||
call print(.(' Size ',0)); else
|
||||
call crlf;
|
||||
call printx(.(' Recs Bytes Ext Acc',0));
|
||||
l = 0;
|
||||
do while l < fcbn;
|
||||
i = finx(l); /* i is the index to next in order */
|
||||
call multi16; call crlf;
|
||||
/* print the file length */
|
||||
call move(16,.fcbv(0),fcba);
|
||||
fcb(0) = 0;
|
||||
if sizeset then
|
||||
do; call getfilesize(fcba);
|
||||
if rovf <> 0 then call printx(.('65536',0)); else
|
||||
call pdecimal(rrec,10000);
|
||||
call printb;
|
||||
end;
|
||||
call pdecimal(fcbr(i),10000); /* rrrrr */
|
||||
call printb; /* blank */
|
||||
call pdecimal(fcbk(i),10000); /* bbbbbk */
|
||||
call printchar('k'); call printb;
|
||||
call pdecimal(fcbe(i),1000); /* eeee */
|
||||
call printb;
|
||||
call printchar('R');
|
||||
call printchar('/');
|
||||
if rol(fcbv(rofile),1) then
|
||||
call printchar('O'); else
|
||||
call printchar('W');
|
||||
call printb;
|
||||
call printchar('A'+cselect); call printchar(':');
|
||||
/* print filename.typ */
|
||||
if (mb:=rol(fcbv(infile),1)) then call printchar('(');
|
||||
call printfn;
|
||||
if mb then call printchar(')');
|
||||
l = l + 1;
|
||||
end;
|
||||
call pralloc;
|
||||
end; else
|
||||
setfileatt: /* label for debug */
|
||||
/* set file attributes */
|
||||
do;
|
||||
l = 0;
|
||||
do while l < fcbn;
|
||||
if break then
|
||||
do; call abortmsg; return;
|
||||
end;
|
||||
i = l;
|
||||
call multi16;
|
||||
call crlf;
|
||||
call printfn;
|
||||
do case scase;
|
||||
/* set to r/o */
|
||||
fcbv(rofile) = fcbv(rofile) or 80h;
|
||||
/* set to r/w */
|
||||
fcbv(rofile) = fcbv(rofile) and 7fh;
|
||||
/* set to sys */
|
||||
fcbv(infile) = fcbv(infile) or 80h;
|
||||
/* set to dir */
|
||||
fcbv(infile) = fcbv(infile) and 7fh;
|
||||
end;
|
||||
/* place name into default fcb location */
|
||||
call move(16,fcbsa,fcba);
|
||||
fcb(0) = 0; /* in case matched user# > 0 */
|
||||
call setind; /* indicators set */
|
||||
call printx(.(' set to ',0));
|
||||
call printx(.fstatlist(shl(scase,2)));
|
||||
l = l + 1;
|
||||
end;
|
||||
end;
|
||||
end getfile;
|
||||
|
||||
setdrivestatus: procedure;
|
||||
/* handle possible drive status assignment */
|
||||
call scan; /* remove drive name */
|
||||
call scan; /* check for = */
|
||||
if accum(0) = '=' then
|
||||
do; call scan; /* get assignment */
|
||||
if compare(.('R/O ')) then
|
||||
do; call setdisk; /* a: ... */
|
||||
call writeprot;
|
||||
end; else
|
||||
call print(.('Invalid Disk Assignment',0));
|
||||
end;
|
||||
else /* not a disk assignment */
|
||||
do; call setdisk;
|
||||
if match(.devl,8) = 3 then call drive$status; else
|
||||
call getfile;
|
||||
end;
|
||||
end setdrivestatus;
|
||||
|
||||
/* save stack pointer and reset */
|
||||
oldsp = stackptr;
|
||||
stackptr = .stack(length(stack));
|
||||
/* process request */
|
||||
if version < cpmversion then
|
||||
call print(.('Wrong CP/M Version (Requires 2.0 or greater)',0));
|
||||
else
|
||||
do;
|
||||
/* size display if $S set in command */
|
||||
ibp = 1; /* initialize buffer pointer */
|
||||
if fcb(0) = 0 and fcb(1) = ' ' then /* stat only */
|
||||
call prstatus; else
|
||||
do;
|
||||
if fcb(0) <> 0 then
|
||||
call setdrivestatus; else
|
||||
do;
|
||||
if not devreq then /* must be file name */
|
||||
call getfile;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
/* restore old stack before exit */
|
||||
stackptr = oldsp;
|
||||
end status;
|
||||
end;
|
||||
|
@@ -1,10 +0,0 @@
|
||||
asm xsub0
|
||||
rmac xsub1
|
||||
link xsub1[os]
|
||||
xsub
|
||||
ddt xsub1.spr
|
||||
ixsub0.hex
|
||||
r
|
||||
g0
|
||||
save 4 xsubnew.com
|
||||
|
@@ -1,135 +0,0 @@
|
||||
; xsub relocator version 2.2
|
||||
version equ 20h
|
||||
; xsub relocator program, included with the module
|
||||
; to perform the move from 200h to the destination address
|
||||
;
|
||||
; copyright (c) 1979, 1980
|
||||
; digital research
|
||||
; box 579
|
||||
; pacific grove, ca.
|
||||
; 93950
|
||||
;
|
||||
org 100h
|
||||
db (lxi or (b shl 3)) ;lxi b,module size
|
||||
org $+2 ;skip address field
|
||||
jmp start
|
||||
db ' Extended Submit Vers '
|
||||
db version/16+'0','.',version mod 16+'0'
|
||||
nogo: db 'Xsub Already Present$'
|
||||
badver: db 'Requires CP/M Version 2.0 or later$'
|
||||
;
|
||||
bdos equ 0005h ;bdos entry point
|
||||
print equ 9 ;bdos print function
|
||||
vers equ 12 ;get version number
|
||||
ccplen equ 0800h ;size of ccp
|
||||
module equ 200h ;module address
|
||||
;
|
||||
start:
|
||||
; ccp's stack used throughout
|
||||
push b ;save the module's length
|
||||
lda bdos+1 ;xsub already present?
|
||||
cpi 06h ;low address must be 06h
|
||||
jnz loaderr
|
||||
lhld bdos+1
|
||||
inx h
|
||||
inx h
|
||||
inx h
|
||||
lxi d,xsubcon
|
||||
mvi c,4
|
||||
present:
|
||||
ldax d
|
||||
cmp m
|
||||
jnz continue
|
||||
inx h
|
||||
inx d
|
||||
dcr c
|
||||
jz loaderr
|
||||
jmp present
|
||||
;
|
||||
loaderr:
|
||||
; bdos or xsub not lowest module in memory, return to ccp
|
||||
mvi c,print
|
||||
lxi d,nogo ;already present message
|
||||
call bdos ;to print the message
|
||||
pop b ;recall length
|
||||
ret ;to the ccp
|
||||
;
|
||||
continue:
|
||||
mvi c,vers
|
||||
call bdos ;version number?
|
||||
cpi version ;2.0 or greater
|
||||
jnc versok
|
||||
;
|
||||
; wrong version
|
||||
mvi c,print
|
||||
lxi d,badver
|
||||
call bdos
|
||||
pop b
|
||||
ret ;to ccp
|
||||
;
|
||||
versok:
|
||||
lxi h,bdos+2;address field of jump to bdos (top memory)
|
||||
mov a,m ;a has high order address of memory top
|
||||
dcr a ;page directly below bdos
|
||||
sui (ccplen shr 8) ;-ccp pages
|
||||
pop b ;recall length of module
|
||||
push b ;and save it again
|
||||
sub b ;a has high order address of reloc area
|
||||
mov d,a
|
||||
mvi e,0 ;d,e addresses base of reloc area
|
||||
push d ;save for relocation below
|
||||
;
|
||||
lxi h,module;ready for the move
|
||||
move: mov a,b ;bc=0?
|
||||
ora c
|
||||
jz reloc
|
||||
dcx b ;count module size down to zero
|
||||
mov a,m ;get next absolute location
|
||||
stax d ;place it into the reloc area
|
||||
inx d
|
||||
inx h
|
||||
jmp move
|
||||
;
|
||||
reloc: ;storage moved, ready for relocation
|
||||
; hl addresses beginning of the bit map for relocation
|
||||
pop d ;recall base of relocation area
|
||||
pop b ;recall module length
|
||||
push h ;save bit map base in stack
|
||||
mov h,d ;relocation bias is in d
|
||||
;
|
||||
rel0: mov a,b ;bc=0?
|
||||
ora c
|
||||
jz endrel
|
||||
;
|
||||
; not end of the relocation, may be into next byte of bit map
|
||||
dcx b ;count length down
|
||||
mov a,e
|
||||
ani 111b ;0 causes fetch of next byte
|
||||
jnz rel1
|
||||
; fetch bit map from stacked address
|
||||
xthl
|
||||
mov a,m ;next 8 bits of map
|
||||
inx h
|
||||
xthl ;base address goes back to stack
|
||||
mov l,a ;l holds the map as we process 8 locations
|
||||
rel1: mov a,l
|
||||
ral ;cy set to 1 if relocation necessary
|
||||
mov l,a ;back to l for next time around
|
||||
jnc rel2 ;skip relocation if cy=0
|
||||
;
|
||||
; current address requires relocation
|
||||
ldax d
|
||||
add h ;apply bias in h
|
||||
stax d
|
||||
rel2: inx d ;to next address
|
||||
jmp rel0 ;for another byte to relocate
|
||||
;
|
||||
endrel: ;end of relocation
|
||||
pop d ;clear stacked address
|
||||
; h has the high order 8-bits of relocated module address
|
||||
mvi l,0
|
||||
pchl ;go to relocated program
|
||||
xsubcon:
|
||||
db 'xsub'
|
||||
end
|
||||
|
@@ -1,232 +0,0 @@
|
||||
; xsub 'Extended Submit Facility' version 2.2
|
||||
;
|
||||
;
|
||||
;
|
||||
; xsub loads below ccp, and feeds command lines to
|
||||
; programs which read buffered input
|
||||
;
|
||||
bias equ 0000h ;bias for relocation
|
||||
base equ 0ffffh ;no intercepts below here
|
||||
wboot equ 0000h
|
||||
bdos equ 0005h
|
||||
bdosl equ bdos+1
|
||||
dbuff equ 0080h
|
||||
;
|
||||
cr equ 0dh ;carriage return
|
||||
lf equ 0ah ;line feed
|
||||
modnum equ 14 ;module number position
|
||||
pbuff equ 9 ;print buffer
|
||||
rbuff equ 10 ;read buffer
|
||||
openf equ 15 ;open file
|
||||
closef equ 16 ;close file
|
||||
delf equ 19 ;delete file
|
||||
dreadf equ 20 ;disk read
|
||||
dmaf equ 26 ;set dma function
|
||||
;
|
||||
;
|
||||
org 0000h+bias
|
||||
; initialize jmps to include xsub module
|
||||
jmp start
|
||||
ds 3
|
||||
trapjmp:
|
||||
jmp trap
|
||||
db 'xsub'
|
||||
start:
|
||||
lhld wboot+1
|
||||
shld savboot
|
||||
lxi h,wstart
|
||||
shld wboot+1
|
||||
lhld bdosl
|
||||
shld rbdos+1 ;real bdos entry
|
||||
lxi h,trapjmp ;address to fill
|
||||
shld bdosl ;jmp @0005 leads to trap
|
||||
pop h ;ccp return address
|
||||
shld ccpret
|
||||
pchl ;back to ccp
|
||||
;
|
||||
savboot:
|
||||
ds 2 ;warm boot saved and restored at end
|
||||
;of submit file
|
||||
;
|
||||
wstart:
|
||||
lxi sp,stack
|
||||
mvi c,pbuff ;print message
|
||||
CALL GET$SUBADDR
|
||||
lxi d,actmsg
|
||||
<EFBFBD> CNZ rbdos
|
||||
lxi h,dbuff ;restore default buffer
|
||||
shld udma
|
||||
call rsetdma
|
||||
lxi h,trapjmp
|
||||
shld bdosl ;fixup low jump address
|
||||
lhld ccpret ;back to ccp
|
||||
pchl
|
||||
|
||||
actmsg: db cr,lf,'(xsub active)$'
|
||||
;
|
||||
trap: ;arrive here at each bdos call
|
||||
pop h ;return address
|
||||
push h ;back to stack
|
||||
mov a,h ;high address
|
||||
cpi base shr 8
|
||||
jnc rbdos ;skip calls on bdos above here
|
||||
mov a,c ;function number
|
||||
cpi rbuff
|
||||
jz rnbuff ;read next buffer
|
||||
cpi dmaf ;set dma address?
|
||||
jnz rbdos ;skip if not
|
||||
xchg ;dma to hl
|
||||
shld udma ;save it
|
||||
xchg
|
||||
rbdos: jmp 0000h ;filled in at initialization
|
||||
;
|
||||
setdma:
|
||||
lxi d,combuf
|
||||
SETDMA1:
|
||||
mvi c,dmaf
|
||||
JMP RBDOS
|
||||
;
|
||||
rsetdma:
|
||||
lhld udma
|
||||
xchg
|
||||
JMP SETDMA1
|
||||
;
|
||||
GET$SUBADDR:
|
||||
LHLD RBDOS+1
|
||||
MVI L,09H
|
||||
MOV E,M
|
||||
INX H
|
||||
MOV D,M
|
||||
XCHG
|
||||
MOV A,M
|
||||
ORA A
|
||||
RET
|
||||
;
|
||||
DELETE$SUB:
|
||||
CALL GET$SUBADDR
|
||||
MVI M,0
|
||||
MVI C,DELF
|
||||
LXI D,SUBFCB
|
||||
;
|
||||
<EFBFBD>fbdos:
|
||||
push b
|
||||
push d
|
||||
call setdma
|
||||
pop d
|
||||
pop b
|
||||
call rbdos
|
||||
push psw
|
||||
call rsetdma
|
||||
pop psw
|
||||
ret
|
||||
;
|
||||
cksub: ;check for sub file present
|
||||
CALL GET$SUBADDR
|
||||
RZ
|
||||
INX H
|
||||
LXI D,SUBS1
|
||||
MVI C,20
|
||||
;
|
||||
MOVE:
|
||||
INR C
|
||||
MOVE1:
|
||||
ORA C
|
||||
DCR C
|
||||
RZ
|
||||
MOV A,M
|
||||
STAX D
|
||||
INX H
|
||||
INX D
|
||||
JMP MOVE1
|
||||
;
|
||||
rnbuff:
|
||||
push d ;command address
|
||||
call cksub ;sub file present?
|
||||
pop d
|
||||
mvi c,rbuff
|
||||
ORA A
|
||||
jz restor ;no sub file
|
||||
;
|
||||
push d
|
||||
lda subrc ;length of file
|
||||
ora a ;zero?
|
||||
jz rbdos ;skip if so
|
||||
dcr a ;length - 1
|
||||
sta subcr ;next to read
|
||||
mvi c,dreadf
|
||||
lxi d,subfcb
|
||||
call fbdos ;read record
|
||||
ORA A
|
||||
JZ READOK
|
||||
|
||||
CALL DELETE$SUB
|
||||
MVI C,0
|
||||
restor:
|
||||
lhld savboot
|
||||
<EFBFBD> shld wboot+1
|
||||
jmp rbdos
|
||||
|
||||
READOK:
|
||||
; now print the buffer with cr,lf
|
||||
|
||||
lxi h,combuf
|
||||
mov e,m ;length
|
||||
mvi d,0 ;high order 00
|
||||
dad d ;to last character position
|
||||
inx h
|
||||
mvi m,cr
|
||||
inx h
|
||||
mvi m,lf
|
||||
inx h
|
||||
mvi m,'$'
|
||||
mvi c,pbuff
|
||||
lxi d,combuf+1
|
||||
LDAX D
|
||||
CPI 3
|
||||
CNZ rbdos ;to print it
|
||||
pop h ;.max length
|
||||
lxi d,combuf
|
||||
ldax d ;how long?
|
||||
cmp m ;cy if ok
|
||||
jc movlin
|
||||
mov a,m ;max length
|
||||
stax d ;truncate length
|
||||
movlin:
|
||||
mov c,a ;length to c
|
||||
inr c ;+1
|
||||
inx h ;to length of line
|
||||
XCHG
|
||||
CALL MOVE
|
||||
CALL GET$SUBADDR
|
||||
|
||||
PUSH H ;.SUBFLAG
|
||||
INX H ;.FCB(S1)
|
||||
INX H ;.FCB(S2)
|
||||
INX H ;.FCB(RC)
|
||||
DCR M
|
||||
POP H
|
||||
CZ DELETE$SUB
|
||||
LDA COMBUF+1 ;^C?
|
||||
CPI 3
|
||||
RNZ
|
||||
MVI C,PBUFF
|
||||
LXI D,CTLCMSG
|
||||
CALL RBDOS
|
||||
JMP WBOOT
|
||||
;
|
||||
subfcb:
|
||||
db 1 ;a:
|
||||
db '$$$ '
|
||||
db 'SUB'
|
||||
<EFBFBD> db 0
|
||||
SUBS1:
|
||||
DB 0,0
|
||||
subrc:
|
||||
ds 1
|
||||
ds 16 ;map
|
||||
subcr: ds 1
|
||||
;
|
||||
CTLCMSG:DB '^C$'
|
||||
combuf: ds 131
|
||||
udma: dw dbuff
|
||||
ccpret: ds 2 ;ccp return address
|
@@ -1,4 +0,0 @@
|
||||
mount a transfer
|
||||
mount b disk
|
||||
mount c COBOL
|
||||
go
|
@@ -1,23 +0,0 @@
|
||||
; Program "Call" called by "Testcall"; this is assembler version;
|
||||
; compare with functionally equivalent COBOL version.
|
||||
|
||||
cseg
|
||||
|
||||
ldax b ; read first param: A = text length
|
||||
loop:
|
||||
dcr a ; count down length
|
||||
rm ; finished
|
||||
push psw
|
||||
ldax d ; next byte from second param = text
|
||||
inx d
|
||||
push d
|
||||
mov e,a
|
||||
mvi c,6 ; CP/M function code
|
||||
call 5 ; call CP/M to send character
|
||||
pop d
|
||||
pop psw
|
||||
jmp loop
|
||||
|
||||
; End of demonstration program "Call"
|
||||
|
||||
end
|
@@ -1,26 +0,0 @@
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000* Program "Call" called by "Testcall"; this is COBOL version;
|
||||
000000* compare with functionally equivalent assembler version.
|
||||
000000*
|
||||
000000******************************************************************
|
||||
000000 Working-storage section.
|
||||
000000 01 temp pic 9(2) comp.
|
||||
000000 01 text-buffer value space.
|
||||
000000 02 tbuf-table pic x occurs 80.
|
||||
000000 Linkage section.
|
||||
000000 01 mess-text.
|
||||
000000 02 mtex-table pic x occurs 80.
|
||||
000000 01 mess-size pic 9(2) comp.
|
||||
000000 Procedure division using mess-size,mess-text.
|
||||
000000 l.
|
||||
000000 move 0 to temp perform move-byte until temp = mess-size.
|
||||
000000 display text-buffer.
|
||||
000000 exit program.
|
||||
000000 move-byte.
|
||||
000000 add 1 to temp move mtex-table (temp) to tbuf-table (temp).
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000* End of demonstration program "Call"
|
||||
000000*
|
||||
000000******************************************************************
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,240 +0,0 @@
|
||||
000000 IDENTIFICATION DIVISION.
|
||||
000000******************************************************************
|
||||
000000* *
|
||||
000000* COPYRIGHT (C) 1982,1982 MICRO FOCUS LTD. *
|
||||
000000* *
|
||||
000000* MICRO FOCUS LTD. *
|
||||
000000* 58, ACACIA ROAD, *
|
||||
000000* ST. JOHNS WOOD, *
|
||||
000000* LONDON NW8 6AG. *
|
||||
000000* *
|
||||
000000* TEL. 01 722 8843/4/5/6/7 *
|
||||
000000* TELEX 28536 MICROF G *
|
||||
000000* *
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000 PROGRAM-ID. COMMAND LINE INTERPRETOR.
|
||||
000000 AUTHOR. MICRO FOCUS LTD.
|
||||
000000 INSTALLATION. MICRO FOCUS - SWINDON.
|
||||
000000 DATE-WRITTEN. 6TH DECEMBER 1982.
|
||||
000000 DATE-COMPILED. 6TH DECEMBER 1982.
|
||||
000000*
|
||||
000000 ENVIRONMENT DIVISION.
|
||||
000000 SOURCE-COMPUTER. 8080.
|
||||
000000 OBJECT-COMPUTER. 8080.
|
||||
000000 SPECIAL-NAMES. CONSOLE IS CRT.
|
||||
000000/*****************************************************************
|
||||
000000* *
|
||||
000000* DATA USED BY THE CLI TO STORE THE USER'S INSTRUCTIONS. *
|
||||
000000* *
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000 DATA DIVISION.
|
||||
000000 WORKING-STORAGE SECTION.
|
||||
000000*
|
||||
000000 01 TEMP PIC 9(2) COMP.
|
||||
000000 01 SUB1 PIC 9(2) COMP.
|
||||
000000 01 SUB2 PIC 9(2) COMP.
|
||||
000000 01 SUB2-SAV PIC 9(2) COMP.
|
||||
000000 01 TMAX PIC 9(2) COMP.
|
||||
000000 01 CHOICE PIC X.
|
||||
000000*
|
||||
000000 01 RTS-ROUTINES.
|
||||
000000 02 POKE-CLI PIC X VALUE X"91".
|
||||
000000 02 CHAIN PIC X VALUE X"84".
|
||||
000000 02 GET-CHAR PIC X VALUE X"D8".
|
||||
000000 02 SOUND-ALARM PIC X VALUE X"E5".
|
||||
000000*
|
||||
000000* DISPLAY LINES
|
||||
000000*
|
||||
000000 01 INIT-LINE.
|
||||
000000 02 INIT-LINE-1 PIC X(68) VALUE "COBOL: A(nimate) C(ompile) D(
|
||||
000000- "rive) F(orms2) Q(uit) R(un) S(witches)".
|
||||
000000 02 FILLER PIC X(4).
|
||||
000000 02 INIT-CHOICE PIC X.
|
||||
000000*
|
||||
000000 01 FILE-QUESTION-LINE.
|
||||
000000 02 FQL-1 PIC X(22) VALUE "Enter name of file to ".
|
||||
000000 02 VERB PIC X(8).
|
||||
000000*
|
||||
000000* COMMAND-LINE COMPONENTS
|
||||
000000*
|
||||
000000 01 SWITCH-AREA.
|
||||
000000 02 FILLER PIC X VALUE "(".
|
||||
000000 02 SWITCHES PIC X(40) VALUE SPACE.
|
||||
000000*
|
||||
000000 01 FILE-NAME PIC X(16).
|
||||
000000*
|
||||
000000 01 CLI-REST PIC X(80).
|
||||
000000*
|
||||
000000 01 WORK-AREA.
|
||||
000000 02 WORK-BYTE PIC 9(2) OCCURS 80 COMP.
|
||||
000000*
|
||||
000000 01 OUTPUT-CLI VALUE SPACE.
|
||||
000000 02 OUT-BYTE PIC 9(2) OCCURS 128 COMP.
|
||||
000000*
|
||||
000000 01 PROG-AREA.
|
||||
000000 02 DRIVE PIC X VALUE SPACE.
|
||||
000000 02 FILLER PIC X VALUE ":".
|
||||
000000 02 PROG-NAME PIC X(16).
|
||||
000000*
|
||||
000000/*****************************************************************
|
||||
000000* *
|
||||
000000* MAIN ENTRY TO CLI PROGRAM. IS USED BY ORDINARY ENTRY TO *
|
||||
000000* COMMAND LINE INTERPRETOR, AS WELL AS BY PROGRAMS WHICH ARE *
|
||||
000000* RETURNING CONTROL TO THE CLI FOR CONTINUATION COMMANDS. *
|
||||
000000* *
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000 PROCEDURE DIVISION.
|
||||
000000 MAIN-ENTRY.
|
||||
000000*
|
||||
000000* TEST IF SCREEN SHOULD BE CLEARED. IF "X" ON COMMAND LINE, THEN
|
||||
000000* THIS IS A SECOND OR SUBSEQUENT ENTRY, AND THE SCREEN SHOULD
|
||||
000000* NOT BE CLEARED.
|
||||
000000*
|
||||
000000 ACCEPT WORK-AREA FROM CONSOLE.
|
||||
000000 IF WORK-AREA NOT = "X"
|
||||
000000 DISPLAY SPACE.
|
||||
000000 CALL SOUND-ALARM.
|
||||
000000*
|
||||
000000 LOOP.
|
||||
000000 MOVE SPACE TO INIT-CHOICE.
|
||||
000000 DISPLAY INIT-LINE.
|
||||
000000 DISPLAY LOW-VALUE AT 0170.
|
||||
000000 CALL GET-CHAR USING CHOICE.
|
||||
000000 DISPLAY SPACE.
|
||||
000000 MOVE CHOICE TO INIT-CHOICE.
|
||||
000000 DISPLAY INIT-LINE.
|
||||
000000*
|
||||
000000 IF CHOICE = "A" OR "a"
|
||||
000000 MOVE "ANIMATE:" TO VERB
|
||||
000000 MOVE "ANIMATE.COM" TO PROG-NAME
|
||||
000000 GO TO FILE-QUESTION.
|
||||
000000 IF CHOICE = "C" OR "c"
|
||||
000000 MOVE "COMPILE:" TO VERB
|
||||
000000 MOVE "COBOL.COM" TO PROG-NAME
|
||||
000000 GO TO FILE-QUESTION.
|
||||
000000 IF CHOICE = "D" OR "d"
|
||||
000000 GO TO DRIVE-SET.
|
||||
000000 IF CHOICE = "F" OR "f"
|
||||
000000 MOVE "FORMS2.COM" TO PROG-NAME
|
||||
000000 MOVE 0 TO SUB2
|
||||
000000 GO TO LOADER.
|
||||
000000 IF CHOICE = "Q" OR "q"
|
||||
000000 GO TO EXITING.
|
||||
000000 IF CHOICE = "R" OR "r"
|
||||
000000 MOVE "RUN:" TO VERB
|
||||
000000 MOVE "RUN.COM" TO PROG-NAME
|
||||
000000 GO TO FILE-QUESTION.
|
||||
000000 IF CHOICE = "S" OR "s"
|
||||
000000 GO TO SWITCH-SET.
|
||||
000000 CALL SOUND-ALARM.
|
||||
000000 GO TO LOOP.
|
||||
000000*
|
||||
000000/*****************************************************************
|
||||
000000* *
|
||||
000000* CODE TO HANDLE FILENAME OF PROGRAM TO BE COMPILED, ANIMATED *
|
||||
000000* OR EXECUTED. *
|
||||
000000* *
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000 FILE-QUESTION.
|
||||
000000 MOVE SPACE TO FILE-NAME.
|
||||
000000 DISPLAY FILE-QUESTION-LINE AT 0201.
|
||||
000000 ACCEPT FILE-NAME AT 0232.
|
||||
000000 IF FILE-NAME = SPACES
|
||||
000000 GO TO LOOP.
|
||||
000000*
|
||||
000000 PERFORM CLEAR-LINES.
|
||||
000000 MOVE SPACE TO CLI-REST.
|
||||
000000 DISPLAY "Any further command line ?" AT 0201.
|
||||
000000 ACCEPT CLI-REST AT 0301.
|
||||
000000*
|
||||
000000 MOVE 0 TO SUB2.
|
||||
000000 IF "RUN.COM" = PROG-NAME
|
||||
000000 IF SPACE NOT = SWITCHES
|
||||
000000 MOVE SWITCH-AREA TO WORK-AREA
|
||||
000000 MOVE 41 TO TMAX
|
||||
000000 MOVE 0 TO SUB1
|
||||
000000 PERFORM TRANSFER-BUFFER
|
||||
000000 ADD 1 TO SUB2
|
||||
000000 MOVE 41 TO OUT-BYTE (SUB2).
|
||||
000000 MOVE FILE-NAME TO WORK-AREA.
|
||||
000000 MOVE 0 TO SUB1.
|
||||
000000 MOVE 16 TO TMAX.
|
||||
000000 PERFORM TRANSFER-BUFFER.
|
||||
000000 MOVE CLI-REST TO WORK-AREA.
|
||||
000000 MOVE 0 TO SUB1.
|
||||
000000 MOVE 80 TO TMAX.
|
||||
000000 PERFORM TRANSFER-BUFFER.
|
||||
000000 IF SUB2 > 80
|
||||
000000 GO TO CLI-OVF.
|
||||
000000*
|
||||
000000* COMMAND LINE NOW CREATED, CHAIN TO THE NEXT PROGRAM. THIS
|
||||
000000* IS DONE BY SETTING A COMMAND LINE FOR THE RTS TO EXECUTE.
|
||||
000000*
|
||||
000000 LOADER.
|
||||
000000 CALL POKE-CLI USING SUB2, OUTPUT-CLI.
|
||||
000000 PERFORM CLEAR-LINES.
|
||||
000000 DISPLAY "Loading ..." at 0201.
|
||||
000000 DISPLAY LOW-VALUE AT 0301.
|
||||
000000 IF DRIVE = SPACE
|
||||
000000 CALL CHAIN USING PROG-NAME
|
||||
000000 ELSE
|
||||
000000 CALL CHAIN USING PROG-AREA.
|
||||
000000*
|
||||
000000/*****************************************************************
|
||||
000000* *
|
||||
000000* SUPPORT CLI ROUTINES, USED TO MANIPULATE THE FIELDS BEFORE *
|
||||
000000* CONTROL IS TRANSFERRED TO A SUPPORT PROGRAM. *
|
||||
000000* *
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000 SWITCH-SET.
|
||||
000000 MOVE SPACE TO SWITCHES.
|
||||
000000 DISPLAY "Switches:" AT 0201.
|
||||
000000 ACCEPT SWITCHES AT 0211.
|
||||
000000 INSPECT SWITCHES REPLACING
|
||||
000000 ALL "(" BY SPACE
|
||||
000000 ALL ")" BY SPACE.
|
||||
000000 GO TO LOOP.
|
||||
000000*
|
||||
000000 DRIVE-SET.
|
||||
000000 DISPLAY "Enter Drive:" AT 0201.
|
||||
000000 ACCEPT DRIVE AT 0214.
|
||||
000000 GO TO LOOP.
|
||||
000000*
|
||||
000000 EXITING.
|
||||
000000 DISPLAY "Returning to CP/M" AT 0201.
|
||||
000000 DISPLAY LOW-VALUE AT 0301.
|
||||
000000 STOP RUN.
|
||||
000000*
|
||||
000000/*****************************************************************
|
||||
000000* *
|
||||
000000* WORK ROUTINES USED TO MANIPULATE THE SCREEN. *
|
||||
000000* *
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000 CLI-OVF.
|
||||
000000 PERFORM CLEAR-LINES.
|
||||
000000 DISPLAY "Command buffer overflow" AT 0301.
|
||||
000000 GO TO LOOP.
|
||||
000000*
|
||||
000000 CLEAR-LINES.
|
||||
000000 MOVE SPACE TO WORK-AREA.
|
||||
000000 DISPLAY WORK-AREA AT 0201.
|
||||
000000 DISPLAY WORK-AREA AT 0301.
|
||||
000000*
|
||||
000000 TRANSFER-BUFFER.
|
||||
000000 ADD 1 TO SUB1.
|
||||
000000 ADD 1 TO SUB2.
|
||||
000000 MOVE WORK-BYTE (SUB1) TO TEMP.
|
||||
000000 IF TEMP NOT = 32
|
||||
000000 MOVE SUB2 TO SUB2-SAV
|
||||
000000 MOVE TEMP TO OUT-BYTE (SUB2).
|
||||
000000 IF SUB1 < TMAX
|
||||
000000 GO TO TRANSFER-BUFFER.
|
||||
000000 MOVE SUB2-SAV TO SUB2.
|
||||
000000 ADD 1 TO SUB2.
|
||||
000000*
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,160 +0,0 @@
|
||||
Compiler error; consult Technical Support
|
||||
Illegal format : Data-name
|
||||
Illegal format : Literal, or invalid use of ALL
|
||||
Illegal format : Character
|
||||
Data-name not unique
|
||||
Too many data or procedure names declared
|
||||
Illegal character in column 7 or continuation error
|
||||
Nested COPY statement or unknown COPY file specified
|
||||
'.' missing
|
||||
Statement starts in wrong area of source line
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
'.' missing
|
||||
DIVISION missing
|
||||
SECTION missing
|
||||
IDENTIFICATION missing
|
||||
PROGRAM-ID missing
|
||||
AUTHOR missing
|
||||
INSTALLATION missing
|
||||
DATE-WRITTEN missing
|
||||
SECURITY missing
|
||||
ENVIRONMENT missing
|
||||
CONFIGURATION missing
|
||||
SOURCE-COMPUTER missing
|
||||
OBJECT-COMPUTER/SPECIAL-NAMES clause error
|
||||
OBJECT-COMPUTER missing
|
||||
Compiler error; consult Technical Support
|
||||
SPECIAL-NAMES missing
|
||||
SWITCH clause error or system name/mnemonic name error
|
||||
DECIMAL-POINT clause error
|
||||
CONSOLE clause error
|
||||
Illegal currency symbol
|
||||
'.' missing
|
||||
DIVISION missing
|
||||
SECTION missing
|
||||
INPUT-OUTPUT missing
|
||||
FILE-CONTROL missing
|
||||
ASSIGN missing
|
||||
SEQUENTIAL or RELATIVE or INDEXED missing
|
||||
ACCESS missing on indexed/relative file
|
||||
SEQUENTIAL or DYNAMIC missing or > 64 alternate keys
|
||||
Illegal ORGANIZATION/ACCESS/KEY combination
|
||||
Unrecognized phrase in SELECT clause
|
||||
RERUN clause syntax error
|
||||
SAME AREA clause syntax error
|
||||
Missing or illegal file-name
|
||||
DATA DIVISION missing
|
||||
PROCEDURE DIVISION missing or unknown statement
|
||||
Program collating sequence not defined
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
'.' missing
|
||||
DIVISION missing
|
||||
SECTION missing
|
||||
File-name not specified in SELECT stmt or invalid CD name
|
||||
RECORD SIZE integer missing or line sequential rec > 1024 bytes
|
||||
Illegal level no (01-49),01 level reqd,or level hierarachy wrong
|
||||
FD, CD or SD qualification syntax error
|
||||
WORKING-STORAGE missing
|
||||
PROCEDURE DIVISION missing or unknown statement
|
||||
Data description qualifier or '.' missing
|
||||
Incompatible PICTURE clause and qualifiers
|
||||
BLANK illegal with non-numeric data-item
|
||||
PICTURE clause too long
|
||||
VALUE with non-elementary item,wrong data-type or value truncated
|
||||
VALUE in error or illegal for PICTURE type
|
||||
Non-elementary item has FILLER/SYNC/JUST/BLANK clause
|
||||
Preceding item at this level has > 8192 bytes or 0 bytes
|
||||
REDEFINES of unequal fields or different levels
|
||||
Data storage exceeds 64K bytes
|
||||
Compiler error; consult Technical Support
|
||||
Data description qualifier inappropriate or repeated
|
||||
REDEFINES data-name not declared
|
||||
USAGE must be COMP,DISPLAY or INDEX
|
||||
SIGN must be LEADING or TRAILING
|
||||
SYNCHRONIZED must be LEFT or RIGHT
|
||||
JUSTIFIED must be RIGHT
|
||||
BLANK must be ZERO
|
||||
OCCURS must be numeric, non-zero, unsigned or DEPENDING
|
||||
VALUE must be literal, numeric literal or figurative constant
|
||||
PICTURE string has illegal precedence or illegal char
|
||||
INDEXED data-name missing or already declared
|
||||
Numeric-edited PICTURE string is too large
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Unrecognized verb
|
||||
IF....ELSE mismatch
|
||||
Operand has wrong data-type, is not declared or '.' missing
|
||||
Procedure not unique
|
||||
Procedure name same as data-name
|
||||
Name required
|
||||
Wrong combination of data-types
|
||||
Conditional statement not allowed in this context
|
||||
Malformed subscript
|
||||
ACCEPT/DISPLAY wrong or Communications syntax incorrect
|
||||
Illegal syntax used with I-O verb
|
||||
Invalid arithmetic statement
|
||||
Invalid arithmetic expression
|
||||
Compiler error; consult Technical Support
|
||||
Invalid conditional expression
|
||||
IF stmts nested too deep, or too many AFTERs in PERFORM stmt
|
||||
Incorrect structure of PROCEDURE DIVISION
|
||||
Reserved word missing or incorrectly used
|
||||
Too many subscripts in one statement (internal buffer overflow)
|
||||
Too many operands in one statement
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Inter-segment procedure name duplication
|
||||
Unterminated condition at end of source
|
||||
Operand has wrong data-type or not declared
|
||||
Procedure name undeclared
|
||||
INDEX data-name declared twice
|
||||
Bad cursor control : illegal AT clause
|
||||
KEY declaration missing or illegal
|
||||
STATUS declaration missing
|
||||
Bad STATUS record
|
||||
Undefined inter-segment reference or error in ALTERed para
|
||||
PROCEDURE DIVISION in error
|
||||
USING parameter not declared in LINKAGE SECTION
|
||||
USING parameter not level 01 or 77
|
||||
USING parameter used twice in parameter list
|
||||
FD missing
|
||||
Compiler error; consult Technical Support
|
||||
Incorrect structure of PROCEDURE DIVISION
|
||||
Compiler error; consult Technical Support
|
||||
Compiler error; consult Technical Support
|
||||
Too many operands in one statement
|
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.
@@ -1,83 +0,0 @@
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. PI-CALC.
|
||||
AUTHOR. PF/TR.
|
||||
*
|
||||
ENVIRONMENT DIVISION.
|
||||
CONFIGURATION SECTION.
|
||||
OBJECT-COMPUTER. MDS-800.
|
||||
SPECIAL-NAMES. CONSOLE IS CRT.
|
||||
*
|
||||
DATA DIVISION.
|
||||
WORKING-STORAGE SECTION.
|
||||
*
|
||||
01 SCREEN PIC X(1920).
|
||||
*
|
||||
01 DI-1 REDEFINES SCREEN.
|
||||
02 FILLER PIC X(160).
|
||||
02 DI-TX1 PIC X(160).
|
||||
02 DI-TX2 PIC X(13).
|
||||
02 DI-TERM PIC X(15).
|
||||
02 FILLER PIC X(136).
|
||||
02 DI-TX3 PIC X(6).
|
||||
02 DI-PI PIC X(15).
|
||||
02 FILLER PIC X(1415).
|
||||
*
|
||||
01 DI-2 REDEFINES SCREEN.
|
||||
02 FILLER PIC X(333).
|
||||
02 DI-TERM2 PIC X(15).
|
||||
02 FILLER PIC X(142).
|
||||
02 DI-PI2 PIC X(15).
|
||||
02 FILLER PIC X(1415).
|
||||
*
|
||||
01 WORK-AREA.
|
||||
02 PI PIC S9V9(14).
|
||||
02 TERM PIC S9V9(14).
|
||||
02 W PIC S9V9(14).
|
||||
02 N PIC 9999.
|
||||
02 N1 PIC 9999.
|
||||
02 N2 PIC 9999.
|
||||
02 ED PIC -9.9(12).
|
||||
*
|
||||
01 CONSTANTS.
|
||||
02 TX1 PIC X(17) VALUE "CALCULATION OF PI".
|
||||
02 TX2 PIC X(12) VALUE "NEXT TERM IS".
|
||||
02 TX3 PIC X(5) VALUE "PI IS".
|
||||
*
|
||||
PROCEDURE DIVISION.
|
||||
LA-START.
|
||||
DISPLAY SPACE.
|
||||
MOVE SPACE TO SCREEN.
|
||||
MOVE TX1 TO DI-TX1.
|
||||
MOVE TX2 TO DI-TX2.
|
||||
MOVE TX3 TO DI-TX3.
|
||||
MOVE 0.5 TO ED.
|
||||
MOVE ED TO DI-TERM.
|
||||
MOVE 3 TO ED.
|
||||
MOVE ED TO DI-PI.
|
||||
DISPLAY DI-1.
|
||||
MOVE 0.5 TO PI.
|
||||
MOVE 0.5 TO TERM.
|
||||
MOVE 3 TO N.
|
||||
LOOP.
|
||||
MOVE N TO N2.
|
||||
SUBTRACT 2 FROM N2.
|
||||
MULTIPLY N2 BY N2.
|
||||
MULTIPLY N2 BY TERM.
|
||||
MOVE N TO N1.
|
||||
SUBTRACT 1 FROM N1.
|
||||
MULTIPLY N BY N1.
|
||||
MULTIPLY 4 BY N1.
|
||||
DIVIDE N1 INTO TERM.
|
||||
IF TERM < 0.0000000000001 THEN GO TO HALT.
|
||||
ADD TERM TO PI.
|
||||
MOVE PI TO W.
|
||||
MULTIPLY 6 BY W.
|
||||
MOVE W TO ED.
|
||||
MOVE ED TO DI-PI2.
|
||||
MOVE TERM TO ED.
|
||||
MOVE ED TO DI-TERM2.
|
||||
DISPLAY DI-2.
|
||||
ADD 2 TO N.
|
||||
IF N < 100 GO TO LOOP.
|
||||
HALT.
|
||||
STOP RUN.
|
Binary file not shown.
@@ -1,59 +0,0 @@
|
||||
000010 IDENTIFICATION DIVISION.
|
||||
000020 PROGRAM-ID. STOCK-FILE-SET-UP.
|
||||
000030 AUTHOR. MICRO FOCUS LTD.
|
||||
000040 ENVIRONMENT DIVISION.
|
||||
000050 CONFIGURATION SECTION.
|
||||
000060 SOURCE-COMPUTER. MDS-800.
|
||||
000070 OBJECT-COMPUTER. MDS-800.
|
||||
000075 SPECIAL-NAMES. CONSOLE IS CRT.
|
||||
000080 INPUT-OUTPUT SECTION.
|
||||
000090 FILE-CONTROL.
|
||||
000100 SELECT STOCK-FILE ASSIGN "STOCK.IT"
|
||||
000110 ORGANIZATION INDEXED
|
||||
000120 ACCESS DYNAMIC
|
||||
000130 RECORD KEY STOCK-CODE.
|
||||
000140 DATA DIVISION.
|
||||
000150 FILE SECTION.
|
||||
000160 FD STOCK-FILE; RECORD 32.
|
||||
000170 01 STOCK-ITEM.
|
||||
000180 02 STOCK-CODE PIC X(4).
|
||||
000190 02 PRODUCT-DESC PIC X(24).
|
||||
000200 02 UNIT-SIZE PIC 9(4).
|
||||
000210 WORKING-STORAGE SECTION.
|
||||
000220 01 SCREEN-HEADINGS.
|
||||
000230 02 ASK-CODE PIC X(21) VALUE "STOCK CODE < >".
|
||||
000240 02 FILLER PIC X(59).
|
||||
000250 02 ASK-DESC PIC X(16) VALUE "DESCRIPTION <".
|
||||
000260 02 SI-DESC PIC X(25) VALUE " >".
|
||||
000270 02 FILLER PIC X(39).
|
||||
000280 02 ASK-SIZE PIC X(21) VALUE "UNIT SIZE < >".
|
||||
000290 01 ENTER-IT REDEFINES SCREEN-HEADINGS.
|
||||
000300 02 FILLER PIC X(16).
|
||||
000310 02 CRT-STOCK-CODE PIC X(4).
|
||||
000320 02 FILLER PIC X(76).
|
||||
000330 02 CRT-PROD-DESC PIC X(24).
|
||||
000340 02 FILLER PIC X(56).
|
||||
000350 02 CRT-UNIT-SIZE PIC 9(4).
|
||||
000360 02 FILLER PIC X.
|
||||
000370 PROCEDURE DIVISION.
|
||||
000380 SR1.
|
||||
000390 DISPLAY SPACE.
|
||||
000400 OPEN I-O STOCK-FILE.
|
||||
000410 DISPLAY SCREEN-HEADINGS.
|
||||
000420 NORMAL-INPUT.
|
||||
000430 MOVE SPACE TO ENTER-IT.
|
||||
000440 DISPLAY ENTER-IT.
|
||||
000450 CORRECT-ERROR.
|
||||
000460 ACCEPT ENTER-IT.
|
||||
000470 IF CRT-STOCK-CODE = SPACE GO TO END-IT.
|
||||
000480 IF CRT-UNIT-SIZE NOT NUMERIC GO TO CORRECT-ERROR.
|
||||
000490 MOVE CRT-PROD-DESC TO PRODUCT-DESC.
|
||||
000500 MOVE CRT-UNIT-SIZE TO UNIT-SIZE.
|
||||
000510 MOVE CRT-STOCK-CODE TO STOCK-CODE.
|
||||
000520 WRITE STOCK-ITEM; INVALID GO TO CORRECT-ERROR.
|
||||
000530 GO TO NORMAL-INPUT.
|
||||
000540 END-IT.
|
||||
000550 CLOSE STOCK-FILE.
|
||||
000560 DISPLAY SPACE.
|
||||
000570 DISPLAY "END OF PROGRAM".
|
||||
000580 STOP RUN.
|
@@ -1,119 +0,0 @@
|
||||
IDENTIFICATION DIVISION.
|
||||
PROGRAM-ID. GOODS-IN.
|
||||
AUTHOR. MICRO FOCUS LTD.
|
||||
ENVIRONMENT DIVISION.
|
||||
CONFIGURATION SECTION.
|
||||
SOURCE-COMPUTER. MDS-800.
|
||||
OBJECT-COMPUTER. MDS-800.
|
||||
SPECIAL-NAMES. CONSOLE IS CRT.
|
||||
INPUT-OUTPUT SECTION.
|
||||
FILE-CONTROL.
|
||||
SELECT STOCK-FILE ASSIGN "STOCK.IT"
|
||||
ORGANIZATION INDEXED
|
||||
ACCESS DYNAMIC
|
||||
RECORD KEY STOCK-CODE.
|
||||
SELECT TRANS-FILE
|
||||
ASSIGN "STOCK.TRS"
|
||||
ORGANIZATION SEQUENTIAL.
|
||||
/
|
||||
DATA DIVISION.
|
||||
FILE SECTION.
|
||||
FD STOCK-FILE; RECORD 32.
|
||||
01 STOCK-ITEM.
|
||||
02 STOCK-CODE PIC X(4).
|
||||
02 STOCK-DESCRIPT PIC X(24).
|
||||
02 UNIT-SIZE PIC 9(4).
|
||||
FD TRANS-FILE; RECORD 30.
|
||||
01 TRANS-RECORD.
|
||||
02 TRAN-NO PIC 9(4).
|
||||
02 TF-STOCK-CODE PIC X(4).
|
||||
02 TF-QUANTITY PIC 9(8).
|
||||
02 TF-ORDER-NO PIC X(6).
|
||||
02 TF-DATE PIC X(8).
|
||||
WORKING-STORAGE SECTION.
|
||||
01 STOCK-INWARD-FORM.
|
||||
02 PRG-TITLE PIC X(20) VALUE " GOODS INWARD".
|
||||
02 FILLER PIC X(140).
|
||||
02 CODE-HDNG PIC X(23) VALUE "STOCK CODE < >".
|
||||
02 FILLER PIC X(57).
|
||||
02 ORDER-NO-HDNG PIC X(23) VALUE "ORDER NO < >".
|
||||
02 FILLER PIC X(57).
|
||||
02 DATE-HDNG PIC X(24) VALUE "DELIVERY DATE MM/DD/YY".
|
||||
02 FILLER PIC X(56).
|
||||
02 UNITS-HDNG PIC X(23) VALUE "NO OF UNITS < >".
|
||||
01 STOCK-RECEIPT REDEFINES STOCK-INWARD-FORM.
|
||||
02 FILLER PIC X(178).
|
||||
02 SR-STOCK-CODE PIC X(4).
|
||||
02 FILLER PIC X(74).
|
||||
02 SR-ORDER-NO PIC X(6).
|
||||
02 FILLER PIC X(73).
|
||||
02 SR-DATE.
|
||||
04 SR-MM PIC 99.
|
||||
04 FILLER PIC X.
|
||||
04 SR-DD PIC 99.
|
||||
04 FILLER PIC X.
|
||||
04 SR-YY PIC 99.
|
||||
02 FILLER PIC X(75).
|
||||
02 SR-NO-OF-UNITS PIC 9(4).
|
||||
01 CONFIRM-MSG REDEFINES STOCK-INWARD-FORM.
|
||||
02 FILLER PIC X(184).
|
||||
02 CM-STOCK-DESCRIPT PIC X(24).
|
||||
02 FILLER PIC X(352).
|
||||
02 UNIT-SIZE-HDNG PIC X(18).
|
||||
02 CM-UNIT-SIZE PIC 9(4).
|
||||
02 FILLER PIC X(58).
|
||||
02 QUANTITY-HDNG PIC X(14).
|
||||
02 CM-QUANTITY PIC 9(8).
|
||||
02 FILLER PIC X(58).
|
||||
02 OK-HDNG PIC X(3).
|
||||
02 CM-Y-OR-N PIC X.
|
||||
/
|
||||
PROCEDURE DIVISION.
|
||||
START-PROC.
|
||||
OPEN I-O STOCK-FILE.
|
||||
OPEN OUTPUT TRANS-FILE.
|
||||
DISPLAY SPACE.
|
||||
MOVE 0 TO TRAN-NO.
|
||||
DISPLAY STOCK-INWARD-FORM.
|
||||
GET-INPUT.
|
||||
ACCEPT STOCK-RECEIPT.
|
||||
IF SR-STOCK-CODE = SPACE GO TO END-IT.
|
||||
IF SR-NO-OF-UNITS NOT NUMERIC GO TO INVALID-ENTRY.
|
||||
MOVE SR-STOCK-CODE TO STOCK-CODE.
|
||||
READ STOCK-FILE; INVALID GO TO INVALID-CODE.
|
||||
*VALID ENTRY, CALCULATE AND DISPLAY TOTAL QUANTITY IN TO CONFIRM
|
||||
MOVE STOCK-DESCRIPT TO CM-STOCK-DESCRIPT.
|
||||
MOVE "UNIT SIZE" TO UNIT-SIZE-HDNG.
|
||||
MOVE UNIT-SIZE TO CM-UNIT-SIZE.
|
||||
MOVE "QUANTITY IN" TO QUANTITY-HDNG.
|
||||
MOVE UNIT-SIZE TO TF-QUANTITY.
|
||||
MULTIPLY SR-NO-OF-UNITS BY TF-QUANTITY.
|
||||
MOVE TF-QUANTITY TO CM-QUANTITY.
|
||||
MOVE "OK?" TO OK-HDNG.
|
||||
DISPLAY CONFIRM-MSG.
|
||||
ACCEPT CM-Y-OR-N AT 1004.
|
||||
IF CM-Y-OR-N = "Y" PERFORM WRITE-TRANS.
|
||||
*CLEAR INPUT DATA ON SCREEN
|
||||
MOVE SPACE TO CONFIRM-MSG.
|
||||
MOVE "MM/DD/YY" TO SR-DATE.
|
||||
DISPLAY STOCK-RECEIPT.
|
||||
DISPLAY CONFIRM-MSG.
|
||||
GO TO GET-INPUT.
|
||||
WRITE-TRANS.
|
||||
ADD 1 TO TRAN-NO.
|
||||
MOVE STOCK-CODE TO TF-STOCK-CODE.
|
||||
MOVE SR-ORDER-NO TO TF-ORDER-NO.
|
||||
MOVE GET-INPUT TO TF-DATE.
|
||||
WRITE TRANS-RECORD.
|
||||
INVALID-ENTRY.
|
||||
DISPLAY "NON-NUMERIC NO OF UNITS" AT 0325.
|
||||
GO TO GET-INPUT.
|
||||
INVALID-CODE.
|
||||
DISPLAY "INVALID CODE " AT 0325.
|
||||
GO TO GET-INPUT.
|
||||
END-IT.
|
||||
CLOSE STOCK-FILE.
|
||||
CLOSE TRANS-FILE.
|
||||
DISPLAY SPACE.
|
||||
DISPLAY "END OF PROGRAM".
|
||||
STOP RUN.
|
@@ -1,19 +0,0 @@
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000* Program "Testcall" to demonstrate L/II COBOL calling mechanism
|
||||
000000*
|
||||
000000******************************************************************
|
||||
000000 Working-storage section.
|
||||
000000 01 progname pic x(4).
|
||||
000000 01 message-size pic 9(2) comp value 60.
|
||||
000000 01 message-text pic x(60) value
|
||||
000000 "This message is sent via a called program to the screen.".
|
||||
000000 Procedure division.
|
||||
000000 move "call" to progname.
|
||||
000000 call progname using message-size,message-text
|
||||
000000 overflow display "call overflowed".
|
||||
000000******************************************************************
|
||||
000000*
|
||||
000000* End of demonstration program "Testcall"
|
||||
000000*
|
||||
000000******************************************************************
|
Binary file not shown.
BIN
emu/yaze/disk
BIN
emu/yaze/disk
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.
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
yaze -v
|
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
cd /usr/local/src/yaze-1.14/
|
||||
yaze -v
|
@@ -1,6 +0,0 @@
|
||||
#!/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
|
@@ -1,6 +0,0 @@
|
||||
#!/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.
@@ -1,6 +0,0 @@
|
||||
#!/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
|
@@ -1,32 +0,0 @@
|
||||
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
|
@@ -1,161 +0,0 @@
|
||||
#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;
|
||||
}
|
@@ -1,375 +0,0 @@
|
||||
; 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
|
@@ -1,74 +0,0 @@
|
||||
; 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.
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@@ -1,13 +0,0 @@
|
||||
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
|
@@ -1,582 +0,0 @@
|
||||
; 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
|
@@ -1,67 +0,0 @@
|
||||
; 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.
@@ -1,212 +0,0 @@
|
||||
; 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
|
@@ -1,59 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@@ -1,503 +0,0 @@
|
||||
; 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
|
@@ -1,177 +0,0 @@
|
||||
; 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
|
@@ -1,74 +0,0 @@
|
||||
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
|
@@ -1,868 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
# 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
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* 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
|
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@@ -1,6 +0,0 @@
|
||||
# use this to unlink the common parts of Z80 simulation
|
||||
|
||||
rm sim[0-7].c
|
||||
rm simfun.c
|
||||
rm simint.c
|
||||
rm simglb.[hc]
|
@@ -1,22 +0,0 @@
|
||||
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.
|
@@ -1,85 +0,0 @@
|
||||
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
|
@@ -1,54 +0,0 @@
|
||||
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.
@@ -1,41 +0,0 @@
|
||||
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
|
@@ -1,144 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* 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[];
|
@@ -1,503 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
@@ -1,309 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* 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);
|
@@ -1,360 +0,0 @@
|
||||
/*
|
||||
* 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));
|
||||
}
|
@@ -1,446 +0,0 @@
|
||||
/*
|
||||
* 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
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user