$title ('GENDEF - Library Generator for DISKDEF') gd: do; /* l i b r a r y g e n e r a t o r f o r D I S K D E F */ $include(copyrt.lit) /* Generation Procedure on VAX asm86 scd.a86 plm86 gendef.plm debug xref optimize(3) date(10/5/81) pagewidth(100) plm86 gscan.plm debug xref optimize(3) date(10/5/81) pagewidth(100) plm86 emit.plm debug xref optimize(3) date(10/5/81) pagewidth(100) plm86 token.plm debug xref optimize(3) date(10/5/81) pagewidth(100) link86 scd.obj,gendef.obj,gscan.obj,emit.obj,token.obj - to gendef.lnk loc86 gendef.mod od(sm(code,dats,data,stack,const)) - ad(sm(code(0h))) ss(stack(+32)) h86 gendef Then on a micro vax gendef $fans gencmd gendef data[b17c] notes: b17c is derived from module map in the GENDEF.MP2 file generated by LOC86. The 'CONST segment' is located last to force hex generation. Stack is extended to insure against interrupts on MP/M-86. */ $include (:f1:glit.plb) declare true lit '1', false lit '0', forever lit 'while true', cr lit '0dh', tab lit '09h'; /* global procedures */ boot: procedure external; end boot; printchar: procedure(c) external; declare c byte; end printchar; print: procedure(a) external; declare a address; end print; crlf: procedure external; end crlf; abort: procedure(msg) external; declare msg address; end abort; scan: procedure external; end scan; scan$ini: procedure external; end scan$ini; setup: procedure external; /* set up the input file on each pass */ end setup; putline: procedure external; end putline; writerrs: procedure external; end writerrs; errptr: procedure(msg) external; declare msg address; end errptr; /* code emitters */ emitbyte: procedure(b) external; declare b byte; end emitbyte; emitcrlf: procedure external; end emitcrlf; emitoptab: procedure(a) external; declare a address; end emitoptab; emitcomma: procedure external; end emitcomma; emitaddr: procedure(a) external; declare a address; end emitaddr; emitchar: procedure(a) external; declare a address; end emitchar; emitline: procedure external; end emitline; emitcharn: procedure(a,n) external; declare a address, n byte; /* symbol, followed by two digit n */ end emitcharn; emitcomment: procedure(a) external; declare a address; end emitcomment; emitdec8: procedure(b) external; declare b byte; end emitdec8; emitdec16: procedure(w) external; declare w address; end emitdec16; emitdecb: procedure(w) external; declare w address; end emitdecb; emitdw: procedure external; end emitdw; emitdb: procedure external; end emitdb; emitdwn: procedure(n) external; declare n address; end emitdwn; emitdbn: procedure(n) external; declare n byte; end emitdbn; emitdwnc: procedure(n,c) external; declare (n,c) address; end emitdwnc; emitdbnc: procedure(n,c) external; declare n byte, c address; end emitdbnc; efinis: procedure external; end efinis; emittab: procedure external; end emittab; emitnulcom: procedure external; end emitnulcom; /* global variables */ declare parm (26) byte external, comm$tog byte at (.parm(2)), /* disk comment */ off$tog byte at (.parm(14)), /* generate 'offset' */ scan$tog byte at (.parm(18)), /* scanner trace */ z80$tog byte at (.parm(25)); /* z80, 8080, 8085 mode */ declare errset byte external, eofset byte external, cbuff(8) byte external, value address external, nextc byte external, token byte external, continue byte external, acclen byte external, accum(32) byte external; /* code emitters */ setemit: procedure external; end setemit; prnib: procedure(d); declare d byte; /* print nibble d */ if d > 9 then d = 'A' + d - 10; else d = d + '0'; call printchar(d); end prnib; prhex: procedure(h); declare h byte; call prnib(shr(h,4)); call prnib(h and 0fh); end prhex; praddr: procedure(a); declare a address; call prhex(high(a)); call prhex(low(a)); end praddr; prdig: procedure(d); declare d byte; /* print the decimal number given by d */ call printchar('0'+d); end prdig; prdec: procedure(b); declare b byte; /* print the decimal value of b */ call prdig(b/100); call prdig(b/10 mod 10); call prdig(b mod 10); end prdec; /* trace functions */ declare ident lit '1', number lit '2', string lit '3', special lit '4'; trace: procedure(msga); declare msga address, (i,c) byte; if scan$tog then do; call putline; call print(msga); call printchar(','); do i = 1 to acclen; if (c:=accum(i-1)) < ' ' then do; call printchar('#'); call prhex(c); end; else call printchar(c); end; call printchar(':'); call prdec(token); if token = number then do; call printchar(','); call praddr(value); call printchar('H'); end; if eofset then call print(.('End-File$')); end; end trace; /* parsing procedures for non terminals */ bypass: procedure(x) byte; declare x byte; if token = x then do; call scan; return true; end; return false; end bypass; declare eltinx byte; /* index into set when 'element' returns true */ element: procedure(list) byte; declare list address; /* address of set to search */ /* element searches for the current token in the set of tokens addressed by 'list' and returns true if item is found. as a side-effect, 'eltinx' is set to the item's index */ declare set based list (1) byte, x byte; eltinx = -1; do forever; if (x := set(eltinx:=eltinx+1)) = 0 then return false; if token = x then return true; end; end element; endline: procedure byte; /* return true if end of line or file */ return (token = cr) or eofset; end endline; recover: procedure; do while not endline; call scan; end; end recover; emitdollar: procedure; if not z80$tog then call emitchar(.('offset $')); call emitbyte('$'); end emitdollar; declare /* diskdef parameter values */ maxdisks lit '16', ndisks byte, /* number of disks */ diskset (maxdisks) byte; /* true if included in diskdef */ disks: procedure; /* handle the disks n macro */ declare i byte; if ndisks > 0 then ndisks = 0; else if token = number then ndisks = value; else ndisks = 0; if ndisks = 0 or ndisks > maxdisks then call errptr(.('bad val$')); call scan; /* dpbase equ $ */ call emitchar(.('dpbase$')); call emitoptab(.('equ$')); if off$tog then call emitdollar; else call emitbyte('$'); call emitcomment(.('Base of Disk Parameter Blocks$')); do i = 1 to ndisks; /* dpe00: dw xlt00,0000h */ call emitcharn(.('dpe$'),i-1); if z80$tog then call emitbyte(':'); call emitdw; call emitcharn(.('xlt$'),i-1); call emitcomma; call emitaddr(0); call emitcomment(.('Translate Table$')); /* dw 0000h,0000h */ call emitdw; call emitaddr(0); call emitcomma; call emitaddr(0); call emitcomment(.('Scratch Area$')); /* dw dirbuf,dpb00 */ call emitdw; call emitchar(.('dirbuf,$')); call emitcharn(.('dpb$'),i-1); call emitcomment(.('Dir Buff, Parm Block$')); /* dw csv00,alv00 */ call emitdw; call emitcharn(.('csv$'),i-1); call emitcomma; call emitcharn(.('alv$'),i-1); call emitcomment(.('Check, Alloc Vectors$')); end; end disks; declare npar lit '11', rpar lit '9', /* no. of required parms */ dn lit '0', /* disk number */ fsc lit '1', /* first sector */ lsc lit '2', /* last sector */ skf lit '3', /* skew factor */ bls lit '4', /* block size */ dks lit '5', /* disk size */ dir lit '6', /* directory size */ cks lit '7', /* check sum size */ ofs lit '8', /* offset tracks */ com lit '9', /* CP/M 1.4 compatibility flag */ prm lit '10'; /* permanent disk drive */ declare lower (*) address data /* dn fsc lsc skf bls */ (0000, 0000, 0001, 0000, 1024, /* dks dir cks ofs com */ 0001, 0001, 0000, 0000, 0000, /* prm */ 0000), upper (*) address data /* dn fsc lsc skf bls */ (0015, 0015, 65535, 0255, 16384, /* dks dir cks ofs com */ 65535, 65534, 65534, 65535, 0000, /* prm */ 0000), optional (*) byte data /* dn fsc lsc skf bls */ (false, false, false, true, false, /* dks dir cks ofs com */ false, false, false, false, true, /* prm */ true); declare dsmax (*) address data /* value of bls */ /* 1024 2048 4096 8192 16384 */ ( 8192, 4096, 2048, 1024, 512 ); declare bsh (*) byte data /* 1024 2048 4096 8192 16384 */ ( 3, 4, 5, 6, 7 ), blm (*) byte data /* 1024 2048 4096 8192 16384 */ ( 7, 15, 31, 63, 127 ), dsm (*) byte data /* 1024 2048 4096 8192 16384 */ ( 0, 1, 3, 7, 15 ); declare ddir (*) address data /* 1024 2048 4096 8192 16384 */ ( 32, 64, 128, 256, 512 ); range: procedure; call errptr(.('range $')); end range; diskdef: procedure; /* handle diskdef, first item scanned */ declare pv (npar) address, parmissing (npar) byte, (pc, i) byte, (d, v) address; declare sectors address, (nxtsec, nxtbas, neltst, nelts) address; gcd: procedure(m,n) address; declare (m,n,r) address; do forever; r = m mod n; if r = 0 then return n; m = n; n = r; end; end gcd; equiv: procedure(a,b); declare (a,b) address; /* dpb1 equ dpb0 */ call emitcharn(a,pv(0)); call emitoptab(.('equ$')); call emitcharn(a,pv(1)); call emitcomment(b); end equiv; comment: procedure(v,a); declare (v, a) address; /* write diskdef comment line */ call emitbyte(';'); call emittab; call emitdecb(v); call emitbyte(':'); call emittab; call emitchar(a); call emitcrlf; end comment; do i = 0 to last(parmissing); parmissing(i) = true; end; pc = 0; token = ','; do while not (endline or pc = npar); call trace(.(' diskparm$')); pv(pc) = 0; if not bypass(',') then call errptr(.('delimit$')); else if (parmissing (pc) := (token = cr or token = ',')) then do; if not optional(pc) then call errptr(.('missing$')); end; else do; if token <> number then call errptr(.('numeric$')); else do; /* numeric value, check range */ if value < lower(pc) or value > upper(pc) then call range; else /* make special range checks */ if pc = dn then do; if diskset(value) then call errptr(.('duplic $')); diskset(value) = true; end; else if pc = lsc and value <= pv(fsc) then call range; else if pc = skf and value > (pv(lsc) - pv(fsc)) then call range; else if pc = bls then do; if value = 1024 then value = 0; else if value = 2048 then value = 1; else if value = 4096 then value = 2; else if value = 8192 then value = 3; else if value = 16384 then value = 4; else call range; end; else if pc = dks then do; if value > 256 and pv(bls) = 0 then call range; else if value > dsmax(pv(bls)) then call range; end; else if pc = dir then do; if (value and 11b) <> 0 then call range; else do; /* compute alloc vector */ v = 0; d = value; /* loop until zero or negative */ do while not rol(high(d-1),1); d = d - ddir(pv(bls)); if low(v) then do; call errptr(.('Alloc $')); d = 0; end; else v = shr(v,1) or 8000h; end; end; end; else if pc = cks and ((value and 11b) <> 0 or value > pv(dir)) then call range; if pc = prm and pv(cks) > 0 then call errptr(.('conflict$')); pv(pc) = value; end; call scan; end; if errset then return; pc = pc + 1; end; /* check for abbreviated form */ if not endline then return; if pc = 2 then do; if not diskset(pv(1)) then call errptr(.('no disk$')); if comm$tog then do; call emitnulcom; call emitbyte(';'); call emittab; call emitchar(.('Disk $')); call emitdec8(pv(0)); call emitchar(.(' is the same as Disk $')); call emitdec8(pv(1)); call emitcrlf; call emitnulcom; end; call equiv(.('dpb$'),.('Equivalent Parameters$')); call equiv(.('als$'),.('Same Allocation Vector Size$')); call equiv(.('css$'),.('Same Checksum Vector Size$')); call equiv(.('xlt$'),.('Same Translate Table$')); return; end; else if pc < rpar then do; call errptr(.('too few$')); return; end; /* write general disk statistics */ sectors = pv(lsc) - pv(fsc) + 1; if pv(skf) = 0 then parmissing(skf) = true; if comm$tog then do; /* ;;Disk 000 is CP/M 1.4 Single(/Double) .. */ call emitnulcom; if not parmissing(com) then do; call emitbyte(';'); call emittab; call emitchar(.('Disk $')); call emitdec8(pv(dn)); call emitchar( .(' is CP/M 1.4 Double Density Compatible$')); call emitcrlf; end; /* pv(dks) * 8/16/32/64/128 for 1k/2k/4k/8k/16k */ d = pv (dks) * shl(100b,pv(bls)+1); call emitbyte(';'); call emittab; if d > 0 then call emitdecb(d); else call emitchar(.('65536$')); call emitbyte(':'); call emittab; call emitchar(.('128 Byte Record Capacity$')); call emitcrlf; /* pv(dks) * 1k/2k/4k/8k/16k */ d = 1; if pv(bls) > 0 then d = shl(d,pv(bls)); call comment(pv(dks) * d,.('Kilobyte Drive Capacity$')); call comment(pv(dir),.('32 Byte Directory Entries$')); call comment(pv(cks),.('Checked Directory Entries$')); if not parmissing(com) then d = 128; else do; /* extents are folded */ if pv(dks) > 256 then d = 32; else d = 64; d = shl(d,pv(bls)+1); end; call comment(d,.('Records / Extent$')); call comment(shl(100b,pv(bls)+1), .('Records / Block$')); call comment(sectors,.('Sectors / Track$')); call comment(pv(ofs),.('Reserved Tracks$')); if not parmissing(skf) then call comment(pv(skf),.('Sector Skew Factor$')); call emitnulcom; end; /* dpb0 equ $ */ call emitcharn(.('dpb$'),pv(dn)); call emitoptab(.('equ$')); call emitdollar; call emitcomment(.('Disk Parameter Block$')); call emitdwnc(sectors, .('Sectors Per Track$')); call emitdbnc(bsh(pv(bls)), .('Block Shift$')); call emitdbnc(blm(pv(bls)), .('Block Mask$')); i = pv(bls); if pv(dks) > 256 then i = i - 1; if parmissing(com) then call emitdbnc(dsm(i),.('Extnt Mask$')); else call emitdbnc(pv(com),.('1.4 Compatible$')); call emitdwnc(pv(dks)-1,.('Disk Size - 1$')); call emitdwnc(pv(dir)-1,.('Directory Max$')); /* compute allocation vector initialization */ call emitdbnc(high(v),.('Alloc0$')); call emitdbnc(low(v),.('Alloc1$')); if parmissing(prm) then call emitdwnc(pv(cks)/4,.('Check Size$')); else call emitdwnc(8000h,.('Permanent Disk$')); call emitdwnc(pv(ofs),.('Offset$')); /* generate allocation vector */ call emitcharn(.('xlt$'),pv(dn)); call emitoptab(.('equ$')); if parmissing(skf) then do; call emitdec8(0); call emitcomment(.('No Translate Table$')); end; else do; call emitdollar; call emitcomment(.('Translate Table$')); nxtsec, nxtbas = 0; neltst = sectors/gcd(sectors,pv(skf)); nelts = neltst; do d = 0 to sectors-1; if d mod 4 <> 0 then call emitcomma; else do; if d > 0 then call emitcrlf; if sectors < 256 then call emitdb; else call emitdw; end; call emitdec16(nxtsec+pv(fsc)); nxtsec = nxtsec + pv(skf); if nxtsec >= sectors then nxtsec = nxtsec - sectors; if (nelts := nelts - 1) = 0 then do; nxtsec = (nxtbas := nxtbas + 1); nelts = neltst; end; end; call emitcrlf; end; /* generate allocation vector size */ call emitcharn(.('als$'),pv(dn)); call emitoptab(.('equ$')); d = pv(dks)/8; if pv(dks) mod 8 <> 0 then d = d + 1; call emitdec16(d); call emitcomment(.('Allocation Vector Size$')); /* generate checksum vector size */ call emitcharn(.('css$'),pv(dn)); call emitoptab(.('equ$')); call emitdec16(pv(cks)/4); call emitcomment(.('Check Vector Size$')); end diskdef; endef: procedure; /* generate end of disk def code */ declare i byte; reserve: procedure; if z80$tog then /* $z set for z80, 8080, or 8085 */ call emitoptab(.('ds$')); else call emitoptab(.('rs$')); end reserve; call emitnulcom; call emitbyte(';'); call emittab; call emitchar(.('Uninitialized Scratch Memory Follows:$')); call emitcrlf; call emitnulcom; /* begdat equ $ */ call emitchar(.('begdat$')); call emitoptab(.('equ$')); call emitdollar; call emitcomment(.('Start of Scratch Area$')); /* dirbuf: ds/rs 128 */ call emitchar(.('dirbuf$')); if z80$tog then call emitbyte(':'); call reserve; call emitdec8(128); call emitcomment(.('Directory Buffer$')); /* alv0: ds als0, csv0: ds css0 */ do i = 0 to last(diskset); if diskset(i) then do; call emitcharn(.('alv$'),i); if z80$tog then call emitbyte(':'); call reserve; call emitcharn(.('als$'),i); call emitcomment(.('Alloc Vector$')); call emitcharn(.('csv$'),i); if z80$tog then call emitbyte(':'); call reserve; call emitcharn(.('css$'),i); call emitcomment(.('Check Vector$')); end; end; /* enddat equ $, datsiz equ $-begdat */ call emitchar(.('enddat$')); call emitoptab(.('equ$')); call emitdollar; call emitcomment(.('End of Scratch Area$')); call emitchar(.('datsiz$')); call emitoptab(.('equ$')); call emitdollar; call emitchar(.('-begdat$')); call emitcomment(.('Size of Scratch Area$')); call emitdbnc(0,.('Marks End of Module$')); end endef; program: procedure; /* handle the entire genlib program */ declare i byte; do i = 0 to last(diskset); diskset(i) = false; end; ndisks = 0; do while not eofset; errset = false; call scan; call emitline; call trace(.('program$')); if token <> cr then if not element(.( tmaclib, tdisks, tdiskdef, tendef, 0)) then call errptr(.('No Stmt$')); else do; do case eltinx; /* maclib */ do; call scan; call trace(.(' maclib$')); call scan; call trace(.(' macpar$')); end; /* disks */ do; call scan; call trace(.(' disks$')); call disks; end; /* diskdef (10 parameters) */ do; call trace(.(' diskdef$')); call diskdef; end; /* endef */ do; call scan; call endef; end; end; if token <> cr then call errptr(.('extra $')); end; call recover; end; end program; plmstart: procedure public; /* main program, called from transient interface */ call setemit; /* setup the code emitters */ call scan$ini; /* initialize the scanner */ call setup; /* set up the input file */ call program; call writerrs; call efinis; /* close the code file */ call boot; end plmstart; end;