Added Nitfol and Frotz source code.
[rodin/chimara.git] / interpreters / nitfol / decode.c
diff --git a/interpreters/nitfol/decode.c b/interpreters/nitfol/decode.c
new file mode 100644 (file)
index 0000000..7f31eac
--- /dev/null
@@ -0,0 +1,164 @@
+/*  Nitfol - z-machine interpreter using Glk for output.
+    Copyright (C) 1999  Evin Robertson
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
+
+    The author can be reached at nitfol@deja.com
+*/
+#include "nitfol.h"
+
+void decode(void)
+{
+  unsigned optypes;
+  int maxoperands;
+
+  while(!exit_decoder) {
+    zbyte opcode = HIBYTE(PC);
+
+    oldPC = PC;
+
+#ifdef DEBUGGING
+    if(do_check_watches)
+      check_watches();
+#endif
+
+    PC++;
+
+#ifndef NO_TICK
+    glk_tick();  /* tick tock hickery dock the mouse ran up the clock */
+#endif
+    
+    /* Top bits decide opcode/operand encoding */
+    switch(opcode >> 4) {
+    case 0: case 1:                         /* long 2OP */
+      operand[0] = HIBYTE(PC);              /* small constant */
+      operand[1] = HIBYTE(PC+1);            /* small constant */
+      numoperands = 2; PC += 2;
+      opcode += OFFSET_2OP - 0x00;
+      break;
+
+
+    case 2: case 3:                         /* long 2OP */
+      operand[0] = HIBYTE(PC);              /* small constant */
+      operand[1] = get_var(HIBYTE(PC+1));   /* variable */
+      numoperands = 2; PC += 2;
+      opcode += OFFSET_2OP - 0x20;
+      break;
+
+
+    case 4: case 5:                         /* long 2OP */
+      operand[0] = get_var(HIBYTE(PC));     /* variable */
+      operand[1] = HIBYTE(PC+1);            /* small constant */
+      numoperands = 2; PC += 2;
+      opcode += OFFSET_2OP - 0x40;
+      break;
+
+
+    case 6: case 7:                         /* long 2OP */
+      operand[0] = get_var(HIBYTE(PC));     /* variable */
+      operand[1] = get_var(HIBYTE(PC+1));   /* variable */
+      numoperands = 2; PC += 2;
+      opcode += OFFSET_2OP - 0x60;
+      break;
+
+
+    case 8:                                 /* short 1OP */
+      operand[0] = HIWORD(PC);              /* large constant */
+      numoperands = 1; PC += ZWORD_SIZE;
+      opcode += OFFSET_1OP - 0x80;
+      break;
+
+
+    case 9:                                 /* short 1OP */
+      operand[0] = HIBYTE(PC);              /* small constant */
+      numoperands = 1; PC += 1;
+      opcode += OFFSET_1OP - 0x90;
+      break;
+
+
+    case 10:                                /* short 1OP */
+      operand[0] = get_var(HIBYTE(PC));     /* variable */
+      numoperands = 1; PC += 1;
+      opcode += OFFSET_1OP - 0xa0;
+      break;
+
+
+    case 11:                                /* short 0OP */
+      if(opcode != 0xbe) {
+       numoperands = 0;
+       opcode += OFFSET_0OP - 0xb0;
+       break;
+      }
+                                            /* EXTENDED */
+      opcode  = HIBYTE(PC);   /* Get the extended opcode */
+      optypes = HIBYTE(PC+1);
+      PC += 2;
+
+#ifndef FAST
+      if(OFFSET_EXT + opcode > OFFSET_END) {
+       n_show_error(E_INSTR, "unknown extended opcode", opcode);
+       break;
+      }
+#endif
+      
+      for(numoperands = 0; numoperands < 4; numoperands++) {
+       switch(optypes & (3 << 6)) {   /* Look at the highest two bits. */
+       case 0 << 6:
+         operand[numoperands] = HIWORD(PC); PC+=ZWORD_SIZE; break;
+       case 1 << 6:
+         operand[numoperands] = HIBYTE(PC); PC++; break;
+       case 2 << 6:
+         operand[numoperands] = get_var(HIBYTE(PC)); PC++; break;
+       default:
+         goto END_OF_EXTENDED;   /* inky says, "use the goto." */
+       }
+       optypes <<= 2;    /* Move the next two bits into position. */
+      }
+    END_OF_EXTENDED:
+      opcode += OFFSET_EXT;
+      break;
+
+    case 12: case 13: case 14: case 15:     /* variable operand count */
+      maxoperands = 4;
+      optypes = ((unsigned) HIBYTE(PC)) << 8; /* Shift left so our loop will */
+                                    /* be the same for both 4 and 8 operands */
+      PC++;
+  
+      if(opcode == 0xec || opcode == 0xfa) {  /* call_vs2 and call_vn2 */
+       maxoperands = 8;
+       optypes |= HIBYTE(PC);  /* Fill the bottom 8 bits */
+       PC++;
+      }
+      
+      for(numoperands = 0; numoperands < maxoperands; numoperands++) {
+       switch(optypes & (3 << 14)) {   /* Look at the highest two bits. */
+       case 0 << 14:
+         operand[numoperands] = HIWORD(PC); PC+=ZWORD_SIZE; break;
+       case 1 << 14:
+         operand[numoperands] = HIBYTE(PC); PC++; break;
+       case 2 << 14:
+         operand[numoperands] = get_var(HIBYTE(PC)); PC++; break;
+       default:
+         goto END_OF_VARIABLE;
+       }
+       optypes <<= 2;    /* Move the next two bits into position. */
+      }
+    END_OF_VARIABLE:
+      opcode += OFFSET_2OP - 0xc0;
+      break;
+    }
+    opcodetable[opcode]();
+  }
+}