IMD 1.17: 24/11/2010 20:05:48 slevy /tmp z8000 cc #2 back: inout,proces,xref.m80 sysgen &syslnk  !  "W N  f kr pX7 p&B :  /B e&7  `   Ce Ԥ!e  N   " et ZEWue T!e 5 &     f r f rvr t@P ! ɋp ȋ?E A Ze   ?    7?JGDA=FC@<EB:741963  !"#$%&'()*+,-./0123456789:bYcKXQY`dMebFHIJLKMY`bdc`YXVWXYZ[\]```abcdeK3]]P0/usr/mdec/uboot 500 7 d--777 0 1 $ 00 ~K0]0%D~K1]0?0N258; 0D 369147:vӟv0f),00/&|0xgH0Y϶M0Xϵ|01 kF0 kE00kD0d  kB0+[_VSK0 ϵ{00k;m0j !k:0Uϵ|0 >NQHKOkA0I RILPSJkI ...Qputbootezxt.cXoburn.cJp.careloc.cKalarm = 1.204 ~~ 1 + 1/5 */ n = nwords + nwords/5; /* gives number of 4-digit groups */ hp->firstnz++; /* ignore first word ( = 3._z.hdrcmon211.z]exdep.s\pq[mxpi.cFto.cYtab.cZprtln ) */ obuf[0] = 1; /* select std output for obuf */ ln = 10; /* 10 groups per line */ g = 5; /* of 5 digits each */ i = WmxpiVerfleUban.cTbanSextape.cRzxtbself.cPmerge4; /* extract in groups of 4 */ for(;;) { if(++i >= 4) { if(--n <= 0) break; k = multiply(hp, 10000); i = 3; do0 M]TWZk<0Q?^pϵ|025t 0ϵ{NextapeOrom.cMtk5tk.c`hex.c^down.cIpi.cHpii.s0~rm0g{m0P g}m0g{mGpi2.sLpack.cEpiDpi.1100.timeCpxtr.c=rand.sApi23@pi23.1100.time0WfRK0 re07g{m0gzm?pi23.c>pi23.timeBmakesetup<putinterp;mon5.z:fixbd.c9azbugs8slice.c0pgzm0v g{m0   g|m0' o7slice6diffsdtk.old.c$0%( 0B9<@C:=Mg|m0DGJNg|m0Eg|m0Wg{m0ϋ*0 ZRUX[_xg}m0vbe\`ψs real 10:21.0 user 9:29.7 sys 5.1 0 cf]adgsg}m0+x0ւ.0#t~K&]0 jrJnt(hp) struct header *hp; { register int i, g; register unsigned int k; int n, ln; char dig[4]; /* log(65536) / log(10000) RDS) { if((vsum = sbrk(2*nwords*2)) == -1) { write(2, toomuch, sizeof toomuch); exit(-1); } vterm = vsum + nw#define NWORDS 200 int nwords NWORDS; struct header { int *last; /* pointer past last word of data */ int *firstnz; /* pointords; } } div2 = div3 = split = 0; clear(&sum, vsum); clear(&term, vterm); vterm[0] = 4; /* 4 * arctan(1/2) */ factor =er to first nonzero data word */ } sum, term; int t1[NWORDS], t2[NWORDS]; int *vsum = t1; int *vterm = t2; char toomuch[] = " 1; sign = 1; divide(&term, 2, &term); do { if(divadd(&term, factor, &sum, sign) == 0) break; div2++; factor =+ 2; siCan't allocate that much storage\n"; main(argc, argv) char **argv; { int factor, sign; int div2, div3, split2; extern int spgn = ~sign; } while(divide(&term, 2*2, &term) != 0); clear(&term, vterm); split2 = split; vterm[0] = 4; /* 4 * arctan(1/3) lit; int divadd(), divsub(); if(argc > 1) { nwords = atoi(argv[1]); if(nwords <= 0) nwords = NWORDS; if(nwords > NWOreal 10:21.0 user 9:29.7 sys 5.1  { dig[i] = k % 10 + '0'; k =/ 10; } while(--i >= 0); i = 0; } putc(dig[i], obuf); if(--g <= 0) { if(--ln ww n rm5A1`R   %  A'f   r e0@Aa1 <= 0) { putc('\n', obuf); ln = 10; } else putc(' ', obuf); g = 5; } } putc('\n', obuf); fflush(obuf); }  r   | @a& .  |  .  |  . |  . | Rw8w "DCA@@ r# @ww r @w r `@ ` @7& w X r |@ @f& CD pAa@ `K &f$      vrƅ& 6 vrUw ~w^ DeT  N  % bw7 : 7 : ׯ0 - ( & w real 5:17.0 user 4:35.0 sys 4.6 7   .w eB J ӕ-  o^ xU d  w r f e0&   ԕ- k  vA W  ~e0fv  O MJ  . ҋ D~C "  ( v  ӕ0 (f vLv Le0 9e  7wVe&   fA  ^ y   F y @0fA  @9 fA @e&7w7@B w7 fwmH wwmfwH wwt f@wdw   vrƅ& 6 vrUw ~w` DeV  P  % fw7 < 7 < ׯ2 - * ( */ factor = 1; sign = 1; divide(&term, 3, &term); do { if(divadd(&term, factor, &sum, sign) == 0) break; div3++; faw 7   .w eB J ӕ-  o^ xU d  w r f e0&ctor =+ 2; sign = ~sign; } while(divide(&term, 3*3, &term) != 0); if(argc > 2) printf("%l div 2 (%l splits), %l div 3 (%l s   ԕ- k  vA W  ~e0fv  O ML  4 ҋ D~C ( plits)\n", div2, split2, div3, split - split2); print(&sum); } clear(hp, vec) register struct header *hp; register int *vec; . v  ӕ0 (f vLv Le0 9e  7wVe&  { register int n; hp->firstnz = vec; n = nwords; do { *vec++ = 0; } while(--n); hp->last = vec; } int obuf[259]; priefer to a byte (if r6 = 1) or a word (if r6 = 2). ; ; The response expected is of the form: ; [] ; If a nuF & 6 % w _%2@ (7\ XP%J Dt 78% "mber is given, and the delimiter is one of those listed below, ; then the contents of @rr4 are altered. ; The delimiter specifie %  m7  7 55T  X  X X %NT fX 6s how rr4 is to be altered ; (e.g., stepped to the next byte or word). ; The delimiters allowed are as follows: ; space -- step e  e@@ 5X X % tX  T ^X X %NT fX 6err4 to the next byte or word, as appropriate. ; '-' -- step rr4 back to the previous byte/word. ; '=' -- leave rr4 pointing to t  e@@ 5X  X % % Nfff eT wF _"w .DC `N wf |@@& BFw B 5  ʥ ʥ ʥ- ʥ9 Wp @@`eʥ0m  b~  b  b~ w7 h ^ Z0   FWp `e0eӕ?f. ,  w7F\ Can't allocate that much storage %l div 2 (%l splits), %l div 3 (%l splits) dp$P   @f  7 6 -fwbA< Q  Oodxfe6cDslurDlO`X(null) ter. $2 ldctlb flags,rh7 jr nz,mod2 ; no digits => don't alter bit r6,#0 jr z,modw ldb @rr4,rl3 ; modify byte jr mod2 meceived. ; Alters: ; r0, r1, r3, r4, r5, r12, r13 ldb rh4,data`lastseg ; pick default segment calr inr3 jr z,get2 cpb rl0,odw: ld @rr4,r3 ; modify word mod2: cpb rl0,#'-' jr ne,mod3 sub r5,r6 ; '-' => back up jr mod6 mod3: cpb rl0,#'@' ; '#' ' jr eq,getseg ; ignore leading blanks get2: ret nz cpb rl0,#'.' jr ne,get1 ldb rh4,rl3 ; segment specified calr inr@' => indirection jr ne,mod8 ld r5,@rr4 ; load offset from current word ldb rh4,data`lastseg ; assume default segment jr mF & 6 % w _%2@ ,7` \T%N Ht 7<% " m  f~  f  f~ w7 j ` \0   HWp `e0eӕ?f0 %  m7 7 55Z  ^  ^ ^ $%NZ f^ : ,&P   @f  7 < -fwdAB Q e  e@@ 5^ ^ $% x^  Z b^ ^ $% #NZ f^  OfA  ^ y   F y @0fA  @9 fA @e&7:e  e@@ 5^ ^ $% % Nfff $eZ wF _"w .DC w7@H w7 fwmN wwmfwN wwv f@wfwbT wf |@@& BFw B 5  ʥ ʥ ʥ- ʥ9 Wp @@`ehe same location ; ',' -- switch to byte mode (alter r6) ; ';' -- switch to word mode (ditto) ; '@' -- take the word @rr4 as theʥ0  w7Fb Can't allocate that much storage %l div 5 (%l splits), %l div 239 (%l splits)  low 16 bits of an address; ; the segment is that most-recently used in an X, E, or D command. ; Rr4 is set to this new address.dtohxfe:cHslurDpOdX(null) ; CR -- normally used to exit a command (end a series of modifications). ; ; When switching modes, if a number is entered, it is taken to be of the ; new type when modifying @rr4. ; If no number is entered when switching to word mode, ; rr4 is rounded dowep rr4 to the next byte or word, as appropriate. ; '-' -- step rr4 back to the previous byte/word. ; '=' -- leave rr4 pointing tod6 mod8: cpb rl0,#'=' jr eq,mod6 add r5,r6 ; else step by address unit mod6: cpb rl0,#cr ; return Z set if CR ret ; go the same location ; ',' -- switch to byte mode (alter r6) ; ';' -- switch to word mode (ditto) ; '@' -- take the word @rr4 as  (then round down to word) $1 calr byteflag ldctlb flags,rh7 ; if no digits on a mode switch, ret nz ; then don't move poinetseg: ; get a segment number and offset from the console and put ; them into rr4. ; returns NZ on error, Z if valid address r down to an even address. ; ; The Z flag is set on return from modify, showmod, and cshowmod ; iff the delimiter was CR. ; ; Alteo, n); perror(" rewrite"); } seek(f, bno, 3); if((n=read(f, buf, 512)) != 512) { printf("%l [%d]", bno, n); perror(" rers: ; r0, r1, rl2, r3, r4, r5, r6, rl7, r12, r13 ; cshowmod: calr colon showmod: calr show modify: calr inr3 jr c,cmderr2 lread"); } } } die(msg, p) char msg[]; { printf(msg, p); putchar('\n'); exit(-1); } the low 16 bits of an address; ; the segment is that most-recently used in an X, E, or D command. ; Rr4 is set to this new addredctlb rh7,flags cpb rl0,#',' ; ',' forces byte mode jr eq,$1 cpb rl0,#semic ; ';' forces word mode jr ne,$2 res r5,#0 ;ss. ; CR -- normally used to exit a command (end a series of modifications). ; ; When switching modes, if a number is entered, i0, r1, r3, r12, r13. inr3: ldk r3,#0 ldb rh0,#2 ; "no digits yet" flag $1 calr indig jr c,$2 ; end of number ldb rh0,#0 ww n rm5A1`T   %  A'f   r e0@Aa ; no -- clear "no digits" flag sla r3,#4 addb rl3,rl1 ; add new digit jr $1 $2 ldk r1,#delims ; check for valid delimi1 r    @a& 2    2    2   2  Vw8w "ter lda rr12,monitor.dlmtab cpirb rl0,@rr12,r1,eq tccb nz,rh0 ; tricky interaction of rh0 flag & NZ rrb rh0 ; force C seDCA@@ r# @ww r @w r `@ ` @7( t if ill delimiter (NZ) ret ; now NC => valid delimiter, Z => valid number rcv'd. ; indig: ; input a hex digit, put its valuw X r |@ @f& CD pAa@ `K &f$   int obuf[259]; main() { register int tab, i, c; int nspaces; obuf[0] = 1; nspaces = tab = 0; while((c = getchar()) != 0)  console in hex ldb rl2,#4 ; shift count to r2 outloop rl r1,#2 ; roll top digit down into rl r1,#2 ; bottom digit's pl{ switch(c) { case ' ': nspaces++; continue; case '\t': nspaces =+ 8 - (tab+nspaces) % 8; continue; case 'ace ldb rl0,#0FH andb rl0,rl1 calr outdig dbjnz rl2,outloop ret outdig ; output a hex digit from rl0 to the console decb \n': nspaces = tab = 0; break; default: if(nspaces > 0) { tab =+ nspaces; if((i = tab/8 - (tab-nspaces)/8) >rl0,#9 jr le,$1 incb rl0,#'A'-'9'+9-10 $1: addb rl0,#'9' jr outch ; modify -- allow modifying contents of @rr4, and/or step 0 && nspaces > 1) { do putc('\t', obuf); while(--i); for(i=tab%8; --i>=0; ) putc(' ', obuf); } else {ping rr4, shown below. ; showmod -- "show" @rr4 and modify ; cshowmod -- print colon, show @rr4, allow modifying. ; ; @rr4 may rf(seek(f, bno, 3) < 0) die("seek 1"); if((n=read(f, buf, 512)) != 512) { printf("%l [%d]", bno, n); perror(" read"); if(t is taken to be of the ; new type when modifying @rr4. ; If no number is entered when switching to word mode, ; rr4 is rounded !errok) continue; } if((n=seek(f, bno, 3)) < 0) die("w seek"); if((n=write(f, buf, 512)) != 512) { printf("%l [%d]", bn Some of the known assembler bugs: (others are on that sheet I gave you) (the most important ones are the "LD memory,#value" and cp mem,#value should generate code of the form:
-- but now, they gennd "CP @RR,#value") No error given on "cp pmach.gdirp,r0" (just generates wrong code) No error given on "rr rh4,#1" "jp $1 erate
. It's impossible to include a semicolon in a character string -- it th... $1: " never filled in the jp If you refer to a symbol defined in another segment, az should generate reference to -that-inks it's a commment delimiter. Az should be able to put its object file anywhere, with any name, and not only in the directo segment, not the current one! -- or at least warn you. (if you haven't specified a seg explicitly) $ rounded down to even in3 ret nz get1: setflg z ld r5,r3 ret ; byteflag: ; Check rl0 for comma, indicating "byte operation". ; Set r6 to 1 if bytrl0,@rr4 ; load the next byte to print calr outch ; print char inc r5 decb rl0 ; test for end of string jr ge,outmess e, or 2 if word operation. ; Set rl7 to comma if found, otherwise a space. ; Return Z set if byte, NZ if word. ldb rl7,#' 'e into rl1. ; leaves the character found in rl0. ; C set if not hex digit ; Alters: ; rl0, rl1. calr echo ; get char in ; which is marked by a char <= 0. ret ; echo: ; get a char into rl0, map to upper case, echo on console calr in8ch resb rl0,#rl0 ldb rl1,rl0 subb rl1,#'0' ret c ; < '0' => error cpb rl1,#9 jr le,digok ; <= 9 => ok cpb rl0,#'A' ret c ; < 'A' 7 ; quash parity bit orb rl0,rl0 ; NUL? jr eq,echo ; ignore them. cpb rl0,#esc ret eq ; don't echo ESC (confuses our=> error addb rl1,#'0'-'F'-1 ret c ; > 'F' => error incb rl1,#16 digok: resflg c ret ; ; Print a null-terminated message CRT) cpb rl0,#lf jr ne,$1 ; map LF into CR ldb rl0,#cr $1 calr outch cpb rl0,#'a' ret lt cpb rl0,#'z' ret gt resb rl0 pointed to by rr4. ; Message may also be terminated by a byte whose sign bit is set. ; Alters: ; rl0, r4, r5. outmess: ldb main() { char q, n, *L, *S, *T; L = "main() { char q, n, *L, *S, *T; L = "; S = "%s%c%s%c;%cS = %c%s%c;%cT = %c%s%c;%c%s%c}%c" do putc(' ', obuf); while(--nspaces); } nspaces = 0; } if(c >= ' ') tab++; } putc(c, obuf); } fflush(o; T = "q = 042; n = 012; printf(S, L,q,L,q,n,q,S,q,n,q,T,q,n,T,n,n);"; q = 042; n = 012; printf(S, L,q,L,q,n,q,S,q,n,q,T,q,n,T,nbuf); } ,n); }  "ndelims .equ $ - dlmtab" OUT, IN, etc. should allow @R port number. OTIR, etc are useless without it. ld mem,#value a f & 6 % w % M % >eC˥0˥9  4 ˥0˥int errok; int f; char buf[512]; main(argc, argv) char **argv; { register int bno; register int n; register char *p; if(--9Ӌ  4e7˥- m  x7 ˋ%  X    % ˋargc <= 0) die("usage: fixbd [-] device bno bno ..."); p = *++argv; if(*p == '-') { errok++; p = *++argv; argc--; } if %  %4  >@ r&> eX7 N>>e 4 -# %  (*p >= '0' && *p <= '9') { argv--; p = "/dev/rbd0"; } if((f = open(p, 2)) < 0) die("%s: cannot open", p); while(--argc      x % He >>7   rf`  % w&w   > 0) { p = *++argv; if(*p < '0' || *p > '9') { printf("%s: bad block number\n", p); continue; } bno = atoi(p); i/* slice -- prints selected columns from each line * of standard input. * SYNOPSIS * slice [ file ] [ -m ] [ -s ] nn[-[mm]]ry of the source file. "cpb @rr2,#number" -- wrong op code -- uses CP R,IM instead of CP IR,IM form. "ldb rh0,#80H" complain ... * * where nn and mm are column numbers. Fields consisting of only * a single integer refer to just that column. Rangess "byte required". Should allow if -255 <= number <= +255 (i.e., if high byte is all 1's or all 0's) instead of -127 <= n of the form * nn- * refer to column nn onward, however long the line may be. * An output line consists of the characters inumber <= 127, as it is now. LDM gives wrong op code for LDM X(R),R,#n at least -- probably others  selected fields * of the input line, followed by a newline character. * Column numbers begin at one, and include tab expansio ldk r6,#2 cpb rl0,#',' ret ne ldb rl7,#',' ldk r6,#1 ret ; Enter a 16-bit value into r3, terminated by any char in dlmtab. ; C set if invalid delimiter ; Z set if valid number and delimiter received ; Delimiter returned in rl0. ; Alters: ; rargv; if(*p >= '0' && *p <= '9') { cp->high = cp->low = atoi(p); do p++; while(*p >= '0' && *p <= '9'); if(*p++ != ',#5 ; map ASCII lower -> upper case ret in8ch: ; read a full 8-bit character into rl0 inb rl0,chastat bitb rl0,#0 ; test r\0') { if((cp->high = atoi(p)) == 0) cp->high = 32767; } cp++; } else if(*p == '-') { do switch(*+eady bit jr z,in8ch ; if not set, wait inb rl0,chadata ; read char ret .finis +p) { case 's': /* suppress blank lines on output */ canbenull = 0; break; case 'm': /* "Multiple output lines" */ multflag++; /* (one per field) */ } while(*p != '\0'); } else { /* it's a file name */ close(0); if(open(p,  [0] = 1; /* standard output */ ibuf[0] = 0; /* standard input */ col = 1; cp = &field[0]; while((c = getc(ibuf)) != -1) ter struct cols *f1, *f2; { if(f1->low < f2->low && f1->high < f2->high) return(-1); if(f1->low > f2->low && f1->high > f2->hi{ while(col > cp->high) { cp++; if(multflag) newline(); } if(col >= cp->low && c != '\n') { putc(c, obuf); som7 w w wAupNNmf $ ww p@@5 _v fA rBpEu@@`55D   7 ww DC",",  % wf@w fCN& z f& %5 2`D--`f z $`f& %`Df %5 D-wJA 7 fAW,f B@ 8 @&61fA   @ & z C-D-%@@AA@ Nf` $ u_0Nf $ @`5_0f %@e7&1@  1w`fww&wFfwA,Q  OfA  ^ y Cww DCԒ wlw \DCB5ҒS w<f@w^wZ8w  F y @0fA  @9 fA @e&7fwb7\@2wenull = 1; int multflag = 0; /* flag: each field appears on a separate line */ int somedata; int ibuf[259], obuf[259]; char en. * A tab is said to be in the column where it begins, so * tabs which hop into or through fields may not be included. * * rror[] = ": Cannot open\n"; char overlap[] = "Slice: fields must not overlap\n"; char usage[] = "\ Usage: slice [file] [-s] [-m]If `-m' is used, each field on the input line is printed as a * separate line of output. * Using `-s' causes blank lines to be nn-mm ... prints selected columns from a file\n"; main(argc, argv) char **argv; { register struct cols *cp; int cmpfield(); suppressed from output; * otherwise, blank lines will appear whenever a line of input * is too short to pass through the sele if(argc <= 1) { write(2, usage, sizeof usage - 1); exit(-1); } { register char *p; cp = &field[0]; do { p = *++cted fields. */ #define NFLDS 20 /* number of field specifications */ struct cols { int low, high; } field[NFLDS]; int canbgh) return(1); write(2, overlap, sizeof overlap - 1); exit(-3); } edata++; } switch(c) { case '\n': if(multflag) { while(cp->low < 32767) { newline(); cp++; } } els0) < 0) { do write(2, p, 1); while(*++p != '\0'); write(2, error, sizeof error - 1); exit(-2); } } } while(--e newline(); col = 1; cp = &field[0]; somedata = 0; break; case '\t': col =+ 8 - col%8; default: col++argc > 1); cp->low = cp->high = 32767; } qsort(field, cp - field, sizeof field[0], &cmpfield); { register col, c; obuf; } } } fflush(obuf); } newline() { if(somedata || canbenull) putc('\n', obuf); somedata = 0; } cmpfield(f1, f2) regis  b = bp->lastb; /* set up file-size entries */ tent.lastb = tent.firstb + bestsz; return((bestszt1 rtio r /dev/rx1t/$2.txt | tr -d \\15 \\14 | tab >t2 diff t1 t2 >$2.diffs shift; shift if $1x != x gotoce[7] = *(p-1); gotdev++; break; case 'f': files++; break; case 't': texts++; } if(gotdev==0 && argc>0) { argc--; loop  device = *++argv; } if((tkfil=open(device, wrtfil?2:0))<0 || seek(tkfil, 2, 3) || read(tkfil, dir, sizeof dir) != sizeof dir) err(1, "Can't access ", device); checkdir(); switch(oper) { case 'l': listdir(); break; case 'g': while(--argc>0) getfile(*++argv); break; case 's': while(--argc>0) savefile(*++argv); putdir(); break; case 'd': while(--argc > 0) delfile(*++argv); putdir(); break; case 'k': crunch(); putdir(); } } err(die, st) char *st; { register n; regstruct direntry *bp, *cp; register tsiz; int bestsz; bp = cp = &dir[dir->numfiles]; bestsz = dir->eovb - bp->lastb; while(ister char *p; char **strs; strs = &st; for(n=nargs(); --n; ) { p = *strs; while(*p++) ; write(2, *strs, p - *strs - 1cp>dir) { tsiz = cp->firstb; cp--; tsiz =- cp->lastb; if(tsiz>bestsz) { bestsz = tsiz; bp = cp; } } tent.first); strs++; } write(2, "\n", 1); if(die) exit(-1); return(-1); } putdir() { dir->access = tent.actime; seek(tkfil, 2, 3)  me[0]>7) goto flaw; was = 0; nfree = 0; for(p = dir; p <= &dir[dir->numfiles]; p++) { if(p->firstblastb < p->firr *ts, *st; register n; ts = tstr; st = str; n = *ts++; do if(*st >= 'a' && *st <= 'z') { if(*st++ + 'A' - 'a' != *ts+stb) goto flaw; nfree =+ p->firstb - was; was = p->lastb; } if(was > dir->eovb) { flaw: err(0, "not a Terak-format dire+) return(1); } else if(*st++ != *ts++) return(1); while(--n); return(*st); } struct direntry *findspace(size) { register ctory"); } nfree =+ dir->eovb - was; time(tv); date = gmtime(tv); tent.actime = (date[3]<<4) + (date[4]+1) + (date[5]<<9); turn(err(0,"No room for ", name)); tstring(name, tent.fname); gblk = tent.firstb; seek(tkfil, gblk, 3); if(texts) { for(cpBE<@CF=AG=gbuf; cp>9 + 2*texts; /* size of file in blocks */ } else size = 0; if((dent=findspace(size))==0) reoppy drives\n"; int repl; int nfree; struct direntry tent; /* temp entry -- for adding new ones */ main(argc, argv) char **ar struct volinfo { int firstb, lastb; int filekind; char vname[7]; int eovb; int numfiles; int access; }; struct direntry gv; { register char *p; char gotdev, wrtfil; char oper; char *device; if(--argc <= 0) err(1, usage); p = *++argv; gotdev{ int firstb, lastb; int filekind; char fname[15]; int lastbyte; int actime; } dir[100]; int tkfil; char gbuf[1024]; int g = 0; oper = 'l'; device = "/dev/rx0t"; while (*p) switch(*p++) { case 's': case 'd': case 'k': case 'c': wrtfil++; cablk; int files, texts; /* flags for 'f' and 't' options */ char usage[] = "Usage: tk {lgrsd}[ft01] [device] file ...\n\ Lise 'g': case 'l': oper = *(p-1); break; case 'r': wrtfil++; repl++; oper = 's'; break; case '0': case '1': devist/Get/Replace/Save/Delete files on a UCSD Pascal-format disk.\n\ f = xfer to UNIX file (else std I/O), t = TEXT files, 0/1 = fl} struct direntry *findfile(name) char *name; { register struct direntry *ep; register num; ep = dir; for(num = dir->numfigister was; register struct direntry *p; int tv[2]; if(dir->numfiles<0 || dir->numfiles>77 || dir->vname[0]<=0 || dir->vnales; num--; ) if(cmpst((++ep)->fname, name)==0) return(ep); return(0); } cmpst(tstr, str) char *tstr, *str; { register cha  1 div r2,r0 bvc 4f jsr pc,split 4: add r0,(r5)+ bcc 2f mov r5,r0 tst -(r0) sec 3: adc -(r0) bcs 3b 2: mov r1,r0 sob , multiplier) / multiplies multiplier into thing, / returns overflow from top word. mov 2(sp),r1 / r1 -> header for thingr4,1b done: mov r0,_drem / save remainder mov sp,r0 / return r0 nonzero done2: mov (sp)+,r4 mov (sp)+,r3 mov (sp)+,r2 mov  mov 4(sp),r2 / r2 = multiplier mov r5,-(sp) mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) clr r0 mov (r1)+,r3 / r3 -> last+1 wo(sp)+,r5 rts pc _divsub: / divide and subtract from destination jsr r5,arget / divsub(source, divisor, dest, sign) tst 16.(rd of thing mov r3,r4 / also r4 sub (r1),r4 / r4 = last - firstnz asr r4 / r4 = number of words ble done2 / if none, do nosp) / negative sign? bmi divadd / if so, use add divsub: 1: mov (r3)+,r1 div r2,r0 bvc 4f jsr pc,split 4: sub r0,(r5)+ bc#define NWORDS 200 int nwords NWORDS; struct header { int *last; /* pointer past last word of data */ int *firstnz; /* point sub r4,r5 / back dest up as far as source sub r4,r5 / (twice, since r4 is in words) rts pc split: / split divides into byteer to first nonzero data word */ } sum, term; int t1[NWORDS], t2[NWORDS]; int *vsum = t1; int *vterm = t2; char toomuch[] = "s when needed inc _split ashc $-8,r0 div r2,r0 bvs die clr -(sp) movb r0,1(sp) clr r0 ashc $8,r0 bisb -2(r3),r1 div rCan't allocate that much storage\n"; main(argc, argv) char **argv; { int factor, sign; int div5, div239, split5; extern int 2,r0 bvs die bis (sp)+,r0 rts pc .bss _drem: . = .+2 _split: . = .+2 split; int divadd(), divsub(); if(argc > 1) { nwords = atoi(argv[1]); if(nwords <= 0) nwords = NWORDS; if(nwords > N cp = gbuf; crumcnt = 0; /* Counts crummy characters in text */ tab = spcnt = 0; /* tab pos'n & extra-space count */ while((c=getc(fbuf)) != -1) { switch(c) { case ' ': spcnt++; break; case '\t': spcnt += 8 - (tab+spcnt) % 8; brer3,r4 asr r4 / r4 = # words in source ble empty / if none, return 0 1: / else verify "1st nonzero word" tst (r3)+ / keep a r2,r0 / fix blasted signed multiply 2: mov r1,(r3) sob r4,1b br done2 / restore regs and return arget: / get args for divdvancing until nonzero bne 2f sob r4,1b / or until end of source empty: / in which case return r0 = 0, tst (sp)+ / indicatiide routines mov sp,r0 mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) mov r5,-(sp) / save ret addr cmp (r0)+,(r0)+ / r0 -> first ang empty source br done2 / return to caller of caller 2: tst -(r3) / overshot NZ word -- back up mov r3,(r1) / repair header'rg mov (r0)+,r3 / r3 = &(source header) mov (r0)+,r2 / r2 = divisor mov *(r0)+,r5 / r5 = dest.last clr r0 / init r0 for divs idea of firstnz sub r4,r5 / back dest up as far as source sub r4,r5 / (twice, since r4 is in words) rts pc divd: / dividesides mov (r3)+,r4 / r4 = source.last mov r3,r1 / save addr of source.firstnz mov (r3),r3 / now r3 -> first nonzero word sub c 2f mov r5,r0 tst -(r0) sec 3: sbc -(r0) bcs 3b 2: mov r1,r0 sob r4,1b br done die: halt _multiply: / multiply(thing  jsr pc,divd sub r1,(r5)+ bcc 2f mov r5,r1 tst -(r1) sec 3: sbc -(r1) bcs 3b 2: sob r4,1b br done die: halt _multiply:.globl _divide, _divadd, _divsub, _multiply .globl _drem, _split halt = 0 .text _divide: / divide (in place if source = dest r2 into r0r1. quot->r1, rem->r0 mov r3,-(sp) mov $16.,r3 1: asl r1 rol r0 cmp r2,r0 bhi 2f sub r2,r0 inc r1 2: sob r3,1bination) jsr r5,arget / divide(source, divisor, dest) 1: / where source and dest are (struct header *) mov (r3)+,r1 div r2, mov (sp)+,r3 rts pc .bss _drem: . = .+2 r0 bvc 4f jsr pc,split 4: mov r0,(r5)+ mov r1,r0 sob r4,1b br done _divadd: / divide and add to destination jsr r5,arget / divadd(source, divisor, dest, sign) tst 16.(sp) / negative sign? bmi divsub / if so, use subtract divadd: 1: mov (r3)+,r / r4 = source.last mov r3,r1 / save addr of source.firstnz mov (r3),r3 / now r3 -> first nonzero word sub r3,r4 asr r4 / rthing 1: mov r0,r5 / hold word carry in r5 mov -(r3),r0 mul r2,r0 add r5,r1 adc r0 tst (r3) bpl 2f add r2,r0 / fix blast4 = # words in source ble empty / if none, return 0 1: / else verify "1st nonzero word" tst (r3)+ / keep advancing until noned signed multiply 2: mov r1,(r3) sob r4,1b br done2 / restore regs and return arget: / get args for divide routines mov zero bne 2f sob r4,1b / or until end of source empty: / in which case return r0 = 0, tst (sp)+ / indicating empty source bsp,r0 mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) mov r5,-(sp) / save ret addr cmp (r0)+,(r0)+ / r0 -> first arg mov (r0)+,r3 /r done2 / return to caller of caller 2: tst -(r3) / overshot NZ word -- back up mov r3,(r1) / repair header's idea of firstnz  r3 = &(source header) mov (r0)+,r2 / r2 = divisor mov *(r0)+,r5 / r5 = dest.last clr r0 / init r0 for divides mov (r3)+,r4(1/239) */ factor = 1; sign = -1; do { if(divide(&term, 239, &term) == 0) break; if(divadd(&term, factor, &sum, sign) ==  / multiply(thing, multiplier) / multiplies multiplier into thing, / returns overflow from top word. mov 2(sp),r1 / r1 -0) break; div239++; factor =+ 2; sign = ~sign; } while(divide(&term, 239, &term) != 0); if(argc > 2) printf("%l div r5,r1 tst -(r1) sec 3: adc -(r1) bcs 3b 2: sob r4,1b done: mov r0,_drem / save remainder mov sp,r0 / return r0 nonzero do> header for thing mov 4(sp),r2 / r2 = multiplier mov r5,-(sp) mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) clr r0 mov (r1)+,r3ne2: mov (sp)+,r4 mov (sp)+,r3 mov (sp)+,r2 mov (sp)+,r5 rts pc _divsub: / divide and subtract from destination jsr r5,a / r3 -> last+1 word of thing mov r3,r4 / also r4 sub (r1),r4 / r4 = last - firstnz asr r4 / r4 = number of words ble done2rget / divsub(source, divisor, dest, sign) tst 16.(sp) / negative sign? bmi divadd / if so, use add divsub: 1: mov (r3)+,r1  / if none, do nothing 1: mov r0,r5 / hold word carry in r5 mov -(r3),r0 mul r2,r0 add r5,r1 adc r0 tst (r3) bpl 2f add  5 (%l splits), %l div 239 (%l splits)\n", div5, split5, div239, split - split5); print(&sum); } clear(hp, vec) register stru5; /* of 5 digits each */ i = 4; /* extract in groups of 4 */ for(;;) { if(++i >= 4) { if(--n <= 0) break; k = mulct header *hp; register int *vec; { register int n; hp->firstnz = vec; n = nwords; do { *vec++ = 0; } while(--n); hp->l.globl _rand, _srand .text _srand: / srand(seed) movb $136,high / nonzero junk to high 8 mov 2(sp),r0 / seed to low 16 brint vec[3]; main() { register char c; gtty(0, vec); vec[2] =| 040; stty(0, vec); /* set raw mode */ for(;;) { c = getc 1f / hop into rand _rand: mov low,r0 1: mov r0,r1 ash $-5,r1 xor r0,r1 clrb r0 bisb high,r0 swab r0 movb r1,-(sp) / shar(); if(c == 04) break; /* control-D = escape */ if(c == '\n') c = '\r'; putchar(c); } vec[2] =& ~040; stty(0, vec); ave high byte mov r0,r1 / 2nd cycle ash $-5,r1 xor r0,r1 clrb r0 bisb (sp)+,r0 swab r0 mov r0,low movb r1,high rts pc }  .data low: 125437 high: .byte 136 .even : writes interpreter from main.b to /dev/rx1t/interp for downloading. if $1x != x goto putfile (zxt main.b -o interp | down -s1; ls -s $i.p rtio w /dev/rx1t/$a <$i.p sync  echo "$") \ | rtio w /dev/rx1t/interp sync exit : putfile zxt main.b -o interp | down -s1 > $1 echo "$" >>$1 tiply(hp, 10000); i = 3; do { dig[i] = k % 10 + '0'; k =/ 10; } while(--i >= 0); i = 0; } putc(dig[i], oast = vec; } int obuf[259]; print(hp) struct header *hp; { register int i, g; register unsigned int k; int n, ln; char digbuf); if(--g <= 0) { if(--ln <= 0) { putc('\n', obuf); ln = 10; } else putc(' ', obuf); g = 5; } } putc('[4]; /* log(65536) / log(10000) = 1.204 ~~ 1 + 1/5 */ n = nwords + nwords/5; /* gives number of 4-digit groups */ hp->firstn\n', obuf); fflush(obuf); } z++; /* ignore first word ( = 3. ) */ obuf[0] = 1; /* select std output for obuf */ ln = 10; /* 10 groups per line */ g =  ctor = 1; sign = 1; divide(&term, 5, &term); do { if(divadd(&term, factor, &sum, sign) == 0) break; div5++; factor =+ 2ity | even | onestop | clk64 rbits7 .equ 01000000I ; 7 bits/byte recevie recenbl .equ 1I ; receive enable com3 .equ rbits7 | ; sign = ~sign; } while(divide(&term, 5*5, &term) != 0); clear(&term, vterm); split5 = split; vterm[0] = 4; /* 4 * arctan08H ; Operator intervention req'd sacmder .equ 0CH ; Command error sanrdy .equ 08H ; Drive Not Ready result ; ; Monitor d fflush(obuf); if(read(2, &obuf[3], 512) <= 0) exit(0); lineno = 0; continue; default: /* expunge illegal cata space -- resides in on-card RAM, segment 0, addresses 800-FFF. data .data .abs data = 0 .block 0800H regs: .block 16*2 if $1x != x goto someargs echo "cat makesetup for help" exit : Builds a Joyce setup file from a Pascal code file, normally on flharacters */ continue; case '\r': case '\t': case 07: case 033: /* tolerate escape codes */ case '\b': oppies. : makesetup [-] xxx [-] [dest] : makesetup xxx : reads from floppy drive 0 the file xxx.code : and writes on floppy dri /* I don't like form feeds */ ; } putc(c, obuf); } fflush(obuf); } ve 1 the file 'setup' {which must already exist}. : makesetup - xxx : reads from the unix file xxx, and writes as above. : makesetup xxx dest : reads xxx.code from floppy 0, and writes to RT-11 file dest on floppy 1. : makesetup xxx - dest : reads from floppy 0, writes to unix file dest. : You get the idea. : someargs if $1 != "-" goto read0 shift pxtr <$1 $1.r | down +8300 -st ; O : send value to output port ; ; The format for the commands is a single letter, followed by ; the required arguments, whi2 >$1.d set i = $1 goto writem : read0 tk 0g $1.code | pxtr /tmp/$1.r | down +8300 -s2 >/tmp/$1.d set i = /tmp/$1 : writem set fch are specified below. ; ; I/O segment ; io .data .abs io = 7FH ; Defined constants ; cr .equ 15B ; carriage return lf  = $1 down -i $i.r -w -s0 +800 >$i.p cat $i.d >>$i.p rm $i.r $i.d echo '$' >>$i.p set a = $f if $2x != "-x" goto writerx1t shift.equ 12B ; line feed esc .equ 33B ; escape bell .equ 7B ; bell semic .equ ':'+1 ; semicolon (az won't tolerate ';'!) SOH if $2x = x goto writefile set a = $2 : writefile mv $i.p $a exit : writerx1t if $2x = x goto writesetup set a = $2 : writesetup .equ 01B ; Start of Header for 8-bit load displn .equ 8 ; # values per line in display nbpts .equ 4 ; # of breakpoints monfcw .equ 0C000H ; monitor's FCW == system + segmented mode nmivec .equ 28H ; NMI vector offset segtvec .equ 20H ; Seg TrapWORDS) { if((vsum = sbrk(2*nwords*2)) == -1) { write(2, toomuch, sizeof toomuch); exit(-1); } vterm = vsum +  vector offset vintvec .equ 3CH ; 0'th vectored interrupt vector offset ; ; command words for SIO ; parity .equ 1I ; paritynwords; } } div5 = div239 = split = 0; clear(&sum, vsum); clear(&term, vterm); vterm[0] = 16; /* 16 * arctan(1/5) */ fa enable even .equ 10I ; even parity onestop .equ 0100I ; one stop bit clk64 .equ 11000000I ; clock rate = x64 com4 .equ par 10I ; " rts com5 .equ txenbl | tbits7 | dtr | rts com1 .equ 00E0H ; wait/rdy enbl + rdy function + TxE rdy reset .equ 0001100erface ; Disk controller commands (uncomplemented form) csainit .equ 12H ; initialize (configure disk) csaclib .equ 05H ; re0I ; reset command for SIO ; Shugart SA 4600 disk controller interface registers rsacmd .equ 0FEFDH ; command register (low calibrate (seek heads to 0) csaseek .equ 04H ; seek csaread .equ 48H ; read multiple sectors csawrt .equ 58H ; write multiplebyte) (complemented) rsaparm .equ 0FEF9H ; parameter register (low byte) (complemented) rsastat .equ 0FEFDH ; status register j\`cfiadbehkorulpsvmqtwn~x{y|z}"ord endregs: nregs .equ [[endregs - regs] >> 1] lastseg .word ; default seg for examine, etc loadseg .word ; default seg for downloading ecksum .word ehxtxt .word bpoints:.block nbpts*6 ; list of breakpoint contents & addrs ; storage area for disk commands saioop: .word sahdcyl:.word sasect: .word vectors .equ [$+255]&0FF00H ; put interrupt, etc. vectors ; on next  ; saved user registers ups: ; user program status uident: .word ; id of cause of trap ufcw: .word ; user flag/control256-byte boundary. topram .equ 400H*4 - 2 ; top of RAM for stack ptr ; ; I/O port numbers ; chastat .equ 1BH ; SIO command/sta word upcseg: .word ; user pc segment no. upc: .word ; user pc upsapseg .word ; user prog. status area ptr. upsapoff .wassumed seg 0!!) .word !2 ; immediate source value .endm initps .word 0 ; set up program status for .word monfcw ; resettus byte chadata .equ 19H ; SIO data byte romon .equ 00H ; access enables ROM (if turned off) romoff .equ 08H ; access disab initpc .word monseg .word init ; unimpps .word 0,monfcw, monseg,untrap ; ps for unimplemented instr. privps .word 0,monfcw, moles phantom ROM ; The ROM is automatically enabled on reset. ; trace .equ xxH ; access triggers NMI timer for 1-instr tracnseg,prtrap ; ps for privileged inst. trap scps .word 0,monfcw, monseg,break ; ps for breakpoint (system call) segps .word 0,mone ; ; ; The Monitor ... ; monitor .code priv .abs monitor = 0 ; monitor is in segment 0 monseg .equ [0 << 8] ; ldim .macro ; fcw, monseg,segtrap ; ps for segmentation violation nmips .word 0,monfcw, monseg,nmi ; ps for non-maskable interrupt nvips .worLoad Immediate memory location -- fixes az bug!! .word 4D05H ; LD (word) (DA, IM) .word 8000H, !1 ; destination address (data (low byte) (complemented) rsarslt .equ 0FEF9H ; result register (low byte) (complemented) rsaseg .equ 0FEF8H ; DMA segment nurecenbl txenbl .equ 1000I ; transmit enable tbits7 .equ 0100000I ; 7 transmit bits dtr .equ 10000000I ; enable dtr rts .equ mber (high byte) rsaaddr .equ 0FEFAH ; DMA offset address (word) rsarst .equ 0FEF6H ; addressing this resets controller & int  sectors csafmt .equ 11H ; format cylinder csacmp .equ 4AH ; compare data (search equal) csavfy .equ 43H ; verify data (read utrr4 lda rr4,monitor.addrmsg ; don't save regs, just print msg jr montrap report ; print message on console relaying cause o& watch for CRC errors) ; SA disk status-register bit numbers sabcbsy .equ 0 ; Command Busy sabpmfl .equ 2 ; Parameter Full f trap ; rr4 must have the address of the message to be printed calr crlf calr outmess ; print cause ldk r8,#0 report2: lsabrslt .equ 3 ; Result Register Full sabintr .equ 4 ; Interrupt Request (operation complete) ; SA disk result-register bit fda rr4,monitor.atmess ; get word " at " calr outmess ldl rr4,data`upcseg sub r5,r8 calr outrr4 ; print seg and offset jr ields sactype .equ 0CH ; Completion Type sacgood .equ 00H ; Good completion sacsser .equ 04H ; Subsystem error sachelp .equ itor cmd ; should not destroy user-prog status ldim vectors+nmivec+6, monnmi ; NMI shouldn't either ld r5,monitor.2(r5) ; Joyce Z8000 monitor program ; ; The commands available in the monitor are as follows: ; X : Examine and change memory ; D : call @rr4 jr getcom cmd .macro .byte !1, !1 .word !2 .endm cmdtbl: cmd "'D'", display cmd "'X'", xamine cmd "'E'", enteDisplay a range of addresses ; G : Go to a user program ; R : Examine and alter registers ; E : Enter a block of data ; B : r cmd "'G'", go cmd "':'", hexload cmd "'B'", breakpt cmd "'R'", register cmd cr, getcom ; ignore cr and lf cmd "'M'", moSet and remove breakpoints ; L : print status for hex loads ; : : Intel hex format pseudo-command ; M : Move a block of memorvemem cmd "'$'", hexstat cmd SOH, binload ; Intel-format 8-bit load cmd "'S'", sastuff cmd "'='", compare cmd "'N'", intenby ; = : Compare two memory areas ; N : enable/disable interrupts (vectored & non-vectored) ; I : display value from input por ld r2,r9 ldb rh3,rh7 ; rh3 = command ldb rl3,#4 ; rl3 = param count .word 0C4E0H ; ldb rh4,#0E0H -- az won't accept thirupt", 0 addrmsg:.byte " (?) Nonexistent", 0 initmess .byte "Joyce Monitor 2.1.0",0 ldmsg1: .byte " cksum, ", 0 ldmsg2: .byte "s! andb rh4,rl2 rr rh4,#1 ; rh4 = head+drive parameter ldb rl4,rh2 ; rl4 = cylinder number ldb rh5,#31 andb rh5,rl2 ; rhd 0,monfcw, monseg,nvi ; ps for nonvectored interrupt ; vips .word 0,monfcw ; vectored interrupt PS value consvect .word mons text errs. Seg ", 0 equmsg: .byte "Match", 0 dlmtab: .byte " ,-=.@", semic, cr ; 8 allowed number-delimiters delims .equ 8 ; eg,consint ; console interrupt (vector 0) endvecs: ; end of vector area ; ; Strings, etc., for monitor usage ; .even sio"8" should be "$-dlmtab", but for az bug ; SA disk messages okmsg: .byte "Ok", 0 nrdymsg:.byte "Not Rdy", 0 crcmsg: .byte "CRC"tbl: .byte reset, 14H, com4, 03H, com3, 05H, com5, 11H, com1 bpmess .byte "Bkpt #", 0 atmess .byte " at ",0 uimess .byte "Unimp, 0 xxxmsg: .byte "xxx", 0 .even ; ; Routines to handle the various traps and interrupts ; trap .macro ; argument: offset of l Inst",0 prmess .byte "Priv Inst", 0 segmess .byte "Seg Trap",0 nmimess .byte "NMI",0 nvimess .byte "NVI",0 usrint .byte "Intermimess montrap: calr outmess jr getcom nonaddr ; Nonexistent memory trap -- used only from within monitor. calr crlf calr o uence in RAM for sacmdo .word 5C29H, 0302H, 0000H ; az bug -- ldm X(R) is wrong. ; fall into sacmdo sacmdo: ; Perform cos segment violations trap segmess ; nmi ; handles nonmaskable interrupt trap nmimess ; nvi ; handles nonvectored interrupt trmessage calr savestat lda rr4,monitor.!1 jr report .endm untrap ; handles unimplemented instruction trap trap uimess ; prtrap nvimess ; consint ; handles console interrupt trap usrint ; ; Routines that support the trap/interrupt handlers ; savestat ap ; handles trap that occurs when a privileged instruction occurs ; in user mode (unprivileged code) trap prmess ; break ; ha; save status after trap: save all registers in the save area in RAM; ; Also save the PSW information and the user's PS area pondles system calls which should be breakpoints calr savestat lda rr4,monitor.bpmess ; report on which bp calr outmess ld r1inters. ldm data`regs,r0,#15 ; save R0..R14 popl rr10,@rr14 ; fetch our return address popl rr2,@rr14 ; pop saved trap-ID &,data`uident ; get sc inst from save area calr outrl1 ldk r8,#2 ; prepare pc-2 => bkpt instr jr report2 ; segtrap ; handlesapseg,r4 ; point our PSAP up there ldctl psapoff,r5 ldb rl0,#[endvecs>>1] ldir @rr4,@rr2,r0 ; copy up through consint (VI getcom ; get next command init: ; executed when the processor is reset lda rr14,data`topram ; initialize stack ptr ldm data#0) lda rr2,rr4(#-4) ld r0,#[[256-endvecs]>>2] ldir @rr4,@rr2,r0 ; fill VI vectors with copy of vector 0 ; ; Configure the `regs,r0,#16 ; save regs (though probably junk) lda rr2,monitor.initps lda rr4,data`ups ldk r0,#4 ldir @rr4,@rr2,r0 ; set uSIO ldk r1,#9 lda rr6,monitor.siotbl ldb rl0,#chastat .word 3A62H, 0100H ; otirb @r0,@rr6,r1 -- az won't accept it! ; ldim p some initial PS clr @rr4 lda rr6,rr4(#2) ; clear following words ld r0,#[[vectors-upsapoff]>>1] ; r0 = # words to 0-fill vectors+nmivec+6, saboot ; NMI after RESET => disk boot ; lda rr4,monitor.initmess ; send initial message calr outmess getcomldir @rr6,@rr4,r0 ; clear PSAP, breakpoints, etc. ldk r3,#initps ld r5,#vectors ; prepare to copy vectors into RAM ldctl p while controller resets itself jr nz,$1 ld r2,#saitab ; feed it the initialize commands calr sacmdo ; initialize, calr sac cmd "'I'", inport cmd "'O'", outport .byte -1, -1 disktbl: ; table of SA disk commands (all with S prefix) cmd "'I'", sainmdo ; recalibrate, calr sacmdo ; seek (to track 32 for visibility). jr sashow ; show results saboot: calr sainit ldb rh4it cmd "'='", sashow cmd "'R'", saread cmd "'W'", sawrite cmd "'Z'", saboot .byte -1, -1 cmderr: ; command error -- no su,#1 ldk r5,#0 ; read into segment 1, address 0 ldk r9,#0 ; start at track 0, sector 0 ldb rh6,#6 ; read 6 sectors (1.0000-ch command, or any error in usage decb rl0,#cr jr ne,$1 calr crlf $1 ldb rl0,#'?' calr outch jr getcom ; sastuff: calr ec0BFF) ldb rh7,#csaread calr saio exit: ldb rh4,#1 ldk r5,#0 ldctl psapseg,r4 ; set PSAP ldctl psapoff,r5 ; to base of ne5 = sector number (r5 mod 32) ldb rl5,rh6 ; rl5 = sector count ld r2,#saioop ;;;;; ldm monitor.0(r2),r3,#3 ; save command seqho lda rr4,disktbl jr cmdlook sainit: ld io`rsarst,r0 ; send reset signal to controller ld r0,#2000 $1 dec r0 ; 3 ms delay 9 = starting sector #, ; rh7 = controller command (csaread or csawrt). ldb io`rsaseg,rh4 ld io`rsaaddr,r5 ; set DMA address, 32 ; seek to track 32 (why not?) .even ; go: ; execute a user program ; syntax: ; G -- continue from last user pc ;,$1 lda rr4,monitor.xxxmsg ; "xxx" -- something else is wrong $1: calr outmess ; print whatever message orb rl1,rl1 ; test  Gseg.offset -- define new pc to go to ld r8,#regs calr getseg ; else get new pc to rr4 jr z,loadnew ; if a good segof FCW popl rr4,@rr14 ; ditto for saved PC resb rh4,#7 ; clear junk bit from PC seg ldctl r6,psapseg ldctl r7,psapoff ; rrcompletion type again ret z ; return if good, calr getcom ; otherwise abort (calr is shorter than jp) sastati: ldb rl0,io6 -> user's trap vector area (PSAP) lda rr8,data`[regs+[15*2]] ; point to save-area for ... ld r1,r15 ;;;;; ldm @rr8,r1,#7 ; `rsastat comb rl0 ret sarslti: ldb rl0,io`rsarslt comb rl0 ret ; SA command tables, etc. saitab: ; initialize-command user's R15, PSW, and PSAP. .word 1C89H, 0106H ; az bug -- doesn't assemble ldm @rr properly ld r9,#vectors ldctl psapseg,r8 sequence .byte csainit, 3, 0F0H, 20H, 08H ; initialize .byte csaclib, 1, 00H ; recalibrate drive .byte csaseek, 2, 00H; reset PSAP for monitor's vectors ldctl psapoff,r9 jp @rr10 ; return. ; monnmi ; NMI from within monitor lda rr4,monitor.naccept segment number ldb data.0(r8),rh2 ; seg spec should be alone on line -- fall into indone indone: call @rr10 ; add ; get a command from the console and execute it lda rr14,data`topram ; reset stack pointer calr crlf ; output carriage retu checksum byte, test result jr z,ignore ; zero => OK. ignore remaining cr/lf inc data.ecksum-loadseg(r8) ; else count checksurn inb rl0,chastat bitb rl0,#0 ; if char already in buffer, skip "> " jr nz,nextcmd ldb rl0,#'>' ; load prompt to send cam error jr flaw ; and ignore anything left gflaw: inc r15,#4 ; pop gbyte's return address flaw: inc data.ehxtxt-loadseg ;lr outch ; print it calr outsp nextcmd: calr echo ; get comm. and echo it to console lda rr4,cmdtbl cmdlook: cpb rl0,@rr count a text error ldb rh0,rl0 ; save lastc for ignore ldb rl0,#bell calr outch ; and ring bell ldb rl0,rh0 ; restore la4 jr eq,gotcmd testb @rr4 jr mi,cmderr inc r5,#4 jr cmdlook gotcmd: ldim [vectors+segtvec+6], nonaddr ; Seg Trap from monback pointers up by 1 unit sub r9,r6 calr outrr4 ; print first address calr cshow ; show contents calr outsp calr outspw program ldps @rr4 ; jump to new program's reset vector saread: ldb rh7,#csaread jr saio0 sawrite: ldb rh7,#csawrt saio ldl rr4,rr8 calr outrr4 ; print second address calr cshow ; show its contents ret ; ranges -- accepts input of form 0: calr ranges ; enter starting addr, "word" count, sector #. add r10,#254 ; round word count to next whole sector ld r6,r10; addr1-addr2 addr3[,] -or- ; addr1 bytecount addr3[,] ; Addr1 and addr3 may specify a segment; addr2 should not. ; Returns wi ; stuff into rh6 calr saio jr sashow saio: ; disk I/O routine ; Entry -- ; rr4 -> memory area, rh6 = sector count, rth: ; rr4 = addr1 rr8 = addr3 ; r6 = 1 if ',' (byte mode), ; r6 = 2 otherwise (word mode). ; r10 = count (or addr2-addr1+1) in b r3 ; r3 is endaddr or byte count jr nz,cmderr1 cpb rl2,#'-' jr ne,$1 sub r3,r5 $1 ld r10,r3 calr getseg jr nz,cmderr1 c destination -or- ; Mstartaddr bytecount destination ; -- moves a block of memory. movemem: calr ranges jr nz,$1 ldir @rr8alr byteflag ex r4,r8 ex r5,r9 ; make rr4 first, rr8 last address. add r10,r6 bit r6,#0 jr nz,$2 srl r10 $2 calr crlf biastati bitb rl0,#sabintr ; await interrupt request jr z,$4 calr sarslti ; read result andb rl0,#sactype ; test completiommand sequence to which r2 points. ; If no error, return; else call sashow and abort. $1 calr sastati bitb rl0,#sabcbsy jr nn type ret z ; return if good ; else fall into sashow, which will abort. sashow: calr sarslti ldb rl1,rl0 ldb rl7,rl0 z,$1 ; await not command busy ldb rl1,monitor.0(r2) ; fetch command byte comb rl1 ldb io`rsacmd,rl1 ldb rh1,monitor.1(r2)  calr outrl1 calr outsp lda rr4,monitor.okmsg ; "Ok" ldb rl1,#sactype andb rl1,rl7 jr z,$1 lda rr4,monitor.nrdymsg ; "Not ; fetch parameter-count byte inc r2,#2 $2 ldb rl1,monitor.0(r2) ; parameter byte inc r2 comb rl1 ldb io`rsaparm,rl1 ; sendRdy" cpb rl7,#sanrdy jr eq,$1 lda rr4,monitor.crcmsg ; "CRC" cpb rl1,#sacsser ; Subsystem error (probably CRC error) jr eqf, load new pc decb rl0,#cr ; if cr, then use old pc jr eq,exec calr cmderr ; (calr is shorter than jump) loadnew ldl da param $3 calr sastati bitb rl0,#sabpmfl ; await not param full jr nz,$3 dbjnz rh1,$2 ; loop for each parameter $4 calr sta.[upcseg-regs](r8),rr4 ; install new upc exec: calr crlf ldl rr0,data.[upsapseg-regs](r8) ldctl psapseg,r0 ldctl psapoff,r1 ;;;; ldm r0,data.0(r8),#16 ; install user's regs .word 5C81H, 000FH, 0000H ; az bug ldps data`ups ; load new program statusst char read ignore: ; ignore any text remaining on line decb rl0,#cr ret z calr echo jr ignore in8bit: ; reads a full : jump ; to user program ; ; hexload ; load an INTEL hex format file lda rr10,gbyte jr intldr ; binload:; like hexload, 8-bit character into rl1 calr in8ch ldb rl1,rl0 jr adcksum gbyte: ; reads a byte into rl1 calr indig jr c,gflaw ldb rlbut uses full 8-bit characters as data lda rr10,in8bit intldr: ld r8,#loadseg ldb rl7,#0 ; rl7 = checksum = 0 ldb rh2,data2,rl1 slab rl2,#4 calr indig jr c,gflaw addb rl1,rl2 ; combine digits adcksum: addb rl7,rl1 ; add to checksum ret ; re.0(r8) ; default seg for loading call @rr10 ldb rh7,rl1 ; rh7 = byte count call @rr10 ldb rh3,rl1 call @rr10 ldb rl3,rlturn, with CC set by checksum value hexstat: ; $ command. Prints number of hex load errors, ; prints current hex loading segment, ; and allows you to change it. Hit CR if not. ; "nnnn checksum, nnnn text errors. Seg nn " ld r8,#loadseg ldk rytes or words, as appropriate. ; Alters: ; r0, r1, rl2, r3, r4, r5, r6, rl7, r8, r9, r12, r13 ; (all except rh2, rh7, r10, r11) 1,#0 ex r1,data.[ecksum-loadseg](r8) calr outr1 lda rr4,monitor.ldmsg1 calr outmess ldk r1,#0 ex r1,data.[ehxtxt-loadseg](; ranges: calr getseg jr nz,cmderr1 ldb data`lastseg,rh4 ldl rr8,rr4 ; start addr ldb rl2,rl0 ; save delimiter calr inr8) calr outr1 lda rr4,monitor.ldmsg2 calr outmess lda rr4,data.0(r8) ldk r6,#1 calr showmod ret ; Mstartaddr-endaddr  s ; (addr1 through addr2 or addr1+bytecount-1 ; against corresponding area beginning at addr3) ; and reports "Match" or dispntenb: calr inr3 jr nz,cmderr2 sla r3,#11 ; move into position for VI & NVI bits .word 0CBC0H ; ldb rl3,#[monfcw>>8] -- az blays first difference. ; Trailing comma compares bytes; otherwise, compares words. compare: calr ranges jr nz,$1 cpsir @rr4,ug orb rh3,rl3 .word 7D3AH ; ldctl fcw,r3 -- az bombs out on this somehow ret ; inport -- display value from input port ; I<@rr8,r10,ne jr $2 $1 cpsirb @rr8,@rr4,r10,ne $2 jr z,$3 lda rr4,monitor.equmsg ; "Match" calr outmess ret $3 sub r5,r6 ; r: ; enter a block of data ; syntax: Eseg.offset[,] calr getseg ; start addr to rr4 jr nz,cmderr1 ; abort on error cd contents (if any) ldctlb flags,rl4 ; ask again -- was it "b+" ? jr eq,addbp testl rr8 ; no, "b-" -- remove bkpt jr z,cmalr byteflag enter1 calr crlf calr outrr4 calr colon enter2: ldb rl0,rl7 ; ' ' or ',' according to word/byte calr outch cderr1 ; if addr = 0, never set -- complain. ld @rr8,r7 ; else restore old contents subl rr4,rr4 ; and clear bkpt address alr outsp calr modify ; enter value jr nz,enter3 ldctlb flags,rh7 ; CR hit; was NZ set (no digits)? ret nz ; if none, q jr bpret addbp: calr getseg ; get the address jr nz,cmderr1 ldb rh6,#7FH ; construct SC instruction in r6 ex r6,@rr4 ;uit enter3: cpb rl0,#' ' jr eq,enter2 ; ' ' => continue jr enter1 ; any other => print address & go on ; xamine ; examine exchange with old contents bpret: push @rr10,r6 ; which we save. pushl @rr10,rr4 ; finally, save bkpt address. ret ; ente unless reg number >= 16 jr lt,$2 ldb rl0,#'P' ; in which case, RP0 .. RP5. ldb rl1,rl2 $2 calr outch $1 ldb rl0,rl1 calr ou $4 add r3,r3 add r3,r8 ; add RPx and/or RLx offsets to reg address lda rr4,data`regs(r3) cpb rl0,#'=' jr eq,rdisp regloop:tdig calr outsp calr showmod ; print & (maybe) modify reg contents ret z ; CR hit => quit cpb rl0,#'@' ; check for indirec1 ; r3 = address call @rr10 ldb rl6,rl1 ; rl6 = "type" field indata: decb rh7 ; any bytes left? jr mi,indone ; not ac calr crlf ldb rl0,#'R' calr outch bit r6,#0 ; byte reg? jr z,regl1 ldb rl0,#'H' ; yes, print RH bit r5,#0 jr z,regl2 cording to the count call @rr10 testb rl6 ; special type field? jr nz,inxseg ; yes, set segment number ld r0,@rr2 bit r3ldb RL0,#'L' ; or rl as approp regl2: calr outch regl1: ld r1,r5 sub r1,#regs rr r1 ldb rl2,rl1 subb rl2,#nregs jr uge,cmd,#0 jr nz,$1 ; select byte to alter ldb rh0,rl1 jr $2 $1 ldb rl0,rl1 $2 ld @rr2,r0 ; this is needed for on-board RAM. inerr1 incb rl2,#nregs-10 ; reg number >= 10 ? jr lt,$1 ldb rl0,#'1' ldb rl1,rl2 ; prepare for R10 .. R15 decb rl2,#16-10 ;c r3 jr indata inxseg: ; set loading-segment number decb rl6,#2 ; was type field = 2 ? jr ne,flaw ldb rh2,rl1 ; yes, .' $1 calr outch dbjnz rh7,dloop3 disp4 dec r9 ; test "one line" flag jr ne,dloop1 ret ; intenb -- enable/disable interru,@rr4,r10 ret $1 ldirb @rr8,@rr4,r10 ret ; ; =addr1-addr2 addr3[,] -or- =addr1 bytecount addr3[,] ; Compares memory areapts ; N -- ; 1-bit set in number => enable non-vectored interrupts ; 2-bit set in number => enable vectored interrupts i portnumber>[' '|','] ; Prints the hex value read from that port. ; Trailing space => word input, trailing comma => byte input. i1 ;;;; outb @r4,rl3 ; az bug .word 3E4BH ret ; ; Support routines ; cmderr2: calr cmderr ; another error abort location nport: calr inr3 jr nz,cmderr2 calr byteflag jr eq,$1 ; skip if byte (",") ;;;; in r1,@r3 ; az bug -- won't assemble .wor(calr < jp) crlf ; prints carriage return and line feed on console ldb rl0,#cr calr outch ldb rl0,#lf jr outch ; ; show -d 3D31H ; in r1,@r3 jr outr1 ; print word received $1 ;;;; inb rl1,@r3 ; az bug .word 3C39H ; inb rl1,@r3 jr outrl1 ; pr- print contents of @rr4 in hex, followed by a space. ; cshow -- like show, but number is preceded by a colon ; A byte or word iint byte ; outport -- send byte or word value to output port ; O [,] outport: calr inr3 jr nz,cmderr2 ld r4,r3 t r6,#0 ret ; breakpt: ; set or remove breakpoints, which are implemented as SC instr's calr echo subb rl0,#'+' ; expect "b and change memory one word at time -- ; stop by typing CR. ; syntax: Xseg.offset[,] calr getseg ; init. addr. to rr4 jr +" ... ldctlb rl4,flags ; (save result of comparison) jr eq,$1 decb rl0,#['-'-'+'] ; or also "b-" jr nz,cmderr1 $1 calr inz,cmderr1 calr byteflag ; watch for comma ldb data`lastseg,rh4 ; we used this seg! exloop: calr crlf calr outrr4 calr cshnr3 ; get breakpoint number jr nz,cmderr1 cp r3,#nbpts jr uge,cmderr1 ; ensure in range 0..3 ld r6,r3 mult rr2,#6 ; cowmod ; show & allow modifying mem loc jr nz,exloop ret ; cmderr1: calr cmderr ; friendly neighborhood error branch ;onvert r3 to bpoints array index lda rr10,data`bpoints(r3) popl rr8,@rr10 ; rr8 = breakpoint address pop r7,@rr10 ; r7 = ol (calr is shorter than jump) ; register ; examine/modify user registers ; syntax: R[ H | L ]startingregnumber[ , | = ] ; Also, the following special registers are accessible: ; RP0 = trap ID word RP1 = Flag&control word ; RP2 = PC segment RP3 = block of memory ; syntax: Dseg.beginningoffset endoffset calr getseg ; get starting address in rr4 jr nz,cmderr2 ; jumPC offset ; RP4 = PSAP segment RP5 = PSAP offset (pointer to trap vector area) ldk r8,#0 $1 calr inr3 ; get starting reg #p on error ldk r9,#0 cpb rl0,#cr ; only 1 address? jr eq,disp1 cpb rl0,#',' ; (also 1 addr, byte display) jr eq,disp1 c jr z,$3 cpb rl0,#'P' jr ne,$2 set r8,#5 ; add 16 wds to offset -- for RP registers jr $1 $2 cpb rl0,#'L' tcc eq,r8 jr alr inr3 ; else get end address to r3 jr z,disp2 jr c,cmderr2 disp1: ld r3,#-1 ; if no endoffset, ldk r9,#1 ; display eq,$1 cpb rl0,#'H' jr eq,$1 jr cmderr1 $3 calr byteflag cp r3,#10H ; map regs 10-15 into A-F on input jr lt,$4 dec r3,#6tion jr ne,regloop ; if not, continue normally jr exloop ; if so, hop into xamine loop rdisp: ; display registers ldk r91 line disp2: ld r8,r3 calr byteflag ldb data`lastseg,rh4 ; remember we used this segment bit r6,#0 jr nz,dloop1 res r8,#0,#1 ; print just 1 line ld r8,#endregs ; or through RP5 if less jr disp3 ; hop into display loop ; ; display ; display a  calr inr3 jr nz,cmderr2 calr byteflag jr eq,$1 ;;;; out @r4,r3 ; az bug -- won't assemble .word 3F43H ; out @r4,r3 ret $ w, monseg,break ; ps for breakpoint (system call) segps .word 0,monfcw, monseg,segtrap ; ps for segmentation violation nmips .woess .byte "NMI",0 nvimess .byte "NVI",0 usrint .byte "Interrupt", 0 addrmsg:.byte " (?) Nonexistent", 0 initmess .byte "Joyce Mo ; if word mode, round down end-address dloop1: calr crlf ; then print cr, lf calr outrr4 calr colon disp3: ldb rh7,#disrd 0,monfcw, monseg,nmi ; ps for non-maskable interrupt nvips .word 0,monfcw, monseg,nvi ; ps for nonvectored interrupt ; vipspln ; load # values per line calr outsp dloop2: calr show cp r5,r8 ; see if done ret uge add r5,r6 dbjnz rh7,dloop2 ;  .word 0,monfcw ; vectored interrupt PS value consvect .word monseg,consint ; console interrupt (vector 0) endvecs: ; end loop till line is filled bit r6,#0 jr z,disp4 ; test for byte mode calr outsp ; yes -- provide el cheapo char dump calr of vector area ; ; Strings, etc., for monitor usage ; .even siotbl: .byte reset, 4, com4, 3, com3, 5, com5, 1, com1 bpmess outsp dec r5,#displn ldb rh7,#displn dloop3 calr outsp ldb rl0,@rr4 inc r5 resb rl0,#7 cpb rl0,#' ' jr ge,$1 ldb rl0,#'n: ; print a ':' ldb rl0,#':' jr outch ; outrr4 -- print address represented by rr4, in the form nn.nnnn in hex, ; and follos displayed, according to the value of r6. ; (See byteflag). ; Alters: ; rl0, rh1, rl2. ; cshow: calr colon show: bit r6,#0 wed by a space. ; Alters: ; rl0, rh1, rl2. ; outrr4: ldb rl1,rh4 resb rl1,#7 calr outrl1 ldb rl0,#'.' calr outch ld r1,r5 ; show byte? jr z,showw ldb rl1,@rr4 ; yes calr outrl1 jr show2 showw: ld r1,@rr4 ; no calr outr1 show2: ; fall int calr outr1 jr outsp ; outr1 -- print contents of r1 as four hex digits ; outrl1 -- print contents of rl1 as two hex digits ; o outsp outsp: ; print a space on console ldb rl0,#' ' ; fall into outch outch: ; print a character from rl0 on the consoAlters: ; rl0, rl2. rh1 is altered by outrl1. ; outrl1: ldb rl2,#2 ldb rh1,rl1 jr outloop outr1: ; print contents of r1 onle push @rr14,r0 $1 inb rl0,chastat bitb rl0,#2 ; loop until xbuf empty jr z,$1 pop r0,@rr14 outb chadata,rl0 ret ; colo: .word ; id of cause of trap ufcw: .word ; user flag/control word upcseg: .word ; user pc segment no. upc: .word ; rrupt Request (operation complete) ; SA disk result-register bit fields sactype .equ 0CH ; Completion Type sacgood .equ 00H user pc upsapseg .word ; user prog. status area ptr. upsapoff .word endregs: nregs .equ [[endregs - regs] >> 1] lastseg .wor; Good completion sacsser .equ 04H ; Subsystem error sachelp .equ 08H ; Operator intervention req'd sacmder .equ 0CH ; Commad ; default seg for examine, etc loadseg .word ; default seg for downloading ecksum .word ehxtxt .word bpoints:.block nbptnd error sanrdy .equ 08H ; Drive Not Ready result ; ; Monitor data space -- resides in on-card RAM, segment 0, addresses 800s*6 ; list of breakpoint contents & addrs ; storage area for disk commands saioop: .word sahdcyl:.word sasect: .word vectors-FFF. data .data .abs data = 0 .block 0800H regs: .block 16*2 ; saved user registers ups: ; user program status uident.byte "Bkpt #", 0 atmess .byte " at ",0 uimess .byte "Unimpl Inst",0 prmess .byte "Priv Inst", 0 segmess .byte "Seg Trap",0 nmim et. ; trace .equ xxH ; access triggers NMI timer for 1-instr trace ; ; ; The Monitor ... ; monitor .code priv .abs monitor =4,monitor.bpmess ; report on which bp calr outmess ld r1,data`uident ; get sc inst from save area calr outrl1 ldk r8,#2 byte "Ok", 0 nrdymsg:.byte "Not Rdy", 0 crcmsg: .byte "CRC", 0 xxxmsg: .byte "xxx", 0 .even ; ; Routines to handle the variou; prepare pc-2 => bkpt instr jr report2 ; segtrap ; handles segment violations trap segmess ; nmi ; handles nonmaskable interrs traps and interrupts ; trap .macro ; argument: offset of message calr savestat lda rr4,monitor.!1 jr report .endm untrap ;upt trap nmimess ; nvi ; handles nonvectored interrupt trap nvimess ; consint ; handles console interrupt trap usrint ; ; Ro handles unimplemented instruction trap trap uimess ; prtrap ; handles trap that occurs when a privileged instruction occurs ;utines that support the trap/interrupt handlers ; savestat ; save status after trap: save all registers in the save area in RAM;nitor 2.1.1",0 ldmsg1: .byte " cksum, ", 0 ldmsg2: .byte " text errs. Seg ", 0 equmsg: .byte "Match", 0 dlmtab: .byte " ,-=.@ in user mode (unprivileged code) trap prmess ; break ; handles system calls which should be breakpoints calr savestat lda rr", semic, cr ; 8 allowed number-delimiters delims .equ 8 ; "8" should be "$-dlmtab", but for az bug ; SA disk messages okmsg: .init .equ 12H ; initialize (configure disk) csaclib .equ 05H ; recalibrate (seek heads to 0) csaseek .equ 04H ; seek csaread r interface registers rsacmd .equ 0FEFDH ; command register (low byte) (complemented) rsaparm .equ 0FEF9H ; parameter registe.equ 48H ; read multiple sectors csawrt .equ 58H ; write multiple sectors csafmt .equ 11H ; format cylinder csacmp .equ 4AH r (low byte) (complemented) rsastat .equ 0FEFDH ; status register (low byte) (complemented) rsarslt .equ 0FEF9H ; result regis; compare data (search equal) csavfy .equ 43H ; verify data (read & watch for CRC errors) ; SA disk status-register bit numberter (low byte) (complemented) rsaseg .equ 0FEF8H ; DMA segment number (high byte) rsaaddr .equ 0FEFAH ; DMA offset address (ws sabcbsy .equ 0 ; Command Busy sabpmfl .equ 2 ; Parameter Full sabrslt .equ 3 ; Result Register Full sabintr .equ 4 ; Inteord) rsarst .equ 0FEF6H ; addressing this resets controller & interface ; Disk controller commands (uncomplemented form) csa 0 ; monitor is in segment 0 monseg .equ [0 << 8] ; ldim .macro ; Load Immediate memory location -- fixes az bug!! .word 4D05H .equ [$+255]&0FF00H ; put interrupt, etc. vectors ; on next 256-byte boundary. topram .equ 400H*4 - 2 ; top of RAM for s ; LD (word) (DA, IM) .word 8000H, !1 ; destination address (data assumed seg 0!!) .word !2 ; immediate source value .endm itack ptr ; ; I/O port numbers ; chastat .equ 1BH ; SIO command/status byte chadata .equ 19H ; SIO data byte romon .equ 00H ;nitps .word 0 ; set up program status for .word monfcw ; reset initpc .word monseg .word init ; unimpps .word 0,monfcw, mo access enables ROM (if turned off) romoff .equ 08H ; access disables phantom ROM ; The ROM is automatically enabled on resnseg,untrap ; ps for unimplemented instr. privps .word 0,monfcw, monseg,prtrap ; ps for privileged inst. trap scps .word 0,monfc ands calr sacmdo ; initialize, calr sacmdo ; recalibrate, jr sacmdo ; seek (to track 32 for visibility). saboot: calr sa> " jr nz,nextcmd ldb rl0,#'>' ; load prompt to send calr outch ; print it calr outsp nextcmd: calr echo ; get comm. ainit lda rr4,boot.0 ; read into segment 1, address 0000 ldk r9,#0 ; start at cylinder 0, head 0, sector 0 ldb rh6,#6 ; read 6 sectors (1.0000-0BFF) ldb rh7,#csaread calr saio ldk r0,#0 ldctl psapoff,r0 ; reset PSAP to ROM area ldps boot.0 ; Jumpetch command byte comb rl1 ldb io`rsacmd,rl1 ldb rh1,monitor.1(r2) ; fetch parameter-count byte inc r2,#2 $2 ldb rl1,monito through new program's reset vector ; Note: the PSAP is that of the monitor ROM (address 0.0000) ; and the RR14 stack is in tr.0(r2) ; parameter byte inc r2 comb rl1 ldb io`rsaparm,rl1 ; send param $3 calr sastati bitb rl0,#sabpmfl ; await not parhe on-card RAM (near 0.0FFE). ; If the disk boot program has its own trap vectors and stack area, ; it should set them itself.am full jr nz,$3 dbjnz rh1,$2 ; loop for each parameter $4 calr sastati bitb rl0,#sabintr ; await interrupt request jr z saread: ldb rh7,#csaread jr saio0 sawrite: ldb rh7,#csawrt saio0: calr ranges ; enter starting addr, "word" count, secto,$4 calr sarslti ; read result andb rl0,#sactype ; test completion type ret z ; return if good ; else fall into sashosemble ldm @rr properly ld r9,#vectors ldctl psapseg,r8 ; reset PSAP for monitor's vectors ldctl psapoff,r9 jp @rr10 ; re ; Also save the PSW information and the user's PS area pointers. ldm data`regs,r0,#15 ; save R0..R14 popl rr10,@rr14 ; fetcturn. ; monnmi ; NMI from within monitor lda rr4,monitor.nmimess montrap: calr outmess jr getcom nonaddr ; Nonexistent memor ld r0,#[[vectors-upsapoff]>>1] ; r0 = # words to 0-fill ldir @rr6,@rr4,r0 ; clear PSAP, breakpoints, etc. ldk r3,#initps h our return address popl rr2,@rr14 ; pop saved trap-ID & FCW popl rr4,@rr14 ; ditto for saved PC resb rh4,#7 ; clear junld r5,#vectors ; prepare to copy vectors into RAM ldctl psapseg,r4 ; point our PSAP up there ldctl psapoff,r5 ldb rl0,#[endk bit from PC seg ldctl r6,psapseg ldctl r7,psapoff ; rr6 -> user's trap vector area (PSAP) lda rr8,data`[regs+[15*2]] ; poivecs>>1] ldir @rr4,@rr2,r0 ; copy up through consint (VI #0) lda rr2,rr4(#-4) ld r0,#[[256-endvecs]>>2] ldir @rr4,@rr2,r0 nt to save-area for ... ld r1,r15 ;;;;; ldm @rr8,r1,#7 ; user's R15, PSW, and PSAP. .word 1C89H, 0106H ; az bug -- doesn't as; fill VI vectors with copy of vector 0 ; ; Configure the SIO ldk r1,#9 lda rr6,monitor.siotbl ldb rl0,#chastat .word 3A62H, 0100H ; otirb @r0,@rr6,r1 -- az won't accept it! ; ldim vectors+nmivec+6, saboot ; NMI after RESET => disk boot ; lda rr4,mo calr echo lda rr4,disktbl jr cmdlook sainit0: calr sainit jr sashow sainit: ld io`rsarst,r0 ; send reset signal to contrnitor.initmess ; send initial message calr outmess getcom ; get a command from the console and execute it lda rr14,data`topraoller ld r0,#2000 $1 dec r0 ; 3 ms delay while controller resets itself jr nz,$1 ld r2,#saitab ; feed it the initialize commm ; reset stack pointer calr crlf ; output carriage return inb rl0,chastat bitb rl0,#0 ; if char already in buffer, skip " s+segtvec+6], nonaddr ; Seg Trap from monitor cmd ; should not destroy user-prog status ldim vectors+nmivec+6, monnmi ; Nwith S prefix) cmd "'I'", sainit0 cmd "'='", sashow cmd "'R'", saread cmd "'W'", sawrite cmd "'Z'", saboot .byte -1, -1 MI shouldn't either ld r5,r7 call @rr4 jr getcom cmd .macro .byte !1, !1 .word !2 .endm cmdtbl: cmd "'D'", display cmdcmderr: ; command error -- no such command, or any error in usage calr maycrlf ldb rl0,#'?' calr outch jr getcom ; sastuff:  "'X'", xamine cmd "'E'", enter cmd "'G'", go cmd "':'", hexload cmd "'B'", breakpt cmd "'R'", register cmd cr, getcom ;  ldb rl4,rh2 ; rl4 = cylinder number ldb rh5,#31 andb rh5,rl2 ; rh5 = sector number (r5 mod 32) ldb rl5,rh6 ; rl5 = sectorr #. add r10,#254 ; round word count to next whole sector ld r6,r10 ; stuff into rh6 calr saio jr sashow saio: ; disk I/ count ld r2,#saioop ;;;;; ldm monitor.0(r2),r3,#3 ; save command sequence in RAM for sacmdo .word 5C29H, 0302H, 0000H ; az buO routine ; Entry -- ; rr4 -> memory area, rh6 = sector count, r9 = starting sector #, ; rh7 = controller command (csareag -- ldm X(R) is wrong. ; fall into sacmdo sacmdo: ; Perform command sequence to which r2 points. ; If no error, returnd or csawrt). ldb io`rsaseg,rh4 ld io`rsaaddr,r5 ; set DMA address ld r2,r9 ldb rh3,rh7 ; rh3 = command ldb rl3,#4 ; rl3; else call sashow and abort. $1 calr sastati bitb rl0,#sabcbsy jr nz,$1 ; await not command busy ldb rl1,monitor.0(r2) ; f = param count .word 0C4E0H ; ldb rh4,#0E0H -- az won't accept this! andb rh4,rl2 rrb rh4,#1 ; rh4 = head+drive parameter alr getseg ; else get new pc to rr4 jr z,loadnew ; if a good segoff, load new pc decb rl0,#cr ; if cr, then use old pc jr crlf calr outmess ; print cause ldk r8,#0 report2: lda rr4,monitor.atmess ; get word " at " calr outmess ldl rr4,data`ur eq,exec calr cmderr ; (calr is shorter than jump) loadnew ldl data.[upcseg-regs](r8),rr4 ; install new upc exec: calr crlpcseg sub r5,r8 calr outrr4 ; print seg and offset jr getcom ; get next command init: ; executed when the processor is rf ldl rr0,data.[upsapseg-regs](r8) ldctl psapseg,r0 ldctl psapoff,r1 ;;;; ldm r0,data.0(r8),#16 ; install user's regs .word eset lda rr14,data`topram ; initialize stack ptr ldm data`regs,r0,#16 ; save regs (though probably junk) lda rr2,monitor.init5C81H, 000FH, 0000H ; az bug ldps data`ups ; load new program status: jump ; to user program ; ; hexload ; load an INTELy trap -- used only from within monitor. calr crlf calr outrr4 lda rr4,monitor.addrmsg ; don't save regs, just print msg jr ps lda rr4,data`ups ldk r0,#4 ldir @rr4,@rr2,r0 ; set up some initial PS clr @rr4 lda rr6,rr4(#2) ; clear following wordsmontrap report ; print message on console relaying cause of trap ; rr4 must have the address of the message to be printed calignore cr and lf cmd "'M'", movemem cmd "'$'", hexstat cmd SOH, binload ; Intel-format 8-bit load cmd "'S'", sastuff cmd "'nd echo it to console lda rr4,cmdtbl cmdlook: popl rr6,@rr4 testb rh6 jr mi,cmderr cpb rl0,rh6 jr ne,cmdlook ldim [vector='", compare cmd "'N'", intenb cmd "'I'", inport cmd "'O'", outport .byte -1, -1 disktbl: ; table of SA disk commands (all  adcksum gbyte: ; reads a byte into rl1 calr indig jr c,gflaw ldb rl2,rl1 slab rl2,#4 calr indig jr c,gflaw addb rl1,r lda rr4,data.0(r8) ldk r6,#1 calr showmod ret ; Mstartaddr-endaddr destination -or- ; Mstartaddr bytecount destinationl2 ; combine digits adcksum: addb rl7,rl1 ; add to checksum ret ; return, with CC set by checksum value hexstat: ; $ com ; -- moves a block of memory. movemem: calr ranges jr nz,$1 ldir @rr8,@rr4,r10 ret $1 ldirb @rr8,@rr4,r10 ret ; ; =addmand. Prints number of hex load errors, ; prints current hex loading segment, ; and allows you to change it. Hit CR if nr1-addr2 addr3[,] -or- =addr1 bytecount addr3[,] ; Compares memory areas ; (addr1 through addr2 or addr1+bytecount-1 ; agaot. ; "nnnn checksum, nnnn text errors. Seg nn " ld r8,#loadseg ldk r1,#0 ex r1,data.[ecksum-loadseg](r8) calr outr1 ldae %  $wRw !$bl %( xZ %%( N  w^w LR  & 6 % $w _   eD5l6̋,5# <&s)%M%" 7 $xWpex  " 7`#e-f&  7`#Ne Ne @0 & &  r eA! y   eu f  7!t Wt @`m 7#ww xd Ne&e T  wpw ^ DC˥a ˥z ! % ( x! %%( N@ % <@0 5 eN  ) eN   e@   w(w 3WpCex5%x B-7""@m7"u-eN   x d  xw_"w 2@e5Be l CeˋҔҕ @efw, which will abort. sashow: calr sarslti ldb rl1,rl0 ldb rl7,rl0 calr outrl1 calr outsp lda rr4,monitor.okmsg ; "Ok" ld hex format file lda rr10,gbyte jr intldr ; binload:; like hexload, but uses full 8-bit characters as data lda rr10,in8bit inb rl1,#sactype andb rl1,rl7 jr z,$1 lda rr4,monitor.nrdymsg ; "Not Rdy" cpb rl7,#sanrdy jr eq,$1 lda rr4,monitor.crcmsg ; tldr: ld r8,#loadseg ldb rl7,#0 ; rl7 = checksum = 0 ldb rh2,data.0(r8) ; default seg for loading call @rr10 ldb rh7,rl1"CRC" cpb rl1,#sacsser ; Subsystem error (probably CRC error) jr eq,$1 lda rr4,monitor.xxxmsg ; "xxx" -- something else is w ; rh7 = byte count call @rr10 ldb rh3,rl1 call @rr10 ldb rl3,rl1 ; r3 = address call @rr10 ldb rl6,rl1 ; rl6 = "typrong $1: calr outmess ; print whatever message orb rl1,rl1 ; test completion type again ret z ; return if good, calr getce" field indata: decb rh7 ; any bytes left? jr mi,indone ; not according to the count call @rr10 testb rl6 ; special type field? jr nz,inxseg ; yes, set segment number ld r0,@rr2 bit r3,#0 jr nz,$1 ; select byte to alter ldb rh0,rl1 jr $2 rr4,monitor.ldmsg1 calr outmess ldk r1,#0 ex r1,data.[ehxtxt-loadseg](r8) calr outr1 lda rr4,monitor.ldmsg2 calr outmess  $1 ldb rl0,rl1 $2 ld @rr2,r0 ; this is needed for on-board RAM. inc r3 jr indata inxseg: ; set loading-segment number d nore remaining cr/lf inc data.ecksum-loadseg(r8) ; else count checksum error jr flaw ; and ignore anything left gflaw: inc&61fA   @ @e7 1@ 1wfwwwfwA r15,#4 ; pop gbyte's return address flaw: inc data.ehxtxt-loadseg(r8) ; count a text error ldb rh0,rl0 ; save lastc for ignQ  OfA  ^ y   F y @0fA  @9 fA ore ldb rl0,#bell calr outch ; and ring bell ldb rl0,rh0 ; restore last char read ignore: ; ignore any text remaining on@e&7HwD7>@w47 $f@wwwf@www fecb rl6,#2 ; was type field = 2 ? jr ne,flaw ldb rh2,rl1 ; yes, accept segment number ldb data.0(r8),rh2 ; seg spec sh line decb rl0,#cr ret z calr echo jr ignore in8bit: ; reads a full 8-bit character into rl1 calr in8ch ldb rl1,rl0 jr ould be alone on line -- fall into indone indone: call @rr10 ; add checksum byte, test result jr z,ignore ; zero => OK. iginst corresponding area beginning at addr3) ; and reports "Match" or displays first difference. ; Trailing comma compares bytes; otherwise, compares words. compare: calr ranges $4: jr nz,$1 cpsir @rr4,@rr8,r10,ne jr $2 $1 cpsirb @rr8,@rr4,r10,ne $2 jr z,$3 lda rr4,monitor.equmsg ; "Match" calr outmess ret $3 pushl @rr14,rr4 sub r5,r6 ; back pointers up by 1 unit calr outrr4 ; print first address calr cshow ; show contents calr outsp calr outsp ldl rr4,rr8 sub r5,r6 ; backspace other% 7 y  "Ne % %& j -"%""7p %&  @ %V  om ; otherwise abort (calr is shorter than jp) sastati: ldb rl0,io`rsastat comb rl0 ret sarslti: ldb rl0,io`rsarslt com4  * B :  N w( _w  %e-&  " %%&   wb rl0 ret ; SA command tables, etc. saitab: ; initialize-command sequence .byte csainit, 3, 0F0H, 20H, 08H ; initialize  w &%M&  Ce lhWpDex 4&  w| w j  %.&  Wp .byte csaclib, 1, 00H ; recalibrate drive .byte csaseek, 2, 00H, 32 ; seek to track 32 (why not?) .even ; go: ; executCexD  w4 w " #DC ̥̋/C ̥ḁze @=w w C&ĔҔe a user program ; syntax: ; G -- continue from last user pc ; Gseg.offset -- define new pc to go to ld r8,#regs cwf@w w fw JA 7 fAW,f B@ 8 @ $& %_" 5 @e5e % 55 ",a" %e, ,) r<R r< r<R r< rWtC` re rwF L  L!7 L%n BRf@wwwf @fA w,w"e"w"ew"~@lw"vv    0!X 7 )ww &ԔAA WpCe6&ԔԔԔ BeWpCeLԔԔAlewi &@t`e w N  ww DeL@40 & n  wԔ& l ed& l ed& l ed& l e@ & l &wvw fA r nw\mw F/%J %K  t5 t5N  5N  5  B-B-%B-B-%D % A r  r e0@ԕ A r e0@w @& BF7Ff@  & n   w2w "DC%: Le`m e rfww p@&f L%j`TM:/CSTCDTDay Mon 00 00:00:00 1900 SunMonTueWedThuFriSatJanFebMarAprMayJunJulAugSepOctNovDecroomWrite errorNo room in directoryError in deleteCrunch not yet implementedbadjanfebmaraprmayjunjulaugsepoctnov/devdecnullxdskcodetextdatainfounk6volume: %s has %d files, %d blocks, %d free, largest free = %d %15s %3d %2d %3s %2d  %5s %3d %3d %3dFile not found: file not found: Cannot create unix file: : Cannot create d~ or x f eD cR s l u r Dz On X(null)' %ew l"6 < e5`4 1ʕ 55 um Ne > 5 Ne& > ʥ   &w w &&  w w d ~xPN~ & . e xe*Wpex!=t"7  y Ne bF f 5 >f& %0 %" %EE &tE&&&e : & . e && & . e p w w  , "f %%,w _" w ~wDe   % p wd7 7 ׯ- N  HN& %w w _& N  N& %_" "X X_ LNef  N w7  .weNB J ӕ-Z V o^ xU d @ w r f e0 %_&f  !!! % !_"%& h _h!"Ne %WKӕ %R& %w  0   ww Z Rpm 7 >md (k :̥-+ ̋'Um Um7 4Um& & _"5 Ne % % % A rf5`  %ӕ ӕ@e % N< ̋ԥ/wx w b DCԤ ̥/  w6 w $ `Nef&   ԕ- k  vA W  ~e0fv  O M ҋ D~C b NJ  K@E%@ BDNe r &fe , % r  r Wtu` =f  v ӕ0 (f vLv Le0 9eJD <6 7&wVef d %@e =f H wn $w X _Z DtWtE@`5u-u- _V &  m   p ~  p   p ~ w7   0   Wp `e0eӕ? ruE%@ 55>A vu%f %@ `@ a  ^f ,P   @f l '7 Z 'PH-B:fw w f `_ fo7HN_ RfoD_<_-6_._f@w fwwXwf@ x^ .)",r@.) .)$$ttyЋ7@ 6rw6r@f)wfw@e7^wffwX7` fwwdw4f@wwjw@  P`Hm` bad usage2369:1359tX\dtX\XXj60Nf@wrwnpw fAW @wL fhq1hq7@ 5 enw,v 5& w& bdAEIMQUY]aeimquz   "  0 /dev/rx0tCan't access Can't rewrite directorynot a Tera_L&_H&_D&_@&_<&_8&_4&_0&_,&_(&_$&_ &_&_&_&_&k-format directoryFile already exists: I assume you want me to read from filesCan't read unix file: No room for Not enough Y & 6 % w j_2%@r 7`X%@n   70x  w w _N 5 "N H N& %_ Z" %x&  <" 8"2N  (X "  &  %t77lh z   f   r  ef  N& %_Nef 55 @! e  t55 N 5 N&  7" y7 m% 6 vwb_"w N l  & & % b%w$ 5 lfe& `% 7~Hl  w w 7 2l 7&l7 l,l7 l7l#l Bnkԋw 0 7  i%X%l-gyn&&& ee w<w *  6 7i ̋7 k 7k̋  k7 k7 kkwtw b: B%! Z Z  knk  0 6N j  ~e w w  >i  -2i 7 &iw w ? gNef b N ԝjk Z7 y ww [ Deå>,k "k  kԝk  å>!fe  @-s`ewx_ w `_ pL%7 hL@V %    r    f %@E `@ a l H l Nf %=@w: _4 w " = - r7$LA 7rLL;7a L  L L "  "   " @ %Kt NK* f H *eA r& %fA rWtaf d %5 ww _ t & e@KwpK@t ewtw b uNe` $ wRw < CD w2w  BNc - Ni  l H l_ X%l K--a3JeN $ @@mV'DC ww ~waDea  a % w7 a7 aׯa- a awa7 a .wxaee%lX-\a Na r&5u-u-Vu-&CKe& d %@-s w7N[FXbcdhlqx >\`bjpx/d_ &_&_&_f& f@wL|w f & w }f@wev/rmt1!%s: Cannot open %l-block file system. Type help for help. commands: x file ... extracts named files to files of the wwf r@f&qCB  ԕ- q e0fv   vA W same name or to standard output if redirected. cd directory sets the 'current directory', initially '/'. ls [-lsid] [-r[N]] fi ~fA w,zw"te"w"jew"`@lw"XAlewK &@t`e w w,^le ... like standard ls, prints information about files. Using '-rN' gives directory listings recursive to depth N, or unlw(^w^^w @& BFw B 5  ʥ ʥ ʥ- ʥ9 Wp @@`eʥ0   '5 Neffe , %5Nf b%@-N   wF &w 0 _<Nef b 7"  &  % fe L 7 fe L 7   jNe w:(w $  zj N  \5fhN 5Ph@E%@#*N@&  & 5h@tAeWtE 7 'd  x:    T    B mwBw 0' N tl ww  n& %Rjww ' N j 8j!*j N fff e  j w /* -i or just - => use standard input */ inf = 0; } else inf = tryopen(*argv, 0); } nlack = 0; if(inf >= 0) { k = sizeof filb; while((n = read(inf, &filb, k)) > 0 && (k =- n) > 0) ; if(n < 0) die("Error reading input"); if(k > 0) { p@`/ N3 @E%@ .Nf B wX w B *5 N7 5 Nefrintf("only %d bytes read\n", sizeof filb - k); if(!entire) nlack = k; } } /* Now verify rom, as many times as requestef `% Nef T  w w :Db ̥/ ̋*5 Nefe `% Ne& " zxt boot.b -xo pboot | down -s0 1000- >boot.down rtio w /dev/rx1t/boot  Dv x`ӕ0 (f vLv Le0 9e>`8` 0`*` 7`wVe&  m_ _ ~    ~ w7 _ _ _0   _Wp `e0eӕ?f_ ,_P _ |_ @_len = 2048; /* expected total length */ int crc {0}; /* accumulated checksum from current line */ char blankvalue = -1; /* valuimited depth if N omitted. q quits this program !unixcommand calls the Shell to execute that command. The shell's '>' and '>>' e to put in uninitialized bytes */ char abortonerr {0}; /* abort on error flag */ int ep_id; /* fid on eprom progrmmer */ int i_constructs work. %s: not a directory : %s: cannot create #%l %d/%d%c; /bin/shsh-t!No /bin/sh! copyfile: bad inode %d Efid; /* hex input field */ int line; /* number of lines of hex input */ /* * NOTE! * ep[] needs to be word aligned for all prrror writing block %d lsfile: bad inode %d %3d. d %4s %6s %d %s %s: %s not found dent: Bad inode %d ind [%l]getblk:ogram options to * work correctly. 'dummyvar' insures this, so dont move it */ char ep[EPSIZE]; /* output array */ main(ar bno %d out of range !Error reading tape !Tape record size (%d) not a whole number of blocks! Found only %d bytes on tape, %d expected, at bno %d doxf*ecsl&u8rJDOX(null)fo lflag++; break; case 'e': entire++; break; case 'v': vfycnt = atoi(++p); break; case 'i': case '\0': 0 %ewj  /* rom -- program to read/compare roms * Usage: rom [ -l ] [ -vN ] [ -b | -i | file ] * * with no arguments, transfers the egister int k; register char *p; int romf, inf; int n, nlack, diffs; if(argc < 2) { romf = tryopen("/dev/ep"); if(read(entire rom contents * to standard output. * -b : test for blank rom (all 1's) * -i : compare rom with standard input, e.g. frromf, romb, sizeof romb) != sizeof romb) die("error reading /dev/ep"); write(1, romb, sizeof romb); exit(0); } inf = -1om a pipe. * file:compare rom with given file * * -l : as in "cmp -l", lists all differences * instead of just the first. *; for(k = ROMSIZE; --k >= 0; ) filb[k] = -1; while(--argc) { p = *++argv; if(*p == '-') switch(*++p) { case 'l':  -vN : verifies (rereads and tests the rom) N times. * (otherwise, the rom is only tested once) */ #define ROMSIZE 1024 /* wo: loop echo $L$L--------------------------------------------------------------------------------$L if $1x = x exit echo ' '$1$L } else printf((inf<0) ? "Blank" : "Matched"); putchar('\n'); if(--vfycnt <= 0) break; /* done verifying */ close(romf);  cat $1 shift goto loop ed */ for(;;) { romf = tryopen("/dev/ep"); if(read(romf, romb, sizeof romb) != sizeof romb) die("error reading /dev/ep" } } tryopen(name) char name[]; { register int f; if((f = open(name, 0)) < 0) die("%s: cannot open", name); return(f); } ); if((k = nlack) > 0) { p = &romb[ROMSIZE]; do *--p = -1; while(--k); } diffs = 0; for(k = 0; k < ROMSIZE; k++) { die(msg, param) char *msg; { printf(msg, param); putchar('\n'); exit(-1); }  if(romb[k] != filb[k]) { diffs++; if(lflag) printf((inf<0) ? "%03xx: %04x\n" : "%03xx: %04xr %04x\n", k*2, romb[k], filb[k]); } } if(diffs > 0) { printf((inf<0) ? "%d nonblank words" : "%d differences", diffs); S 1 #else #define PROGRAMMER "/dev/ep" #define MAXPASS 100 #endif #define READ 0 #define WRITE 1 #define MAXK '4' #define KSIZ# /* #define DEBUG 1 /**/ /* #define TEST 1 /**/ /* * burn - burn a 2708 EPROM * calls on the ep-11, a PZ special, to burn theE 1024 #define ERROR -1 #define EPSIZE 8192 #define BUF_SIZE 512 #define END_ROM (&ep[EPSIZE-1]) #define odd(k) (k&01) #define K ROM * burn [-i filename] [[-b] [-w] [-kn] [-a] [-s size (bytes)] * where standard input is the default intel HEX format sourcBYTE 1024 #define KWORD 2048 #define MAX_LIN_LEN 80 #define RAW 1 #define HEX 0 int epmode; /* mode: BYTE,WORD */ char bothbe, * b/w specifies byte/words to be written, kn specifies to write the * nth k of bytes/words into the eprom, -a flag sets aboytes {1}; /* program both bytes, or even/odd bytes only? */ int rawdata {0}; /* flag for whether writing hex or rawdata */ char rt on errors and * size the number of bytes to read in. */ #ifdef TEST #define PROGRAMMER "/usr/chris/epout" #define MAXPASrds in a pair of 2708 roms */ int romb[ROMSIZE], filb[ROMSIZE]; int lflag, entire, vfycnt; main(argc, argv) char **argv; { r! ailable char in input_buffer */ char input_buffer[512]; /* hex input buffer */ int len; /* length come across so far */ int read~.> & 6 % Fw 6_% C-_$ @m̥-#%& 77 ̋{ if(argv[i][0] == '-'){ switch(argv[i][1]){ case '\0': /* standard input input (no its right.....) */ /* standard i     o  xB ?7  @m5   7y   B %nput contains the input data */ i_fid=0; break; case 'r': /* rawdata input, vs. intel format hex */ rawdata=RAW;   %  t B  )eD̥-t te &      case 'i': /* set input file to other thatn stdi */ if(++i!=argc){ i_fid=safe_open(argv[i],READ); }else{ pri   -0  w_"w DCԤ ˋ ww _:te5 D ntf("no input file name given\n"); error++; } break; case 's': /* set size of input data (in bytes) */ read_acts, 'o' to std output (else to `segment.oz'), 't' lists segments. If no flags, '-xt' assumed. If no segments named, all are s   Wp `e0eӕ?f ,P   @f   7(| elected.%s: Cannot open%s: not a z8000 object fileToo many segments for me (%d)-%s: not a segment%s: cannot createerror wr rj-d\f@w fww wfww wf@wwiting %s%c %4xx (%4d.) %.8s error reading %s-%s truncated (warning only)Pd*oxrfecs\l|urD&OX wtf@ww wR f@wvwr w.f @@& BF(null) 7bFxrUsage: zxt file [-xot] [segment ...] -- extracts/lists segs in a z8000 obj file 'x' extrls [-lsid] [-rN] file ... * acts more or less like ls. The "-r[N]" option allows * recursive directory listing to depth N (oddonly {0}; /* write even or odd? */ int sttyv[3]; /* vector for stty of the eprom programmer */ char *writeaddr; /* address tinfinite if omitted). */ int tape; /* file descriptor for mag tape file */ /* tape positioning stty calls: */ #define REWINo start write at */ char lbuf[MAX_LIN_LEN]; /* the hex line holder */ char *lbuf_index; /* pointer into the current line */ charD 5 #define FWDSP 3 #define BKSP 4 int debug; int ninodes; /* number of inodes in file system */ unsigned nfsblks 2 ; /* number *where; /* pointer into lbuf */ int nchars; /* number of chars left in input buffer */ char *i_b_index; /* pointer to next av of blocks */ int cdir 1; /* i-number of "current directory" */ /* buffering */ char tapebuf[32*512]; int tbufpos; /* begin" buf[512]; } cache[NSLOTS]; int cqual; /* current buffering-qualifier */ struct slot *rover &cache[0]; /* roving cache-slot pointer */ char tempbuf[512]; /* user interface */ char *word, *peekword; char lastc; int outfile 1; /* file descr for (possibntf("only %04d bytes read\n",nchars); if(abortonerr) croak("in main switch"); } }else{ printf("size (bytes) outgc,argv) int argc; char *argv;{ /* need to be able to write out straight binary data */ init(argc,argv); switch(rawdata){ ca of range\n"); croak("main"); } break; default: printf("program[mer] error\n"); croak("defaulted in main switch"); se HEX: nchars=safe_read(i_fid,&input_buffer[0],BUF_SIZE); if(!nchars){ printf("input file empty\n"); croak("init"); } prog(); flush(); } init(argc,argv) /* * initialize burn program vars..... */ int argc; char **argv;{ register int i; /* } i_b_index=input_buffer; do{ line++; }while((get_line()) && (lbuf[0]==':') && ((process_line())==1)); break; case  counter */ register char c; /* k number */ register int error; /* error occurred, abort at end */ c= 0; for(i=1; i0)){ nchars=safe_read(i_fid,&ep[0],read_len); if(nchars != read_len){ pri   % wV7 7 ׯ-  w7  .we< B J ӕ-| x o^ xUbu  l 5`u`u e A@vf~ %fEh % 2] ,+ % a4 d b w r f e0&   ԕ- k  vA W  ~e0fv  %  . o z 4   5   D% B  f $%!  O M  ҋ D~C t  z v ӕ0 (f vLv Le0 9e  5 N  te R- ew&_w NfX %L  D-lf ^X 7HwVe&  m, * ~    ~ w7   08  ww & N @%- Nf     ĥ- Fww v~wDe#include "/usr/sys/ino.h" /* extape -- extract file(s) from UNIX file system image * on magnetic tape. Runs interactively. * Commands have the form * cmd param ... [ > file or >> file or | unixcommand ] * available cmd's are: * b nnn ... * extractning tape rec # of contents of tape buf */ int trecsize; /* record size of tape (in blocks) */ int rewindable; /* flag: may rewind tape to beginning of file system */ #define NSLOTS 10 struct slot { unsigned bno; char worth, qworth; int qual; char # list() { register struct slot *p; if(getword() != 0) { debug = 0; error++; return; } debug = 1; for(p = cache; p < &c*bufp; cqual++; if(iget(inum, &ino) < 0) { err("copyfile: bad inode %d\n", inum); return(-1); } bno = 0; while((n = ge numbered block(s) from file system, * write to standard output or whatever. * x file ... * extract named file(s), write toache[NSLOTS]; p++) { printf("#%l %d/%d%c; ", p->bno, p->worth, p->qworth, (p->qual==cqual) ? 'y' : 'n'); } putchar('\n files of the * same name or to standard output if redirected. * cd directory set "current directory" on tape file system *  files of the same name\n\ or to standard output if redirected.\n\ cd directory sets the 'current directory', initially '/'.\n Cannot open\n", tapename); if(rewindable) tapecmd(REWIND); super = getblk(1, 0, 0); ninodes = super[0]*16; nfsblks = super[\ ls [-lsid] [-r[N]] file ...\n\ like standard ls, prints information about files.\n\ Using '-rN' gives directory listings r1]; printf("%l-block file system. Type help for help.\n", nfsblks); setexit(); signal(2, &reset); for(;;) { switch(*getwecursive to depth N,\n\ or unlimited depth if N omitted.\n\ q quits this program\n\ !unixcommand calls the Shell to execute tord()) { case 'b': copyblocks(); break; case 'x': extract(); break; case 'l': list(); break; case 'c': cd(); break; cahat command.\n\ The shell's '>' and '>>' constructs work.\n\ "); break; } error = 0; if(outfile > 1) { close(outfilese 'd': debuglist(); break; case 'q': exit(0); break; case 'h': printf("\ commands:\n\ x file ... extracts named files to= 0; return(0); } word = p; while(*p != 0) p++; if(error) { error = 0; word = 0; } return(word); } getline() { regetword() == 0) cdir = 1; else { if((inum = find(word)) != 0) { index = 0; if(dent(inum, &index, &tempbuf) != 0) { /ister char *p; again: printf(": "); flush(); if(getchar() == '!') { unix(0); await(); goto again; } skipblanks(); * it's a plausible directory */ cdir = inum; } else err("%s: not a directory\n", word); } } } char line[100]; char * if(lastc == '\n') goto again; p = &line[0]; for(;;) { switch(lastc) { case '\n': goto eoln; case ' ': *p++ = 0;  getword() { register char *p; if(error) return(word = peekword = 0); if((p = peekword) != 0) { peekword = 0; return(w skipblanks(); continue; case '>': lookout(); continue; /* pipes don't work case '|': pipeout(); continue; ord = p); } if((p = word) == 0) { getline(); p = &line[0]; } else { p = word; while(*p++) ; } if(*p == 0) { word '); } unix(stdinput) { register int pid, wpid; if((awaiting = fork()) == 0) { if(stdinput > 0) { close(0); dup(stdinurn(lastc); } err(msg, p1, p2, p3) char *msg, *p1, *p2, *p3; { extern int fout; flush(); fout = 1; error++; if(*msg == '!put); } execl("/bin/sh", "sh", "-t", 0); err("!No /bin/sh!\n"); } } await() { register int wpid; if(awaiting != 0) { ') { /* ! signals fatal error */ error = -1; msg++; } printf(msg, p1, p2, p3); flush(); if(error < 0) exit(-1); } debug while((wpid = wait()) != awaiting && wpid > 0) ; awaiting = 0; } } copyfile(inum) { struct inode ino; int bno, n; int $ o++; } } lsfile(inum, name) char *name; { struct inode ino; register char *smsg; if(iget(inum, &ino) < 0) { err("lsfile: /* copy the rest of the line to the pipe, */ getchar(); /* for the shell to read */ write(outfile, &lastc, 1); } while(las bad inode %d\n", inum); return; } /* ordinary file listing */ if(lsflags&IFLAG) printf("%3d. ", inum); if(lsflags&LFLAG) tc != '\n'); unix(pipef[1]); } #endif skipblanks() { while(lastc == ' ') getchar(); } getchar() { read(0, &lastc, 1); ret{ smsg = (ino.i_mode&IFMT) == IFDIR ? "d %4s " : "%6s "; printf(smsg, locv(ino.i_size0, ino.i_size1)); } if(lsflags&SFLAG) printf("%d ", (ino.i_size0<<7) + (((ino.i_size1 + 511) >> 9) & 0777)); printf("%s\n", name); if((ino.i_mode&IFMT) ==ly redirected) std output */ int error; int awaiting; /* pid for spawned child processes */ int lsflags; int recursion 1; #de IFDIR && recursion > 0 && name[0] != '.') lsdir(inum, name); } lsdir(inum, name) char *name; { int index; struct diren); outfile = 1; } await(); } } copyblocks() { register unsigned bno; register char *p; register int *bp; while((p fine LFLAG 01 #define SFLAG 02 #define IFLAG 04 struct dirent { int inum; char dname[14]; } ; char *getword(); char *getblk= getword()) != 0) { bno = atoi(p); bp = getblk(bno, 0, 0); write(outfile, bp, 512); } } extract() { register char *p; (), *taperead(); main(argc, argv) char **argv; { register int *super; register char *tapename; extern reset(); rewindable register int inum; while((p = getword()) != 0) { if((inum = find(p)) != 0) copyfile(inum); } } list() { register char = (argc <= 1 || *argv[1] == 'r'); tapename = (argc > 2) ? argv[2] : "/dev/rmt1"; if((tape=open(tapename, 0)) < 0) err("!%s: *p; register int inum; register int listed; extern int fout; flush(); fout = outfile; listed = 0; lsflags = 0; recursion = 1; cqual++; while((p=getword()) != 0) { if(*p == '-') { while(*++p) switch(*p) { case 'l': lsflags =| LFLAG; bre*/ case '\\': *p++ = getchar(); continue; default: *p++ = lastc; getchar(); } } eoln: *p++ = 0; *p = 0; }ak; case 's': lsflags =| SFLAG; break; case 'd': recursion = 0; break; case 'i': lsflags =| IFLAG; break; case 'r':  lookout() { char fname[40]; register char *p; register char c; c = getchar(); p = &fname[0]; if(c != '>') lastc = c; s recursion = atoi(p+1); if(recursion==0) recursion = 9999; } } else { listed++; if((inum = find(p)) != 0) kipblanks(); while(lastc != ' ' && lastc != '\n') { *p++ = lastc; getchar(); } *p = 0; if(c == '>') { /* >> file */ oulsfile(inum, p); } } if(listed == 0) lsdir(cdir, 0); flush(); fout = 1; } cd() { register int inum; int index; if(gtfile = open(fname, 1); if(outfile > 0) seek(outfile, 0, 2); else outfile = creat(fname, 0666); } else { /* > file */ outfile = creat(fname, 0666); } if(outfile < 0) { error++; outfile = 1; printf("%s: cannot create\n", fname); } } #tmap(&ino, bno, &bufp)) > 0) { if(write(outfile, bufp, n) != n) { err("Error writing block %d\n", bno); return; } bnifdef piping /* commented out for now -- doesn't work */ pipeout() { int pipef[2]; pipe(pipef); outfile = pipef[0]; do { % lot; int cheapest, slotcost; if(debug) printf(" [%l]", bno); if(bno < 0 || bno >= nfsblks) { err("getblk: bno %d out of raeapest = slotcost; cheapslot = slot; } } while(slot != rover); if(cheapest <= qworth) { /* worth cacheing ? */ slonge\n", bno); clrbuf(&tempbuf, 256); return(&tempbuf); } for(slot = &cache[0]; slot < &cache[NSLOTS]; slot++) { if(slot-t = cheapslot; slot->bno = bno; copybuf(bp, &slot->buf, 256); found: if(slot->qworth < qworth) slot->qworth = qwort>bno == bno) { if(slot->qual != cqual) slot->qworth = 0; goto found; } } bp = taperead(bno); if(worth + qworth > 0) {h; if(slot->worth < worth) slot->worth = worth; slot->qual = cqual; rover = slot; return(&slot->buf); } } return cheapest = 9999; slot = rover; do { if(++slot >= &cache[NSLOTS]) slot = &cache[0]; slotcost = (slot->qual==cquap++ != '/') ; } return(inum); } match(pathname, dname) char *pathname; char *dname; { register char *p, *d; register int litem for a path name, * starting at cdir if appropriate. * Return the i-number or 0 if not found. */ find(pathname) char *pathmit; limit = 14; p = pathname; d = dname; while(*p++ == *d++ && --limit); return(((*--p == 0 || *p == '/') && (*--d == 0))name; { register char *p; register int inum, idir; int index; struct dirent entry; p = pathname; inum = cdir; if(*p == ' || limit == 0); } /* Returns a directory entry. Initialize index to 0, * and pass its address as indexp. This routine wil/') { p++; inum = 1; } while(*p != 0) { idir = inum; index = 0; while((inum = dent(idir, &index, &entry)) != 0) il return * the i-number of the next file in the directory, or 0 * if none exists. It copies the entry into the structure to wt entry; char trail; trail = 0; /* trailing 0 for directory entry name */ if(name != 0) printf("%s:\n", name); recursion--;f(match(p, &entry.dname)) break; if(inum == 0) { printf("%s not found\n", pathname); break; } while(*p != 0 && * index = 0; while(dent(inum, &index, &entry) != 0) lsfile(entry.inum, &entry.dname); recursion++; } /* Search the file sys(0); nbytes = ip->i_size1 % 512; } worth = (ip->i_mode&IFMT) == IFDIR ? 1 : 0; if(ip->i_mode & ILARG) { /* large file */  dp++; } while(--nleft); } *indexp = index; clrbuf(dentp, 8); return(0); } /* getmap -- reads block bno of file ip, seti = bno / 256; if(i >= 7) { /* huge file */ if((b = ip->i_addr[7]) != 0) { bp = getblk(b, worth, 2); b = bp[i-7]; s bufpp to point to it, * and returns the number of bytes read, 0 => EOF. */ getmap(aip, bno, bufpp) struct inode *aip; unsign } } else b = ip->i_addr[i]; if(b != 0) { if(debug) printf(" ind"); bp = getblk(b, worth, 2); b = bp[bno % 256]; ed bno; char **bufpp; { register struct inode *ip; register int b; register int *bp; unsigned i, nfblks; int nbytes, worth; } } else /* small file */ b = ip->i_addr[bno]; if(b == 0) { clrbuf(&tempbuf, 256); *bufpp = &tempbuf; } else *bu ip = aip; nfblks = (ip->i_size0<<7) + ((ip->i_size1>>9)&0777); nbytes = 512; if(bno >= nfblks) { if(bno > nfblks) returnl) ? slot->qworth : slot->worth - (cqual-slot->qual)/4; /* fudged aging function */ if(cheapest > slotcost) { ch&  and return * the address of a buffer containing it. * It maintains a buffer cache, with each buffer having two * priorities  - tbufpos) != 0) { tbufpos =+ delta; if(delta < 0) { if(tbufpos == 0 && rewindable) tapecmd(REWIND); else do tape(bp); } /* taperead -- find a block on tape. If it is already in * the tape buffer, return its address; otherwise position *cmd(BKSP); while(++delta <= 0); } else while(--delta > 0) tapecmd(FWDSP); n = read(tape, &tapebuf, sizeof tapebuf); if the tape and read a record. */ char *taperead(bno) unsigned bno; { register int delta, n; if(trecsize == 0) { /* nothing re(n != trecsize*512) printf("Found only %d bytes on tape, %d expected,\ at bno %d\n", n, trecsize*512, bno); } return(&tapead yet */ tbufpos = 0; n = read(tape, &tapebuf, sizeof tapebuf); if(n < 0) err("!Error reading tape\n"); else if(n % 512buf[(bno - tbufpos*trecsize) * 512]); } tapecmd(cmd) { int svec[3]; svec[0] = cmd; stty(tape, &svec); } clrbuf(at, words)  != 0) err("\ !Tape record size (%d) not a whole number of blocks!\n", n); trecsize = n / 512; } if((delta = bno/trecsize:;< =>>>?>A>@>A]UUE=A"AAAAB~AA~AA~C>A@@@A>D~AAAAA~E~@@|@@~F~@@|@@@G>A@OAA?HAhich * dentp points. */ dent(idir, indexp, dentp) int *indexp; struct dirent *dentp; { int bno; register int index, nleft; AAAAAI>>JA>KABLpLBAL@@@@@@McUUIIAANaQQIEECO>AAAAA>P~AA~@@@Q>AAAI>R~AA~BAAS>A@>A>TUAAAAAA>VAA"struct inode ino; struct dirent *dp; if(iget(idir, &ino) < 0) { err("dent: Bad inode %d\n", idir); return(0); } if((ino"WAAIII6XA""AYA"Z [\ ]<<^*** a>?A?b@@@~AA~c>A@@>d?A.i_mode&IFMT) != IFDIR) return(0); index = *indexp; while((nleft = getmap(&ino, index/32, &dp) / sizeof(*dp)) > 0) { dp =+ iA?e>A@>f! p gAAA>p~AA~@@q?AA?r~A@@@ndex % 32; do { index++; if(dp->inum != 0) { *indexp = index; copybuf(dp, dentp, 8); return(dp->inum); } , 044, 030, 045, 0102, 075, 0, '*', 0, 030, 030, 010, 0, 0, 0, 0, /* ' */ '(', 04, 010, 020, 020, 020, 010, 04, 0, ')', 020, 01or "prices" : one global price and one * local (qualified) price. The global price applies over all time; * the local applies0, 04, 04, 04, 010, 020, 0, '*', 0, 010, 052, 034, 052, 010, 0, 0, '+', 0, 010, 010, 0177, 010, 010, 0, 0, ',', 0, 0, 0, 0, 0, 0fpp = getblk(b, worth, worth); return(nbytes); } iget(inumber, ip) struct inode *ip; { register int *bp; if(inumber <= 0 | only while "cqual", the current qualifier, * matches the "qual" element of the buffer. * This is for marking buffers as impor| inumber > ninodes) { clrbuf(ip, 16); return(-1); } inumber =+ 31; bp = getblk(inumber/16, 2, 2); copybuf(bp + (inumbertant during one * transaction, but less important afterwards. * "Worth" is the global price requested, and "qworth" the local %16) * 16, ip, 16); if((ip->i_mode & IALLOC) == 0) return(-2); return(0); } /* getblk -- read a file system block into memoryone. */ char *getblk(bno, qworth, worth) unsigned bno; { register char *bp; register struct slot *slot; struct slot *cheaps' 30, 030, 010, '*', 0, 0, 0, 0177, 0, 0, 0, 0, /* - */ '*', 0, 0, 0, 0, 0, 030, 030, 0, /* . */ '/', 0, 02, 04, 010, 020, 040, 0, 0, '0', 076, 0101, 0105, 0111, 0121, 0101, 076, 0, '1', 010, 030, 010, 010, 010, 010, 034, 0, '2', 076, 0101, 01, 01, 076, 0100, 0177, 0, '3', 076, 0101, 01, 016, 01, 0101, 076, 0, '4', 06, 012, 022, 042, 0177, 02, 02, 0, '5', 0177, 0100, 0176, 01, 01, 10, 010, 010, 010, 010, 0, 'U', 0101, 0101, 0101, 0101, 0101, 0101, 076, 0, 'V', 0101, 0101, 042, 042, 024, 024, 010, 0, 'W', 010101, 076, 0, '6', 076, 0100, 0136, 0141, 0101, 0101, 076, 0, '7', 0177, 0102, 04, 010, 070, 020, 020, 0, '8', 076, 0101, 0101, 01, 0101, 0111, 0111, 0111, 066, 024, 0, 'X', 0101, 042, 024, 010, 024, 042, 0101, 0, 'Y', 0101, 042, 024, 010, 010, 010, 010, 0076, 0101, 0101, 076, 0, '9', 076, 0101, 0101, 0103, 075, 01, 076, 0, ':', 0, 030, 030, 0, 030, 030, 0, 0, ';', 0, 0, 030, 030, , 'Z', 0177, 02, 04, 034, 020, 040, 0177, 0, '[', 036, 020, 020, 020, 020, 020, 036, 0, '\\', 0, 040, 020, 010, 04, 02, 0, 0, ']0, 030, 030, 010, '<', 04, 010, 020, 040, 020, 010, 04, 0, '=', 0, 0, 076, 0, 076, 0, 0, 0, '>', 020, 010, 04, 02, 04, 010, 020,', 074, 04, 04, 04, 04, 04, 074, 0, '^', 0, 010, 034, 052, 010, 010, 010, 0, '*', 0, 0, 0, 0, 0, 0, 0, 0177, /* _ */ '*', 0, 01 & 6 % w bDe@ @m!U-K ?F  ^78%2*;7 "8  int *at; { register int *t; register int n; if((n = words) > 0) { t = at; do *t++ = 0; while(--n); } } copybuf(from, t^5@  %!   ^7F%@87P f7 y  ew w _&o, words) int *from, *to; { register int *f, *t; register int n; if((n = words) > 0) { f = from; t = to; do *t++ = *f+% _e-x p ldu@ @å%F > : åaåz C +; while(--n); } } CËve-Wp AN@Wp aAf , %    %  %  s>@>>t p !uAAAA>vAA"wAAI*xccyA!>z { 8 |}~*D*-ilsuwFHdj( r chars[] { ' ', 0, 0, 0, 0, 0, 0, 0, 0, '!', 010, 010, 010, 010, 010, 0, 010, 0, '"', 0, 024, 024, 024, 0, 0, 0, 0, '#', 024, 024, 0177, 024, 0177, 024, 024, 0, '$', 010, 076, 0110, 076, 011, 076, 010, 0, '%', 0, 062, 064, 010, 026, 046, 0, 0, '&', 0, 030w7   0   Wp `e0eӕ?fl ,bP X R @f 60, 010, 076, 0, 'J', 01, 01, 01, 01, 01, 0101, 076, 0, 'K', 0101, 0102, 0114, 0160, 0114, 0102, 0101, 0, 'L', 0100, 0100, 0100,   7$ H - f   7  7 7 fwbw 0, '?', 0, 076, 0101, 01, 076, 0, 010, 0, '@', 076, 0101, 0135, 0125, 0125, 0105, 075, 0, 'A', 034, 042, 0101, 0101, 0177, 01010100, 0100, 0100, 0177, 0, 'M', 0143, 0125, 0125, 0111, 0111, 0101, 0101, 0, 'N', 0141, 0121, 0121, 0111, 0105, 0105, 0103, 0, ', 0101, 0, 'B', 0176, 0101, 0101, 0176, 0101, 0101, 0176, 0, 'C', 076, 0101, 0100, 0100, 0100, 0101, 076, 0, 'D', 0176, 0101, 01O', 076, 0101, 0101, 0101, 0101, 0101, 076, 0, 'P', 0176, 0101, 0101, 0176, 0100, 0100, 0100, 0, 'Q', 076, 0101, 0101, 0101, 01101, 0101, 0101, 0101, 0176, 0, 'E', 0176, 0100, 0100, 0174, 0100, 0100, 0176, 0, 'F', 0176, 0100, 0100, 0174, 0100, 0100, 0100, 1, 076, 010, 0, 'R', 0176, 0101, 0101, 0176, 0102, 0101, 0101, 0, 'S', 076, 0101, 0100, 076, 01, 0101, 076, 0, 'T', 0177, 010, 00, 'G', 076, 0101, 0100, 0117, 0101, 0101, 077, 0, 'H', 0101, 0101, 0101, 0177, 0101, 0101, 0101, 0, 'I', 076, 010, 010, 010, 01 0, 'x', 0, 0, 0143, 024, 010, 024, 0143, 0, 'y', 0, 0, 0101, 041, 021, 017, 01, 076, 'z', 0, 0, 0177, 02, 034, 040, 0177, 0, '{  % _ %w _w  R@ %  B06 wtw b D̥0 ', 014, 020, 020, 070, 020, 020, 014, 0, '|', 0, 010, 010, 010, 010, 010, 010, 0, '}', 030, 04, 04, 016, 04, 04, 030, 0, '~', 0,̥9 Wp @@`ew>f@www.f @@& BF7.F 0, 021, 052, 0104, 0, 0, 0, '*', 0177, 0177, 0177, 0177, 0177, 0177, 0177, 0, }; main(argc,argv) char **argv; { register cha !"#$>H> >%24&&$%B=*()***+r **ap; int s; for(ap = &argv[1]; ap < &argv[argc]; ap++) { if(**ap == '-') { switch(*++*ap) { /* * print a ,**/ 0>AEIQA>12>A>@3>AA>4 "5@~A>6>@^aAA>7B88>AA>AA>9>AAC=>er sum; sum = 0; sp = st; while (*sp >= '0' && *sp <= '9') sum = sum * 10 + *sp++ - '0'; return(sum); } # /* * banner program with full ascii */ #define BACK '\b' #define SPACE ' ' #define MASK 0100 char *bp; int width 128; int uonly; int indent; char blank[] " "; char lbuf[130]; char star; char newl '\n'; /* * character codes */ cha)  NfP %& ww lCԔ CԔlwvf@wv fwwZwVfw(i=1; i<9; i++) { for (bp=lbuf; bp<&lbuf[width]; bp++) *bp = SPACE; bp = lbuf; ln = line; while (c = *ln++) { if (c=pwl j`w*f @@& BF7*F/bin//usr/bin/ =BACK) { if (bp> &lbuf[7]) bp =- 9; continue; } if (uonly && c >= 'a' && c <= 'z') c =- 040; c =- 040; if Bx & 6  jw X%   5  j f $%f %anged to %o : %06o: %06oignored: dLoFxfe$c2slr crt0.oe  f $%f % % f $%E0f H% f $%startmxpi.o~mainaddrargckmemaddr2cmdcount~getint(cf %    L 57l@_ j E-L   r    l nexdep.olmfpi @ mtpi printf.oformp looprjust ndigit gnumwi e  r  2 ܆ r  2 8 tE  e \& t $   7 2^Nwf@wFwBTwpf@w*w&ZwN f@w w`w*f@dth ndfnd swtabdecimaloctalLhexFfloatsciencharac$string2logical@& HADCBF7F ;deq.(/dev/kmemCannot open /dev/kmem saved PS at %o is %o, ch4, 014, 010, 0, 0, 0, 0, /* ` */ 'a', 0, 0, 076, 01, 077, 0101, 077, 0, 'b', 0100, 0100, 0100, 0176, 0101, 0101, 0176, 0, 'c', - */ case '-': break; /* * indent banner */ case 'i': indent = getn(++*ap); if (indent > 16) indent =0, 0, 076, 0101, 0100, 0100, 076, 0, 'd', 01, 01, 01, 077, 0101, 0101, 077, 0, 'e', 0, 0, 076, 0101, 0177, 0100, 076, 0, 'f', 03 16; continue; /* * use upper and lower case */ case 'l': uonly = 0; continue; /* * slew n line6, 041, 040, 0160, 040, 040, 040, 0, 'g', 0, 0, 016, 021, 016, 074, 0102, 074, 'h', 0100, 0100, 0176, 0101, 0101, 0101, 0101, 0,s */ case 's': s = getn(++*ap); while(s--) write(1,&newl,1); continue; /* * upper case only */ ca 'i', 010, 0, 010, 010, 010, 010, 010, 0, 'j', 0, 02, 0, 02, 02, 02, 0102, 074, 'k', 0100, 0100, 0103, 0114, 0160, 0114, 0103, 0se 'u': uonly++; continue; /* * set maximum width */ case 'w': width = getn(++*ap); if (width > 128) width = 128; continue; /* * set char to print */ default: star = **ap; continue; } } putline(*ap); H& & 6 % w  @ @m ef eNf NfJ (%& } } putline(line) char *line; { register i; register char c; char *ln; /* * for each line in the character */ for* (c >= 0 && bp < &lbuf[width]) { putch(chars[c*9+i], star?star:chars[c*9]); } } while(bp >= lbuf && *--bp == ' ') ; a rr12,monitor.dlmtab cpirb rl0,@rr12,r1,eq tccb nz,rh0 ; tricky interaction of rh0 flag & NZ rrb rh0 ; force C set if il*++bp = '\n'; if(bp > lbuf) write(1, blank, indent); write(1, lbuf, ++bp-lbuf); } write(1,&newl,1); } /* * put one lil delimiter (NZ) ret ; now NC => valid delimiter, Z => valid number rcv'd. ; indig: ; input a hex digit, put its value into ne of one character, using ch for dark areas */ putch(c,ch) { register i, mask; bp++; mask = MASK; for (i=0; i<8; i++) { rl1. ; leaves the character found in rl0. ; C set if not hex digit ; Alters: ; rl0, rl1. calr echo ; get char in rl0 ld bp++; if (c & mask) *bp = ch; mask =>> 1; } } /* * convert ascii to integer */ getn(st) { register char *sp; regist ;  27 y _wZw H rå  å0å9 t@`e F(w~  w ~w De   % 2w7 7 ׯ-  (w7  .weB J ӕ- R r f e0 @ >j ҋ D~8@D Hӕ0 $f v Le0 9e  7we&  m  2~  2  2~ . $2 ldctlb flags,rh7 jr nz,mod2 ; no digits => don't alter bit r6,#0 jr z,modw ldb @rr4,rl3 ; modify byte jr mod2 modwn to an even address. ; ; The Z flag is set on return from modify, showmod, and cshowmod ; iff the delimiter was CR. ; ; Alters:: ld @rr4,r3 ; modify word mod2: cpb rl0,#'-' jr ne,mod3 sub r5,r6 ; '-' => back up ret mod3: cpb rl0,#'@' ; '@' => i, 'l', 030, 010, 010, 010, 010, 010, 010, 0, 'm', 0, 0, 0176, 0111, 0111, 0111, 0111, 0, 'n', 0, 0, 0176, 0101, 0101, 0101, 0101 ; r0, r1, rl2, r3, r4, r5, r6, rl7, r12, r13 ; cshowmod: calr colon showmod: calr show modify: calr inr3 jr c,cmderr2 ldct, 0, 'o', 0, 0, 076, 0101, 0101, 0101, 076, 0, 'p', 0, 0, 0176, 0101, 0101, 0176, 0100, 0100, 'q', 0, 0, 077, 0101, 0101, 077, 0lb rh7,flags cpb rl0,#',' ; ',' forces byte mode jr eq,$1 cpb rl0,#semic ; ';' forces word mode jr ne,$2 res r5,#0 ; (t1, 01, 'r', 0, 0, 0176, 0101, 0100, 0100, 0100, 0, 's', 0, 0, 076, 0100, 076, 01, 076, 0, 't', 040, 040, 0160, 040, 040, 041, 03hen round down to word) $1 calr byteflag ldctlb flags,rh7 ; if no digits on a mode switch, ret nz ; then don't move pointer6, 0, 'u', 0, 0, 0101, 0101, 0101, 0101, 076, 0, 'v', 0, 0, 0101, 0101, 042, 024, 010, 0, 'w', 0, 0, 0101, 0101, 0111, 052, 024, -- clear "no digits" flag sla r3,#4 addb rl3,rl1 ; add new digit jr $1 $2 ldk r1,#delims ; check for valid delimiter ld+ 8: cpb rl0,#'=' jr eq,mod6 add r5,r6 ; else step by address unit mod6: cpb rl0,#cr ; return Z set if CR ret ; getseg:  is marked by a char <= 0. ret ; echo: ; get a char into rl0, map to upper case, echo on console calr in8ch resb rl0,#7 ; qb rl1,rl0 subb rl1,#'0' ret c ; < '0' => error cpb rl1,#9 jr le,digok ; <= 9 => ok cpb rl0,#'A' ret c ; < 'A' => errouash parity bit cpb rl0,#esc ret eq ; don't echo ESC (confuses our CRT) cpb rl0,#lf jr ne,$1 ; map LF into CR ldb rl0,#r addb rl1,#'0'-'F'-1 ret c ; > 'F' => error incb rl1,#16 digok: resflg c ret ; ; Print a null-terminated message pointecr $1 calr outch cpb rl0,#'a' ret lt cpb rl0,#'z' ret gt resb rl0,#5 ; map ASCII lower -> upper case ret in8ch: ; read a d to by rr4. ; Message may also be terminated by a byte whose sign bit is set. ; Alters: ; rl0, r4, r5. outmess: ldb rl0,@rrfull 8-bit character into rl0 inb rl0,chastat bitb rl0,#0 ; test ready bit jr z,in8ch ; if not set, wait inb rl0,chadata4 ; load the next byte to print calr outch ; print char inc r5 decb rl0 ; test for end of string jr ge,outmess ; whichlen=atoi(&argv[i][2]); if(!read_len){ printf("number expected after 's' flag\n"); error++; } break; cas exit(-1); } e 'e': case 'o': oddonly = (argv[i][1]=='o'); bothbytes = 0; epmode = 0; break; case 'b': case 'w': /* cant have words if bothbytes not set */ epmode=(argv[i][1] == 'w'); bothbytes= 1; break; case 'k': /* set which k to burn */ c=argv[i][2]; if(c){ if(c >= '0' && c <= MAXK){ c = c-'0'; }else{ printf("bad number aremoteprbufprstrffltpr.o(putchr.o2fllgetchr.obadretopen.oread.oseek.o; get a segment number and offset from the console and put ; them into rr4. ; returns NZ on error, Z if valid address received$write.oHexit.ojcsv.otcerror.osavr5$ _exit"j_main"_u$f_psave$_savedps$_l. ; Alters: ; r0, r1, r3, r4, r5, r12, r13 ldb rh4,data`lastseg ; pick default segment calr inr3 jr z,get2 cpb rl0,#' ' jastc$csv"t_open"_printf"_seek"$_read"_write"H_flush"`_getchar"_getint"(_exam"r eq,getseg ; ignore leading blanks get2: ret nz cpb rl0,#'.' jr ne,get1 ldb rh4,rl3 ; segment specified calr inr3 ret l_putchar"2_dep"tcret"pfloat"(pscien"(_fout$ _errno$_fin$cerror"ndirection jr ne,mod8 ld r5,@rr4 ; load offset from current word ldb rh4,data`lastseg ; assume default segment jr mod6 modnz get1: setflg z ld r5,r3 ret ; byteflag: ; Check rl0 for comma, indicating "byte operation". ; Set r6 to 1 if byte, or 2, < 0) || (laddr > EPSIZE)){ printf("illegal la field, line=%02d\n",line); croak("process_line"); } if(tt=get_byte()){ if generate an array of bytes to * be programmed. */ register char llen; register char *dp; /* pointer into data array */ regist(tt<0){ printf("bad tt field, line=%02d\n",line); croak("process_line"); }else return(1); } dp= &ep[0] + laddr; wh if word operation. ; Set rl7 to comma if found, otherwise a space. ; Return Z set if byte, NZ if word. ldb rl7,#' ' ldk rer char tt; /* screwy hex field */ unsigned int laddr; /* program address of this line */ unsigned int get_word(); crc=0; /* ch6,#2 cpb rl0,#',' ret ne ldb rl7,#',' ldk r6,#1 ret ; Enter a 16-bit value into r3, terminated by any char in dlmtab. ;ecksum for current line */ #ifdef DEBUG printf("line is -- %s\n",&lbuf[0]); #endif where= &lbuf[1]; /* lbuf[0] is a colon */  C set if invalid delimiter ; Z set if valid number and delimiter received ; Delimiter returned in rl0. ; Alters: ; r0, r1, if((llen=get_byte())<0){ printf("illegal ll field, line=%02d\n",line); croak("process_line"); } if(((laddr = get_word()) r3, r12, r13. inr3: ldk r3,#0 ldb rh0,#2 ; "no digits yet" flag $1 calr indig jr c,$2 ; end of number ldb rh0,#0 ; nocode=write(ep_id,writeaddr,size))!=size){ printf("error writing eprom, pass=%04d, bytes=%04d\n",pass,code); croak("prog"); ; read char ret .finis  } } } swab(addr, nwds) int *addr; { register int *p; register int n; register char t; struct { char low, high; } ; n = nwds; p = addr; do { t = p->low; p->low = p->high; p->high = t; p++; } while(--n > 0); } croak(str) /* * gorp! fatal error. * print an error message and die horribly */ register char *str;{ /* pointer to fatal error (message of) */ perrofter 'k' flag\n"); error++; } }else{ printf("number expected after 'k' flag\n"); error++; } bre#&)!$'*"%(+/ak; case 'a': abortonerr=0; break; default: printf("unknown flag - %c\n",argv[i][1]); } }else{ /* no '-' in argument */ printf("illegal argument - %s\n",argv[i]); error++; } } /* of for */ if(error || (argc==1)){ printf(" burn [-i filename] [[-b] [-w]] [-kn] [-a] [-s size (bytes)]\n"); exit(-1); } ep_id=safe_open(PROGRAMMER,WRITE); sttyv[1]=e- watch that line length */ ov_count=MAX_LIN_LEN+1; lbuf_index=lbuf-1; while(1){ while(nchars-- && --ov_count){ *++lbuf_inet_line"); } i_b_index = input_buffer; } } } /* end of get_line */ process_line(){ /* * process a line of input anddex= *i_b_index++; if(*lbuf_index=='\n'){ *lbuf_index='\0'; return(1); } if(!nchars){ nchars=safe_read(i_ficified chunk of bytes to the eprom programmer * * can write any 1K part of the 4K buffer out (words or bytes, depending * on  line */ if(!llen){ if(get_byte() > ERROR){ crc&= 0377; if(crc){ printf("checksum error line= %02d\n",line); ifthe arguments used). */ register int code; /* return code from write */ register int pass; /* number of passes through ROM */ r(abortonerr) croak("process_line"); } return(1); /* everything is ok */ }else{ printf("error reading crc on lineegister int size; /* number of bytes being written (each time) */ #ifdef DEBUG printf("len=%04d\n",len); #endif size=(KSIZE <<  %02d\n",line); if(abortonerr) croak("process_line"); return(1); } } /* bad. overflowed eprom */ printf("overflowepmode); if(epmode != 0) /* word transfer -- swap bytes */ swab(writeaddr, KSIZE); for(pass=0; passdp)){ if((*dp=get_byte()) > ERROR){ len++; if(bothbytes || (oddonly==odd(dp))) dp++; llen--;ed eprom, %02x bytes left in line %02d\n",llen,line); return(1); } /* end of process_line */ prog(){ /* * write out the spe }else{ printf("error reading data field, line=%02d\n",line); croak("process_line"); } } /* reached crc field in hex) */ register char mode;{ /* type of open..... */ register int fid; /* fid returned by open */ if((fid=open(name,mode))<0){ pr(str); exit(-1); } safe_read(id,addr,size) /* * do a read and call croak on an error * such as <0 returned */ int id; /*rintf("open on file - %s failed\n",name); croak("safe_open"); } return(fid); } get_byte(){ /* * take two hex digits, st fid to do read from */ register char *addr; /* where to put it */ register int size;{ /* how much to get */ register int scr; /arting at wh and convert to into * a byte (char) */ register char i; /* loop var */ register char src; /* compute the byte her* how much really read */ if((scr=read(id,addr,size))<0){ printf("read error\n"); croak("safe_read"); } return(scr); } e */ int hexi[2]; /* array of the hex digits */ for(i=0; i<=1; i++){ #ifdef DEBUG printf("lbuf char = %c\n",*where); #endif ssafe_open(name,mode) /* * open file name in mode mode and croak on error */ register char *name; /* name of file.....(yawn....d,&input_buffer[0],BUF_SIZE); if(!nchars){ printf("EOF on input but still reading\n"); croak("get_line"); } pmode; stty(ep_id,sttyv); writeaddr = ep + (c*(KSIZE<[,] ; ; D : Display a range of addresses D-[,] {or} D[,] ; ; G : Go to a user program s; /* result 2 from get_byte calls */ if((r=get_byte()) < 0) return(-1); /* nothing there */ if((s=get_byte()) < 0) returnG {or} G ; ; R : Examine and alter registers R[P][H|L][,] ; The RPi are special registers, to wit: ; RP0: tra(-1); /* " " */ return((r<<8) | s); } p ID, RP1: flag word, RP2: PC seg, RP3: PC offset, ; RP4: PSAP seg, RP5: PSAP offset. ; ; E : Enter a block of data E[,] ; ; B : Set and remove breakpoints B+ {or} B- ; ; $ : print status for hex loads $ -- respond withs that an operation ; may apply to either bytes or words. ; Using the comma selects bytes; using anything else, ; e.g. CR, selec CR or seg number ; ; : : Intel hex format pseudo-command See Intel data catalog or code ; ; M : Move a block of memory M] ; Ifr>- [,] ; {or} M [,] ; = : Compare two memory areas =- [ a number is given, and the delimiter is one of those listed below, ; then the location is altered. ; The delimiter specifies ho,] ; {or} = [,] ; N : enable/disable interrupts N ; 1-bit in number => NVI, 2-bit => VI w to step to the next location to examine/alter. ; The delimiters allowed are as follows: ; space -- step to the next byte or word, as appropriate. ; `-' -- step back to the previous byte/word. ; `=' -- look again at the same location ; `,' (comma) -- sele,036-147sjm}>A8;^nqhkorilp #-$'ct byte mode. If examining words, start using bytes instead. ; `;' (semicolon) -- select word mode. ; `@' -- indirection -- takewitch(*where){ case '\0': return(-1); case '0': case '1': case '2': case '3': case '4': case '5': case '6': *. case '7': case '8': case '9': hexi[i] = *where - '0'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': hexi[i] = (*where - 'A') +10; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': hexi[i] = (*where - 'a') +10; break; default: return(-1); } where++; } /* end of for */ src= ((hexi[0]<<4)|(hexi[1]) ); #ifdef DEBUG printf("hex chars are %02x\n",src); #endif crc+= src; return(src&0377); } unsigned int get_word; Joyce Z8000 monitor program version 2.1.1 ; ; The commands available in the monitor are as follows: ; ; X : Examine and chan(){ /* * call get_byte twice to get a word from the hex input line */ register int r; /* result from get_byte */ register int / .. & 6 % w %?eN &  ' N #   w78FAlarm time after  seconds 0 %CӋNf %  %wpfw7  fAW @w f17 5 ew 5& wl&L&H&D&@&<&8&4&~0&x,&r(&l$&f &`&Z&T&N&H &B&<&6f& f@#f@ww accepted everywhere. ; No backspacing is possible for numbers; however, since only the ; last four digits of a number are signienable. ; I : display value from input port I[,] ; ; O : send value to output port O [,] ; ; Sficant, one may correct ; a mistyped digit by re-entering the four-digit number. ; ; An illegal character (e.g., ESCAPE) will geI : initialize SA 4000 disk SI ; ; S= : print disk status S= ; ; SR : read from disk to memory SR- an address of form [.], e.g. `135A' or `7F> ; {or} SR ; SW : write from memory to disk SW- ; {or}.F000' ; an address-offset without segment specification, e.g. `320'. ; An optional trailing comma (`[,]') always mean SW ; ; ; All numbers (except register numbers) are hexadecimal. ; Both lower and upper case areu 0C000H ; monitor's FCW == system + segmented mode nmivec .equ 28H ; NMI vector offset segtvec .equ 20H ; Seg Trap vector ken to be ; of the new type when modifying. ; ; ; I/O segment ; io .data .abs io = 7FH ; Segment for disk bootstrap (sectoroffset vintvec .equ 3CH ; 0'th vectored interrupt vector offset ; ; command words for SIO ; com4 .equ 44H ; x 16 clock, 1 sts 0..5 into addresses 0-BFF) boot .code priv .abs boot = 1 ; Defined constants ; cr .equ 15B ; carriage return lf .equ 12Bop bit, no parity com3 .equ 0C1H ; Rx 8 bits/char, Rx enable com5 .equ 0EAH ; Tx 8 bits/char, Tx enable, DTR, RTS on com1 .equ ; line feed esc .equ 33B ; escape bell .equ 7B ; bell semic .equ ':'+1 ; semicolon (az won't tolerate ';'!) SOH .equ 01 018H ; int on Rx char only; no wait/ready stuff reset .equ 00011000I ; reset command for SIO ; Shugart SA 4600 disk controlle the word being examined as the low 16 address bits. ; The segment is that most recently used in an X, E, or D command. ; CR (reB ; Start of Header for 8-bit load displn .equ 8 ; # values per line in display nbpts .equ 4 ; # of breakpoints monfcw .eqturn) -- quit modifying -- don't look at any more locations. ; ; When switching byte/word mode, if a number is entered, it is tawf |@@& BFw B 5  ʥ ʥ ʥ- ʥ9 Wp @@`eʥ00  A-F on input jr lt,$4 dec r3,#6 $4 add r3,r3 add r3,r8 ; add RPx and/or RLx offsets to reg address lda rr4,data`regs(r3) jr nz,cmderr1 ; abort on error calr byteflag enter1 calr crlf calr outrr4 calr colon enter2: ldb rl0,rl7 ; ' ' or ',' accstartingregnumber[ , | = ] ; Also, the following special registers are accessible: ; RP0 = trap ID word RP1 = Flag&controcpb rl0,#'=' jr eq,rdisp regloop: calr crlf ldb rl0,#'R' calr outch bit r6,#0 ; byte reg? jr z,regl1 ldb rl0,#'H' ; yes,l word ; RP2 = PC segment RP3 = PC offset ; RP4 = PSAP segment RP5 = PSAP offset (pointer to trap vector area) ldk r8,#0 $ print RH bit r5,#0 jr z,regl2 ldb RL0,#'L' ; or rl as approp regl2: calr outch regl1: ld r1,r5 sub r1,#regs rr r1 ldb rl1 calr inr3 ; get starting reg # jr z,$3 cpb rl0,#'P' jr ne,$2 set r8,#5 ; add 16 wds to offset -- for RP registers jr $2,rl1 subb rl2,#nregs jr uge,cmderr1 incb rl2,#nregs-10 ; reg number >= 10 ? jr lt,$1 ldb rl0,#'1' ldb rl1,rl2 ; prepare1 $2 cpb rl0,#'L' tcc eq,r8 jr eq,$1 cpb rl0,#'H' jr eq,$1 jr cmderr1 $3 calr byteflag cp r3,#10H ; map regs 10-15 into f e0&   ԕ- k  vA W  ~e0fv  O MT   \    55#n"f b 7rT %P @Bm8 7r0 f @%( l ҋ D~C `  f v  ӕ0 (f vLv Le0 9e     N @ N @  N" @    %    j ww   e7 wVe&  m   ~    ~ w7 r  h d 0   P Wp ` r    ww }/ w}/w |~wh De^  X  % w\e0eӕ?f8  ,. P $   @f  7  t   -  7 D 7 D ׯ: - 2 0 w$ 7 &  .w e( B J ӕ-  o^ xU d  w r ʥ ʥ- ʥ9 Wp @@`eʥ0  w7VF6rw6r@f@% r<R r< r<R r< rWtC` re rwF V   V !b7b  P`Hm` BalphUsage: prtln [file] [-p[pagsize]] [-l] [-a] - ... %s: Cannot open Ran V %n    0!  7 (ww  ԔAA WpCe ԔԔԔ BeWpges cannot overlap %s Page %d %o%6o:%3d: doxfeVcdslurDOX(nulCe ԔԔԔ& v ed& v ed& v ed& v e@ & v wvw fA r nw\l)`T M:/CSTCDTDay Mon 00 00:00:00 1900 SunMonTueWedThuFriSatJanFebMarAmw FD % A r  r e0@ԕ A r e0@w @& BFw B 5  ʥy, save bkpt address. ret ; enter: ; enter a block of data ; syntax: Eseg.offset[,] calr getseg ; start addr to rr4 1 $`f& T%`Df %5 D-& 0 C-D-%@@AA@ Nf`  u# /* Program to test an idea about the 11/40 -- * that I can use the mtpi/mfpi instructions * to get at kernel space if I canddress & go on ; xamine ; examine and change memory one word at time -- ; stop by typing CR. ; syntax: Xseg.offset[,] calr  just * get the "previous kernel mode" field set * in the PS. To do this, I simply write in /dev/kmem * at the point where igetseg ; init. addr. to rr4 jr nz,cmderr1 calr byteflag ; watch for comma ldb data`lastseg,rh4 ; we used this seg! exloop:t says my PS was saved. */ #include "/usr/sys/param.h" #include "/usr/sys/reg.h" #include "/usr/sys/user.h" int *psave; int sa calr crlf calr outrr4 calr cshowmod ; show & allow modifying mem loc jr nz,exloop ret ; cmderr1: calr cmderr ; friendlvedps; char lastc; main(argc) { int kmem; char cmd; register int *addr, *addr2; register int count; if((kmem = open("/devording to word/byte calr outch calr outsp calr modify ; enter value jr nz,enter3 ldctlb flags,rh7 ; CR hit; was NZ set (y neighborhood error branch ; (calr is shorter than jump) ; register ; examine/modify user registers ; syntax: R[ H | L ]no digits)? ret nz ; if none, quit enter3: cpb rl0,#' ' jr eq,enter2 ; ' ' => continue jr enter1 ; any other => print a  & 6 % w % @ _$eD̥- 7,  y ̥0int ibuf[259]; int obuf[259]; main(argc, argv) char **argv; { register int c; int lineno, pagelen; pagelen = 20; while(--a ̥9 7 P̋K̥01̥9. 3 ̥9 ̥0̥- ̋  sԥ+ 3`rgc > 0) { argv++; c = **argv; if(c >= '0' && c <= '9') pagelen = atoi(*argv); else if(fopen(*argv, ibuf) < 0) { prin e  &   @   %3NJB@ r& etf("%s: cannot open\n", *argv); exit(-1); } } obuf[0] = 1; /* standard output */ lineno = 0; while((c = getc(ibuf)) >= " @ % 7" Ne Ne  w w  55755 _ 0) { if((c =& 0177) < ' ') switch(c) { case '\n': if(++lineno != pagelen) break; /* reached end of page */_Nf  @`5_f T%Cww  \DCԒ wxw h6DCB5f@)w6fwlz JA 7 j fAW,f B@ 8 @&61fAҒS wHf BRf @w N  ww DeL@4 & h     @ @e71@  1ww w w AupNNmf  ww  @@5w/%J %K  t5~  t5 N 5N 5 R B-B-%B-B- _, fA rBpEu@@`55DCN& 0 f& J %5 2`D--`f 0 % & h   w2w "DC%: V e`m e rfww p@&f F 2  @#e @  / N  w"w G6  3 &n& %"fe %` H,  @   ww _ 5D̋P ˋ   3  X& ^ % t tAp t? $   @ ?  wx"w b_  ar(); switch(cmd) { case 'q': exit(0); case 'e': /* e loc loc-loc ... examine locations */ do { addr = addr2 = getint() /kmem", (argc>1) ? 2 : 0)) < 0) { printf("Cannot open /dev/kmem\n"); exit(0); } seek(kmem, &0140000->u_ar0, 0); read(kmem& ~1; if(lastc == '-') addr2 = getint(); count = 0; do { if(count%8 == 0) printf("%06o: ", addr); printf(" %06o, &psave, 2); psave =+ RPS; seek(kmem, psave, 0); read(kmem, &savedps, 2); printf("saved PS at %o is %o, ", psave, savedps);", exam(addr)); addr++; if(++count % 8 == 0) putchar('\n'); } while(addr <= addr2); if(count%8 != 0) putchar('\n') seek(kmem, psave, 0); savedps =& ~030000; /* set prev kernel mode */ write(kmem, &savedps, 2); savedps = -1; seek(kmem, ps; } while(lastc == ' '); break; case 'd': addr = getint() & ~1; while(lastc == ' ') dep(getint(), addr++); break; dave, 0); read(kmem, &savedps, 2); printf("changed to %o\n", savedps); for(;;) { printf(": "); flush(); lastc = cmd = getch66 %e w6 _"w  _2m@ 8 =l h  \ & 6 % w " _% = % @-)@u!@p@ @m _z~Eo p lt e r< :  r<N Q&& t % HKOFILPSVYQT Ne[  ,i % @ !  @m  @ @m   @ 7  %   @ 7  & %n& ^ % %kWpenw  [6t    2@te 7xt@7EP@ @ 85 e%6  '   e`t&ĝ& %Et&& %  74  t'? ? =   &  %d  %ww 3  ' &2%2`ĝT& %2& ^ %  7 m 7  v  r ww p@C   t7 HE̕ E% ̕5 %427e ww >1   & %"fe& ^ %7ˋ* % :  %˥- 4  p e& V ww ,  % 0 3 @ p@ ww (& " @ ,  @ ) wvw d9De %@ %d4 %_w>*_w &F    ,s   x =l h5     f& t %5ԝ A r@A r5 e0? @e!ww C ˥0 ˥9       %ww L| %d B - 6 7 %l fe?e2Ҕ%Wp @@`eC-=ww  D?(  " ww * 6A@   66 %6 D  w@fw(w$ . >w0ffwwDw f@wwprMayJunJulAugSepOctNovDecJwf@wwPw f@wwVwf @fA w,xw"re"w"hew"^@lw"VAlewI &@t`e @& BFf7z F6rw| 6r@ /dev/rk081prP stSd ttfdszsp@ read.o^ seek.o write.o exit.o nargs.o jsrsd\tsti`cmpibaddidjmpihbriefault: printf("ignored: "); do { putchar(lastc = getchar()); } while(lastc != '\n' && lastc != ';'); if(lastc != '\n') lcsv.o@ getpid.oZ getpidcleanup.d cerror.of ldiv.ot savr5$_exit" start"_main"_aputchar('\n'); case '\n': case ';': ; /* line terminators */ } } } getint() { register int n; register char c; wproc# _swapdev# _ttlist# _eol1# _bdlist# _eol2# _procs$n_cproc$_ccmd$_cmdtbl# _spcl#hile((c = getchar()) == ' ') ; n = 0; while(c >= '0' && c <= '9') { n = n*8 + c - '0'; c = getchar(); } lastc = c; retu8_desc"J_whatty"@_files"_cdir"_sigs"_regs"_cmds$_param$0_pwid#l_ubuf$2_needu: & t %5 r  . A r e0@? ? ~is?d ` rn(n); }  xn w _&w _%d  %d_f  =   _ & %fe& ^ % k f& %"fe& ^ %@E% ) t tAp eˋ8   @ r5)E7  @ rA 17@0 V @   t? L H4 c< 8@ ' t tAp t  @ / N 4 n header */ unsigned s_size; /* size in bytes */ char s_name[TOKLEN]; /* name */ unsigned s_x : 1; /* executable */ unsigne; /* symbol/segment name */ int r_type; /* reference type (R_SEG, R_ADDR, R_WORD) */ unsigned r_off; /* offset into segment d s_r : 1; /* readable */ unsigned s_w : 1; /* writable */ unsigned s_p : 1; /* privileged */ unsigned s_s : 1; /* stack where reference is */ } ; struct nlist { char n_name[TOKLEN]; /* symbol name */ char n_segnm[TOKLEN]; /* segment where symbol*/ unsigned s_ab : 1; /* is absolute segment */ unsigned s_nm : 7; /* segment number if absolute */ unsigned s_segrefsize; /* is defined */ int n_type; /* symbol type (??) */ unsigned n_offset; /* offset of symbol within segment */ } ; /* Format of  size of list of refs to this segment */ unsigned s_refsize; /* size of reference table */ } ; #define R_SEG 0 #define R_ADDRMTFPTKILBUSSEGSYSPIPigndierrrrrrspp012345pcsdir=ttyPpu  %ewcrsdsstutstiTcucsctp cdsirdeu8eg9ug;J@Pt0.7.opq.o~mainargcargvnpmemcurfunc~myselfwhich@  rk0rk1prioPpidststsizetextdatastkutimstimtimetimech.utpt~filescfilecinodeic~sigsis~regsimch.stimch.timepidef.uidef.giduidgidProcess Query. pq [sel1 sel2 ... ] cmdstring -- try pq pttd /usr/lib/pqup/usr/liip1p2rbuf~descJp~cdircinodebp~whatty@cib/pqup not found -- update impossible /dev/memCan't read /dev/mem SWRCDTshutpipettyHUPINTQITINSTRCIOTEmfpi = 6500^tst mtpi = 6600^tst .globl _exam, _dep _exam: / exam(location) -- examines word in prev space mfpi *2(sp) mov (s$2_nouser$4_lbuf$6_line$_mem$_swap$_ldivr$csv"@ _write" _execv" _csel"_gp)+,r0 rts pc _dep: / dep(value, location) -- write word in prev space mov 4(sp),r0 mov 2(sp),-(sp) mtpi (r0) rts pc etcmds" _open"@ _seek" _read"^ _pselect"T _getu"_putst" _myself"cret"L _puti" _ldiv"t _tab" _putdev" _snams#z_lastpid#_regos#_sels$_myval$_sflg$_getpid"Z _getuid"6 _getn"V _pads#_nargs" cerror"f __exectr$__cleanu"d _errno$_lrem" the z8000 object file: * 1) header -- an instance of struct exec. * 2) segment table -- "z_nsegs" instances of struct seghea 1 #define R_WORD 2 /* reference table entry -- for .extern symbols & external segments */ struct rlist { char r_name[TOKLEN]d. * 3) segment bodies -- z_nsegs of them * Each one has the form: * 3.1) code/data for this segment (s_size bytes) * 3.2) 5  i.e., (s_segrefsize/2) entries. * 3.3) list of references to external symbols or segments. * These are instances of struct calr outch $1 ldb rl0,rl1 calr outdig calr outsp calr showmod ; print & (maybe) modify reg contents ret z ; CR hit => quitrlist. The r_type field * tells what to do with the symbol. * R_SEG: place segment number in bits 14-8 of the word. * R_A cpb rl0,#'@' ; check for indirection jr ne,regloop ; if not, continue normally jr exloop ; if so, hop into xamine loop rdiDDR: add symbol value to the location. It is assumed * to look like an offset: if bit 15 is off, * the value is added to sp: ; display registers ldk r9,#1 ; print just 1 line ld r8,#endregs ; or through RP5 if less jr disp3 ; hop into displist of words referring to current segment. * At link (or load) time, one must put the number of the * current segment into the low byte (short seg offset) * otherwise the value is added to the following word. * R_WORD: simply add symbol value to the high bytes of the words * whose offsets are given here. * The total size of the reference list is s_segrefsize bytes, * } while(nleft > 0 && (addr =+ nleft) < lowaddr); addr =- nleft; bufp = &ibuf[(lowaddr - addr) / 2]; nleft =- lowaddr - addrnodei~getuflgfoffsetsize~cselasis; do { if((need =- nleft) < 0) nleft =+ need; while((nleft =- 2) >= 0) printf("%x ", *bufp++); bufp = &ibuf; } while~pselectT ip~getcmds spcmspecialcmn~putdev dev(need > 0 && (nleft = read(inf, ibuf, 512)) > 0); printf("\r\n"); fflush(obuf); } hextoi(p, pp) register char *p; char **pp; ~puti nbnbufpbase~getnV npcpnp{ register int n; register int dig; n = 0; while((dig = hexdig(*p++)) >= 0) n = (n<<4) + dig; *pp = p-1; return(n); } ~putst sp~tab lengthcexecv.o rttgetuid.o6 open.o return; } if (tbuf[7] != 0) { /* relocation? */ write (1, "No relocation bits\n", 19); return; } t1 = tbuf[1]; t2 = /* header for z.out file */ #define TOKLEN 8 #define Z_MAGIC 01010 /* z8000 object file magic number */ struct exec { int z_tbuf[2]; t4 = tbuf[4]; txtloc = 020; if (argc>3 && argv[3][1]=='o') { dotdot =+ 020; tbuf[0] = 0405; /* old magic */ tbmagic; /* magic number */ int z_nsegs; /* number of segments in this file */ long z_segsz; /* (total) size of the segments uf[1] =+ tbuf[2]; tbuf[2] = 0; tbuf[4] = tbuf[3]; tbuf[3] = 0; tbuf[6] = 0240; tbuf[7] = t7 = 0240; } txtsiz = tbuf[*/ char z_entseg[TOKLEN]; /* name of entry-point segment */ unsigned z_entpt; /* offset of entry point */ long z_syms; /* le1]+tbuf[2]; relloc = txtloc+txtsiz; txtsiz = (txtsiz>>1) & 077777; seek(fin, relloc&~0777, 0); read(fin, rbuf, 512); txtp =ngth of symbol table (in what units??) */ int z_flag; /* ??? */ int z_unused; } ; struct seghead { /* segment table entry i for R10 .. R15 decb rl2,#16-10 ; unless reg number >= 16 jr lt,$2 ldb rl0,#'P' ; in which case, RP0 .. RP5. ldb rl1,rl2 $2 6 0); seek(fout, relloc&~0777, 0); txtw = read(fin, tbuf, 512); txtp = &tbuf[(relloc&0777) >> 1] + 4; while((txtsiz =- 6) > 0) &tbuf[8]; relp = &rbuf[(relloc&0777) >> 1]; if (argc>3) /* nop out "setd" at start */ if (tbuf[8] == 0170011) tbuf[8] = { switch(*txtp & 77) { case 2: case 3: case 4: *(txtp + 1) =+ dotdot; } adv6(); } if(txtp != &tbuf[0]) writ 0240; while(txtsiz--) { switch (*relp & 017) { case 01: /* pc ref to abs */ *txtp =- dotdot; break; case 02: /* e(fout, &tbuf[0], txtw); } advance() { relp++; relloc =+ 2; if (relp == &rbuf[256]) { seek(fin, relloc, 0); read(fin,ref to text */ case 04: /* ref to data */ case 06: /* ref to bss */ *txtp =+ dotdot; } advance(); } if (txtp !=  &rbuf[0], 512); relp = &rbuf[0]; } txtp++; txtloc =+ 2; if (txtp >= &tbuf[256]) { write(fout, &tbuf[0], txtw); seek(f&tbuf[0]) write(fout, &tbuf[0], txtw); txtsiz = (t4 >> 1) & 077777; relloc = 020 + 2*(t1 + t2); seek(fin, relloc&~0777, ntinue; case 's': segment = hextoi(++p, argv); continue; } else if(*p == '+') offset = hextoi(++p, argv); elsint segment, offset; unsigned int lowaddr, need; int ibuf[256]; int obuf[259]; main(argc, argv) char **argv; { register char e { need = 0xFFFF; lowaddr = hextoi(p, argv) & ~1; p = *argv; if(*p == '-') { if(*++p != '\0') { need = hexthe word. * The total size of (3.3) is s_refsize bytes, or * (s_refsize / size of the rlist structure) entries. * * 4*p; register unsigned int addr; int inf, nleft; int *bufp; if(--argc <= 0) die( "hex [-i file] [-sSegment] [+offset] [addr) Global symbol table -- instances of struct nlist. * The total size is z_syms bytes (I think), or however many entries. [-addr]]"); inf = 0; /* input is std in by default */ obuf[0] = 1; /* output is standard output */ do { p = *++argv; if */ (*p == '-') switch(*++p) { case 'i': if((inf = open(*++argv, 0)) < 0) die("%s: cannot open", *argv); argc--; co /* * relocate command-- * reloc file [-]octal [ - ] * * relocate object or a.out file up in core * by the possibly negatedhexdig(c) register char c; { if(c >= '0' && c <= '9') return(c - '0'); if(c >= 'a' && c <= 'f') return(c - 'a' + 10); if( octal number. * * if optional 3rd arg is given, * replace "setd" at start by "nop" */ int tbuf[256]; int rbuf[256]; int fic >= 'A' && c <= 'F') return(c - 'A' + 10); return(-1); } die(msg, p1, p2) char *msg; { fflush(obuf); obuf[0] = 2; /* outn; int fout; int *txtp; int *relp; int relloc; int txtloc; int dotdot; int txtsiz; int t1; int t2; int t4; int t7; int txtw; maput to error log */ printf(msg, p1, p2); putchar('\n'); fflush(obuf); exit(-1); } putchar(c) { putc(c, obuf); } in(argc, argv) char *argv[]; { int sign, c; if (argc<3) { usage: write(1, "reloc file [-]octal\n", 20); return; } dotd7  not readable\n", 18); return; } if ((fout = open(argv[1], 1)) < 0) { write(1, "File not writable\n", 18); return; } tr5 calr outr1 jr outsp ; outr1 -- print contents of r1 as four hex digits ; outrl1 -- print contents of rl1 as two hex digitsxtw = read(fin, tbuf, 512); if (tbuf[0]!=0411 && tbuf[0]!=0410 && tbuf[0]!=0407) { /* magic */ write(1, "Bad format\n", 11); 10 = count (or addr2-addr1+1) in bytes or words, as appropriate. ; Alters: ; r0, r1, rl2, r3, r4, r5, r6, rl7, r8, r9, r12, r13 in, txtloc, 0); txtw = read(fin, &tbuf[0], 512); txtp = &tbuf[0]; } } adv6() { txtp =+ 6; if(txtp >= &tbuf[256]) { writ; (all except rh2, rh7, r10, r11) ; ranges: calr getseg jr nz,cmderr1 ldb data`lastseg,rh4 ldl rr8,rr4 ; start addr ldb re(fout, tbuf, txtw); txtw = read(fin, tbuf, 512); txtp =- 256; } } l2,rl0 ; save delimiter calr inr3 ; r3 is endaddr or byte count jr nz,cmderr1 cpb rl2,#'-' jr ne,$1 sub r3,r5 $1 ld r10,r3 calr getseg jr nz,cmderr1 calr byteflag ex r4,r8 ex r5,r9 ; make rr4 first, rr8 last address. add r10,r6 bit r6,#0 display value from input port ; I[' '|','] ; Prints the hex value read from that port. ; Trailing space => word inpucpb rl0,#' ' jr ge,$1 ldb rl0,#'.' $1 calr outch dbjnz rh7,dloop3 disp4 dec r9 ; test "one line" flag jr ne,dloop1 ret t, trailing comma => byte input. inport: calr inr3 jr nz,cmderr2 calr byteflag jr eq,$1 ; skip if byte (",") ;;;; in r1,@r3; intenb -- enable/disable interrupts ; N -- ; 1-bit set in number => enable non-vectored interrupts ; 2-bit set in numb ; az bug -- won't assemble .word 3D31H ; in r1,@r3 jr outr1 ; print word received $1 ;;;; inb rl1,@r3 ; az bug .word 3C3er => enable vectored interrupts intenb: calr inr3 jr nz,cmderr2 sla r3,#11 ; move into position for VI & NVI bits .word 0CB9H ; inb rl1,@r3 jr outrl1 ; print byte ; outport -- send byte or word value to output port ; O [,] outport: ctoi(p, argv) - lowaddr; p = *argv; } } if(*p != '\0') die("funny argument"); } } while(--argc > 0); printf("C0H ; ldb rl3,#[monfcw>>8] -- az bug orb rh3,rl3 .word 7D3AH ; ldctl fcw,r3 -- az bombs out on this somehow ret ; inport -- e%x %x 00000000", segment, lowaddr + offset); addr = 0; do { if((nleft = read(inf, ibuf, 512)) < 0) die("error reading");nsole push @rr14,r0 $1 inb rl0,chastat bitb rl0,#2 ; loop until xbuf empty jr z,$1 pop r0,@rr14 outb chadata,rl0 ret ; cot = 0; if (*argv[2] == '-') { sign = -1; argv[2]++; } else sign = 1; while (*argv[2]) { c = *argv[2]++ - '0'; if (olon: ; print a ':' ldb rl0,#':' jr outch ; outrr4 -- print address represented by rr4, in the form nn.nnnn in hex, ; and foc<0 || c>7) goto usage; dotdot = (dotdot<<3) + c; } dotdot =* sign; if ((fin = open(argv[1], 0)) < 0) { write(1, "Filellowed by a space. ; Alters: ; rl0, rh1, rl2. ; outrr4: ldb rl1,rh4 resb rl1,#7 calr outrl1 ldb rl0,#'.' calr outch ld r1,8  on console in hex ldb rl2,#4 ; shift count to r2 outloop rl r1,#2 ; roll top digit down into rl r1,#2 ; bottom digit'sr ; another error abort location (calr < jp) maycrlf: ; prints crlf if last character input was CR decb rl0,#cr ret ne ; place ldb rl0,#0FH andb rl0,rl1 calr outdig dbjnz rl2,outloop ret outdig ; output a hex digit from rl0 to the console de fall into crlf crlf: ; prints carriage return and line feed on console ldb rl0,#cr calr outch ldb rl0,#lf jr outch ; ; shocb rl0,#9 jr le,$1 incb rl0,#'A'-'9'+9-10 $1: addb rl0,#'9' jr outch ; modify -- allow modifying contents of @rr4, and/or stepping rr4, shown below. ; showmod -- "show" @rr4 and modify ; cshowmod -- print colon, show @rr4, allow modifying. ; ; @rr4 majr nz,$2 srl r10 $2 calr crlf bit r6,#0 ret ; breakpt: ; set or remove breakpoints, which are implemented as SC instr's caly refer to a byte (if r6 = 1) or a word (if r6 = 2). ; ; The response expected is of the form: ; [] ; If ar echo subb rl0,#'+' ; expect "b+" ... ldctlb rl4,flags ; (save result of comparison) jr eq,$1 decb rl0,#['-'-'+'] ; or a number is given, and the delimiter is one of those listed below, ; then the contents of @rr4 are altered. ; The delimiter specilso "b-" jr nz,cmderr1 $1 calr inr3 ; get breakpoint number jr nz,cmderr1 cp r3,#nbpts jr uge,cmderr1 ; ensure in range fies how rr4 is to be altered ; (e.g., stepped to the next byte or word). ; The delimiters allowed are as follows: ; space -- st0..3 ld r6,r3 mult rr2,#6 ; convert r3 to bpoints array index lda rr10,data`bpoints(r3) popl rr8,@rr10 ; rr8 = breakpoinbit r6,#0 jr nz,dloop1 res r8,#0 ; if word mode, round down end-address dloop1: calr crlf ; then print cr, lf calr outrrlay loop ; ; display ; display a block of memory ; syntax: Dseg.beginningoffset endoffset calr getseg ; get starting ad4 calr colon disp3: ldb rh7,#displn ; load # values per line calr outsp dloop2: calr show cp r5,r8 ; see if done ret ugdress in rr4 jr nz,cmderr2 ; jump on error ldk r9,#0 cpb rl0,#cr ; only 1 address? jr eq,disp1 cpb rl0,#',' ; (also 1 ae add r5,r6 dbjnz rh7,dloop2 ; loop till line is filled bit r6,#0 jr z,disp4 ; test for byte mode calr outsp ; yes -- ddr, byte display) jr eq,disp1 calr inr3 ; else get end address to r3 jr z,disp2 jr c,cmderr2 disp1: ld r3,#-1 ; if no provide el cheapo char dump calr outsp dec r5,#displn ldb rh7,#displn dloop3 calr outsp ldb rl0,@rr4 inc r5 resb rl0,#7 endoffset, ldk r9,#1 ; display 1 line disp2: ld r8,r3 calr byteflag ldb data`lastseg,rh4 ; remember we used this segment w -- print contents of @rr4 in hex, followed by a space. ; cshow -- like show, but number is preceded by a colon ; A byte or woralr inr3 jr nz,cmderr2 ld r4,r3 calr inr3 jr nz,cmderr2 calr byteflag jr eq,$1 ;;;; out @r4,r3 ; az bug -- won't assembled is displayed, according to the value of r6. ; (See byteflag). ; Alters: ; rl0, rh1, rl2. ; cshow: calr colon show: bit r6,#0 ; Alters: ; rl0, rl2. rh1 is altered by outrl1. ; outrl1: ldb rl2,#2 ldb rh1,rl1 jr outloop outr1: ; print contents of r1 .word 3F43H ; out @r4,r3 ret $1 ;;;; outb @r4,rl3 ; az bug .word 3E4BH ret ; ; Support routines ; cmderr2: calr cmder9 -ebuf); if(die) exit(-1); return(-1); } putdir() { dir->access = tent.actime; seek(tkfil, 2, 3); if(write(tkfil, dir, sizeovb - was; time(tv); date = gmtime(tv); tent.actime = (date[3]<<4) + (date[4]+1) + (date[5]<<9); } struct direntry *findfileof dir) != sizeof dir) err(1, "Can't rewrite directory"); } checkdir() { register int *date; register was; register struct(name) char *name; { register struct direntry *ep; register num; ep = dir; for(num = dir->numfiles; num--; ) if(cmpst((+ ; show byte? jr z,showw ldb rl1,@rr4 ; yes calr outrl1 jr show2 showw: ld r1,@rr4 ; no calr outr1 show2: ; fall  direntry *p; int tv[2]; if(dir->numfiles<0 || dir->numfiles>77 || dir->vname[0]<=0 || dir->vname[0]>7) goto flaw; was = 0into outsp outsp: ; print a space on console ldb rl0,#' ' ; fall into outch outch: ; print a character from rl0 on the come to read from files"); files++; } if(files) if(fopen(name,fbuf)) return(err(0,"Can't read unix file: ", name)); else { pointer, too calr outrr4 ; print second address calr cshowmod ; show contents, await CR or space calr crlf popl rr4,@rr1 fstat(fbuf[0], fbuf+100); if(fbuf[105]<0 || fbuf[104]&0177400) size = 0; else size = fbuf[105]>>9 + 2*texts; /* size o4 ret z test r10 ; ensure nonzero count ret z bit r6,#0 ; test byte/word mode jr $4 ; go back & compare some more f file in blocks */ } else size = 0; if((dent=findspace(size))==0) return(err(0,"No room for ", name)); tstring(name, tent.; ranges -- accepts input of form ; addr1-addr2 addr3[,] -or- ; addr1 bytecount addr3[,] ; Addr1 and addr3 may specify a segmefname); gblk = tent.firstb; seek(tkfil, gblk, 3); if(texts) { for(cp=gbuf; cpnumfiles]; p++) { if(p->firstblastb < p->firstb) goto flaw; nfree =+ p &st; bufp = ebuf; for(n=nargs(); --n; ) { p = *strs++; while(*p) *bufp++ = *p++; } *bufp++ = '\n'; write(2, ebuf, bufp->firstb - was; was = p->lastb; } if(was > dir->eovb) { flaw: err(0, "not a Terak-format directory"); } nfree =+ dir->e: +ep)->fname, name)==0) return(ep); return(0); } cmpst(tstr, str) char *tstr, *str; { register char *ts, *st; register n; ttch(oper) { case 'l': listdir(); break; case 'g': while(--argc>0) getfile(*++argv); break; case 's': while(--argc>s = tstr; st = str; n = *ts++; do if(*st >= 'a' && *st <= 'z') { if(*st++ + 'A' - 'a' != *ts++) return(1); } else if(*s0) savefile(*++argv); putdir(); break; case 'd': while(--argc > 0) delfile(*++argv); putdir(); break; case 'k': crt++ != *ts++) return(1); while(--n); return(*st); } struct direntry *findspace(size) { register struct direntry *bp, *cp; runch(); putdir(); } } err(die, st) char *st; { char ebuf[80]; register n; register char *p, *bufp; char **strs; strs =egister tsiz; int bestsz; bp = cp = &dir[dir->numfiles]; bestsz = dir->eovb - bp->lastb; while(cp>dir) { tsiz = cp->firstb; cp--; tsiz =- cp->lastb; if(tsiz>bestsz) { bestsz = tsiz; bp = cp; } } tent.firstb = bp->lastb; /* set up fil *cp++ = ' '+spa; } if(c == -1) continue; /* eof -- don't store */ if(c == '\n') goto newln; } *cp++ = ce-size entries */ tent.lastb = tent.firstb + bestsz; return((bestsz= &gbuf[1024-80]) { wh c; if(cp >= &gbuf[1024]) { if(putbuf()) return; cp = gbuf; } } } if(cp>gbuf) { /* buffer not empty -- flush *ile(cp<&gbuf[1024]) *cp++ = 0; if(putbuf()) return; cp = gbuf; } spa = 0; while((c=getc(fbuf))==' ' || c==/ tent.lastbyte = cp - gbuf; while(++cp < gbuf+1024) *cp = 0; if(putbuf()) return; if(tent.lastbyte <= 512) { if(text'\t') if(c=='\t') spa =+ 8-spa%8; else spa++; if(spa) if(spa==1) *cp++ = ' '; else { *cp++ = 020; t address pop r7,@rr10 ; r7 = old contents (if any) ldctlb flags,rl4 ; ask again -- was it "b+" ? jr eq,addbp testl rr8 char *device; if(--argc <= 0) err(1, usage); p = *++argv; gotdev = 0; oper = 'l'; device = "/dev/rx0t"; while (*p) switc; no, "b-" -- remove bkpt jr z,cmderr1 ; if addr = 0, never set -- complain. ld @rr8,r7 ; else restore old contents subl rh(*p++) { case 's': case 'd': case 'k': case 'c': wrtfil++; case 'g': case 'l': oper = *(p-1); break; case 'r': wrr4,rr4 ; and clear bkpt address jr bpret addbp: calr getseg ; get the address jr nz,cmderr1 ldb rh6,#7FH ; construct SCtfil++; repl++; oper = 's'; break; case '0': case '1': device[7] = *(p-1); gotdev++; break; case 'f': files++;  instruction in r6 ex r6,@rr4 ; exchange with old contents bpret: push @rr10,r6 ; which we save. pushl @rr10,rr4 ; finallbreak; case 't': texts++; } if(gotdev==0 && argc>0) { argc--; device = *++argv; } if((tkfil=open(device, wrtfil?2:0))<0 || seek(tkfil, 2, 3) || read(tkfil, dir, sizeof dir) != sizeof dir) err(1, "Can't access ", device); checkdir(); swi; n directory")); tp = dent+1; for(bp = &dir[++dir->numfiles]; bp>tp; ) *(bp + (sizeof tent / 2)) = *--bp; bp = &tent; n = firstb; if(texts) { if(files) { if(fcreat(name,fbuf)<0) return(err(0, "Cannot create unix file: ", name)); } else { ith 'l' */ printf(" %5s %3d %3d %3d", ftype[dp->filekind], dp->firstb, dp->lastb, dp->lastbyte); putchar('\n'); } } fbuf[0] = 1; fbuf[1] = 0; fbuf[2] = &fbuf[3]; } gblk =+ 2; seek(tkfil, gblk, 3); remain = 0; spcnt = tab = 0; for delfile(name) char *name; { register struct direntry *dent; if(dent=findfile(name)) delete(dent); else err(0, "File not fo(;;) { if(remain <= 0) { if(gblk >= dent->lastb) break; remain=read(tkfil,gbuf,1024); gblk =+ 2; if(gblk>=denund: ", name); } getfile(name) char *name; { register remain; register struct direntry *dent; register char *cp; int spcnt,t->lastb) remain = dent->lastbyte + ((gblk>dent->lastb)?0:512); cp = gbuf; } switch(*cp) { case 0: /* tab; int fbuf[259]; int n; if((dent=findfile(name))==0) return(err(0,"file not found: ", name)); cp = gbuf; gblk = dent-> char **firstname; if(argc < 2) die("\ Usage: zxt file [-xot] [segment ...] -- extracts/lists segs in a z8000 obj file\n\ 'x' #include "z.hdr" /* or whatever it is */ /* * Program to extract/list segments in a z8000 object file * (generated by assembleextracts, 'o' to std output (else to `segment.oz'),\n\ 't' lists segments. If no flags, '-t' assumed.\n\ If no segments named, r 'az' written at SICL, University of Minnesota). * See help message (and program) for options. */ #define MAXSEGS 16 int zfall are selected."); namecount = -1; for(i=1; i < argc; i++) { p = argv[i]; if(*p == '-') { if(list == 2) extr; /* object file descriptor */ char *file; struct exec head; /* header */ struct seghead seg[MAXSEGS]; /* segment table */ intact = list = 0; /* quash defaults */ while(*++p) switch(*p) { case 'x': extract++; break; case 'o': extract = -2; b { register c; register char *cp; int size, spa; struct direntry *dent; int fbuf[259]; if(dent=findfile(name)) if(repl) extract = 0, list = 2; int swapbytes = 0; main(argc, argv) char **argv; { register char *p; register int i; int namecount;  delete(dent); else return(err(0,"File already exists: ", name)); if(files==0 && ttyn(0)!='x') { err(0, "I assume you want sizeof tent / 2; do *tp++ = *bp++; while(--n); } delete(dent) struct direntry *dent; { register *bp, *ep; if(dent==0 || s==0) gblk--; } else tent.lastbyte =- 512; } else tent.lastbyte = 512; tent.lastb = gblk; inserta(dent); } putbuf() { if(dir->numfiles<=1) return(err(0,"Error in delete")); ep = &dir[dir->numfiles]; for(bp=dent; bptent.lastb) return(err(0,"Not enough room")); if(write(tkfil,gbuf,1024)!=1024) return(err(0,"Write error")); retur / 2); dir->numfiles--; } tstring(st, tst) /* copy C string to terak string */ char *st, *tst; /* also handle slashes in pathn(0); } inserta(dent) struct direntry *dent; { register *bp, *tp; register n; if(dir->numfiles>=77) return(err(0,"No room inames */ { register char *s, *t; s = st; t = tst+1; while(*s) { if(*s == '/') t = tst+1; else if(*s>='a' && *s<='z') *t+< --n > 0); *cp++ = 0; return(buf); } crunch() { err(0, "Crunch not yet implemented"); } char *month[] { "bad", "jan", "feb",dp->firstb, (dp->actime>>4)&037, month[dp->actime&017], (dp->actime>>9)&0177 ); if(files) /* full-listing flg when used w "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }, *ftype[] { "null", "xdsk", "code", "text", "data", "rr(0,name,": Cannot create")); } else n = 1; /* std output */ seek(tkfil, gblk, 3); do { remain = read(tkfil,gbuf,512); end-of-page / end-of-file */ remain = 0; break; case 020: remain--; cp++; spcnt =+ (*cp - ' '); break;  if(++gblk == dent->lastb) remain = dent->lastbyte; if(remain>0) write(n,gbuf,remain); } while(remain == 512 && gblk case ' ': spcnt++; break; case '\r': *cp = '\n'; spcnt = tab = 0; default: if(spcnt > 0) { tab < dent->lastb); } }  =+ spcnt; while(--spcnt>=0) putc(' ', fbuf); spcnt = 0; } putc(*cp, fbuf); if(*cp >= ' ') tab++; }  cp++; remain--; } fflush(fbuf); } else { /* normal file */ if(files) { if((n=creat(name,0664))<0) return(e die("Too many segments for me (%d)", head.z_nsegs); zfread(&seg, head.z_nsegs * sizeof seg[0]); } } } /* * now preak; /* extract to standard output */ case 't': list++; break; case 'w': /* extract word stream */ swapbytes++; /*rocess selected segments */ if(namecount > 0) { /* some segments were named */ do { do { p = *++firstname; } while(* instead of byte stream */ break; /* (swap bytes in each word) */ } } else { if(++namecount == 0) { /* first namep == '-'); /* ignore flag args */ for(i = head.z_nsegs; --i >= 0; ) { if(match(&seg[i].s_name, p)) { useseg(i);  is file */ file = p; firstname = &argv[i]; if((zf = open(file, 0)) < 0) die("%s: Cannot open", file); zfread(&h break; } } if(i < 0) die("-%s: not a segment", p); } while(--namecount > 0); } else { /* no segments named, usead, sizeof head); if(head.z_magic != Z_MAGIC) die("%s: not a z8000 object file", file); if(head.z_nsegs > MAXSEGS)  = read(zf, where, count)) < 0) die("error reading %s", file); if(nread != count) die("-%s truncated (warning only)", file)info", "unk6" }; listdir() { register struct direntry *dp; findspace(0); /* find largest free spot */ printf("volume: %s\th; } swab(buf, nbytes) char *buf; { register char t; register char *p; register int count; p = buf; count = nbytes / 2; d+ = *s + 'A' - 'a'; else *t++ = *s; s++; } tst[0] = s-st; } cstring(tst) /* converts terak to C string -- returns pointeras %d files, %d blocks, %d free, largest free = %d\n\n", cstring(dir->vname), dir->numfiles, dir->eovb, nfree, tent.lastb-te */ char *tst; { register n; register char *p, *cp; static buf[20]; p = tst; cp = buf; n = *p++; do *cp++ = *p++; while(nt.firstb); for(dp=dir; ++dp <= &dir[dir->numfiles]; ) { printf("%15s %3d %2d %3s %2d", cstring(dp->fname), dp->lastb - = = 0 || *s2 == '\0') return(1); return(0); /* return nonzero if matched */ } char fname[TOKLEN+4]; char xtbuf[512]; useseg(ni]) > ' ') i++; fname[i] = '.'; fname[i+1] = 'o'; fname[i+2] = 'z'; fname[i+3] = '\0'; if((outf = creat(fname, 0666o { t = *p; *p = *(p+1); *++p = t; p++; } while(--count > 0); } die(msg, p1) char *msg; { extern int fout; register ) int n; { register int unsigned i; register struct seghead *sp; long offszf; int size, outf; offszf = sizeof head + head.char c; flush(); fout = 2; if((c = *msg) == '-') msg++; printf(msg, p1); putchar('\n'); flush(); fout = 1; if(c != '-')/* Intel format downloading program * down [-i file] [-sN] [-x] [-w] [+offset] [addr[-addr]] * * where * -i selects input fi { case 'i': if(fopen(*++argv, ibuf) < 0) die("%s: cannot open", *argv); argc--; continue; case 's': segle (default is standard input) * -sN forces loading to segment N (default left to load receiver) * -x selects 8-bit-wide downlment = hextoi(++p, argv); pickedseg++; continue; case 'x': /* full 8-bit binary output */ eightbit++; continue; oad (default is hex format) * -w selects byte swapping. You need this to send PDP-11 words to z8000. * +offset adds that offs case 'w': /* word-oriented (byte-swapped) transfer */ byteswap++; continue; } else if(*p == '+') offset = hextoet to the addresses to download into * addr starts downloading from that address in the input file * addr-addr downloads only i(++p, argv); else { lowaddr = hextoi(p, argv) & ~1; p = *argv; if(*p == '-') { if(*++p != '\0') { need = hextoi(p, argv) - lowaddr; entire = 0; p = *argv; } } if(*p != '\0') die("funny argument"); } } while(--argmit(address.byte.high); emit(address.byte.low); emit(type); for(i=0; i 0); if(byteswap) { if(lowaddr & 01) { lowaddr--; need++; } need++; need =& ~01; } addr = 0; while(addr < l('\n'); } emit(c) { extern char checksum; if(eightbit) { putchar(c); } else { puthex((c>>4) & 017); puthex(c & 017); owaddr) { addr++; if(getc(ibuf) < 0) die("No data"); } if(pickedseg) { out[0] = segment; line(1, SEGLINE); } maxlen  } checksum =+ c; } puthex(c) register char c; { putchar(c + (c < 10 ? '0' : 'a' - 10)); } die(msg, p1, p2) char *msg; { ff= eightbit ? BINMAX : HEXMAX; do { if(!entire && maxlen > need) { maxlen = need; if(byteswap) { maxlen++; maxlelush(obuf); obuf[0] = 2; /* output to error log */ printf(msg, p1, p2); putchar('\n'); fflush(obuf); exit(-1); } putchar(z_nsegs * sizeof seg[0]; i = n; sp = &seg[0]; if(i != 0) do { offszf += sp->s_size; offszf += sp->s_segrefsize + sp->s_ree all of them */ for(i = 0; i < head.z_nsegs; i++) useseg(i); } } match(s1, s2) /* match strings. s1 has max length TOKfsize; sp++; } while(--i != 0); seek(zf, (int) (offszf>>9), 3); seek(zf, (int) (offszf&0777), 1); if(extract != 0) { if(LEN, */ register char *s1, *s2; /* s2 is null-terminated. */ { register int n; n = TOKLEN; while(*s1++ == *s2++) if(--n <extract < 0) outf = 1; else { /* create file named "segment.oz" */ i = 0; while(i < TOKLEN && (fname[i] = sp->s_name[> of xtbuf; zfread(xtbuf, i); if(swapbytes) swab(xtbuf, i); if(write(outf, xtbuf, i) != i) die("error writing %s", fntchar()), obuf); } fflush(obuf); } nybble(c) register char c; { if(c >= '0' && c <= '9') return(c - '0'); if(c >= 'a' && c ame); size -= i; } if(extract > 0) close(outf); } if(list) { printf("%c %4xx (%4d.) %.8s\n", sp->s_refsize ? 'R' : '-<= 'z') return(c - 'a' + 10); if(c >= 'A' && c <= 'Z') return(c - 'A' + 10); return(-1); } ', sp->s_size, sp->s_size, sp->s_name); } } zfread(where, count) char *where; int count; { register int nread; if((nread= '9') segment = atoi(p); } else if((regfile = creat(--p, 0644)) < 0) die("%s: cannot create", p); } sread(0);v) char **argv; { register char *p; int segment, pickedseg; int byteswap, entire; unsigned int lowaddr, need; unsigned int  if((segsize = word(segment*4 + 2)) == 0) die("Segment %d nonexistent", segment); for(i = word(segment*4); --i > 0; ) sreafrom that range of addresses */ #define BINMAX 128 /* max bytes per line of 8-bit binary load */ #define HEXMAX 16 /* max bytemaxlen; register int count, c; char t; extern unsigned int addr; if(--argc <= 0) die( "down [-i file] [-sSegment] [-x] [-ws per line for hex load */ #define BINFLAG '\01' /* SOH character flags 8-bit load */ #define HEXFLAG ':' /* colon flags hex lo] [+offset] [addr[-addr]]"); ibuf[0] = 0; /* input is std in by default */ obuf[0] = 1; /* output is standard output */ entad */ #define DATALINE 0 /* "type" field for a line of data */ #define SEGLINE 2 /* "type" for specifying segment no. -- NONSTire = 1; need = 0; lowaddr = 0; offset = 0; pickedseg = 0; byteswap = 0; do { p = *++argv; if(*p == '-') switch(*++p)ANDARD */ unsigned int offset, addr; char checksum; int eightbit; char out[128]; int ibuf[259]; int obuf[259]; main(argc, arg 0) n = (n<<4) + dig; *pp = p-1; return(n); } hexdig(c) register char c; { if(c >= '0' && c <= '9') return(c - '0'); if(c >= 'a' && c <= 'f') return(c - 'a' + 10); if(c >= 'A' && c <= 'F') return(c - 'A' + 10); return(-1); } line(count, typeswap) { count++; count =& ~01; for(p = &out[count]; --p >= out; ) { t = *p; *p = p[-1]; *--p = t; } } e) { union { unsigned int word; struct { char low, high; } byte; } address; register int i; extern char checksum; line(count, 0); addr =+ count; } while(c >= 0 && (entire || (need =- count) > 0)); putchar('\r'); putchar('\n'); fflush(obextern int addr, offset; address.word = addr + offset; putchar(eightbit ? BINFLAG : HEXFLAG); checksum = 0; emit(count); euf); } hextoi(p, pp) register char *p; char **pp; { register int n; register int dig; n = 0; while((dig = hexdig(*p++)) >=int obuf[259]; main() { /* packs a stream of hex digits into an 8-bit byte stream */ register c; obuf[0] = 1; while(c = get)) < 0) die("%s: cannot create", fname); } size = sp->s_size; while((i = size) > 0) { if(i > sizeof xtbuf) i = sizechar()) { if(c == '\n') continue; /* newlines are not allowed in the middle of a pair */ putc((nybble(c) << 4) + nybble(ge? /* pxt [-N] [regsetupfile] -- extract segment from a Pascal z8000 code file. * * The code file is standard input, and the output code segment * appears on standard output. * * Segment 1 is extracted by default; * `-N' extracts segment N instead.  * * If a `regsetupfile' argument is given, the program * writes an image of the monitor register area to set all registers  * so as to start execution at procedure 1 of that segment. * The segment code is assumed to start at 8300 hex, segment 2;  * the stack pointer is initially at 8010 hex (same segment, of course). * * To use the regsetupfile, feed it to the `down= jtab-2 - word(jtab-2); if(regfile > 0) { reg[8] = jtab + codeoffset; reg[9] = segsize-2 + codeoffset; reg[11] = ent' program as follows: * down -i regsetupfile -w -s0 +800 -- this will set registers properly. */ char buf1[512], buf2[512];ry + codeoffset; write(regfile, reg, sizeof reg); } } else die("Table of contents not implemented yet"); } sread(nbytes char *bufs[2] = { &buf1, &buf2 }; int which = 0; unsigned filepos = 0; int lastread = 0; int gencode = 1; /* Note: FCW, &c b) { which = 1-which; nbytes += 512; if((lastread = read(0, bufs[which], nbytes)) != nbytes) die(lastread < 0 ? "read errorelow depends on arrangement of Z8000 monitor -- in particular, that the PSW words directly follow saved regs. */ int reg[] =d(0); filepos = 0; if(gencode) { nleft = segsize; do { nleft -= 512; sread(nleft<0 ? nleft : 0); if(write(1, buf" : "file too short"); filepos += lastread; } char *locate(fileaddr) { register int delta; delta = fileaddr - (filepos - lagbuf; while(++cp < gbuf+1024) *cp = 0; if(putbuf()) return; if(tent.lastbyte <= 512) { if(texts==0) gblk--; } else te else { tab += spcnt; do *cp++ = ' '; while(--spcnt); } } *cp++ = c; tab++; } }nt.lastbyte =- 512; } else tent.lastbyte = 512; tent.lastb = gblk; inserta(dent); } putbuf() { if((gblk =+ 2) > tent.lastb) } *cp = 0; if(crumcnt > 0) printf("Note: %d unprintable characters not written to %s\n", crumcnt, name); } else  return(err(0,"Not enough room")); if(write(tkfil,gbuf,1024)!=1024) return(err(0,"Write error")); return(0); } inserta(dent) { tent.filekind = 5; /* is ordinary data file */ cp=gbuf; while((c=getc(fbuf))!= -1) { *cp++ = c; if(cp >= &gbuf[102struct direntry *dent; { register *bp, *tp; register n; if(dir->numfiles>=77) return(err(0,"No room in directory")); tp = d4]) { if(putbuf()) return; cp = gbuf; } } } if(cp>gbuf) { /* buffer not empty -- flush */ tent.lastbyte = cp - @  die(s, p1, p2) char *s; { extern int fout; fout = 2; printf(s, p1, p2); putchar('\n'); flush(); exit(-1); } ar *s, *t; s = st; t = tst+1; while(*s) { if(*s == '/') t = tst+1; else if(*s>='a' && *s<='z') *t++ = *s + 'A' - 'a'; ec) { putc(c, obuf); } lse *t++ = *s; s++; } tst[0] = s-st; } cstring(tst) /* converts terak to C string -- returns pointer */ char *tst; { register n; register char *p, *cp; static buf[20]; p = tst; cp = buf; n = *p++; do *cp++ = *p++; while(--n > 0); *cp++ = 0; return(buf); } crunch() { err(0, "Crunch not yet implemented"); } char *month[] { "bad", "jan", "feb", "mar", "apr", "may", " dent->lastbyte + ((gblk>dent->lastb)?0:512); cp = gbuf; } switch(*cp) { case 0: /* end-of-page / end-of-f { 0, 0, 0, 0, /* r0-r3 */ 0x8010, 0x8010, 0x0200, 0, /* r4-r7 */ 0, 0, 0x0200, 0, /* r8-r11 (r8, r9, r11 filled below) */ 0ile */ remain = 0; break; case 020: remain--; cp++; spcnt =+ (*cp - ' '); break; case ' ': spcnt++x0200, 0x8010, 0x0100, 0x6000, /* r12-r15 */ 0, 0xC000, 0x0100, 0x0008 /* junk, FCW, PCseg, PCoffset. */ }; main(argc, argv) c; break; case '\r': *cp = '\n'; spcnt = tab = 0; default: if(spcnt > 0) { tab =+ spcnt; while(har *argv[]; { int nleft; int codeoffset = 0x8300; int segment = 1; int segsize; int jtab, entry; int regfile = -1; exter--spcnt>=0) putc(' ', fbuf); spcnt = 0; } putc(*cp, fbuf); if(*cp >= ' ') tab++; } cp++; remain--; n int fout; register int i; register char *p; while(--argc > 0) { p = *++argv; if(*p++ == '-') { if(*p >= '0' && *p < ww %$N Ff F m"+ f T wZw HDC̠̥"̥'̋ak; case '\n': /* Suppress trailing blanks at end-of-line */ *cp++ = '\r'; /* Terminate page if necessary */  ԋ ww D̋ = lastread) die("seek outside of buffer!"); return((delta>=0) ? &bufs[which][delta] : &b if(cp >= &gbuf[1024-85]) { while(cp < &gbuf[1024]) *cp++ = '\0'; if(putbuf()) return; cp = &gbuf[0]; } tufs[1-which][delta+512]); } word(fileaddr) { register char *p; union { int word; struct { char low, high; } byte; } w; ab = spcnt = 0; break; default: if(c < ' ' || c >= 0177) crumcnt++; /* Improper text char */ else { if( p = locate(fileaddr); w.byte.high = *p++; w.byte.low = *p; return(w.word); } byte(fileaddr) { return(*locate(fileaddr)); }spcnt > 0) { if(tab == 0) { *cp++ = 020; *cp++ = ' ' + spcnt; tab += spcnt; spcnt = 0; }A   - WpAu!Wpeu@  wtw bNff \Y%@-Vl  rwDw 2D. %, Premature end of fileTemporary label in illegal contextENTER: attempt to enter null into symbol table Cannot enter temporanl  WpCeu 3 @ 3s  xlww Dԥ$  ̋ Wp @@`>>4)&037, month[dp->actime&017], (dp->actime>>9)&0177 ); if(files) /* full-listing flg when used with 'l' */ printf(" jun", "jul", "aug", "sep", "oct", "nov", "dec" }, *ftype[] { "null", "xdsk", "code", "text", "data", "info", "unk6" }; listd %5s %3d %3d %3d", ftype[dp->filekind], dp->firstb, dp->lastb, dp->lastbyte); putchar('\n'); } } delfile(name) char *nir() { register struct direntry *dp; findspace(0); /* find largest free spot */ printf("volume: %s\thas %d files, %d blocks,ame; { register struct direntry *dent; if(dent=findfile(name)) delete(dent); else err(0, "File not found: ", name); } getfi %d free, largest free = %d\n\n", cstring(dir->vname), dir->numfiles, dir->eovb, nfree, tent.lastb-tent.firstb); for(dp=dirle(name) char *name; { register remain; register struct direntry *dent; register char *cp; int spcnt, tab; int fbuf[259]; ; ++dp <= &dir[dir->numfiles]; ) { printf("%15s %3d %2d %3s %2d", cstring(dp->fname), dp->lastb - dp->firstb, (dp->actime @  %4 m@# +$5  fe K e fe K 5 5fe" \Y% Wp@} fflush(fbuf); } else { /* normal file */ if(files) { if((n=creat(name,0664))<0) return(err(0,name,": Cannot crew. w  ofef JO%w w D2o S@w  T4 e64ate")); } else n = 1; /* std output */ seek(tkfil, gblk, 3); do { remain = read(tkfil,gbuf,512); if(++gblk == dent-> && NX%4 % 4 E w H w/D/B %lastb) remain = dent->lastbyte; if(remain>0) write(n,gbuf,remain); } while(remain == 512 && gblk < dent->lastb); } } w/ f& & e w 7 /7 / /ׯ/- / /ׯ/00/w~/7 / .|wt/DoBw: J\/V/ _&QF/ B/ o x d u &/       ӕ- f&ERBSOTDRSOTDRBSOTIRSOTIRBSOUTSOUTBSOUTDSOUTDBSOUTISOUTIBBITBITBRESRESBSETSETBTSETTSETBABSBASEBLOCKBYTECLOSw .ӕ0 N r@A r  f  e0 9e' ) 'v.oҋ ECODECOMMDATAELSEENDIFENDMENDWENTRYEQUEVENEXTERNFINISIFGLOBLINCLUDELISTLWORDMACROMAINORGPAGETITLEWITHWORD~X.R. J. B. p7*.w6. . .ff Fe w7 - - -0 DBad label fieldBad temporary labelBad character in column oneBad characters in source lineRead failed on file %s readbuff  -Wp `e0eӕ?w DCB & @R z f @R  ̥-%0  :B < < @ < @  < <  < IFELSEENDIFEntered expseudo Temporary label used with data pseudoDapwff @@& BFw B 5 l  r e0@$ r ta pseudo used in code segment0Nonterminated stringUnimplemented pseudo00Multiple segment definitionToo many segmentsPRI#define NWORDS 200 int nwords NWORDS; struct header { int *last; /* pointer past last word of data */ int *firstnz; /* pointVBad argument to CODEPRIVWRITEREADBad argument to DATABad baseBad segment numberORG argument can't be less than $Too mer to first nonzero data word */ } sum, term; int t1[NWORDS], t2[NWORDS]; int *vsum = t1; int *vterm = t2; char toomuch[] = "ent+1; for(bp = &dir[++dir->numfiles]; bp>tp; ) *(bp + (sizeof tent / 2)) = *--bp; bp = &tent; n = sizeof tent / 2; do any nested includesWrong segment nameENDM without prior MACROENDIF without prior IFENDW with no previous WITHAssembler erro*tp++ = *bp++; while(--n); } delete(dent) struct direntry *dent; { register *bp, *ep; if(dent==0 || dir->numfiles<=1) returrMissing labelELSE without prior IF"',*&.ENDM.endmEntered exmac %d: %s buffind = %d, nchars = %d Prematn(err(0,"Error in delete")); ep = &dir[dir->numfiles]; for(bp=dent; bpnumfiles--ure end of macro fileCouldn't read macro filenchars = %d Entered expand expanding %s Macro parameter can't be 0Missing mac; } tstring(st, tst) /* copy C string to terak string */ char *st, *tst; /* also handle slashes in pathnames */ { register chr)j)-d)\)f@w fwwpwf@wpw fww~pint n; if((dent=findfile(name))==0) return(err(0,"file not found: ", name)); cp = gbuf; gblk = dent->firstb; if(texts) { ww w (w(AupNNmf V ww (@@5 _W fA rBpEu@@`55Dif(files) { if(fcreat(name,fbuf)<0) return(err(0, "Cannot create unix file: ", name)); } else { fbuf[0] = 1; fbuf[1]CN& W f& (%5 2`D--`f W $`f& X%`Df '%5 D- = 0; fbuf[2] = &fbuf[3]; } gblk =+ 2; seek(tkfil, gblk, 3); remain = 0; spcnt = tab = 0; for(;;) { if(remain <= & W C-D-%@@AA@ Nf` V u_VNf V @`5_Vf X%0) { if(gblk >= dent->lastb) break; remain=read(tkfil,gbuf,1024); gblk =+ 2; if(gblk>=dent->lastb) remain =Cww  ,'DCԒ ww t'DCB5ҒS wTf@wwpwry label into symbol tableMultiply-defined symbol: Bad pseudoBad operator fieldUnmatched IFfilelen = %o octal Code in daf|xwmrpwfwm`fwPpwnwB w  %   N ff 8Y%% ta segment f `  @ $lDllll\p    6& F  @tAWtE@PN e&f 8Y% wxfEf@wwpw f@wwC 0) break; div239++; factor =+ 2; sign = ~sign; } while(divide(&term, 239, &term) != 0); if(argc > 2) printf("%l div r0 bvc 4f jsr pc,split 4: mov r0,(r5)+ mov r1,r0 sob r4,1b br done _divadd: / divide and add to destination jsr r5,arg5 (%l splits), %l div 239 (%l splits)\n", div5, split5, div239, split - split5); print(&sum); } clear(hp, vec) register struet / divadd(source, divisor, dest, sign) tst 16.(sp) / negative sign? bmi divsub / if so, use subtract divadd: 1: mov (r3)+,rct header *hp; register int *vec; { register int n; hp->firstnz = vec; n = nwords; do { *vec++ = 0; } while(--n); hp->l1 div r2,r0 bvc 4f jsr pc,split 4: add r0,(r5)+ bcc 2f mov r5,r0 tst -(r0) sec 3: adc -(r0) bcs 3b 2: mov r1,r0 sob ast = vec; } int obuf[259]; print(hp) struct header *hp; { register int i, g; register unsigned int k; int n, ln; char digr4,1b done: mov r0,_drem / save remainder mov sp,r0 / return r0 nonzero done2: mov (sp)+,r4 mov (sp)+,r3 mov (sp)+,r2 mov [4]; /* log(65536) / log(10000) = 1.204 ~~ 1 + 1/5 */ n = nwords + nwords/5; /* gives number of 4-digit groups */ hp->firstn(sp)+,r5 rts pc _divsub: / divide and subtract from destination jsr r5,arget / divsub(source, divisor, dest, sign) tst 16.(z++; /* ignore first word ( = 3. ) */ obuf[0] = 1; /* select std output for obuf */ ln = 10; /* 10 groups per line */ g = sp) / negative sign? bmi divadd / if so, use add divsub: 1: mov (r3)+,r1 div r2,r0 bvc 4f jsr pc,split 4: sub r0,(r5)+ bcCan't allocate that much storage\n"; main(argc, argv) char **argv; { int factor, sign; int div5, div239, split5; extern int 5; /* of 5 digits each */ i = 4; /* extract in groups of 4 */ for(;;) { if(++i >= 4) { if(--n <= 0) break; k = mulsplit; int divadd(), divsub(); if(argc > 1) { nwords = atoi(argv[1]); if(nwords <= 0) nwords = NWORDS; if(nwords > Ntiply(hp, 10000); i = 3; do { dig[i] = k % 10 + '0'; k =/ 10; } while(--i >= 0); i = 0; } putc(dig[i], oWORDS) { if((vsum = sbrk(2*nwords*2)) == -1) { write(2, toomuch, sizeof toomuch); exit(-1); } vterm = vsum + buf); if(--g <= 0) { if(--ln <= 0) { putc('\n', obuf); ln = 10; } else putc(' ', obuf); g = 5; } } putc('nwords; } } div5 = div239 = split = 0; clear(&sum, vsum); clear(&term, vterm); vterm[0] = 16; /* 16 * arctan(1/5) */ fa\n', obuf); fflush(obuf); } ctor = 1; sign = 1; divide(&term, 5, &term); do { if(divadd(&term, factor, &sum, sign) == 0) break; div5++; factor =+ 2; sign = ~sign; } while(divide(&term, 5*5, &term) != 0); clear(&term, vterm); split5 = split; vterm[0] = 4; /* 4 * arctan.globl _divide, _divadd, _divsub, _multiply .globl _drem, _split halt = 0 .text _divide: / divide (in place if source = dest(1/239) */ factor = 1; sign = -1; do { if(divide(&term, 239, &term) == 0) break; if(divadd(&term, factor, &sum, sign) == ination) jsr r5,arget / divide(source, divisor, dest) 1: / where source and dest are (struct header *) mov (r3)+,r1 div r2,D thing 1: mov r0,r5 / hold word carry in r5 mov -(r3),r0 mul r2,r0 add r5,r1 adc r0 tst (r3) bpl 2f add r2,r0 / fix blast?pi23.c>pi23.timepii.oed signed multiply 2: mov r1,(r3) sob r4,1b br done2 / restore regs and return arget: / get args for divide routines mov sp,r0 mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) mov r5,-(sp) / save ret addr cmp (r0)+,(r0)+ / r0 -> first arg mov (r0)+,r3 / r3 = &(source header) mov (r0)+,r2 / r2 = divisor mov *(r0)+,r5 / r5 = dest.last clr r0 / init r0 for divides mov (r3)+,r4.globl _divide, _divadd, _divsub, _multiply .globl _drem halt = 0 .text _divide: / divide (in place if source = destination) / r4 = source.last mov r3,r1 / save addr of source.firstnz mov (r3),r3 / now r3 -> first nonzero word sub r3,r4 asr r4 / r jsr r5,arget / divide(source, divisor, dest) 1: / where source and dest are (struct header *) mov (r3)+,r1 jsr pc,divd mo4 = # words in source ble empty / if none, return 0 1: / else verify "1st nonzero word" tst (r3)+ / keep advancing until nonv r1,(r5)+ sob r4,1b br done _divadd: / divide and add to destination jsr r5,arget / divadd(source, divisor, dest, sign) zero bne 2f sob r4,1b / or until end of source empty: / in which case return r0 = 0, tst (sp)+ / indicating empty source btst 16.(sp) / negative sign? bmi divsub / if so, use subtract divadd: 1: mov (r3)+,r1 jsr pc,divd add r1,(r5)+ bcc 2f mov r done2 / return to caller of caller 2: tst -(r3) / overshot NZ word -- back up mov r3,(r1) / repair header's idea of firstnz r5,r1 tst -(r1) sec 3: adc -(r1) bcs 3b 2: sob r4,1b done: mov r0,_drem / save remainder mov sp,r0 / return r0 nonzero do sub r4,r5 / back dest up as far as source sub r4,r5 / (twice, since r4 is in words) rts pc split: / split divides into bytene2: mov (sp)+,r4 mov (sp)+,r3 mov (sp)+,r2 mov (sp)+,r5 rts pc _divsub: / divide and subtract from destination jsr r5,ac 2f mov r5,r0 tst -(r0) sec 3: sbc -(r0) bcs 3b 2: mov r1,r0 sob r4,1b br done die: halt _multiply: / multiply(things when needed inc _split ashc $-8,r0 div r2,r0 bvs die clr -(sp) movb r0,1(sp) clr r0 ashc $8,r0 bisb -2(r3),r1 div r, multiplier) / multiplies multiplier into thing, / returns overflow from top word. mov 2(sp),r1 / r1 -> header for thing2,r0 bvs die bis (sp)+,r0 rts pc .bss _drem: . = .+2 _split: . = .+2  mov 4(sp),r2 / r2 = multiplier mov r5,-(sp) mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) clr r0 mov (r1)+,r3 / r3 -> last+1 word of thing mov r3,r4 / also r4 sub (r1),r4 / r4 = last - firstnz asr r4 / r4 = number of words ble done2 / if none, do noGpi2.spixEpiDpi.1100.timepi.opi.timeApi23@pi23.1100.timeE jsr pc,divd sub r1,(r5)+ bcc 2f mov r5,r1 tst -(r1) sec 3: sbc -(r1) bcs 3b 2: sob r4,1b br done die: halt _multiply: r2 into r0r1. quot->r1, rem->r0 mov r3,-(sp) mov $16.,r3 1: asl r1 rol r0 cmp r2,r0 bhi 2f sub r2,r0 inc r1 2: sob r3,1b / multiply(thing, multiplier) / multiplies multiplier into thing, / returns overflow from top word. mov 2(sp),r1 / r1 - mov (sp)+,r3 rts pc .bss _drem: . = .+2 > header for thing mov 4(sp),r2 / r2 = multiplier mov r5,-(sp) mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) clr r0 mov (r1)+,r3 / r3 -> last+1 word of thing mov r3,r4 / also r4 sub (r1),r4 / r4 = last - firstnz asr r4 / r4 = number of words ble done2 / if none, do nothing 1: mov r0,r5 / hold word carry in r5 mov -(r3),r0 mul r2,r0 add r5,r1 adc r0 tst (r3) bpl 2f addF  ̋wn w ^ NE n-@t n-wL w <  n-@ n-w2 w " -  n- .  n-w w  r2,r0 / fix blasted signed multiply 2: mov r1,(r3) sob r4,1b br done2 / restore regs and return arget: / get args for div Nff 28%@-N 0 jw w D̥"̥' ̋@  Ow w 8 N #ide routines mov sp,r0 mov r2,-(sp) mov r3,-(sp) mov r4,-(sp) mov r5,-(sp) / save ret addr cmp (r0)+,(r0)+ / r0 -> first aN 0ewn w ^ \ T8wZ w J N #N 0ew: w * DOŠ ̋w w  @ ȥ$ Nrg mov (r0)+,r3 / r3 = &(source header) mov (r0)+,r2 / r2 = divisor mov *(r0)+,r5 / r5 = dest.last clr r0 / init r0 for div |8%ww DE` ̋ 5rC ww eDfEVpC ̋ rEC ww ides mov (r3)+,r4 / r4 = source.last mov r3,r1 / save addr of source.firstnz mov (r3),r3 / now r3 -> first nonzero word sub pCD` ̋ ACp rC wLw 8D ,& T, w w  Nf 7 5%Nr3,r4 asr r4 / r4 = # words in source ble empty / if none, return 0 1: / else verify "1st nonzero word" tst (r3)+ / keep a 0 @ww BOfef 0%ww w/D/B %w/ f& & e w7 /7 dvancing until nonzero bne 2f sob r4,1b / or until end of source empty: / in which case return r0 = 0, tst (sp)+ / indicati/ /ׯ/- / /ׯ/00/wx/7 z/ .|wn/NBw: JV/P/ _x2@/ > >>>>>#>'>,>0>5>:>?>D>J>O>R>U> 64 ?4  w^w ND + 8 8& 28%~ T8w(w DCԋ w@w DY>\>`>e>j>p>t>y>~>>>>>>>>>>>>>>>>>>>>>>>>? ?????$?+?0?5?:???D?H?O?V?Y?]?a?f?k?q?u?z?????????CԔww AupuN 5 A vB ww N 6ww DeE7 *5 5???????????????@@ @@@@%@+@2@6@;@?@D@H@M@R@X@\@a@g@l@r@w@|@@@@@@@@@@@@@@@@@@@@@@a a HE -P%\PdP 28%} T8 V*%P*φeE7@* F7% w e ;`~lRRaz1: arg count Assembler error optype = %d RLRLBRLCRLCBRLDBRRRRBRRCRRCBRRDBSDASDAB Um*e 7]Pa7 )U ew @e7Ewf@w f@SDALSDLSDLBSDLLSLASLABSLALSLLSLLBSLLLSRASRABSRALSRLSRLBSRLLADCADCBADDADDBADDLCPCPBCPLDABDECDECBDIVDwtPw fwjwfxPwf@wNwJ~Pwf:6wm0Pw$wmfIVLEXTSEXTSBEXTSLINCINCBMULTMULTLNEGNEGBSBCSBCBSUBSUBBSUBLCLRCLRBEXEXBLDLDBLDLLDALDARLDKLDMPOPPOPLPUG    ԕ- k  vA W  ~e0fv  O ML  4 ҋ D~C (  . v  ӕ0 (f vLv Le0 9e  7wVe& { register char t; register char *p; register int count; p = buf; count = nbytes / 2; do { t = *p; *p = *(p+1); *++ m  f~  f  f~ w7 j ` \0   HWp `e0eӕ?f0p = t; p++; } while(--count > 0); } die(msg, p1) char *msg; { extern int fout; register char c; flush(); fout = 2; if( ,&P   @f  7 < -fwdAB Q (c = *msg) == '-') msg++; printf(msg, p1); putchar('\n'); flush(); fout = 1; if(c != '-') exit(-1); }  OfA  ^ y   F y @0fA  @9 fA @e&7e  e@@ 5^ ^ $% x^  Z b^ ^ $% #NZ f^ w7@H w7 fwmN wwmfwN wwv f@wf:e  e@@ 5^ ^ $% % Nfff $eZ wF _"w .DC wbT wf |@@& BFw B 5  ʥ ʥ ʥ- ʥ9 Wp @@`e ww n rm5A1`T   %  A'f   r e0@Aaʥ0  w7Fb Can't allocate that much storage %l div 5 (%l splits), %l div 239 (%l splits) 1 r    @a& 2    2    2   2  Vw8w "dtohxfe:cHslurDpOdX(null)DCA@@ r# @ww r @w r `@ ` @7( w X r |@ @f& CD pAa@ `K &f$   real 5:17.0 user 4:35.0 sys 4.6    vrƅ& 6 vrUw ~w` DeV  P  % fw7 < 7 < ׯ2 - * ( w 7   .w eB J ӕ-  o^ xU d  w r f e0&H )%M%" 7 $xWpex  " 7`#e-f&  7`#Ne Ne N  HN& %w w _& N  N& %_" "X X_ LNef  Nt Wt @`m 7#ww xd Ne&e T  wpw ^ DC˥a ˥z $& %_" 5 @e5e % 55 ",a" %e, ,e@   w(w 3WpCex5%x B-7""@m7"u-wf@w w fw JA 7 fAW,f B@ 8 @  w w _N 5 "N H N& %_ Z" %x&  <" 8"2N&61fA   @ @e7 1@ 1wfwwwfwAef  N& %_Nef 55 @! e  t55 N 5 N& Q  OfA  ^ y   F y @0fA  @9 fA %_&f  !!! % !_"%& h _h!"Ne %WKӕ %R& %@e&7HwD7>@w47 $f@wwwf@www f& & _"5 Ne % % % A rf5`  %ӕ ӕ@e %F & 6 % w _%2@ (7\ XP%J Dt 78% "% 7 y  "Ne % %& j -"%""7p %&  @ %V   %  m7  7 55T  X  X X %NT fX 6 & 6 % $w _   eD5l6̋,5# <&s4  * B :  N w( _w  %e-&  " %%&   w@0 & &  r eA! y   eu f  7! w &%M&  Ce lhWpDex 4&  w| w j  %.&  Wp! % ( x! %%( N@ % <@0 5 eN  ) eN   CexD  w4 w " #DC ̥̋/C ̥ḁze @=w w C&ĔҔeN   x d  xw_"w 2@e5Be l CeˋҔҕ @ef &w w &&  w w d ~xPN~ & . e xe*Wpex!=te %  $wRw !$bl %( xZ %%( N  w^w LR EE &tE&&&e : & . e && & . e p w w I  ww n rm5A1`R   %  A'f   r e0@Aa1  w7F\ Can't allocate that much storage %l div 2 (%l splits), %l div 3 (%l splits) dp r   | @a& .  |  .  |  . |  . | Rw8w "Dodxfe6cDslurDlO`X(null)CA@@ r# @ww r @w r `@ ` @7& w X r |@ @f& CD pAa@ `K &f$    real 10:21.0 user 9:29.7 sys 5.1   vrƅ& 6 vrUw ~w^ DeT  N  % bw7 : 7 : ׯ0 - ( & w 7   .w eB J ӕ-  o^ xU d  w r f e0&   ԕ- k  vA W  ~e0fv  O MJ  . ҋ D~C "  ( v  ӕ0 (f vLv Le0 9e  7wVe&  #define NWORDS 200 int nwords NWORDS; struct header { int *last; /* pointer past last word of data */ int *firstnz; /* pointm  b~  b  b~ w7 h ^ Z0   FWp `e0eӕ?f. ,er to first nonzero data word */ } sum, term; int t1[NWORDS], t2[NWORDS]; int *vsum = t1; int *vterm = t2; char toomuch[] = "$P   @f  7 6 -fwbA< Q  OCan't allocate that much storage\n"; main(argc, argv) char **argv; { int factor, sign; int div2, div3, split2; extern int spfA  ^ y   F y @0fA  @9 fA @e&7wlit; int divadd(), divsub(); if(argc > 1) { nwords = atoi(argv[1]); if(nwords <= 0) nwords = NWORDS; if(nwords > NWOe  e@@ 5X X % tX  T ^X X %NT fX 6e7@B w7 fwmH wwmfwH wwt f@wdw  e@@ 5X  X % % Nfff eT wF _"w .DC `N wf |@@& BFw B 5  ʥ ʥ ʥ- ʥ9 Wp @@`eʥ0J  { dig[i] = k % 10 + '0'; k =/ 10; } while(--i >= 0); i = 0; } putc(dig[i], obuf); if(--g <= 0) { if(--ln  v ӕ0 (f vLv Le0 9eJD <6 7&wVeRDS) { if((vsum = sbrk(2*nwords*2)) == -1) { write(2, toomuch, sizeof toomuch); exit(-1); } vterm = vsum + nw <= 0) { putc('\n', obuf); ln = 10; } else putc(' ', obuf); g = 5; } } putc('\n', obuf); fflush(obuf); } ords; } } div2 = div3 = split = 0; clear(&sum, vsum); clear(&term, vterm); vterm[0] = 4; /* 4 * arctan(1/2) */ factor = 1; sign = 1; divide(&term, 2, &term); do { if(divadd(&term, factor, &sum, sign) == 0) break; div2++; factor =+ 2; sign = ~sign; } while(divide(&term, 2*2, &term) != 0); clear(&term, vterm); split2 = split; vterm[0] = 4; /* 4 * arctan(1/3)  real 10:21.0 user 9:29.7 sys 5.1 */ factor = 1; sign = 1; divide(&term, 3, &term); do { if(divadd(&term, factor, &sum, sign) == 0) break; div3++; factor =+ 2; sign = ~sign; } while(divide(&term, 3*3, &term) != 0); if(argc > 2) printf("%l div 2 (%l splits), %l div 3 (%l splits)\n", div2, split2, div3, split - split2); print(&sum); } clear(hp, vec) register struct header *hp; register int *vec; { register int n; hp->firstnz = vec; n = nwords; do { *vec++ = 0; } while(--n); hp->last = vec; } int obuf[259]; pri l"6 < e5`4 1ʕ 55 um Ne > 5 Ne& > ʥ  nt(hp) struct header *hp; { register int i, g; register unsigned int k; int n, ln; char dig[4]; /* log(65536) / log(10000)"7  y Ne bF f 5 >f& %0 %" % = 1.204 ~~ 1 + 1/5 */ n = nwords + nwords/5; /* gives number of 4-digit groups */ hp->firstnz++; /* ignore first word ( = 3. , "f %%,w _" w ~wDe   % p wd7 7 ׯ-  ) */ obuf[0] = 1; /* select std output for obuf */ ln = 10; /* 10 groups per line */ g = 5; /* of 5 digits each */ i =  w7  .weNB J ӕ-Z V o^ xU d @ w r f e04; /* extract in groups of 4 */ for(;;) { if(++i >= 4) { if(--n <= 0) break; k = multiply(hp, 10000); i = 3; do&   ԕ- k  vA W  ~e0fv  O M ҋ D~CK  & n   w2w "DC%: Le`m e rfww p@&f L%jinfo", "unk6" }; listdir() { register struct direntry *dp; findspace(0); /* find largest free spot */ printf("volume: %s\ths==0) gblk--; } else tent.lastbyte =- 512; } else tent.lastbyte = 512; tent.lastb = gblk; inserta(dent); } putbuf() { if(as %d files, %d blocks, %d free, largest free = %d\n\n", cstring(dir->vname), dir->numfiles, dir->eovb, nfree, tent.lastb-te(gblk =+ 2)>tent.lastb) return(err(0,"Not enough room")); if(write(tkfil,gbuf,1024)!=1024) return(err(0,"Write error")); returnt.firstb); for(dp=dir; ++dp <= &dir[dir->numfiles]; ) { printf("%15s %3d %2d %3s %2d", cstring(dp->fname), dp->lastb - n(0); } inserta(dent) struct direntry *dent; { register *bp, *tp; register n; if(dir->numfiles>=77) return(err(0,"No room idp->firstb, (dp->actime>>4)&037, month[dp->actime&017], (dp->actime>>9)&0177 ); if(files) /* full-listing flg when used w&  m   p ~  p   p ~ w7   0   Wp `e0eӕ?n directory")); tp = dent+1; for(bp = &dir[++dir->numfiles]; bp>tp; ) *(bp + (sizeof tent / 2)) = *--bp; bp = &tent; n = f ,P   @f l '7 Z 'PH-B:fw w sizeof tent / 2; do *tp++ = *bp++; while(--n); } delete(dent) struct direntry *dent; { register *bp, *ep; if(dent==0 || dir->numfiles<=1) return(err(0,"Error in delete")); ep = &dir[dir->numfiles]; for(bp=dent; bpnumfiles--; } tstring(st, tst) /* copy C string to terak string */ char *st, *tst; /* also handle slashes in pathnames */ { register char *s, *t; s = st; t = tst+1; while(*s) { if(*s == '/') t = tst+1; else if(*s>='a' && *s<='z') *t++ = *s + 'A' - 'a'; else *t++ = *s; s++; } tst[0] = s-st; } cstring(tst) /* converts terak to C string -- returns pointer BRf@wwwf @fA w,w"e"w"ew"~@lw"v */ char *tst; { register n; register char *p, *cp; static buf[20]; p = tst; cp = buf; n = *p++; do *cp++ = *p++; while(Alewi &@t`e w N  ww DeL@40 & n  w--n > 0); *cp++ = 0; return(buf); } crunch() { err(0, "Crunch not yet implemented"); } char *month[] { "bad", "jan", "feb",/%J %K  t5 t5N  5N  5  B-B-%B-B-% "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }, *ftype[] { "null", "xdsk", "code", "text", "data", "L  .&J n.%e  %69I n.%9I n.%/ II n.% Ie I n.% scr~codelesscr~pr_s_lnscr~pr_addr8az21.ov~proc_mnvlineop1& I 8%fe~I n.%/NPB 0 w.w . $$8I n- *I&I |8 n- n- L/II op2op3op4~getmode~oplastchptokr~proc_IRope H n-wf.w V.l /6C 0H5@ _ xB5.  . H$HHC .7 ~proc_Ropr~proc_IM4op~proc_BA|oprval~proc_BXop|H & & & .xHbH e.bHA v57nC /7@|B77 y H: .w-,H rsir~proc_Xpopsrt~proc_DA opT, 5 ,5@G , 57`. # ".G -  f , 5%%: .5  " az211.o8~jp8opqu~sdu1u2regcntreg~shift". |G -C -5 dG,& T, 5̥"̥'5 ̋L̋C . D G -wmD-_ C_ F: .5$- - (" "._ " ". F C -e,_ F -F &0t7`,_ ! ". F<   B .N . wT2t t@ff %t @EtE4P@E C -e,_ jF -bF &0 ~, ,fB /t,@B75 y X _  & & P,FF e E4P@EE4P  @ff %4w 1 f / 55@A p W@ p Ww_  & & *,EE e5_ +9_ +wE_  _ E h5C_ @ ".|1w l1 &, N& h5 N&e h5 tw@1w 01.K& KK 4/K / 7LVKKK F5 zE - +%+C . bE\E 4/ +++7 +"7\+ 4EC*E F5 >+C . .+&& & w0%B .fK (7ZKXK 7LK0B .9 .sizes~cleanup i~error str~prerr*i~comp_sts1s2