$title ('MP/M II V2.0 Loader') mpmldr: do; /* Copyright (C) 1979,1980,1981 Digital Research P.O. Box 579 Pacific Grove, CA 93950 Revised: 14 Sept 81 by Thomas Rolander */ declare true literally '0FFH'; declare false literally '0'; declare forever literally 'while true'; declare boolean literally 'byte'; declare start label; declare jmp$to$start structure ( jmp$instr byte, jmp$location address ) data ( 0C3H,.start-3); declare signon (*) byte data ( 0dh, /* Filler */ 0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah, 0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah,0ah, 'MP/M II V2.0 Loader ',0dh,0ah, 'Copyright (C) 1981, Digital Research',0dh,0dh,0ah,'$'); /**************** Warning ******************/ /* */ /* This location must be at or above 015CH */ /* */ /*********************************************/ declare copyright (*) byte data ( 'COPYRIGHT (C) 1981,'); declare company$name (*) byte data ( ' DIGITAL RESEARCH '); declare serial$number (6) byte data ( '654321'); declare err$msgadr address initial (.default$err$msg); declare err$msg based err$msgadr (1) byte; declare default$err$msg (*) byte data ( 'Dsk rd err','$'); declare mon1 literally 'ldmon1'; declare mon2 literally 'ldmon2'; mon1: procedure (func,info) external; declare func byte; declare info address; end mon1; mon2: procedure (func,info) byte external; declare func byte; declare info address; end mon2; declare fcb (1) byte external; declare fcb16 (1) byte external; declare tbuff (1) byte external; /************************************** * * * B D O S Externals * * * **************************************/ write$console: procedure (char); declare char byte; call mon1 (2,char); end write$console; print$buffer: procedure (buffer$address); declare buffer$address address; call mon1 (9,buffer$address); end print$buffer; reset$disk$system: procedure; call mon1 (13,0); end reset$disk$system; open$file: procedure (fcb$address) byte; declare fcb$address address; return mon2 (15,fcb$address); end open$file; read$record: procedure (fcb$address) byte; declare fcb$address address; return mon2 (20,fcb$address); end read$record; set$DMA$address: procedure (DMA$address); declare DMA$address address; call mon1 (26,DMA$address); end set$DMA$address; /************************************** * * * Misc. BDOS procs * * * **************************************/ crlf: procedure; call write$console (0dh); call write$console (0ah); end crlf; printdecimal: procedure (n); declare n byte; declare (digit,pdigit) byte; pdigit = false; digit = '0'; do while n >= 100; pdigit = true; digit = digit + 1; n = n - 100; end; if pdigit then do; call write$console (digit); digit = '0'; end; do while n >= 10; pdigit = true; digit = digit + 1; n = n - 10; end; if pdigit then call write$console (digit); call write$console ('0'+n); end printdecimal; printnib: procedure (n); declare n byte; if n > 9 then call write$console (n+'A'-10); else call write$console (n+'0'); end printnib; printhex: procedure (b); declare b byte; call printnib (shr(b,4)); call printnib (b and 0fh); end printhex; printaddr: procedure (a); declare a address; call write$console (' '); call write$console (' '); call printhex (high(a)); call printhex (low(a)); call write$console ('H'); end printaddr; printstring: procedure (sadr,sz); declare sadr address; declare sz byte; declare s based sadr (1) byte; declare i byte; do i = 0 to sz-1; call write$console (s(i) and 7fh); end; end printstring; printname: procedure (nadr); declare nadr address; call printstring (nadr,11); end printname; printitems: procedure (nadr,base,size); declare (nadr,base,size) address; call print$name (nadr); call printaddr (base); call printaddr (size); call crlf; end printitems; printitemsadr: procedure (nadr,base,size); declare nadr address; declare (base,size) byte; call printitems (nadr, double (base)*256, double (size)*256); end printitemsadr; match$serial: procedure (cpyrtadr,memadr); declare (cpyrtadr,memadr) address; declare (i,j) byte; declare cpyrt based cpyrtadr (1) byte; declare mem based memadr (1) byte; do forever; i,j = -1; do while cpyrt(i:=i+1) = mem(j:=j+1); ; end; if i > 23 then return; if (memadr = 0) or (i > 17) then do; err$msgadr = .('Synchronization: Serial numbers do not match','$'); go to error; end; memadr = memadr + 1; end; end match$serial; declare (base,cur$top,prev$top) address; declare cur$record address; declare sysdatadr address; declare wordadr address; declare word based wordadr address; declare xios$common based cur$top structure ( jmpinstr byte, base address ); declare actual$xios$common$base address; declare nrec byte; declare notdone boolean; declare rspname (11) byte initial ( '????????RSP'); declare brspname (11) byte initial ( '????????BRS'); declare mpm$sys$fcb (36) byte initial ( 0,'MPM ','SYS',0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); declare entry$point (3) address; declare system$data (256) byte at (.fcb); $include (sysdat.lit) declare break boolean; declare debug$RST byte; declare destination based cur$top (1) byte; declare link based cur$top address; declare test$byte based cur$top byte; declare rspcnt byte; print2addr: procedure; call printaddr (cur$top); call printaddr (prev$top-cur$top); call crlf; end print2addr; load$system$data: procedure; declare cntr byte; call set$DMA$address (.system$data); if open$file (.mpm$sys$fcb) = 0ffh then do; call move (4,.(' ?','$'),.mpm$sys$fcb(12)); err$msgadr = .mpm$sys$fcb(1); go to error; end; if read$record (.mpm$sys$fcb) <> 0 then do; go to error; end; call set$DMA$address (.system$data(128)); if read$record (.mpm$sys$fcb) <> 0 then do; go to error; end; sysdatadr, cur$top = shl(double(mem$top),8); call print$buffer (.( 'Nmb of consoles = ','$')); call printnib (nmb$cns); call print$buffer (.(0dh,0ah, 'Breakpoint RST # = ','$')); call printnib (brkpt$RST); /********************************************************** if z80$cpu then call print$buffer (.(0dh,0ah, 'Z80 Alternate register set saved/restored', ' by dispatcher','$')); if bank$switched <> 0 then do; call print$buffer (.(0dh,0ah, 'Common base addr =','$')); call printaddr (double (common$base) * 256); end; if banked$bdos then call print$buffer (.(0dh,0ah, 'Banked BDOS file manager','$')); call print$buffer (.(0dh,0ah, 'Nmb of ticks/second = ','$')); call printdecimal (ticks$per$second); call print$buffer (.(0dh,0ah, 'System drive = ','$')); call write$console ('A'+system$drive-1); call write$console (':'); call print$buffer (.(0dh,0ah, 'Max lckd recs/proc = ','$')); call printdecimal (max$locked$records); call print$buffer (.(0dh,0ah, 'Totl lckd recs/sys = ','$')); call printdecimal (total$system$locked$records); call print$buffer (.(0dh,0ah, 'Max open files/proc = ','$')); call printdecimal (max$open$files); call print$buffer (.(0dh,0ah, 'Totl open files/sys = ','$')); call printdecimal (total$system$open$files); call print$buffer (.(0dh,0ah, 'Tođ oć MP/M-80 =','$')); call printaddr (cur$top + 255); *************************************************************/ call print$buffer (.(0dh,0ah, 'Memory Segment Table:',0dh,0ah,'$')); call printitems (.('SYSTEM DAT'),cur$top,256); cur$top = cur$top - (prev$top := (shr(nmb$cns-1,2)+1)*256); call printitems (.('TMPD DAT'),cur$top,prev$top); if sys$call$stks then do; cur$top = cur$top - (prev$top := (shr(nmb$mem$seg-2,2)+1)*256); call printitems (.('USERSYS STK'),cur$top,prev$top); end; end load$system$data; display$OS: procedure; declare (base,cntr) byte; declare rspsadr (16) address; declare temp$rspl address; declare temp$rspl$adr based temp$rspl address; call printitemsadr (.('XIOSJMP TBL'), xios$jmp$tbl$base, 1); call printitemsadr (.('RESBDOS SPR'), resbdos$base, xios$jmp$tbl$base-resbdos$base); call printitemsadr (.('XDOS SPR'), xdos$base, resbdos$base-xdos$base); if nmb$rsps <> 0 then do; cntr = 0; temp$rspl = rspl; do while (rspsadr(cntr):=temp$rspl) <> 0; cntr = cntr + 1; temp$rspl = temp$rspl$adr; end; rspsadr(cntr) = double (xdos$base)*256; do while (cntr:=cntr-1) <> -1; call move (8,rspsadr(cntr)+6+2,.rspname); call printitems (.rspname, rspsadr(cntr), rspsadr(cntr+1)-rspsadr(cntr)); end; end; call printitemsadr (.('BNKXIOS SPR'), bnkxios$base, rsp$base-bnkxios$base); call printitemsadr (.('BNKBDOS SPR'), bnkbdos$base, bnkxios$base-bnkbdos$base); call printitemsadr (.('BNKXDOS SPR'), bnkxdos$base, bnkbdos$base-bnkxdos$base); call printitemsadr (.('TMP SPR'), tmp$base, bnkxdos$base-tmp$base); if nmb$brsps <> 0 then do; cntr = 0; temp$rspl = brspl; do while (rspsadr(cntr):=temp$rspl) <> 0; cntr = cntr + 1; temp$rspl = temp$rspl + 2; temp$rspl = temp$rspl$adr; end; rspsadr(cntr) = double (tmp$base)*256; do while (cntr:=cntr-1) <> -1; call move (8,rspsadr(cntr)+4,.brspname); call printitems (.brspname, rspsadr(cntr), rspsadr(cntr+1)-rspsadr(cntr)); end; base = brsp$base; end; else do; base = tmp$base; end; cntr = base - high (total$list$items*10 + 255); call printitemsadr (.('LCKLSTS DAT'), cntr, base-cntr); if nmb$cns <> 0 then do; base = cntr; cntr = base - nmb$cns; call printitemsadr (.('CONSOLE DAT'), cntr, base-cntr); end; end display$OS; display$mem$map: procedure; declare msgadr address; call print$buffer (.( '-------------------------',0dh,0ah,'$')); msgadr = .('MP/M II Sys','$'); do nrec = 0 to nmb$mem$seg-1; call print$buffer (msgadr); msgadr = .('Memseg Usr','$'); call printaddr (shl(double(mem$seg$tbl(nrec).base),8)); call printaddr (shl(double(mem$seg$tbl(nrec).size),8)); if bank$switched <> 0 then do; call print$buffer (.(' Bank ','$')); call printdecimal (mem$seg$tbl(nrec).bank); end; call crlf; end; end display$mem$map; Restart$instr: procedure; disable; /* this disable is overlayed with RST x */ end Restart$instr; xeq$mpm: procedure; declare brkpt$adr address data (.Restart$instr); declare brkpt based brkpt$adr byte; declare loc$0007 byte at (0007h); stack$ptr = .entry$point(2); /* if command tail starts with 'B' then break */ if break then do; if mem$top >= loc$0007 then do; errmsg$adr = .('No break, CP/M debugger overlaid by MP/M', '$'); go to error; end; brkpt = 1100$0111b or shl(debug$RST,3); call Restart$instr; end; end xeq$mpm; command$tail: procedure; declare fcbstr$adr address; declare fcbstr based fcbstr$adr (1) byte; break = false; fcbstr$adr = .fcb; if fcbstr(1) = ' ' then return; if fcbstr(1) = '$' then do; if fcbstr(2) = 'B' then do; break = true; if fcbstr(3) = ' ' then debug$RST = 7; else debug$RST = fcbstr(3) and 0000$0111b; end; fcbstr$adr = .fcb16; end; if (fcbstr( 9) = 'S') and (fcbstr(10) = 'Y') and (fcbstr(11) = 'S') then do; call move (9,fcbstr$adr,.mpm$sys$fcb); end; end command$tail; /* Main Program */ start: /* disable; -> removed from base of MP/M 1.x loader */ call reset$disk$system; call command$tail; call print$buffer (.signon); call load$system$data; cur$top = sysdatadr; cur$record = 1; do while (cur$record:=cur$record+1) <> nmb$records; call set$DMA$address (cur$top:=cur$top-128); if read$record (.mpm$sys$fcb) <> 0 then do; errmsg$adr = .('failed to read MPM.SYS','$'); go to error; end; end; entry$point(2) = double (xdos$base)*256; call match$serial (.company$name,.system$data); call display$OS; call display$mem$map; call move (256,.system$data,sysdatadr); call xeq$mpm; error: call print$buffer (.(0dh,0ah, 'MPMLDR error: ','$')); call print$buffer (err$msgadr); do forever; stackptr = 0; disable; halt; end; end mpmldr;