Update interpreters to latest Garglk codebase
[projects/chimara/chimara.git] / interpreters / nitfol / op_table.c
1 /*  Nitfol - z-machine interpreter using Glk for output.
2     Copyright (C) 1999  Evin Robertson
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18     The author can be reached at nitfol@deja.com
19 */
20 #include "nitfol.h"
21
22 void op_copy_table(void)
23 {
24   offset i;
25   zword first = operand[0];
26   zword second = operand[1];
27   zword size = operand[2];
28
29   if(second == 0) {                          /* zero 'first' bytes */
30     for(i = 0; i < size; i++)
31       LOBYTEwrite(first + i, 0);
32   } else {
33     if(first > second || is_neg(size)) {
34       if(is_neg(size))
35         size = neg(size);
36
37       for(i = 0; i < size; i++)              /* copy forward */
38         LOBYTEcopy(second + i, first + i);
39     }
40     else {
41       for(i = 0; i < size; i++)              /* copy backward */
42         LOBYTEcopy(second + size - i - 1, first + size - i - 1);
43     }
44   }
45 }
46
47
48 void op_scan_table(void)
49 {
50   zword i;
51   int form = operand[3];
52   zword address = operand[1];
53   if(numoperands < 4)
54     form = 0x82; /* default form - scan for words, increment by two bytes */
55
56   if(form & b10000000) {  /* Bit 8 set means scan for words */
57     for(i = 0; i < operand[2]; i++) {
58       if(LOWORD(address) == operand[0]) {
59         mop_store_result(address);
60         mop_take_branch();
61         return;
62       }
63       address += form & b01111111; /* Bottom 7 bits give amount to increment */
64     }
65     mop_store_result(0);
66     mop_skip_branch();
67   } else {          /* Bit 8 clear means scan for bytes */
68     for(i = 0; i < operand[2]; i++) {
69       if(LOBYTE(address) == operand[0]) {
70         mop_store_result(address);
71         mop_take_branch();
72         return;
73       }
74       address += form & b01111111;
75     }
76     mop_store_result(0);
77     mop_skip_branch();
78   }
79 }
80
81 void op_loadb(void)
82 {
83   mop_store_result(LOBYTE(operand[0] + operand[1]));
84 }
85
86 void op_loadw(void)
87 {
88   mop_store_result(LOWORD(operand[0] + operand[1] * ZWORD_SIZE));
89 }
90
91 static void z_write_header(zword i, zbyte val)
92 {
93   zbyte diff = LOBYTE(i) ^ val;
94   if(diff == 0)
95     return;
96   if(i >= 0x40) {
97     LOBYTEwrite(i, val);
98     return;
99   }
100   if(i != HD_FLAGS2 + 1) {
101     n_show_error(E_MEMORY, "attempt to write to non-dynamic byte in header", i);
102     return;
103   }
104   if(diff > b00000111) {
105     n_show_error(E_MEMORY, "attempt to change non-dynamic bits in flags2", val);
106     return;
107   }
108   LOBYTEwrite(i, val);
109   if(diff & b00000001) {
110     if(val & b00000001) {
111       operand[0] = 2;
112       op_output_stream();
113     } else {
114       operand[0] = neg(2);
115       op_output_stream();
116     }
117   }
118   if(diff & b00000010) {
119     if(val & b00000010) {
120       set_fixed(TRUE);
121     } else {
122       set_fixed(FALSE);
123     }
124   }
125 }
126
127 void op_storeb(void)
128 {
129   zword addr = operand[0] + operand[1];
130   if(addr < 0x40)
131     z_write_header(addr, (zbyte) operand[2]);
132   else
133     LOBYTEwrite(addr, operand[2]);
134 }
135
136 void op_storew(void)
137 {
138   zword addr = operand[0] + operand[1] * ZWORD_SIZE;
139   if(addr < 0x40) {
140     z_write_header(addr,     (zbyte) (operand[2] >> 8));
141     z_write_header(addr + 1, (zbyte) (operand[2] & 0xff));
142   } else {
143     LOWORDwrite(addr, operand[2]);
144   }
145 }
146
147
148 void header_extension_write(zword w, zword val)
149 {
150   w *= ZWORD_SIZE;
151   if(z_headerext == 0)
152     return;
153
154   if(LOWORD(z_headerext) < w)
155     return;
156
157   LOWORDwrite(z_headerext + w, val);
158 }
159
160 zword header_extension_read(unsigned w)
161 {
162   w *= ZWORD_SIZE;
163   if(z_headerext == 0)
164     return 0;
165
166   if(LOWORD(z_headerext) < w)
167     return 0;
168
169   return LOWORD(z_headerext + w);
170 }