Path: utzoo!utgpu!news-server.csri.toronto.edu!clyde.concordia.ca!mcgill-vision!bloom-beacon!eru!luth!sunic!mcsun!unido!marco!leo From: leo@marco.UUCP (Matthias Pfaller) Newsgroups: comp.os.minix Subject: playing infocom adventures with minix -- zmachine part 1/2 Keywords: infocom (e.g. starcross, deadline, suspended, ...) minix Message-ID: <323@alice.marco.UUCP> Date: 12 Mar 90 16:35:21 GMT Organization: marco GmbH, 8047 Karlsfeld, West-Germany Lines: 2038 Do you like infocom adventures? This is an interpreter for infocom interactive fiction games (NOT interactive fiction plus). So it should be possible to play most of infocom's games with minix. I have tried this interpreter only with the games I own (starcross, deadline and suspended). If the interpreter fails with a game, please send me a bug report. leo@marco.uucp # ----------------------- cut ----------------------- echo x - zmachine.doc sed '/^X/s///' > zmachine.doc << '/' XWith zmachine you can play Interactive Fiction games of Infocom X(NOT Interactive Fiction Plus!!!) X XUsage: zmachine [ -p protocolfile ] [ -w protocol linewith ] X [ -s storyfile ] [ -r restorefile ] [ .dat ] X [ .sav ] X X-p protocolfile : send output after script command to protocolfile X-w protocol linewith: set protocol linewith to linewith X-s storyfile : use storyfile (only necessary if storyfile ends X not with .dat) X-r restorefile : restore savefile restorefile before starting game X (only necessary if restorefile ends not with .sav) X.dat : use storyfile.dat X.sav : restore restorefile.dat X XIf you call zmachine without arguments, it trys to open the file Xstory.dat on the current working directory. If you call zmachine with a Xsavefile argument only, it first tries to open a file with the name Xsavefile.dat, then a file with the name story.dat. X XEditing keys: XIf the TERMCAP-Entry for your terminal is complete, you can use the Xcorresponding special keys on your keyboard; X XCursor left : ^B XCursor right : ^F XUp in history : ^P XDown in history : ^N XDelete left : 0x7f, 0x08 XDelete right : ^D XStart of line : ^A XEnd of line : ^E XKill to end of line : ^K XKill to start of line : ^X XProgram function key : ^I (TAB) XUndo : ^Y XFunction key 0-9 : ^X0 - ^X9 X X XBug reports to leo@marco.UUCP / echo x - zmachine.c sed '/^X/s///' > zmachine.c << '/' X/* X* @(#)zmachine.c 2.24 X*/ X X# include "zmachine.h" X Xchar *story_name; Xstruct dev *printer; X Xjmp_buf restart_buf; X X/************************************************************************/ Xint release; Xint status_type; X XBYTE *ff0; XBYTE *fec; Xchar *terms, *my_terms; /* word terminators */ XBYTE *first_word, *last_word; XUWORD word_len, word_num; X Xchar *line; /* line buffer during status */ Xint use_line = 0; /* line output */ XUWORD *stack, *framep, *sp; /* stack management */ X X#ifdef DEBUG XUWORD ops_ix = 0; Xstruct { X BYTE c_op; X struct address c_pc; X UWORD c_sp; X UWORD c_fp; X} ops[256]; X#endif X XBYTE *short_cuts; Xint save_len; Xint status_len; /* number of status lines */ X Xint line_cnt; X Xint in_status = 1; X X/************************************************************************/ X XWORD l116b2(d0) Xregister WORD d0; X{ X WORD l116ca(); X X if (--d0 < 0) X return(fetchw_op()); X else if (d0 == 0) X return(fetchb_op()); X else if ((d0 = fetchb_op()) != 0) X return(l116ca(d0)); X else X return(*(sp++)); X} X XWORD l116c2(d0) XWORD d0; X{ X WORD l116ca(); X X if (!d0) X return(*sp); X else X return(l116ca(d0)); X} X XWORD l116ca(d0) XWORD d0; X{ X if (d0 < 0x10) X return(framep[- d0 + 1]); X else X return(word_get(&fec[(d0 - 0x10)*2])); X} X Xvoid l116ee(d0, d1) XWORD d0, d1; X{ X if (!d0) X *sp = d1; X else X if (d0 < 0x10) X framep[- d0 + 1] = d1; X else X word_put(&fec[(d0 - 0x10)*2], d1); X} X Xvoid l11720(d0) XWORD d0; X{ X WORD d1; X X if (d1 = fetchb_op()) X l116ee(d1, d0); X else X *(--sp) = d0; X} X Xvoid l1171c(d0) XWORD d0; X{ X l11720(d0 & 0xff); X} X X#ifdef DEBUG Xvoid zcore_dump() X{ X int i, ix; X FILE *fp; X X fp = fopen("zcore", "w"); X if (!fp) X fp = stderr; X X fprintf(fp, "sp = %04x fp = %04x\n", sp-stack, framep-stack); X X fprintf(fp, "Stack:"); X for (i = 0; i < 256; i++) X { X if (!(i % 8)) X fprintf(fp, "\n%04x: ", i); X X fprintf(fp, "%04x ", stack[i]); X } X X fprintf(fp, "\nLast instructions(fp:sp:addr:op):\n"); X for (i = 256; i; i--) X { X ix = (ops_ix++ & 0xff); X if (!(i % 4)) X fprintf(fp, "\n"); X X fprintf(fp, "%02x:%02x:%05lx:%02x ", ops[ix].c_fp, ops[ix].c_sp, X (long)ops[ix].c_pc.offset|((long)ops[ix].c_pc.segment<<9), X ops[ix].c_op); X } X fprintf(fp, "\n"); X unlink("zcore.sav"); X save_gf("zcore.sav"); X} X#endif X X/************************************************************************/ X/* op-codes */ X X/************************************************************************/ X/* op-code utilities */ X X# define dojmp() jump(0) X# define dontjmp() jump(1) X Xvoid jump(d1) Xregister WORD d1; X{ X register WORD d0; X void ret_0(), ret_1(); X X d0 = fetchb_op(); X if(d0 & 0x80) X d1++; X X d0 &= ~0x80; X X if (!(d0 & 0x40)) X { X d0 &= ~0x40; X d0 <<= 8; X d0 |= fetchb_op(); X if (d0 & 0x2000) X d0 |= ~0x3fff; X } X else X d0 &= ~0x40; X X if (--d1) X { X if (!d0) X ret_0(); X else if (!(--d0)) X ret_1(); X else X { X pc.offset += (d0 - 1); X load_code(); X } X } X} X XBYTE *l11846(d0) XWORD d0; X{ X return(ff0+9*d0+0x35); X} X XBYTE *l11856(a0) XBYTE *a0; X{ X register BYTE *p; X register WORD d; X X p = main_p + word_get(a0+7); X d = *(p++)*2; X return(p + d); X} X XBYTE *l11870(a0) XBYTE *a0; X{ X register WORD d; X X d = (*(a0++)>>5) + 1; X return(a0 + d); X} X Xvoid illegal() X{ X#ifdef DEBUG X zcore_dump(); X#endif X fatal("Bad operation", story_name); X} X X/************************************************************************/ X/* class 0 */ X Xvoid ret_1() X{ X void ret(); X ret(1); X} X Xvoid ret_0() X{ X void ret(); X ret(0); X} X Xvoid print_im() X{ X decode(&pc); X load_code(); X} X Xvoid printcr_im() X{ X void newline(); X print_im(); X newline(); X ret_1(); X} X Xvoid nop() X{ X} X Xvoid save_g() X{ X char *name; X int save_gf(); X X if (!(name = read_sname())) X dojmp(); X else X jump(save_gf(name)); X} X Xint save_gf(p) Xchar *p; X{ X extern char *iovers; X UWORD *csp; X X if (open_save_w(p)) X return(0); X X csp = sp; X *(--sp) = pc.segment; X *(--sp) = pc.offset; X#ifdef GEMDOS X /* sorry, its awful but compatibel to infocom's interpreter */ X *(--((long *)sp)) = (BYTE *)framep - (BYTE *)stack; X *(--sp) = release; X *(((long *)stack)) = (BYTE *)sp - (BYTE *)stack; X *(stack + sizeof(long)/sizeof(UWORD)) = atoi(iovers); X#else X *(--sp) = framep - stack; X *(--sp) = release; X *stack = sp - stack; X *(stack + 1) = atoi(iovers); X#endif X sp = csp; X X if (write_save(0, 1, stack)) X return(0); X X if (write_save(1, save_len, main_p)) X return(0); X X if (save_keys()) X return(0); X X if (close_save()) X return(0); X X return(1); X} X Xvoid restore_g() X{ X char *name; X int restore_gf(); X X if (!(name = read_rname())) X dojmp(); X else X jump(restore_gf(name)); X} X Xint restore_gf(p) Xchar *p; X{ X extern char *iovers; X int sv; X X if (open_save_r(p)) X return(0); X X if (read_save(0, 1, stack)) X fatal("Save file read error", p); X X#ifdef GEMDOS X sp = (UWORD *)((BYTE *)stack + *((long *)stack)); X#else X sp = stack + *stack; X#endif X X if (*sp++ != release) X fatal("Wrong save file version", p); X X#ifdef GEMDOS X framep = (BYTE *)stack + *(((long *)sp)++); X#else X framep = stack + *sp++; X#endif X pc.offset = *(sp++); X pc.segment = *(sp++); X X sv = word_get(main_h->reserved5); X if (read_save(1, save_len, main_p)) X fatal("Save file read error", p); X word_put(main_h->reserved5, sv); X X#ifdef GEMDOS X if (*(stack + sizeof(long)/sizeof(UWORD)) == atoi(iovers)) X#else X if (*(stack + 1) == atoi(iovers)) X#endif X if (restore_keys()) X fatal("Save file read error", p); X X close_save(); X load_code(); X X return(1); X} X Xvoid restart_g() X{ X line_cnt = 0; X output_chr('\n'); X longjmp(restart_buf); X} X Xvoid ret_sp() X{ X void ret(); X ret(*(sp++)); X} X Xvoid inc_sp() X{ X sp++; X} X Xvoid halt() X{ X clean_up(); X exit(userexit(0)); X} X Xvoid newline() X{ X output_chr('\n'); X} X Xvoid status() X{ X char room[256]; X char *score; X char am_pm; X int hour; X X void write_num(); X void l11e24(); X X use_line = 1; X line = room; X X *line++ = ' '; X l11e24(l116c2(0x10)); X *(line++) = '\0'; X score = line; X if (!status_type) X { X strcpy(line, "Score: "); X write_num(l116c2(0x11)); X *line++ = '/'; X write_num(l116c2(0x12)); X } X else X { X if ((hour = l116c2(0x11)) > 12) X { X hour -= 12; X am_pm = 'p'; X } X else X am_pm = 'a'; X X if (hour == 0) X hour = 12; X X/* X sprintf(line, "Time: %2d:%02d %cm", hour, l116c2(0x12), am_pm); X*/ X strcpy(line, "Time: "); X line += strlen(line); X if (hour < 10) X *line++ = ' '; X write_num(hour); X *line++ = ':'; X if (l116c2(0x12) < 10) X *line++ = '0'; X write_num(l116c2(0x12)); X *line++ = ' '; X *line++ = am_pm; X *line++ = 'm'; X } X *line++ = ' '; X *line++ = '\0'; X output_status(room, score); X use_line = 0; X} X Xvoid verify() X{ X struct address a, end; X int m_len; X long sum; X X output_str("Z-Code 3 interpreter V2.24 for "); X output_str(sysname); X output_str("\n"); X X m_len = main_l; X main_l = 0; X X a.segment = 0; X a.offset = 0x40; X sum = 0; X waddr_to_vaddr(&end, word_get(main_h->len)); X X while(a.segment != end.segment || a.offset != end.offset) X sum += fetchb_data(&a); X X main_l = m_len; X X jump((UWORD)sum == word_get(main_h->checksum)); X} X X/************************************************************************/ X/* class 1 */ X Xvoid bne(d0) XWORD d0; X{ X if(d0) X dojmp(); X else X dontjmp(); X} X Xvoid l1190c(d0) XWORD d0; X{ X register BYTE d1; X X l11720(d1 = l11846(d0)[5]); X X if (d1) X dontjmp(); X else X dojmp(); X} X Xvoid l118f2(d0) XWORD d0; X{ X register BYTE d1; X X l11720(d1 = l11846(d0)[6]); X X if (d1) X dontjmp(); X else X dojmp(); X} X Xvoid l118e4(d0) XWORD d0; X{ X l11720(l11846(d0)[4]); X} X Xvoid l11a7e(d0) XWORD d0; X{ X l11720((main_p[d0-1]>>5)+1); X} X Xvoid l11aac(d0) XWORD d0; X{ X l116ee(d0,l116c2(d0)+1); X} X Xvoid l11aba(d0) XWORD d0; X{ X l116ee(d0,l116c2(d0)-1); X} X Xvoid print_near(d0) XWORD d0; X{ X struct address a; X baddr_to_vaddr(&a,d0); X decode(&a); X} X Xvoid l118a2(d1) XWORD d1; X{ X register BYTE *a0, *a1; X register UWORD d0; X X a1 = l11846(d1); X if (d0 = a1[4]) X { X d0 = (a0 = l11846(d0))[6]; X if (d1 == d0) X a0[6] = a1[5]; X else X { X while ((d0 = (a0 = l11846(d0))[5]) != d1) X ; X a0[5] = a1[5]; X } X a1[4] = a1[5] = 0; X } X} X Xvoid l11e24(d0) XWORD d0; X{ X struct address a; X X baddr_to_vaddr(&a, word_get(l11846(d0)+7) + 1); X decode(&a); X} X Xvoid ret(d0) XWORD d0; X{ X sp = framep + 1; X#ifdef GEMDOS X framep = (BYTE *)stack + *(((long *)sp)++); X#else X framep = stack + *sp++; X#endif X pc.offset = *(sp++); X pc.segment = *(sp++); X load_code(); X l11720(d0); X} X Xvoid bra(d0) XWORD d0; X{ X pc.offset += (d0 - 2); X load_code(); X} X Xvoid print_far(d0) XWORD d0; X{ X struct address a; X waddr_to_vaddr(&a, d0); X decode(&a); X} X Xvoid l11a96(d0) XWORD d0; X{ X l11720(l116c2(d0)); X} X Xvoid not(d0) XWORD d0; X{ X l11720(~d0); X} X X/************************************************************************/ X/* class 2 */ X Xvoid l11824(a0) Xregister WORD *a0; X{ X register WORD d0, d1; X X d1 = *(a0++) - 1; X d0 = *(a0++); X X for(;;) X if(*(a0++) == d0) X { X dontjmp(); X break; X } X else if (!--d1) X { X dojmp(); X break; X } X} X Xvoid cbge(d0, d1) XWORD d0, d1; X{ X jump(d0 < d1); X} X Xvoid cble(d0, d1) XWORD d0, d1; X{ X jump(d0 > d1); X} X Xvoid dcbge(d0, d1) /* decrement, compare and jump greater equal */ XWORD d0, d1; /* dcbge */ X{ X register WORD d2; X X d2 = l116c2(d0) - 1; X l116ee(d0,d2); X if (d2 < d1) X dontjmp(); X else X dojmp(); X} X Xvoid icble(d0, d1) /* increment, compare and jump less equal */ XWORD d0, d1; /* icble */ X{ X register WORD d2; X X d2 = l116c2(d0) + 1; X l116ee(d0,d2); X if (d2 > d1) X dontjmp(); X else X dojmp(); X} X Xvoid l11926(d0, d1) XWORD d0, d1; X{ X if (l11846(d0)[4] == d1) X dontjmp(); X else X dojmp(); X} X Xvoid l11806(d0, d1) XWORD d0, d1; X{ X jump((d1 & ~d0) == 0); X} X Xvoid or(d0, d1) XWORD d0, d1; X{ X l11720(d0 | d1); X} X Xvoid and(d0, d1) X{ X l11720(d0 & d1); X} X X#define tst(a0, d0) (a0[d0 >> 3] & (1<<((~d0)&7))) X#define clr(a0, d0) (a0[d0 >> 3] &= ~(1<<((~d0)&7))) X#define set(a0, d0) (a0[d0 >> 3] |= (1<<((~d0)&7))) X Xvoid tstbit_jz(d0, d1) XWORD d0, d1; X{ X if (tst(l11846(d0), d1)) X dontjmp(); X else X dojmp(); X} X Xvoid setbit(d0, d1) XWORD d0, d1; X{ X set(l11846(d0), d1); X} X Xvoid clrbit(d0, d1) XWORD d0, d1; X{ X clr(l11846(d0), d1); X} X Xvoid l11a9e(d0, d1) XWORD d0, d1; X{ X l116ee(d0, d1); X} X Xvoid l1187c(d0, d1) XWORD d0, d1; X{ X register BYTE *a0, *a1; X void l118a2(); X X l118a2(d0); X a1 = l11846(d1); X a0 = l11846(d0); X X a0[5] = a1[6]; X a0[4] = d1; X a1[6] = d0; X} X Xvoid l11a16(d0, d1) XWORD d0, d1; X{ X struct address a; X baddr_to_vaddr(&a, d0 + d1 * 2); X l11720(fetchw_data(&a)); X} X Xvoid l11a28(d0, d1) XWORD d0, d1; X{ X struct address a; X baddr_to_vaddr(&a, d0 + d1); X l1171c(fetchb_data(&a)); X} X Xvoid l11936(d0, d1) Xregister WORD d0, d1; X{ X register BYTE *a0; X X for (a0 = l11856(l11846(d0)); d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0)) X ; X X if (d1 == d0) X { X if (!(*(a0++) & 0x20)) X l1171c(*a0); X else X l11720(word_get(a0)); X } X else X l11720(word_get(&ff0[(d1-1) * 2])); X X} X Xvoid l11a54(d0, d1) Xregister WORD d0, d1; X{ X register BYTE *a0; X X for (a0 = l11856(l11846(d0)); d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0)) X ; X X if (d1 != d0) X l11720(0); X else X l11720(++a0 - main_p); X} X Xvoid l119a4(d0, d1) Xregister WORD d0, d1; X{ X register BYTE *a0; X X a0 = l11856(l11846(d0)); X X if (d1) X { X for(; d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0)) X ; X if (d1 != d0) X fatal("Non-existant next property", story_name); X else X a0 = l11870(a0); X } X l11720(*a0 & 0x1f); X} X Xvoid add(d0, d1) XWORD d0, d1; X{ X l11720(d0 + d1); X} X Xvoid sub(d0, d1) XWORD d0, d1; X{ X l11720(d0 - d1); X} X Xvoid mul(d0, d1) XWORD d0, d1; X{ X l11720(d0 * d1); X} X Xvoid div(d0, d1) XWORD d0, d1; X{ X l11720(d0 / d1); X} X Xvoid mod(d0, d1) XWORD d0, d1; X{ X l11720(d0 % d1); X} X Xvoid call(a0) Xregister WORD *a0; X{ X register WORD d0, d1, d2; X X d2 = *(a0++); X if ((d0 = *(a0++)) == 0) X l11720(0); X else X { X d2--; X *(--sp) = pc.segment; X *(--sp) = pc.offset; X#ifdef GEMDOS X *(--((long *)sp)) = (BYTE *)framep - (BYTE *)stack; X#else X *(--sp) = framep - stack; X#endif X waddr_to_vaddr(&pc,d0); X load_code(); X framep = sp - 1; X if (d1 = fetchb_op()) X { X do X { X d0 = fetchw_op(); X if (--d2 >= 0) X d0 = *(a0++); X *(--sp) = d0; X } X while (--d1 > 0); X } X } X} X Xvoid l11a38(d0, d1, d2) XWORD d0, d1, d2; X{ X word_put(&main_p[d0 + d1 * 2], d2); X} X X Xvoid l11a48(d0, d1, d2) XWORD d0, d1; WORD d2; X{ X main_p[d0+d1] = (BYTE)d2; X} X Xvoid l1196e(d0, d1, d2) Xregister WORD d0, d1; WORD d2; X{ X register BYTE *a0; X X for (a0 = l11856(l11846(d0)); d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0)) X ; X X if (d1 != d0) X fatal("Non-existant put property", story_name); X X if (*(a0++) & 0x20) X word_put(a0, d2); X else X *a0 = d2; X} X XUWORD findword(a0) XUWORD *a0; X{ X register UWORD d0, step, code0, code1; X register BYTE *word; X X d0 = word_num; X step = word_len; X X code0 = *a0; X code1 = *(a0+1); X X for ( d0 >>= 1, step <<= 1; d0 >>= 1; step <<= 1) X ; X X word = &first_word[step - word_len]; X X do X { X step >>= 1; X d0 = word_get(word); X if (code0 <= d0) X { X if (code0 != d0) X word -= step; X else X { X d0 = word_get(word+2); X if (code1 <= d0) X { X if (code1 != d0) X word -= step; X else X return(word - main_p); X } X else X { X word += step; X if (last_word < word) X word = last_word; X } X } X } X else X { X word += step; X if (last_word < word) X word = last_word; X } X } X while(word_len <= step); X return(0); X} X Xchar *wordend(c) Xregister char c; X{ X register char *p; X X for(p = terms; *p; p++) X if (*p == c) X return (p); X return(NULL); X} X Xvoid input(a0) XWORD *a0; X{ X char c; X char *inp; /* input field */ X char *end; /* end of input line */ X BYTE *out; /* output field */ X BYTE *outp; /* pointer into output field */ X char src_word[8]; /* source word */ X UWORD dst_word[4]; /* word coded in z-code */ X register char *lp; /* pointer into line */ X register char *cp; /* pointer into src_word */ X char *ws; /* pointer into line (start of line) */ X register int wc; /* word count */ X register char *p; /* scratch */ X static struct hist_buf history = {I_HIST_LEN, NULL, NULL}; X /* history buffer */ X X if (!history.hb) X { X if (!(history.undo = history.hb = malloc(history.len))) X no_mem_error(); X else X history.hb[0] = history.hb[1] = '\0'; X } X X inp = (char *)&main_p[a0[1]]; X out = &main_p[a0[2]]; X X status(); X output_chr(FLUSH); X X end = read_str(inp, &history); X X lp = inp + 1; X outp = out + 2; X wc = 0; X X for(;;) X { X cp = src_word; X ws = lp; X while (lp < end) X { X if (p = wordend(c = *lp++)) X break; X else X if (cp < src_word + 6) X *cp++ = c; X } X X if (lp < end) X { X if (cp != src_word) X lp--; X else if (p < my_terms) X *cp++ = c; X else X continue; X } X else X { X if (src_word == cp) X break; X } X X if (++wc >= out[0]) X { X output_chr('\n'); X output_str("too many words for internal buffer\n"); X out[1] = 0; X return; X } X X outp[2] = (char)(lp - ws); X outp[3] = (char)(ws - inp); X *cp = '\0'; X encode(dst_word, src_word); X word_put(outp, findword(dst_word)); X outp += 4; X } X out[1] = wc; X X if (word_get(main_h->reserved5) & 1) X { X for (p = inp; *++p; ) X putc_dev(*p, printer); X putc_dev('\n', printer); X } X} X Xvoid l11dcc(d0) XWORD d0; X{ X output_chr(d0); X} X Xvoid write_num(d0) XWORD d0; X{ X char buf[16]; X register char *p; X int flag; X X flag = 0; X if (d0 < 0) X { X flag = 1; X d0 = -d0; X } X X p = buf + 15; X *p = '\0'; X do X *--p = d0 % 10 + '0'; X while(d0 /= 10); X X if (flag) X *--p = '-'; X X output_str(p); X} X Xvoid rnd(d0) XWORD d0; X{ X extern long zrandom(); X/* X static UWORD rnd0 = 0xffff, rnd1 = 0; X register long d1; X X if (rnd0 == 0xffff) X { X d1 = Random(); X rnd0 = d1 >> 16; X rnd1 = d1; X } X X d1 = rnd0; X d1 |= (rnd0 = rnd1) << 16; X d1 >>= 1; X d1 = (rnd1 ^= d1); X d1 &= 0x7fff; X l11720(((UWORD)d1 % d0) + 1); X*/ X l11720((((UWORD)zrandom() & (UWORD)0x7fff) % d0) + 1); X} X Xvoid l11aa2(d0) XWORD d0; X{ X *(--sp) = d0; X} X Xvoid l11aa6(d0) XWORD d0; X{ X l116ee(d0, *(sp++)); X} X Xvoid l11e5e(d0) XWORD d0; X{ X status_len = d0; X} X Xvoid l11e7e(d0) XWORD d0; X{ X static int x,y; X X if (d0 == 0) X { X if (in_status) X gotoXY(x,y); X X in_status = 0; X } X else if(d0 == 1) X { X if (!in_status) X storeXY(&x, &y); X X in_status = 1; X gotoXY(0,1); X } X} X X/************************************************************************/ X/* main interpreter loop */ X Xvoid (*class0[])() = { X ret_1, /* op 0xb0 */ X ret_0, /* op 0xb1 */ X print_im, /* op 0xb2 */ X printcr_im, /* op 0xb3 */ X nop, /* op 0xb4 */ X save_g, /* op 0xb5 */ X restore_g, /* op 0xb6 */ X restart_g, /* op 0xb7 */ X ret_sp, /* op 0xb8 */ X inc_sp, /* op 0xb9 */ X halt, /* op 0xba */ X newline, /* op 0xbb */ X status, /* op 0xbc */ X verify, /* op 0xbd */ X illegal, /* op 0xbe */ X illegal /* op 0xbf */ X}; X Xvoid (*class1[])() = { X bne, X l1190c, X l118f2, X l118e4, X l11a7e, X l11aac, X l11aba, X print_near, X illegal, X l118a2, X l11e24, X ret, X bra, X print_far, X l11a96, X not X}; X Xstruct { X void (*func)(); X BYTE flag; X } class2[] = { X { illegal, 1 }, /* 00 */ X { l11824, 0 }, /* 01 */ X { cbge, 1 }, /* 02 */ X { cble, 1 }, /* 03 */ X { dcbge, 1 }, /* 04 */ X { icble, 1 }, /* 05 */ X { l11926, 1 }, /* 06 */ X { l11806, 1 }, /* 07 */ X { or, 1 }, /* 08 */ X { and, 1 }, /* 09 */ X { tstbit_jz, 1 }, /* 0a */ X { setbit, 1 }, /* 0b */ X { clrbit, 1 }, /* 0c */ X { l11a9e, 1 }, /* 0d */ X { l1187c, 1 }, /* 0e */ X { l11a16, 1 }, /* 0f */ X { l11a28, 1 }, /* 10 */ X { l11936, 1 }, /* 11 */ X { l11a54, 1 }, /* 12 */ X { l119a4, 1 }, /* 13 */ X { add, 1 }, /* 14 */ X { sub, 1 }, /* 15 */ X { mul, 1 }, /* 16 */ X { div, 1 }, /* 17 */ X { mod, 1 }, /* 18 */ X { illegal, 1 }, /* 19 */ X { illegal, 1 }, /* 1a */ X { illegal, 1 }, /* 1b */ X { illegal, 1 }, /* 1c */ X { illegal, 1 }, /* 1d */ X { illegal, 1 }, /* 1e */ X { illegal, 1 }, /* 1f */ X { call, 0 }, /* 20 */ X { l11a38, 1 }, /* 21 */ X { l11a48, 1 }, /* 22 */ X { l1196e, 1 }, /* 23 */ X { input, 0 }, /* 24 */ X { l11dcc, 1 }, /* 25 */ X { write_num, 1 }, /* 26 */ X { rnd, 1 }, /* 27 */ X { l11aa2, 1 }, /* 28 */ X { l11aa6, 1 }, /* 29 */ X { l11e5e, 1 }, /* 2a */ X { l11e7e, 1 }, /* 2b */ X { illegal, 1 }, /* 2c */ X { illegal, 1 }, /* 2d */ X { illegal, 1 }, /* 2e */ X { illegal, 1 }, /* 2f */ X { illegal, 1 }, /* 30 */ X { illegal, 1 }, /* 31 */ X { illegal, 1 }, /* 32 */ X { illegal, 1 }, /* 33 */ X { illegal, 1 }, /* 34 */ X { illegal, 1 }, /* 35 */ X { illegal, 1 }, /* 36 */ X { illegal, 1 }, /* 37 */ X { illegal, 1 }, /* 38 */ X { illegal, 1 }, /* 39 */ X { illegal, 1 }, /* 3a */ X { illegal, 1 }, /* 3b */ X { illegal, 1 }, /* 3c */ X { illegal, 1 }, /* 3d */ X { illegal, 1 }, /* 3e */ X { illegal, 1 } /* 3f */ X}; X Xint oc; Xint o1; X Xvoid run() X{ X register UWORD d0, d1, d2, d3, d4; X register UWORD *argp, *bp; X UWORD args[6]; X UWORD bits[4]; X X argp = args; X for(;;) X { X#ifdef DEBUG X ops[ops_ix].c_pc.offset = pc.offset; X ops[ops_ix].c_pc.segment = pc.segment; X ops[ops_ix].c_sp = sp - stack; X ops[ops_ix].c_fp = framep - stack; X ops[ops_ix].c_op = d0 = fetchb_op(); X ops_ix = (ops_ix + 1) & 0xff; X#else X d0 = fetchb_op(); X#endif X if (d0 < 0x80) X { X d1 = l116b2((d0 & 0x40)?2:1); X d2 = l116b2((d0 & 0x20)?2:1); X X if (class2[d0 & 0x1f].flag) X (*class2[d0 & 0x1f].func)(d1, d2); X else X { X argp[0] = 2; X argp[1] = d1; X argp[2] = d2; X (*class2[d0 & 0x1f].func)(argp); X } X } X else if (d0 < 0xb0) X (*class1[d0 & 0x0f])(l116b2((d0 >> 4) & 0x03)); X else if (d0 < 0xc0) X (*class0[d0 & 0x0f])(); X else X { X d2 = d0; X bp = &bits[4]; X d0 = fetchb_op(); X *(--bp) = d0; X *(--bp) = (d0 >>= 2); X *(--bp) = (d0 >>= 2); X *(--bp) = (d0 >>= 2); X for (d4 = 0, d3 = 4; d3; d3--) X { X if ((d0 = *(bp++) & 3) == 3) X break; X argp[++d4] = l116b2(d0); X } X argp[0] = d4; X X if (class2[d2 & 0x3f].flag) X (*class2[d2 & 0x3f].func) X (argp[1],argp[2],argp[3],argp[4]); X else X (*class2[d2 & 0x3f].func)(argp); X } X } X} X X/************************************************************************/ X/* initializiation */ Xno_mem_error() X{ X fatal("Out of memory", NULL); X} X Xmain(argc,argv) Xint argc; char **argv; X{ X struct header h; X register BYTE *p, *q, *r; X register int i; X X char space[128]; X extern int optind; X extern char *optarg; X char *usage; X X int c, sflag, rflag; X char *restore_name; X char *strchr(), *strrchr(); X X# if defined(OSK) X usage = "\15\12Usage:\tzmachine [ -p protocolfile ] [ -w protocol linewith ]\ X\15\12\t[ -s storyfile ] [ -r restorefile ] [ .dat ]\ X\15\12\t[ .sav ]\15\12"; X# else X usage = "\r\nUsage:\tzmachine [ -p protocolfile ] [ -w protocol linewith ]\ X\r\n\t[ -s storyfile ] [ -r restorefile ] [ .dat ]\ X\r\n\t[ .sav ]\r\n"; X# endif X X story_name = restore_name = NULL; X X sflag = rflag = 0; X while ((c = getopt(argc, argv, "s:p:r:w:")) != EOF) X { X switch(c) X { X case 's': X story_name = optarg; X sflag++; X break; X X case 'p': X print_name = optarg; X break; X X case 'r': X restore_name = optarg; X rflag++; X break; X X case 'w': X if (!(printer_width = atoi(optarg))) X printer_width = 80; X break; X X default: X write(2, usage, strlen(usage)); X exit(userexit(1)); X } X } X X while (optind < argc) X { X char *tmp; X X if ((tmp = strrchr(argv[optind],'.')) && X (!strcmp(tmp,".dat") || !strcmp(tmp, ".DAT"))) X story_name = argv[optind]; X else if (tmp && (!strcmp(tmp, ".sav") || !strcmp(tmp, ".SAV"))) X { X rflag++; X restore_name = argv[optind]; X } X else X { X fatal("Unknown filetype", argv[optind]); X } X optind++; X } X X X if (!story_name && restore_name && strchr(restore_name,'.')) X { X strcpy(space, restore_name); X strcpy(strchr(space, '.'), ".dat"); X if (access(space,0)) X story_name = "story.dat"; X else X story_name = space; X } X X if (!story_name) X story_name = "story.dat"; X X if (open_story()) X fatal("Can't open", story_name); X X read_header(&h); X X if (h.zmachine != 3) X fatal("Wrong Z-machine version", story_name); X X mmu_init(&h); X X read_story(0, main_l, main_p); X X in_status = 0; X X release = word_get(h.release); X X status_type = (h.flags & 2) >> 1; X X ff0 = main_p + word_get(h.reserved2); X fec = main_p + word_get(h.reserved3); X short_cuts = main_p + word_get(h.short_cuts); X save_len = btop((long)word_get(h.save_len)); X if (!(stack = (UWORD *)malloc(0x100 * sizeof(WORD)))) X no_mem_error(); X X printer = init_dev(prot_write, prot_crlf, printer_width, 0, 0); X X if (!(terms = malloc(0x40))) X no_mem_error(); X X q = main_p + word_get(h.vocabulary); X for(p = (BYTE *)terms, i = *(q++); i; i--) X *p++ = *q++; /* copy terminators */ X X my_terms = (char *)p; X for(r = (BYTE *)" \011\015.,?"; *p++ = *r++;) X ; /* copy my terminators */ X X word_len = *q++; /* word-len */ X word_num = word_get(q); /* number of words */ X q += 2; X X first_word = q; /* start of words */ X last_word = (word_num - 1) * word_len + first_word; X /* end of words */ X X if (setjmp(restart_buf)) X { X rflag = 0; X i = word_get(main_h->reserved5); X read_story(0, save_len, main_p); X word_put(main_h->reserved5, i); X } X X printer->bp = printer->buffer; X printer->count = 0; X main_h->flags |= 32; X X status_len = 1; X init_con(); X if (!rflag) X { X sp = &stack[0x100]; X framep = sp - 1; X baddr_to_vaddr(&pc, word_get(h.initial_pc)); X load_code(); X } X else X { X if (restore_gf(restore_name)) X jump(1); X else X fatal("Cannot load restore file", restore_name); X } X run(); X} / echo x - zmachine.h sed '/^X/s///' > zmachine.h << '/' X/* X* @(#)zmachine.h 2.24 X*/ X X# include X# include X# include "config.h" X Xchar *lmalloc(), *malloc(), *realloc(); X Xstruct dev { X char *buffer; X int width; X int height; X char *bp; X int count; X void (*out_f)(); X int wrap; X void (*crlf_f)(); X }; X Xstruct hist_buf { X int len; X char *hb; X char *undo; X }; X Xstruct header X { X BYTE zmachine; /* 00 */ X BYTE flags; /* 01 */ X ZWORD release; /* 02 */ X ZWORD minmem; /* 04 */ X ZWORD initial_pc; /* 06 */ X ZWORD vocabulary; /* 08 */ X ZWORD reserved2; /* 0a ? */ X ZWORD reserved3; /* 0c ? */ X ZWORD save_len; /* 0e */ X ZWORD reserved5; /* 10 zero */ X BYTE serial[6]; /* 12 */ X ZWORD short_cuts; /* 18 */ X ZWORD len; /* 1a */ X ZWORD checksum; /* 1c */ X ZWORD reserved8; /* 1e zero */ X ZWORD reserved9[16]; /* 20 zero */ X }; X X Xstruct virt_page { X WORD page; X unsigned long lru; X BYTE *paddr; X }; X Xstruct address X { X WORD segment; X WORD offset; /* MUST be signed */ X }; X X# define FLUSH 0x7f /* Flush output buffer */ X Xextern char *story_name; /* Name of story file */ Xextern char *print_name; /* Name of protocol file */ Xextern int printer_width; /* Character-width of protocol X file */ Xextern struct dev *screen, *printer; /* screen and protocol device X structures */ X Xextern int main_l; /* len of main memory in pages */ Xextern BYTE *main_p; /* start of main memory */ Xextern struct header *main_h; /* pointer to header structure X in main memory */ Xextern struct address pc; /* programcounter */ Xextern struct virt_page *pc_page; /* currently executed page */ X Xextern char *sysname; /* system name */ X X/* from io.c */ X Xstruct dev *init_dev(); Xvoid scr_write(); Xvoid prot_write(); Xvoid prot_crlf(); Xvoid output_status(); Xvoid output_chr(); Xvoid output_str(); Xchar *read_str(); Xint save_keys(); Xint restore_keys(); X Xextern int pfile; X X/* from zbios.c */ X Xlong zrandom(); Xvoid con_flush(); Xvoid con_chr(); Xvoid con_str1(); Xvoid con_str2(); Xvoid con_crlf(); Xvoid reverseON(); Xvoid reverseOFF(); Xvoid cursorON(); Xvoid cursorOFF(); Xvoid gotoXY(); Xvoid storeXY(); Xint con_getc(); Xvoid init_con(); X Xint open_story(); Xint close_story(); Xvoid read_story(); Xvoid read_header(); X Xchar *read_sname(); Xchar *read_rname(); Xint open_save_w(); Xint open_save_r(); Xint close_save(); Xint write_save(); Xint read_save(); Xvoid fatal(); Xvoid clean_up(); Xint userexit(); X X/* from mem.c */ X Xvoid load_code(); XBYTE *load_page(); Xlong ptob(); XUWORD btob(); XUWORD word_get(); Xvoid word_put(); XBYTE fetchb_data(); XUWORD fetchw_data(); XBYTE fetchb_op(); XUWORD fetchw_op(); Xvoid baddr_to_vaddr(); Xvoid waddr_to_vaddr(); X X/* from code.c */ X Xvoid decode(); Xvoid encode(); / echo x - mem.c sed '/^X/s///' > mem.c << '/' X/* X* @(#)mem.c 2.24 X*/ X X# include "zmachine.h" X X# define LOCK 0xffffffffL X XBYTE *main_p; /* main memory pointer */ Xint main_l; /* main memory len in pages */ Xstruct header *main_h; /* header pointer */ X Xstruct virt_page *pc_page; /* page of current pc */ Xstruct virt_page main_page; /* page control for main memory */ Xstruct virt_page *c_page; /* current active page */ Xstruct virt_page *virt_p; /* the virtual memory array */ Xstruct address pc; /* program counter */ X Xunsigned long lruc = 0; /* LRU counter */ X X/************************************************************************/ X X/* find free page */ X Xstruct virt_page *find_page() X{ X register struct virt_page *u, *v; X register long t; X X for(v = virt_p, t = LOCK; v->page != -1; v++) X if (v->lru < t) X { X t = v->lru; X u = v; X } X X return(u); X} X X X/* load a page */ X XBYTE *load_page(page) Xregister WORD page; X{ X register struct virt_page *v; X X if (page != c_page->page) X { X lruc++; X for (v = virt_p; v->page != -1; v++) X { X if (v->page == page) X { X if (pc_page->page != page) X v->lru = lruc; X X c_page = v; X return(c_page->paddr); X } X } X c_page = find_page(); X c_page->page = page; X c_page->lru = lruc; X read_story(c_page->page, 1, c_page->paddr); X } X return(c_page->paddr); X} X X X/* load page for current pc */ X Xvoid load_code() X{ X pc.segment += pc.offset >> 9; /* pc.offset may be negative */ X pc.offset &= 0x1ff; X if (pc.segment != pc_page->page) X { X pc_page->lru = lruc; X X if (pc.segment >= main_l) X { X load_page(pc.segment); X pc_page = c_page; X pc_page->lru = LOCK; X } X else X { X main_page.page = pc.segment; X main_page.paddr = main_p+ptob(pc.segment); X pc_page = &main_page; X } X } X} X X X/* page to byte address */ X Xlong ptob(page) XUWORD page; X{ X return(((long)page << (long)9) & 0x1ffffL); X} X X X/* byte to page address */ X XUWORD btop(byte) Xlong byte; X{ X return((byte & 0x1ff ? (byte >> 9)+1:(byte >> 9)) & 0xff); X} X X X/* get word */ X XUWORD word_get(p) XBYTE *p; X{ X register UWORD i; X i = *p++ << 8; X return(i | *p); X} X X X/* put word */ X Xvoid word_put(p, d) XBYTE *p; register UWORD d; X{ X p[1] = d & 0xff; X p[0] = d >> 8; X} X X X/* fetch byte data */ X XBYTE fetchb_data(a) Xregister struct address *a; X{ X BYTE *load_page(); X register BYTE r; X X if (a->segment < main_l) X r = main_p[ptob(a->segment) | a->offset]; X else X r = load_page(a->segment)[a->offset]; X X if (++(a->offset) == 0x200) X { X a->offset = 0; X (a->segment)++; X } X return(r); X} X X X/* fetch word data */ X XUWORD fetchw_data(a) Xstruct address *a; X{ X register UWORD r; X r = fetchb_data(a); X return((r << 8) | fetchb_data(a)); X} X X X/* fetch next byte from pc */ X XBYTE fetchb_op() X{ X register BYTE r; X X r = pc_page->paddr[pc.offset]; X if (++pc.offset >= 0x200) X load_code(); X X return(r); X} X X X/* fetch next word from pc */ X XUWORD fetchw_op() X{ X register UWORD r; X X r = fetchb_op() << 8; X return(r | fetchb_op()); X} X X X/* byte address to virtual address */ X Xvoid baddr_to_vaddr(vaddress, baddress) Xregister struct address *vaddress; register UWORD baddress; X{ X vaddress->segment = (baddress >> 9) & 0xff; X vaddress->offset = baddress & 0x1ff; X} X X X/* word address to virtual address */ X Xvoid waddr_to_vaddr(vaddress, waddress) Xstruct address *vaddress; register UWORD waddress; X{ X vaddress->segment = (waddress >> 8) & 0xff; X vaddress->offset = (waddress & 0xff) * 2; X} X X X/* initialize mmu */ X X#if defined(minix) Xextern int brk(); Xextern char *sbrk(); Xstatic char *oldbrk = NULL; Xstatic char *lmalloc(s) Xlong s; X{ X char *m; X if (!oldbrk) X oldbrk = sbrk(0); X X m = sbrk(0); X if (brk(m + s + 0x2000) != 0) X { X brk(m); X return(NULL); X } X else X { X brk(m + s); X return(m); X } X} X Xstatic free(p) Xchar *p; X{ X brk(oldbrk); X} X#endif X Xvoid mmu_init(h) Xstruct header *h; X{ X long virt_l; X int i; X X if (main_p = (BYTE *)lmalloc(btop((long)word_get(h->len) * 2L) * 512L)) X { X main_l = btop((long)word_get(h->len) * 2L); X virt_l = 2; X if (!(virt_p = (struct virt_page *)lmalloc((0x200L + X sizeof(struct virt_page)) * 2 + X sizeof(struct virt_page)))) X { X free(main_p); X goto low_mem; X } X } X else X { Xlow_mem: X if ((main_p = (BYTE *) X lmalloc((long)btop((long)word_get(h->minmem)) * 512L)) X == NULL) X no_mem_error(); X X main_l = btop((long)word_get(h->minmem)); X X for (virt_l = btop((long)word_get(h->len) * 2L - X (long)word_get(h->minmem)); X virt_l >= 2 && virt_p == NULL; virt_l--) X virt_p = (struct virt_page *)lmalloc((long) X (virt_l * (0x200L + X sizeof(struct virt_page)) + X sizeof(struct virt_page))); X X if (virt_l < 2) X no_mem_error(); X } X X for (i = 0; i < virt_l; i++) X { X virt_p[i].page = -2; X virt_p[i].lru = 0L; X virt_p[i].paddr = (BYTE *)virt_p + X (long)(sizeof(struct virt_page) * X (virt_l + 1L) + 0x200L * (long)i); X } X virt_p[i].page = -1; X X pc_page = c_page = virt_p; X main_h = (struct header *)main_p; X} /