1 |
cebix |
1.1 |
/* |
2 |
|
|
* SAM.h - Simple Assembler and Monitor With Integrated System Explorer |
3 |
|
|
* |
4 |
cebix |
1.4 |
* Frodo (C) 1994-1997,2002-2004 Christian Bauer |
5 |
cebix |
1.1 |
* |
6 |
|
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
|
* it under the terms of the GNU General Public License as published by |
8 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
9 |
|
|
* (at your option) any later version. |
10 |
|
|
* |
11 |
|
|
* This program is distributed in the hope that it will be useful, |
12 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
|
|
* GNU General Public License for more details. |
15 |
|
|
* |
16 |
|
|
* You should have received a copy of the GNU General Public License |
17 |
|
|
* along with this program; if not, write to the Free Software |
18 |
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
|
|
*/ |
20 |
|
|
|
21 |
|
|
#include "sysdeps.h" |
22 |
|
|
|
23 |
|
|
#include "SAM.h" |
24 |
|
|
#include "C64.h" |
25 |
|
|
#include "CPUC64.h" |
26 |
|
|
#include "CPU1541.h" |
27 |
|
|
#include "VIC.h" |
28 |
|
|
#include "SID.h" |
29 |
|
|
#include "CIA.h" |
30 |
|
|
|
31 |
|
|
|
32 |
|
|
// Pointers to chips |
33 |
|
|
static MOS6510 *TheCPU; |
34 |
|
|
static MOS6502_1541 *TheCPU1541; |
35 |
|
|
static MOS6569 *TheVIC; |
36 |
|
|
static MOS6581 *TheSID; |
37 |
|
|
static MOS6526_1 *TheCIA1; |
38 |
|
|
static MOS6526_2 *TheCIA2; |
39 |
|
|
|
40 |
|
|
// 6510/6502 registers |
41 |
|
|
static MOS6510State R64; |
42 |
|
|
static MOS6502State R1541; |
43 |
|
|
|
44 |
|
|
static bool access_1541; // false: accessing C64, true: accessing 1541 |
45 |
|
|
|
46 |
|
|
// Access to 6510/6502 address space |
47 |
|
|
static inline uint8 SAMReadByte(uint16 adr) |
48 |
|
|
{ |
49 |
|
|
if (access_1541) |
50 |
|
|
return TheCPU1541->ExtReadByte(adr); |
51 |
|
|
else |
52 |
|
|
return TheCPU->ExtReadByte(adr); |
53 |
|
|
} |
54 |
|
|
|
55 |
|
|
static inline void SAMWriteByte(uint16 adr, uint8 byte) |
56 |
|
|
{ |
57 |
|
|
if (access_1541) |
58 |
|
|
TheCPU1541->ExtWriteByte(adr, byte); |
59 |
|
|
else |
60 |
|
|
TheCPU->ExtWriteByte(adr, byte); |
61 |
|
|
} |
62 |
|
|
|
63 |
|
|
|
64 |
|
|
// Streams for input, output and error messages |
65 |
|
|
static FILE *fin, *fout, *ferr; |
66 |
|
|
|
67 |
|
|
// Input line |
68 |
|
|
#define INPUT_LENGTH 80 |
69 |
|
|
static char input[INPUT_LENGTH]; |
70 |
|
|
static char *in_ptr; |
71 |
|
|
|
72 |
|
|
static uint16 address, end_address; |
73 |
|
|
|
74 |
|
|
|
75 |
|
|
// Input tokens |
76 |
|
|
enum Token { |
77 |
|
|
T_NULL, // Invalid token |
78 |
|
|
T_END, // End of line |
79 |
|
|
T_NUMBER, // Hexadecimal number |
80 |
|
|
T_STRING, // String enclosed in "" |
81 |
|
|
T_LPAREN, // '(' |
82 |
|
|
T_RPAREN, // ')' |
83 |
|
|
T_ADD, // '+' |
84 |
|
|
T_SUB, // '-' |
85 |
|
|
T_MUL, // '*' |
86 |
|
|
T_DIV, // '/' |
87 |
|
|
T_COMMA, // ',' |
88 |
|
|
T_IMMED, // '#' |
89 |
|
|
T_X, // 'x' |
90 |
|
|
T_Y, // 'y' |
91 |
|
|
T_PC, // 'pc' |
92 |
|
|
T_SP, // 'sp' |
93 |
|
|
|
94 |
|
|
T_A, // 'a' (get_reg_token() only) |
95 |
|
|
T_DR, // 'dr' (get_reg_token() only) |
96 |
|
|
T_PR // 'pr' (get_reg_token() only) |
97 |
|
|
}; |
98 |
|
|
|
99 |
|
|
static enum Token the_token; // Last token read |
100 |
|
|
static uint16 the_number; // Contains the number if the_token==T_NUMBER |
101 |
|
|
static char the_string[INPUT_LENGTH]; // Contains the string if the_token==T_STRING |
102 |
|
|
|
103 |
|
|
|
104 |
|
|
// Addressing modes |
105 |
|
|
enum { |
106 |
|
|
A_IMPL, |
107 |
|
|
A_ACCU, // A |
108 |
|
|
A_IMM, // #zz |
109 |
|
|
A_REL, // Branches |
110 |
|
|
A_ZERO, // zz |
111 |
|
|
A_ZEROX, // zz,x |
112 |
|
|
A_ZEROY, // zz,y |
113 |
|
|
A_ABS, // zzzz |
114 |
|
|
A_ABSX, // zzzz,x |
115 |
|
|
A_ABSY, // zzzz,y |
116 |
|
|
A_IND, // (zzzz) |
117 |
|
|
A_INDX, // (zz,x) |
118 |
|
|
A_INDY // (zz),y |
119 |
|
|
}; |
120 |
|
|
|
121 |
|
|
// Mnemonics |
122 |
|
|
enum { |
123 |
|
|
M_ADC, M_AND, M_ASL, M_BCC, M_BCS, M_BEQ, M_BIT, M_BMI, M_BNE, M_BPL, |
124 |
|
|
M_BRK, M_BVC, M_BVS, M_CLC, M_CLD, M_CLI, M_CLV, M_CMP, M_CPX, M_CPY, |
125 |
|
|
M_DEC, M_DEX, M_DEY, M_EOR, M_INC, M_INX, M_INY, M_JMP, M_JSR, M_LDA, |
126 |
|
|
M_LDX, M_LDY, M_LSR, M_NOP, M_ORA, M_PHA, M_PHP, M_PLA, M_PLP, M_ROL, |
127 |
|
|
M_ROR, M_RTI, M_RTS, M_SBC, M_SEC, M_SED, M_SEI, M_STA, M_STX, M_STY, |
128 |
|
|
M_TAX, M_TAY, M_TSX, M_TXA, M_TXS, M_TYA, |
129 |
|
|
|
130 |
|
|
M_ILLEGAL, // Undocumented opcodes start here |
131 |
|
|
|
132 |
|
|
M_IANC, M_IANE, M_IARR, M_IASR, M_IDCP, M_IISB, M_IJAM, M_INOP, M_ILAS, |
133 |
|
|
M_ILAX, M_ILXA, M_IRLA, M_IRRA, M_ISAX, M_ISBC, M_ISBX, M_ISHA, M_ISHS, |
134 |
|
|
M_ISHX, M_ISHY, M_ISLO, M_ISRE, |
135 |
|
|
|
136 |
|
|
M_MAXIMUM // Highest element |
137 |
|
|
}; |
138 |
|
|
|
139 |
|
|
// Mnemonic for each opcode |
140 |
|
|
static const char mnemonic[256] = { |
141 |
|
|
M_BRK , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, // 00 |
142 |
|
|
M_PHP , M_ORA , M_ASL , M_IANC, M_INOP, M_ORA, M_ASL , M_ISLO, |
143 |
|
|
M_BPL , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, // 10 |
144 |
|
|
M_CLC , M_ORA , M_INOP, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, |
145 |
|
|
M_JSR , M_AND , M_IJAM, M_IRLA, M_BIT , M_AND, M_ROL , M_IRLA, // 20 |
146 |
|
|
M_PLP , M_AND , M_ROL , M_IANC, M_BIT , M_AND, M_ROL , M_IRLA, |
147 |
|
|
M_BMI , M_AND , M_IJAM, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA, // 30 |
148 |
|
|
M_SEC , M_AND , M_INOP, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA, |
149 |
|
|
M_RTI , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, // 40 |
150 |
|
|
M_PHA , M_EOR , M_LSR , M_IASR, M_JMP , M_EOR, M_LSR , M_ISRE, |
151 |
|
|
M_BVC , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, // 50 |
152 |
|
|
M_CLI , M_EOR , M_INOP, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, |
153 |
|
|
M_RTS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, // 60 |
154 |
|
|
M_PLA , M_ADC , M_ROR , M_IARR, M_JMP , M_ADC, M_ROR , M_IRRA, |
155 |
|
|
M_BVS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, // 70 |
156 |
|
|
M_SEI , M_ADC , M_INOP, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, |
157 |
|
|
M_INOP, M_STA , M_INOP, M_ISAX, M_STY , M_STA, M_STX , M_ISAX, // 80 |
158 |
|
|
M_DEY , M_INOP, M_TXA , M_IANE, M_STY , M_STA, M_STX , M_ISAX, |
159 |
|
|
M_BCC , M_STA , M_IJAM, M_ISHA, M_STY , M_STA, M_STX , M_ISAX, // 90 |
160 |
|
|
M_TYA , M_STA , M_TXS , M_ISHS, M_ISHY, M_STA, M_ISHX, M_ISHA, |
161 |
|
|
M_LDY , M_LDA , M_LDX , M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX, // a0 |
162 |
|
|
M_TAY , M_LDA , M_TAX , M_ILXA, M_LDY , M_LDA, M_LDX , M_ILAX, |
163 |
|
|
M_BCS , M_LDA , M_IJAM, M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX, // b0 |
164 |
|
|
M_CLV , M_LDA , M_TSX , M_ILAS, M_LDY , M_LDA, M_LDX , M_ILAX, |
165 |
|
|
M_CPY , M_CMP , M_INOP, M_IDCP, M_CPY , M_CMP, M_DEC , M_IDCP, // c0 |
166 |
|
|
M_INY , M_CMP , M_DEX , M_ISBX, M_CPY , M_CMP, M_DEC , M_IDCP, |
167 |
|
|
M_BNE , M_CMP , M_IJAM, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP, // d0 |
168 |
|
|
M_CLD , M_CMP , M_INOP, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP, |
169 |
|
|
M_CPX , M_SBC , M_INOP, M_IISB, M_CPX , M_SBC, M_INC , M_IISB, // e0 |
170 |
|
|
M_INX , M_SBC , M_NOP , M_ISBC, M_CPX , M_SBC, M_INC , M_IISB, |
171 |
|
|
M_BEQ , M_SBC , M_IJAM, M_IISB, M_INOP, M_SBC, M_INC , M_IISB, // f0 |
172 |
|
|
M_SED , M_SBC , M_INOP, M_IISB, M_INOP, M_SBC, M_INC , M_IISB |
173 |
|
|
}; |
174 |
|
|
|
175 |
|
|
// Addressing mode for each opcode |
176 |
|
|
static const char adr_mode[256] = { |
177 |
|
|
A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 00 |
178 |
|
|
A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, |
179 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 10 |
180 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, |
181 |
|
|
A_ABS , A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 20 |
182 |
|
|
A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, |
183 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 30 |
184 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, |
185 |
|
|
A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 40 |
186 |
|
|
A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, |
187 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 50 |
188 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, |
189 |
|
|
A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 60 |
190 |
|
|
A_IMPL, A_IMM , A_ACCU, A_IMM , A_IND , A_ABS , A_ABS , A_ABS, |
191 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 70 |
192 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, |
193 |
|
|
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 80 |
194 |
|
|
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, |
195 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY, // 90 |
196 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY, |
197 |
|
|
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // a0 |
198 |
|
|
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, |
199 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY, // b0 |
200 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY, |
201 |
|
|
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // c0 |
202 |
|
|
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, |
203 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // d0 |
204 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, |
205 |
|
|
A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // e0 |
206 |
|
|
A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, |
207 |
|
|
A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // f0 |
208 |
|
|
A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX |
209 |
|
|
}; |
210 |
|
|
|
211 |
|
|
// Chars for each mnemonic |
212 |
|
|
static const char mnem_1[] = "aaabbbbbbbbbbcccccccdddeiiijjllllnopppprrrrssssssstttttt?aaaadijnlllrrsssssssss"; |
213 |
|
|
static const char mnem_2[] = "dnscceimnprvvllllmppeeeonnnmsdddsorhhlloottbeeetttaasxxy?nnrscsaoaaxlrabbhhhhlr"; |
214 |
|
|
static const char mnem_3[] = "cdlcsqtielkcscdivpxycxyrcxypraxyrpaapaplrisccdiaxyxyxasa?cerrpbmpsxaaaxcxasxyoe"; |
215 |
|
|
|
216 |
|
|
// Instruction length for each addressing mode |
217 |
|
|
static const char adr_length[] = {1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2}; |
218 |
|
|
|
219 |
|
|
|
220 |
|
|
// Prototypes |
221 |
|
|
static void error(char *s); |
222 |
|
|
static void handle_abort(...); |
223 |
|
|
static void init_abort(void); |
224 |
|
|
static void exit_abort(void); |
225 |
|
|
static bool aborted(void); |
226 |
|
|
|
227 |
|
|
static void read_line(void); // Scanner |
228 |
|
|
static char get_char(void); |
229 |
|
|
static void put_back(char c); |
230 |
|
|
static enum Token get_token(void); |
231 |
|
|
static enum Token get_reg_token(void); |
232 |
|
|
static uint16 get_number(void); |
233 |
|
|
static enum Token get_string(char *str); |
234 |
|
|
|
235 |
|
|
static bool expression(uint16 *number); // Parser |
236 |
|
|
static bool term(uint16 *number); |
237 |
|
|
static bool factor(uint16 *number); |
238 |
|
|
static bool address_args(void); |
239 |
|
|
static bool range_args(int def_range); |
240 |
|
|
static bool instr_args(uint16 *number, char *mode); |
241 |
|
|
|
242 |
|
|
static void help(void); // Routines for commands |
243 |
|
|
static void registers(void); |
244 |
|
|
static void display_registers(void); |
245 |
|
|
static void memory_dump(void); |
246 |
|
|
static void ascii_dump(void); |
247 |
|
|
static char conv_from_64(char c); |
248 |
|
|
static void screen_dump(void); |
249 |
|
|
static char conv_from_scode(char c); |
250 |
|
|
static void binary_dump(void); |
251 |
|
|
static void sprite_dump(void); |
252 |
|
|
static void byte_to_bin(uint8 byte, char *str); |
253 |
|
|
static void disassemble(void); |
254 |
|
|
static int disass_line(uint16 adr, uint8 op, uint8 lo, uint8 hi); |
255 |
|
|
static void assemble(void); |
256 |
|
|
static char find_mnemonic(char op1, char op2, char op3); |
257 |
|
|
static bool find_opcode(char mnem, char mode, uint8 *opcode); |
258 |
|
|
static void mem_config(void); |
259 |
|
|
static void fill(void); |
260 |
|
|
static void compare(void); |
261 |
|
|
static void transfer(void); |
262 |
|
|
static void modify(void); |
263 |
|
|
static void print_expr(void); |
264 |
|
|
static void redir_output(void); |
265 |
|
|
static void int_vectors(void); |
266 |
|
|
static void view_state(void); |
267 |
|
|
static void view_cia_state(void); |
268 |
|
|
static void dump_cia_ints(uint8 i); |
269 |
|
|
static void view_sid_state(void); |
270 |
|
|
static void dump_sid_waveform(uint8 wave); |
271 |
|
|
static void view_vic_state(void); |
272 |
|
|
static void dump_spr_flags(uint8 f); |
273 |
|
|
static void dump_vic_ints(uint8 i); |
274 |
|
|
static void view_1541_state(void); |
275 |
|
|
static void dump_via_ints(uint8 i); |
276 |
|
|
static void load_data(void); |
277 |
|
|
static void save_data(void); |
278 |
|
|
|
279 |
|
|
|
280 |
|
|
/* |
281 |
|
|
* Open and handle SAM |
282 |
|
|
*/ |
283 |
|
|
|
284 |
|
|
void SAM(C64 *the_c64) |
285 |
|
|
{ |
286 |
|
|
bool done = false; |
287 |
|
|
char c; |
288 |
|
|
|
289 |
|
|
TheCPU = the_c64->TheCPU; |
290 |
|
|
TheCPU1541 = the_c64->TheCPU1541; |
291 |
|
|
TheVIC = the_c64->TheVIC; |
292 |
|
|
TheSID = the_c64->TheSID; |
293 |
|
|
TheCIA1 = the_c64->TheCIA1; |
294 |
|
|
TheCIA2 = the_c64->TheCIA2; |
295 |
|
|
|
296 |
|
|
// Get CPU registers and current memory configuration |
297 |
|
|
TheCPU->GetState(&R64); |
298 |
|
|
TheCPU->ExtConfig = (~R64.ddr | R64.pr) & 7; |
299 |
|
|
TheCPU1541->GetState(&R1541); |
300 |
|
|
|
301 |
|
|
#ifdef __riscos__ |
302 |
|
|
Wimp_CommandWindow((int)"SAM"); |
303 |
|
|
#endif |
304 |
|
|
|
305 |
|
|
#ifdef AMIGA |
306 |
|
|
if (!(fin = fout = ferr = fopen("CON:0/0/640/480/SAM", "w+"))) |
307 |
|
|
return; |
308 |
|
|
#else |
309 |
|
|
fin = stdin; |
310 |
|
|
fout = stdout; |
311 |
|
|
ferr = stdout; |
312 |
|
|
#endif |
313 |
|
|
|
314 |
|
|
access_1541 = false; |
315 |
|
|
address = R64.pc; |
316 |
|
|
|
317 |
|
|
fprintf(ferr, "\n *** SAM - Simple Assembler and Monitor ***\n *** Press 'h' for help ***\n\n"); |
318 |
|
|
init_abort(); |
319 |
|
|
display_registers(); |
320 |
|
|
|
321 |
|
|
while (!done) { |
322 |
|
|
if (access_1541) |
323 |
|
|
fprintf(ferr, "1541> "); |
324 |
|
|
else |
325 |
|
|
fprintf(ferr, "C64> "); |
326 |
|
|
fflush(ferr); |
327 |
|
|
read_line(); |
328 |
|
|
while ((c = get_char()) == ' ') ; |
329 |
|
|
|
330 |
|
|
switch (c) { |
331 |
|
|
case 'a': // Assemble |
332 |
|
|
get_token(); |
333 |
|
|
assemble(); |
334 |
|
|
break; |
335 |
|
|
|
336 |
|
|
case 'b': // Binary dump |
337 |
|
|
get_token(); |
338 |
|
|
binary_dump(); |
339 |
|
|
break; |
340 |
|
|
|
341 |
|
|
case 'c': // Compare |
342 |
|
|
get_token(); |
343 |
|
|
compare(); |
344 |
|
|
break; |
345 |
|
|
|
346 |
|
|
case 'd': // Disassemble |
347 |
|
|
get_token(); |
348 |
|
|
disassemble(); |
349 |
|
|
break; |
350 |
|
|
|
351 |
|
|
case 'e': // Interrupt vectors |
352 |
|
|
int_vectors(); |
353 |
|
|
break; |
354 |
|
|
|
355 |
|
|
case 'f': // Fill |
356 |
|
|
get_token(); |
357 |
|
|
fill(); |
358 |
|
|
break; |
359 |
|
|
|
360 |
|
|
case 'h': // Help |
361 |
|
|
help(); |
362 |
|
|
break; |
363 |
|
|
|
364 |
|
|
case 'i': // ASCII dump |
365 |
|
|
get_token(); |
366 |
|
|
ascii_dump(); |
367 |
|
|
break; |
368 |
|
|
|
369 |
|
|
case 'k': // Memory configuration |
370 |
|
|
get_token(); |
371 |
|
|
mem_config(); |
372 |
|
|
break; |
373 |
|
|
|
374 |
|
|
case 'l': // Load data |
375 |
|
|
get_token(); |
376 |
|
|
load_data(); |
377 |
|
|
break; |
378 |
|
|
|
379 |
|
|
case 'm': // Memory dump |
380 |
|
|
get_token(); |
381 |
|
|
memory_dump(); |
382 |
|
|
break; |
383 |
|
|
|
384 |
|
|
case 'n': // Screen code dump |
385 |
|
|
get_token(); |
386 |
|
|
screen_dump(); |
387 |
|
|
break; |
388 |
|
|
|
389 |
|
|
case 'o': // Redirect output |
390 |
|
|
get_token(); |
391 |
|
|
redir_output(); |
392 |
|
|
break; |
393 |
|
|
|
394 |
|
|
case 'p': // Sprite dump |
395 |
|
|
get_token(); |
396 |
|
|
sprite_dump(); |
397 |
|
|
break; |
398 |
|
|
|
399 |
|
|
case 'r': // Registers |
400 |
|
|
get_reg_token(); |
401 |
|
|
registers(); |
402 |
|
|
break; |
403 |
|
|
|
404 |
|
|
case 's': // Save data |
405 |
|
|
get_token(); |
406 |
|
|
save_data(); |
407 |
|
|
break; |
408 |
|
|
|
409 |
|
|
case 't': // Transfer |
410 |
|
|
get_token(); |
411 |
|
|
transfer(); |
412 |
|
|
break; |
413 |
|
|
|
414 |
|
|
case 'v': // View machine state |
415 |
|
|
view_state(); |
416 |
|
|
break; |
417 |
|
|
|
418 |
|
|
case 'x': // Exit |
419 |
|
|
done = true; |
420 |
|
|
break; |
421 |
|
|
|
422 |
|
|
case ':': // Change memory |
423 |
|
|
get_token(); |
424 |
|
|
modify(); |
425 |
|
|
break; |
426 |
|
|
|
427 |
|
|
case '1': // Switch to 1541 mode |
428 |
|
|
access_1541 = true; |
429 |
|
|
break; |
430 |
|
|
|
431 |
|
|
case '6': // Switch to C64 mode |
432 |
|
|
access_1541 = false; |
433 |
|
|
break; |
434 |
|
|
|
435 |
|
|
case '?': // Compute expression |
436 |
|
|
get_token(); |
437 |
|
|
print_expr(); |
438 |
|
|
break; |
439 |
|
|
|
440 |
|
|
case '\n': // Blank line |
441 |
|
|
break; |
442 |
|
|
|
443 |
|
|
default: // Unknown command |
444 |
|
|
error("Unknown command"); |
445 |
|
|
break; |
446 |
|
|
} |
447 |
|
|
} |
448 |
|
|
|
449 |
|
|
exit_abort(); |
450 |
|
|
|
451 |
|
|
#ifdef AMIGA |
452 |
|
|
fclose(fin); |
453 |
|
|
#endif |
454 |
|
|
if (fout != ferr) |
455 |
|
|
fclose(fout); |
456 |
|
|
|
457 |
|
|
#ifdef __riscos__ |
458 |
|
|
Wimp_CommandWindow(-1); |
459 |
|
|
#endif |
460 |
|
|
|
461 |
|
|
// Set CPU registers |
462 |
|
|
TheCPU->SetState(&R64); |
463 |
|
|
TheCPU1541->SetState(&R1541); |
464 |
|
|
} |
465 |
|
|
|
466 |
|
|
|
467 |
|
|
/* |
468 |
|
|
* Print error message |
469 |
|
|
*/ |
470 |
|
|
|
471 |
|
|
static void error(char *s) |
472 |
|
|
{ |
473 |
|
|
fprintf(ferr, "*** %s\n", s); |
474 |
|
|
} |
475 |
|
|
|
476 |
|
|
|
477 |
|
|
/* |
478 |
|
|
* CTRL-C pressed? |
479 |
|
|
*/ |
480 |
|
|
|
481 |
|
|
static bool WasAborted; |
482 |
|
|
|
483 |
|
|
#ifdef HAVE_SIGACTION |
484 |
|
|
struct sigaction my_sa; |
485 |
|
|
#endif |
486 |
|
|
|
487 |
|
|
static void handle_abort(...) |
488 |
|
|
{ |
489 |
|
|
WasAborted = true; |
490 |
|
|
#if !defined(HAVE_SIGACTION) && defined(HAVE_SIGNAL) |
491 |
|
|
#ifdef __riscos__ |
492 |
|
|
signal(SIGINT, (Handler*) handle_abort); |
493 |
|
|
#else |
494 |
|
|
signal(SIGINT, (sighandler_t) handle_abort); |
495 |
|
|
#endif |
496 |
|
|
#endif |
497 |
|
|
} |
498 |
|
|
|
499 |
|
|
static void init_abort(void) |
500 |
|
|
{ |
501 |
|
|
WasAborted = false; |
502 |
|
|
#if defined(HAVE_SIGACTION) |
503 |
|
|
my_sa.sa_handler = (void (*)(int))handle_abort; |
504 |
|
|
my_sa.sa_flags = 0; |
505 |
|
|
sigemptyset(&my_sa.sa_mask); |
506 |
|
|
sigaction(SIGINT, &my_sa, NULL); |
507 |
|
|
#elif defined(HAVE_SIGNAL) |
508 |
|
|
#ifdef __riscos__ |
509 |
|
|
signal(SIGINT, (Handler*) handle_abort); |
510 |
|
|
#else |
511 |
|
|
signal(SIGINT, (sighandler_t) handle_abort); |
512 |
|
|
#endif |
513 |
|
|
#endif |
514 |
|
|
} |
515 |
|
|
|
516 |
|
|
static void exit_abort(void) |
517 |
|
|
{ |
518 |
|
|
#if defined(HAVE_SIGACTION) |
519 |
|
|
my_sa.sa_handler = SIG_DFL; |
520 |
|
|
sigaction(SIGINT, &my_sa, NULL); |
521 |
|
|
#elif defined(HAVE_SIGNAL) |
522 |
|
|
signal(SIGINT, SIG_DFL); |
523 |
|
|
#endif |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
static bool aborted(void) |
527 |
|
|
{ |
528 |
|
|
bool ret = WasAborted; |
529 |
|
|
|
530 |
|
|
WasAborted = false; |
531 |
|
|
return ret; |
532 |
|
|
} |
533 |
|
|
|
534 |
|
|
|
535 |
|
|
/* |
536 |
|
|
* Read a line from the keyboard |
537 |
|
|
*/ |
538 |
|
|
|
539 |
|
|
static void read_line(void) |
540 |
|
|
{ |
541 |
|
|
#ifdef __riscos__ |
542 |
|
|
OS_ReadLine(in_ptr = input, INPUT_LENGTH, 0, 255, 0); |
543 |
|
|
#else |
544 |
|
|
fgets(in_ptr = input, INPUT_LENGTH, fin); |
545 |
|
|
#endif |
546 |
|
|
} |
547 |
|
|
|
548 |
|
|
|
549 |
|
|
/* |
550 |
|
|
* Read a character from the input line |
551 |
|
|
*/ |
552 |
|
|
|
553 |
|
|
static char get_char(void) |
554 |
|
|
{ |
555 |
|
|
return *in_ptr++; |
556 |
|
|
} |
557 |
|
|
|
558 |
|
|
|
559 |
|
|
/* |
560 |
|
|
* Stuff back a character into the input line |
561 |
|
|
*/ |
562 |
|
|
|
563 |
|
|
static void put_back(char c) |
564 |
|
|
{ |
565 |
|
|
*(--in_ptr) = c; |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
|
569 |
|
|
/* |
570 |
|
|
* Scanner: Get a token from the input line |
571 |
|
|
*/ |
572 |
|
|
|
573 |
|
|
static enum Token get_token(void) |
574 |
|
|
{ |
575 |
|
|
char c; |
576 |
|
|
|
577 |
|
|
// Skip spaces |
578 |
|
|
while ((c = get_char()) == ' ') ; |
579 |
|
|
|
580 |
|
|
switch (c) { |
581 |
|
|
case '\n': |
582 |
|
|
return the_token = T_END; |
583 |
|
|
case '(': |
584 |
|
|
return the_token = T_LPAREN; |
585 |
|
|
case ')': |
586 |
|
|
return the_token = T_RPAREN; |
587 |
|
|
case '+': |
588 |
|
|
return the_token = T_ADD; |
589 |
|
|
case '-': |
590 |
|
|
return the_token = T_SUB; |
591 |
|
|
case '*': |
592 |
|
|
return the_token = T_MUL; |
593 |
|
|
case '/': |
594 |
|
|
return the_token = T_DIV; |
595 |
|
|
case ',': |
596 |
|
|
return the_token = T_COMMA; |
597 |
|
|
case '#': |
598 |
|
|
return the_token = T_IMMED; |
599 |
|
|
case 'x': |
600 |
|
|
return the_token = T_X; |
601 |
|
|
case 'y': |
602 |
|
|
return the_token = T_Y; |
603 |
|
|
case 'p': |
604 |
|
|
if (get_char() == 'c') |
605 |
|
|
return the_token = T_PC; |
606 |
|
|
else { |
607 |
|
|
error("Unrecognized token"); |
608 |
|
|
return the_token = T_NULL; |
609 |
|
|
} |
610 |
|
|
case 's': |
611 |
|
|
if (get_char() == 'p') |
612 |
|
|
return the_token = T_SP; |
613 |
|
|
else { |
614 |
|
|
error("Unrecognized token"); |
615 |
|
|
return the_token = T_NULL; |
616 |
|
|
} |
617 |
|
|
case '0': case '1': case '2': case '3': case '4': |
618 |
|
|
case '5': case '6': case '7': case '8': case '9': |
619 |
|
|
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
620 |
|
|
put_back(c); |
621 |
|
|
the_number = get_number(); |
622 |
|
|
return the_token = T_NUMBER; |
623 |
|
|
case '"': |
624 |
|
|
return the_token = get_string(the_string); |
625 |
|
|
default: |
626 |
|
|
error("Unrecognized token"); |
627 |
|
|
return the_token = T_NULL; |
628 |
|
|
} |
629 |
|
|
} |
630 |
|
|
|
631 |
|
|
static enum Token get_reg_token(void) |
632 |
|
|
{ |
633 |
|
|
char c; |
634 |
|
|
|
635 |
|
|
// Skip spaces |
636 |
|
|
while ((c = get_char()) == ' ') ; |
637 |
|
|
|
638 |
|
|
switch (c) { |
639 |
|
|
case '\n': |
640 |
|
|
return the_token = T_END; |
641 |
|
|
case 'a': |
642 |
|
|
return the_token = T_A; |
643 |
|
|
case 'd': |
644 |
|
|
if (get_char() == 'r') |
645 |
|
|
return the_token = T_DR; |
646 |
|
|
else { |
647 |
|
|
error("Unrecognized token"); |
648 |
|
|
return the_token = T_NULL; |
649 |
|
|
} |
650 |
|
|
case 'p': |
651 |
|
|
if ((c = get_char()) == 'c') |
652 |
|
|
return the_token = T_PC; |
653 |
|
|
else if (c == 'r') |
654 |
|
|
return the_token = T_PR; |
655 |
|
|
else { |
656 |
|
|
error("Unrecognized token"); |
657 |
|
|
return the_token = T_NULL; |
658 |
|
|
} |
659 |
|
|
case 's': |
660 |
|
|
if (get_char() == 'p') |
661 |
|
|
return the_token = T_SP; |
662 |
|
|
else { |
663 |
|
|
error("Unrecognized token"); |
664 |
|
|
return the_token = T_NULL; |
665 |
|
|
} |
666 |
|
|
case 'x': |
667 |
|
|
return the_token = T_X; |
668 |
|
|
case 'y': |
669 |
|
|
return the_token = T_Y; |
670 |
|
|
default: |
671 |
|
|
error("Unrecognized token"); |
672 |
|
|
return the_token = T_NULL; |
673 |
|
|
} |
674 |
|
|
} |
675 |
|
|
|
676 |
|
|
static uint16 get_number(void) |
677 |
|
|
{ |
678 |
|
|
char c; |
679 |
|
|
uint16 i = 0; |
680 |
|
|
|
681 |
|
|
while (((c = get_char()) >= '0') && (c <= '9') || (c >= 'a') && (c <= 'f')) |
682 |
|
|
if (c < 'a') |
683 |
|
|
i = (i << 4) + (c - '0'); |
684 |
|
|
else |
685 |
|
|
i = (i << 4) + (c - 'a' + 10); |
686 |
|
|
|
687 |
|
|
put_back(c); |
688 |
|
|
return i; |
689 |
|
|
} |
690 |
|
|
|
691 |
|
|
static enum Token get_string(char *str) |
692 |
|
|
{ |
693 |
|
|
char c; |
694 |
|
|
|
695 |
|
|
while ((c = get_char()) != '\n') { |
696 |
|
|
if (c == '"') { |
697 |
|
|
*str = 0; |
698 |
|
|
return T_STRING; |
699 |
|
|
} |
700 |
|
|
*str++ = c; |
701 |
|
|
} |
702 |
|
|
|
703 |
|
|
error("Unterminated string"); |
704 |
|
|
return T_NULL; |
705 |
|
|
} |
706 |
|
|
|
707 |
|
|
|
708 |
|
|
/* |
709 |
|
|
* expression = term {(ADD | SUB) term} |
710 |
|
|
* true: OK, false: Error |
711 |
|
|
*/ |
712 |
|
|
|
713 |
|
|
static bool expression(uint16 *number) |
714 |
|
|
{ |
715 |
|
|
uint16 accu, trm; |
716 |
|
|
|
717 |
|
|
if (!term(&accu)) |
718 |
|
|
return false; |
719 |
|
|
|
720 |
|
|
for (;;) |
721 |
|
|
switch (the_token) { |
722 |
|
|
case T_ADD: |
723 |
|
|
get_token(); |
724 |
|
|
if (!term(&trm)) |
725 |
|
|
return false; |
726 |
|
|
accu += trm; |
727 |
|
|
break; |
728 |
|
|
|
729 |
|
|
case T_SUB: |
730 |
|
|
get_token(); |
731 |
|
|
if (!term(&trm)) |
732 |
|
|
return false; |
733 |
|
|
accu -= trm; |
734 |
|
|
break; |
735 |
|
|
|
736 |
|
|
default: |
737 |
|
|
*number = accu; |
738 |
|
|
return true; |
739 |
|
|
} |
740 |
|
|
} |
741 |
|
|
|
742 |
|
|
|
743 |
|
|
/* |
744 |
|
|
* term = factor {(MUL | DIV) factor} |
745 |
|
|
* true: OK, false: Error |
746 |
|
|
*/ |
747 |
|
|
|
748 |
|
|
static bool term(uint16 *number) |
749 |
|
|
{ |
750 |
|
|
uint16 accu, fact; |
751 |
|
|
|
752 |
|
|
if (!factor(&accu)) |
753 |
|
|
return false; |
754 |
|
|
|
755 |
|
|
for (;;) |
756 |
|
|
switch (the_token) { |
757 |
|
|
case T_MUL: |
758 |
|
|
get_token(); |
759 |
|
|
if (!factor(&fact)) |
760 |
|
|
return false; |
761 |
|
|
accu *= fact; |
762 |
|
|
break; |
763 |
|
|
|
764 |
|
|
case T_DIV: |
765 |
|
|
get_token(); |
766 |
|
|
if (!factor(&fact)) |
767 |
|
|
return false; |
768 |
|
|
if (fact == 0) { |
769 |
|
|
error("Division by 0"); |
770 |
|
|
return false; |
771 |
|
|
} |
772 |
|
|
accu /= fact; |
773 |
|
|
break; |
774 |
|
|
|
775 |
|
|
default: |
776 |
|
|
*number = accu; |
777 |
|
|
return true; |
778 |
|
|
} |
779 |
|
|
} |
780 |
|
|
|
781 |
|
|
|
782 |
|
|
/* |
783 |
|
|
* factor = NUMBER | PC | SP | LPAREN expression RPAREN |
784 |
|
|
* true: OK, false: Error |
785 |
|
|
*/ |
786 |
|
|
|
787 |
|
|
static bool factor(uint16 *number) |
788 |
|
|
{ |
789 |
|
|
switch (the_token) { |
790 |
|
|
case T_NUMBER: |
791 |
|
|
*number = the_number; |
792 |
|
|
get_token(); |
793 |
|
|
return true; |
794 |
|
|
|
795 |
|
|
case T_PC: |
796 |
|
|
get_token(); |
797 |
|
|
*number = access_1541 ? R1541.pc : R64.pc; |
798 |
|
|
return true; |
799 |
|
|
|
800 |
|
|
case T_SP: |
801 |
|
|
get_token(); |
802 |
|
|
*number = access_1541 ? R1541.sp : R64.sp; |
803 |
|
|
return true; |
804 |
|
|
|
805 |
|
|
case T_LPAREN: |
806 |
|
|
get_token(); |
807 |
|
|
if (expression(number)) |
808 |
|
|
if (the_token == T_RPAREN) { |
809 |
|
|
get_token(); |
810 |
|
|
return true; |
811 |
|
|
} else { |
812 |
|
|
error("Missing ')'"); |
813 |
|
|
return false; |
814 |
|
|
} |
815 |
|
|
else { |
816 |
|
|
error("Error in expression"); |
817 |
|
|
return false; |
818 |
|
|
} |
819 |
|
|
|
820 |
|
|
case T_END: |
821 |
|
|
error("Required argument missing"); |
822 |
|
|
return false; |
823 |
|
|
|
824 |
|
|
default: |
825 |
|
|
error("'pc', 'sp', '(' or number expected"); |
826 |
|
|
return false; |
827 |
|
|
} |
828 |
|
|
} |
829 |
|
|
|
830 |
|
|
|
831 |
|
|
/* |
832 |
|
|
* address_args = [expression] END |
833 |
|
|
* |
834 |
|
|
* Read start to "address" |
835 |
|
|
* |
836 |
|
|
* true: OK, false: Error |
837 |
|
|
*/ |
838 |
|
|
|
839 |
|
|
static bool address_args(void) |
840 |
|
|
{ |
841 |
|
|
if (the_token == T_END) |
842 |
|
|
return true; |
843 |
|
|
else { |
844 |
|
|
if (!expression(&address)) |
845 |
|
|
return false; |
846 |
|
|
return the_token == T_END; |
847 |
|
|
} |
848 |
|
|
} |
849 |
|
|
|
850 |
|
|
|
851 |
|
|
/* |
852 |
|
|
* range_args = [expression] [[COMMA] expression] END |
853 |
|
|
* |
854 |
|
|
* Read start address to "address", end address to "end_address" |
855 |
|
|
* |
856 |
|
|
* true: OK, false: Error |
857 |
|
|
*/ |
858 |
|
|
|
859 |
|
|
static bool range_args(int def_range) |
860 |
|
|
{ |
861 |
|
|
end_address = address + def_range; |
862 |
|
|
|
863 |
|
|
if (the_token == T_END) |
864 |
|
|
return true; |
865 |
|
|
else { |
866 |
|
|
if (!expression(&address)) |
867 |
|
|
return false; |
868 |
|
|
end_address = address + def_range; |
869 |
|
|
if (the_token == T_END) |
870 |
|
|
return true; |
871 |
|
|
else { |
872 |
|
|
if (the_token == T_COMMA) get_token(); |
873 |
|
|
if (!expression(&end_address)) |
874 |
|
|
return false; |
875 |
|
|
return the_token == T_END; |
876 |
|
|
} |
877 |
|
|
} |
878 |
|
|
} |
879 |
|
|
|
880 |
|
|
|
881 |
|
|
/* |
882 |
|
|
* instr_args = END |
883 |
|
|
* | IMMED NUMBER END |
884 |
|
|
* | NUMBER [COMMA (X | Y)] END |
885 |
|
|
* | LPAREN NUMBER (RPAREN [COMMA Y] | COMMA X RPAREN) END |
886 |
|
|
* |
887 |
|
|
* Read arguments of a 6510 instruction, determine address and addressing mode |
888 |
|
|
* |
889 |
|
|
* true: OK, false: Error |
890 |
|
|
*/ |
891 |
|
|
|
892 |
|
|
static bool instr_args(uint16 *number, char *mode) |
893 |
|
|
{ |
894 |
|
|
switch (the_token) { |
895 |
|
|
|
896 |
|
|
case T_END: |
897 |
|
|
*mode = A_IMPL; |
898 |
|
|
return true; |
899 |
|
|
|
900 |
|
|
case T_IMMED: |
901 |
|
|
get_token(); |
902 |
|
|
if (the_token == T_NUMBER) { |
903 |
|
|
*number = the_number; |
904 |
|
|
*mode = A_IMM; |
905 |
|
|
get_token(); |
906 |
|
|
return the_token == T_END; |
907 |
|
|
} else { |
908 |
|
|
error("Number expected"); |
909 |
|
|
return false; |
910 |
|
|
} |
911 |
|
|
|
912 |
|
|
case T_NUMBER: |
913 |
|
|
*number = the_number; |
914 |
|
|
get_token(); |
915 |
|
|
switch (the_token) { |
916 |
|
|
|
917 |
|
|
case T_END: |
918 |
|
|
if (*number < 0x100) |
919 |
|
|
*mode = A_ZERO; |
920 |
|
|
else |
921 |
|
|
*mode = A_ABS; |
922 |
|
|
return true; |
923 |
|
|
|
924 |
|
|
case T_COMMA: |
925 |
|
|
get_token(); |
926 |
|
|
switch (the_token) { |
927 |
|
|
|
928 |
|
|
case T_X: |
929 |
|
|
get_token(); |
930 |
|
|
if (*number < 0x100) |
931 |
|
|
*mode = A_ZEROX; |
932 |
|
|
else |
933 |
|
|
*mode = A_ABSX; |
934 |
|
|
return the_token == T_END; |
935 |
|
|
|
936 |
|
|
case T_Y: |
937 |
|
|
get_token(); |
938 |
|
|
if (*number < 0x100) |
939 |
|
|
*mode = A_ZEROY; |
940 |
|
|
else |
941 |
|
|
*mode = A_ABSY; |
942 |
|
|
return the_token == T_END; |
943 |
|
|
|
944 |
|
|
default: |
945 |
|
|
error("Illegal index register"); |
946 |
|
|
return false; |
947 |
|
|
} |
948 |
|
|
|
949 |
|
|
default: |
950 |
|
|
return false; |
951 |
|
|
} |
952 |
|
|
|
953 |
|
|
case T_LPAREN: |
954 |
|
|
get_token(); |
955 |
|
|
if (the_token == T_NUMBER) { |
956 |
|
|
*number = the_number; |
957 |
|
|
get_token(); |
958 |
|
|
switch (the_token) { |
959 |
|
|
|
960 |
|
|
case T_RPAREN: |
961 |
|
|
get_token(); |
962 |
|
|
switch (the_token) { |
963 |
|
|
|
964 |
|
|
case T_END: |
965 |
|
|
*mode = A_IND; |
966 |
|
|
return true; |
967 |
|
|
|
968 |
|
|
case T_COMMA: |
969 |
|
|
get_token(); |
970 |
|
|
if (the_token == T_Y) { |
971 |
|
|
*mode = A_INDY; |
972 |
|
|
get_token(); |
973 |
|
|
return the_token == T_END; |
974 |
|
|
} else { |
975 |
|
|
error("Only 'y' index register allowed"); |
976 |
|
|
return false; |
977 |
|
|
} |
978 |
|
|
|
979 |
|
|
default: |
980 |
|
|
error("Illegal characters after ')'"); |
981 |
|
|
return false; |
982 |
|
|
} |
983 |
|
|
|
984 |
|
|
case T_COMMA: |
985 |
|
|
get_token(); |
986 |
|
|
if (the_token == T_X) { |
987 |
|
|
get_token(); |
988 |
|
|
if (the_token == T_RPAREN) { |
989 |
|
|
*mode = A_INDX; |
990 |
|
|
get_token(); |
991 |
|
|
return the_token == T_END; |
992 |
|
|
} else { |
993 |
|
|
error("')' expected"); |
994 |
|
|
return false; |
995 |
|
|
} |
996 |
|
|
} else { |
997 |
|
|
error("Only 'x' index register allowed"); |
998 |
|
|
return false; |
999 |
|
|
} |
1000 |
|
|
|
1001 |
|
|
default: |
1002 |
|
|
error("')' or ',' expected"); |
1003 |
|
|
return false; |
1004 |
|
|
} |
1005 |
|
|
} else { |
1006 |
|
|
error("Number expected"); |
1007 |
|
|
return false; |
1008 |
|
|
} |
1009 |
|
|
|
1010 |
|
|
default: |
1011 |
|
|
error("'(', '#' or number expected"); |
1012 |
|
|
return false; |
1013 |
|
|
} |
1014 |
|
|
} |
1015 |
|
|
|
1016 |
|
|
|
1017 |
|
|
/* |
1018 |
|
|
* Display help |
1019 |
|
|
* h |
1020 |
|
|
*/ |
1021 |
|
|
|
1022 |
|
|
static void help(void) |
1023 |
|
|
{ |
1024 |
|
|
fprintf(fout, "a [start] Assemble\n" |
1025 |
|
|
"b [start] [end] Binary dump\n" |
1026 |
|
|
"c start end dest Compare memory\n" |
1027 |
|
|
"d [start] [end] Disassemble\n" |
1028 |
|
|
"e Show interrupt vectors\n" |
1029 |
|
|
"f start end byte Fill memory\n" |
1030 |
|
|
"i [start] [end] ASCII/PETSCII dump\n" |
1031 |
|
|
"k [config] Show/set C64 memory configuration\n" |
1032 |
|
|
"l start \"file\" Load data\n" |
1033 |
|
|
"m [start] [end] Memory dump\n" |
1034 |
|
|
"n [start] [end] Screen code dump\n" |
1035 |
|
|
"o [\"file\"] Redirect output\n" |
1036 |
|
|
"p [start] [end] Sprite dump\n" |
1037 |
|
|
"r [reg value] Show/set CPU registers\n" |
1038 |
|
|
"s start end \"file\" Save data\n" |
1039 |
|
|
"t start end dest Transfer memory\n" |
1040 |
|
|
"vc1 View CIA 1 state\n" |
1041 |
|
|
"vc2 View CIA 2 state\n" |
1042 |
|
|
"vf View 1541 state\n" |
1043 |
|
|
"vs View SID state\n" |
1044 |
|
|
"vv View VIC state\n" |
1045 |
|
|
"x Return to Frodo\n" |
1046 |
|
|
": addr {byte} Modify memory\n" |
1047 |
|
|
"1541 Switch to 1541\n" |
1048 |
|
|
"64 Switch to C64\n" |
1049 |
|
|
"? expression Calculate expression\n"); |
1050 |
|
|
} |
1051 |
|
|
|
1052 |
|
|
|
1053 |
|
|
/* |
1054 |
|
|
* Display/change 6510 registers |
1055 |
|
|
* r [reg value] |
1056 |
|
|
*/ |
1057 |
|
|
|
1058 |
|
|
static void registers(void) |
1059 |
|
|
{ |
1060 |
|
|
enum Token the_reg; |
1061 |
|
|
uint16 value; |
1062 |
|
|
|
1063 |
|
|
if (the_token != T_END) |
1064 |
|
|
switch (the_reg = the_token) { |
1065 |
|
|
case T_A: |
1066 |
|
|
case T_X: |
1067 |
|
|
case T_Y: |
1068 |
|
|
case T_PC: |
1069 |
|
|
case T_SP: |
1070 |
|
|
case T_DR: |
1071 |
|
|
case T_PR: |
1072 |
|
|
get_token(); |
1073 |
|
|
if (!expression(&value)) |
1074 |
|
|
return; |
1075 |
|
|
|
1076 |
|
|
switch (the_reg) { |
1077 |
|
|
case T_A: |
1078 |
|
|
if (access_1541) |
1079 |
|
|
R1541.a = value; |
1080 |
|
|
else |
1081 |
|
|
R64.a = value; |
1082 |
|
|
break; |
1083 |
|
|
case T_X: |
1084 |
|
|
if (access_1541) |
1085 |
|
|
R1541.x = value; |
1086 |
|
|
else |
1087 |
|
|
R64.x = value; |
1088 |
|
|
break; |
1089 |
|
|
case T_Y: |
1090 |
|
|
if (access_1541) |
1091 |
|
|
R1541.y = value; |
1092 |
|
|
else |
1093 |
|
|
R64.y = value; |
1094 |
|
|
break; |
1095 |
|
|
case T_PC: |
1096 |
|
|
if (access_1541) |
1097 |
|
|
R1541.pc = value; |
1098 |
|
|
else |
1099 |
|
|
R64.pc = value; |
1100 |
|
|
break; |
1101 |
|
|
case T_SP: |
1102 |
|
|
if (access_1541) |
1103 |
|
|
R1541.sp = (value & 0xff) | 0x0100; |
1104 |
|
|
else |
1105 |
|
|
R64.sp = (value & 0xff) | 0x0100; |
1106 |
|
|
break; |
1107 |
|
|
case T_DR: |
1108 |
|
|
if (!access_1541) |
1109 |
|
|
R64.ddr = value; |
1110 |
|
|
break; |
1111 |
|
|
case T_PR: |
1112 |
|
|
if (!access_1541) |
1113 |
|
|
R64.pr = value; |
1114 |
|
|
break; |
1115 |
|
|
default: |
1116 |
|
|
break; |
1117 |
|
|
} |
1118 |
|
|
break; |
1119 |
|
|
|
1120 |
|
|
default: |
1121 |
|
|
return; |
1122 |
|
|
} |
1123 |
|
|
|
1124 |
|
|
display_registers(); |
1125 |
|
|
} |
1126 |
|
|
|
1127 |
|
|
static void display_registers(void) |
1128 |
|
|
{ |
1129 |
|
|
if (access_1541) { |
1130 |
|
|
fprintf(fout, " PC A X Y SP NVDIZC Instruction\n"); |
1131 |
|
|
fprintf(fout, "%04lx %02lx %02lx %02lx %04lx %c%c%c%c%c%c ", |
1132 |
|
|
R1541.pc, R1541.a, R1541.x, R1541.y, R1541.sp, |
1133 |
|
|
R1541.p & 0x80 ? '1' : '0', R1541.p & 0x40 ? '1' : '0', R1541.p & 0x08 ? '1' : '0', |
1134 |
|
|
R1541.p & 0x04 ? '1' : '0', R1541.p & 0x02 ? '1' : '0', R1541.p & 0x01 ? '1' : '0'); |
1135 |
|
|
disass_line(R1541.pc, SAMReadByte(R1541.pc), SAMReadByte(R1541.pc+1), SAMReadByte(R1541.pc+2)); |
1136 |
|
|
} else { |
1137 |
|
|
fprintf(fout, " PC A X Y SP DR PR NVDIZC Instruction\n"); |
1138 |
|
|
fprintf(fout, "%04lx %02lx %02lx %02lx %04lx %02lx %02lx %c%c%c%c%c%c ", |
1139 |
|
|
R64.pc, R64.a, R64.x, R64.y, R64.sp, R64.ddr, R64.pr, |
1140 |
|
|
R64.p & 0x80 ? '1' : '0', R64.p & 0x40 ? '1' : '0', R64.p & 0x08 ? '1' : '0', |
1141 |
|
|
R64.p & 0x04 ? '1' : '0', R64.p & 0x02 ? '1' : '0', R64.p & 0x01 ? '1' : '0'); |
1142 |
|
|
disass_line(R64.pc, SAMReadByte(R64.pc), SAMReadByte(R64.pc+1), SAMReadByte(R64.pc+2)); |
1143 |
|
|
} |
1144 |
|
|
} |
1145 |
|
|
|
1146 |
|
|
|
1147 |
|
|
/* |
1148 |
|
|
* Memory dump |
1149 |
|
|
* m [start] [end] |
1150 |
|
|
*/ |
1151 |
|
|
|
1152 |
|
|
#define MEMDUMP_BPL 16 // Bytes per line |
1153 |
|
|
|
1154 |
|
|
static void memory_dump(void) |
1155 |
|
|
{ |
1156 |
|
|
bool done = false; |
1157 |
|
|
short i; |
1158 |
|
|
uint8 mem[MEMDUMP_BPL + 2]; |
1159 |
|
|
uint8 byte; |
1160 |
|
|
|
1161 |
|
|
mem[MEMDUMP_BPL] = 0; |
1162 |
|
|
|
1163 |
|
|
if (!range_args(16 * MEMDUMP_BPL - 1)) // 16 lines unless end address specified |
1164 |
|
|
return; |
1165 |
|
|
|
1166 |
|
|
do { |
1167 |
|
|
fprintf(fout, "%04lx:", address); |
1168 |
|
|
for (i=0; i<MEMDUMP_BPL; i++, address++) { |
1169 |
|
|
if (address == end_address) done = true; |
1170 |
|
|
|
1171 |
|
|
fprintf(fout, " %02lx", byte = SAMReadByte(address)); |
1172 |
|
|
if ((byte >= ' ') && (byte <= '~')) |
1173 |
|
|
mem[i] = conv_from_64(byte); |
1174 |
|
|
else |
1175 |
|
|
mem[i] = '.'; |
1176 |
|
|
} |
1177 |
|
|
fprintf(fout, " '%s'\n", mem); |
1178 |
|
|
} while (!done && !aborted()); |
1179 |
|
|
} |
1180 |
|
|
|
1181 |
|
|
|
1182 |
|
|
/* |
1183 |
|
|
* ASCII dump |
1184 |
|
|
* i [start] [end] |
1185 |
|
|
*/ |
1186 |
|
|
|
1187 |
|
|
#define ASCIIDUMP_BPL 64 // Bytes per line |
1188 |
|
|
|
1189 |
|
|
static void ascii_dump(void) |
1190 |
|
|
{ |
1191 |
|
|
bool done = false; |
1192 |
|
|
short i; |
1193 |
|
|
uint8 mem[ASCIIDUMP_BPL + 2]; |
1194 |
|
|
uint8 byte; |
1195 |
|
|
|
1196 |
|
|
mem[ASCIIDUMP_BPL] = 0; |
1197 |
|
|
|
1198 |
|
|
if (!range_args(16 * ASCIIDUMP_BPL - 1)) // 16 lines unless end address specified |
1199 |
|
|
return; |
1200 |
|
|
|
1201 |
|
|
do { |
1202 |
|
|
fprintf(fout, "%04lx:", address); |
1203 |
|
|
for (i=0; i<ASCIIDUMP_BPL; i++, address++) { |
1204 |
|
|
if (address == end_address) done = true; |
1205 |
|
|
|
1206 |
|
|
byte = SAMReadByte(address); |
1207 |
|
|
if ((byte >= ' ') && (byte <= '~')) |
1208 |
|
|
mem[i] = conv_from_64(byte); |
1209 |
|
|
else |
1210 |
|
|
mem[i] = '.'; |
1211 |
|
|
} |
1212 |
|
|
fprintf(fout, " '%s'\n", mem); |
1213 |
|
|
} while (!done && !aborted()); |
1214 |
|
|
} |
1215 |
|
|
|
1216 |
|
|
|
1217 |
|
|
/* |
1218 |
|
|
* Convert PETSCII->ASCII |
1219 |
|
|
*/ |
1220 |
|
|
|
1221 |
|
|
static char conv_from_64(char c) |
1222 |
|
|
{ |
1223 |
|
|
if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z')) |
1224 |
|
|
return c ^ 0x20; |
1225 |
|
|
else |
1226 |
|
|
return c; |
1227 |
|
|
} |
1228 |
|
|
|
1229 |
|
|
|
1230 |
|
|
/* |
1231 |
|
|
* Screen code dump |
1232 |
|
|
* n [start] [end] |
1233 |
|
|
*/ |
1234 |
|
|
|
1235 |
|
|
#define SCRDUMP_BPL 64 // Bytes per line |
1236 |
|
|
|
1237 |
|
|
static void screen_dump(void) |
1238 |
|
|
{ |
1239 |
|
|
bool done = false; |
1240 |
|
|
short i; |
1241 |
|
|
uint8 mem[SCRDUMP_BPL + 2]; |
1242 |
|
|
uint8 byte; |
1243 |
|
|
|
1244 |
|
|
mem[SCRDUMP_BPL] = 0; |
1245 |
|
|
|
1246 |
|
|
if (!range_args(16 * SCRDUMP_BPL - 1)) // 16 Zeilen unless end address specified |
1247 |
|
|
return; |
1248 |
|
|
|
1249 |
|
|
do { |
1250 |
|
|
fprintf(fout, "%04lx:", address); |
1251 |
|
|
for (i=0; i<SCRDUMP_BPL; i++, address++) { |
1252 |
|
|
if (address == end_address) done = true; |
1253 |
|
|
|
1254 |
|
|
byte = SAMReadByte(address); |
1255 |
|
|
if (byte < 90) |
1256 |
|
|
mem[i] = conv_from_scode(byte); |
1257 |
|
|
else |
1258 |
|
|
mem[i] = '.'; |
1259 |
|
|
} |
1260 |
|
|
fprintf(fout, " '%s'\n", mem); |
1261 |
|
|
} while (!done && !aborted()); |
1262 |
|
|
} |
1263 |
|
|
|
1264 |
|
|
|
1265 |
|
|
/* |
1266 |
|
|
* Convert screen code->ASCII |
1267 |
|
|
*/ |
1268 |
|
|
|
1269 |
|
|
static char conv_from_scode(char c) |
1270 |
|
|
{ |
1271 |
|
|
c &= 0x7f; |
1272 |
|
|
|
1273 |
|
|
if (c <= 31) |
1274 |
|
|
return c + 64; |
1275 |
|
|
else |
1276 |
|
|
if (c >= 64) |
1277 |
|
|
return c + 32; |
1278 |
|
|
else |
1279 |
|
|
return c; |
1280 |
|
|
} |
1281 |
|
|
|
1282 |
|
|
|
1283 |
|
|
/* |
1284 |
|
|
* Binary dump |
1285 |
|
|
* b [start] [end] |
1286 |
|
|
*/ |
1287 |
|
|
|
1288 |
|
|
static void binary_dump(void) |
1289 |
|
|
{ |
1290 |
|
|
bool done = false; |
1291 |
|
|
char bin[10]; |
1292 |
|
|
|
1293 |
|
|
bin[8] = 0; |
1294 |
|
|
|
1295 |
|
|
if (!range_args(7)) // 8 lines unless end address specified |
1296 |
|
|
return; |
1297 |
|
|
|
1298 |
|
|
do { |
1299 |
|
|
if (address == end_address) done = true; |
1300 |
|
|
|
1301 |
|
|
byte_to_bin(SAMReadByte(address), bin); |
1302 |
|
|
fprintf(fout, "%04lx: %s\n", address++, bin); |
1303 |
|
|
} while (!done && !aborted()); |
1304 |
|
|
} |
1305 |
|
|
|
1306 |
|
|
|
1307 |
|
|
/* |
1308 |
|
|
* Sprite data dump |
1309 |
|
|
* p [start] [end] |
1310 |
|
|
*/ |
1311 |
|
|
|
1312 |
|
|
static void sprite_dump(void) |
1313 |
|
|
{ |
1314 |
|
|
bool done = false; |
1315 |
|
|
short i; |
1316 |
|
|
char bin[10]; |
1317 |
|
|
|
1318 |
|
|
bin[8] = 0; |
1319 |
|
|
|
1320 |
|
|
if (!range_args(21 * 3 - 1)) // 21 lines unless end address specified |
1321 |
|
|
return; |
1322 |
|
|
|
1323 |
|
|
do { |
1324 |
|
|
fprintf(fout, "%04lx: ", address); |
1325 |
|
|
for (i=0; i<3; i++, address++) { |
1326 |
|
|
if (address == end_address) done = true; |
1327 |
|
|
|
1328 |
|
|
byte_to_bin(SAMReadByte(address), bin); |
1329 |
|
|
fprintf(fout, "%s", bin); |
1330 |
|
|
} |
1331 |
|
|
fputc('\n', fout); |
1332 |
|
|
} while (!done && !aborted()); |
1333 |
|
|
} |
1334 |
|
|
|
1335 |
|
|
|
1336 |
|
|
/* |
1337 |
|
|
* Convert byte to binary representation |
1338 |
|
|
*/ |
1339 |
|
|
|
1340 |
|
|
static void byte_to_bin(uint8 byte, char *str) |
1341 |
|
|
{ |
1342 |
|
|
short i; |
1343 |
|
|
|
1344 |
|
|
for (i=0; i<8; i++, byte<<=1) |
1345 |
|
|
if (byte & 0x80) |
1346 |
|
|
str[i] = '#'; |
1347 |
|
|
else |
1348 |
|
|
str[i] = '.'; |
1349 |
|
|
} |
1350 |
|
|
|
1351 |
|
|
|
1352 |
|
|
/* |
1353 |
|
|
* Disassemble |
1354 |
|
|
* d [start] [end] |
1355 |
|
|
*/ |
1356 |
|
|
|
1357 |
|
|
static void disassemble(void) |
1358 |
|
|
{ |
1359 |
|
|
bool done = false; |
1360 |
|
|
short i; |
1361 |
|
|
uint8 op[3]; |
1362 |
|
|
uint16 adr; |
1363 |
|
|
|
1364 |
|
|
if (!range_args(31)) // 32 bytes unless end address specified |
1365 |
|
|
return; |
1366 |
|
|
|
1367 |
|
|
do { |
1368 |
|
|
fprintf(fout, "%04lx:", adr = address); |
1369 |
|
|
for (i=0; i<3; i++, adr++) { |
1370 |
|
|
if (adr == end_address) done = true; |
1371 |
|
|
op[i] = SAMReadByte(adr); |
1372 |
|
|
} |
1373 |
|
|
address += disass_line(address, op[0], op[1], op[2]); |
1374 |
|
|
} while (!done && !aborted()); |
1375 |
|
|
} |
1376 |
|
|
|
1377 |
|
|
|
1378 |
|
|
/* |
1379 |
|
|
* Disassemble one instruction, return length |
1380 |
|
|
*/ |
1381 |
|
|
|
1382 |
|
|
static int disass_line(uint16 adr, uint8 op, uint8 lo, uint8 hi) |
1383 |
|
|
{ |
1384 |
|
|
char mode = adr_mode[op], mnem = mnemonic[op]; |
1385 |
|
|
|
1386 |
|
|
// Display instruction bytes in hex |
1387 |
|
|
switch (adr_length[mode]) { |
1388 |
|
|
case 1: |
1389 |
|
|
fprintf(fout, " %02lx ", op); |
1390 |
|
|
break; |
1391 |
|
|
|
1392 |
|
|
case 2: |
1393 |
|
|
fprintf(fout, " %02lx %02lx ", op, lo); |
1394 |
|
|
break; |
1395 |
|
|
|
1396 |
|
|
case 3: |
1397 |
|
|
fprintf(fout, " %02lx %02lx %02lx ", op, lo, hi); |
1398 |
|
|
break; |
1399 |
|
|
} |
1400 |
|
|
|
1401 |
|
|
// Tag undocumented opcodes with an asterisk |
1402 |
|
|
if (mnem > M_ILLEGAL) |
1403 |
|
|
fputc('*', fout); |
1404 |
|
|
else |
1405 |
|
|
fputc(' ', fout); |
1406 |
|
|
|
1407 |
|
|
// Print mnemonic |
1408 |
|
|
fprintf(fout, "%c%c%c ", mnem_1[mnem], mnem_2[mnem], mnem_3[mnem]); |
1409 |
|
|
|
1410 |
|
|
// Pring argument |
1411 |
|
|
switch (mode) { |
1412 |
|
|
case A_IMPL: |
1413 |
|
|
break; |
1414 |
|
|
|
1415 |
|
|
case A_ACCU: |
1416 |
|
|
fprintf(fout, "a"); |
1417 |
|
|
break; |
1418 |
|
|
|
1419 |
|
|
case A_IMM: |
1420 |
|
|
fprintf(fout, "#%02lx", lo); |
1421 |
|
|
break; |
1422 |
|
|
|
1423 |
|
|
case A_REL: |
1424 |
|
|
fprintf(fout, "%04lx", ((adr + 2) + (int8)lo) & 0xffff); |
1425 |
|
|
break; |
1426 |
|
|
|
1427 |
|
|
case A_ZERO: |
1428 |
|
|
fprintf(fout, "%02lx", lo); |
1429 |
|
|
break; |
1430 |
|
|
|
1431 |
|
|
case A_ZEROX: |
1432 |
|
|
fprintf(fout, "%02lx,x", lo); |
1433 |
|
|
break; |
1434 |
|
|
|
1435 |
|
|
case A_ZEROY: |
1436 |
|
|
fprintf(fout, "%02lx,y", lo); |
1437 |
|
|
break; |
1438 |
|
|
|
1439 |
|
|
case A_ABS: |
1440 |
|
|
fprintf(fout, "%04lx", (hi << 8) | lo); |
1441 |
|
|
break; |
1442 |
|
|
|
1443 |
|
|
case A_ABSX: |
1444 |
|
|
fprintf(fout, "%04lx,x", (hi << 8) | lo); |
1445 |
|
|
break; |
1446 |
|
|
|
1447 |
|
|
case A_ABSY: |
1448 |
|
|
fprintf(fout, "%04lx,y", (hi << 8) | lo); |
1449 |
|
|
break; |
1450 |
|
|
|
1451 |
|
|
case A_IND: |
1452 |
|
|
fprintf(fout, "(%04lx)", (hi << 8) | lo); |
1453 |
|
|
break; |
1454 |
|
|
|
1455 |
|
|
case A_INDX: |
1456 |
|
|
fprintf(fout, "(%02lx,x)", lo); |
1457 |
|
|
break; |
1458 |
|
|
|
1459 |
|
|
case A_INDY: |
1460 |
|
|
fprintf(fout, "(%02lx),y", lo); |
1461 |
|
|
break; |
1462 |
|
|
} |
1463 |
|
|
|
1464 |
|
|
fputc('\n', fout); |
1465 |
|
|
return adr_length[mode]; |
1466 |
|
|
} |
1467 |
|
|
|
1468 |
|
|
|
1469 |
|
|
/* |
1470 |
|
|
* Assemble |
1471 |
|
|
* a [start] |
1472 |
|
|
*/ |
1473 |
|
|
|
1474 |
|
|
static void assemble(void) |
1475 |
|
|
{ |
1476 |
|
|
bool done = false; |
1477 |
|
|
char c1, c2, c3; |
1478 |
|
|
char mnem, mode; |
1479 |
|
|
uint8 opcode; |
1480 |
|
|
uint16 arg; |
1481 |
|
|
int16 rel; |
1482 |
|
|
|
1483 |
|
|
// Read parameters |
1484 |
|
|
if (!address_args()) |
1485 |
|
|
return; |
1486 |
|
|
|
1487 |
|
|
do { |
1488 |
|
|
fprintf(fout, "%04lx> ", address); |
1489 |
|
|
fflush(ferr); |
1490 |
|
|
read_line(); |
1491 |
|
|
|
1492 |
|
|
c1 = get_char(); |
1493 |
|
|
c2 = get_char(); |
1494 |
|
|
c3 = get_char(); |
1495 |
|
|
|
1496 |
|
|
if (c1 != '\n') { |
1497 |
|
|
|
1498 |
|
|
if ((mnem = find_mnemonic(c1, c2, c3)) != M_ILLEGAL) { |
1499 |
|
|
|
1500 |
|
|
get_token(); |
1501 |
|
|
if (instr_args(&arg, &mode)) { |
1502 |
|
|
|
1503 |
|
|
// Convert A_IMPL -> A_ACCU if necessary |
1504 |
|
|
if ((mode == A_IMPL) && find_opcode(mnem, A_ACCU, &opcode)) |
1505 |
|
|
mode = A_ACCU; |
1506 |
|
|
|
1507 |
|
|
// Handle relative addressing seperately |
1508 |
|
|
if (((mode == A_ABS) || (mode == A_ZERO)) && find_opcode(mnem, A_REL, &opcode)) { |
1509 |
|
|
mode = A_REL; |
1510 |
|
|
rel = arg - (address + 2) & 0xffff; |
1511 |
|
|
if ((rel < -128) || (rel > 127)) { |
1512 |
|
|
error("Branch too long"); |
1513 |
|
|
continue; |
1514 |
|
|
} else |
1515 |
|
|
arg = rel & 0xff; |
1516 |
|
|
} |
1517 |
|
|
|
1518 |
|
|
if (find_opcode(mnem, mode, &opcode)) { |
1519 |
|
|
|
1520 |
|
|
// Print disassembled line |
1521 |
|
|
fprintf(fout, "\v%04lx:", address); |
1522 |
|
|
disass_line(address, opcode, arg & 0xff, arg >> 8); |
1523 |
|
|
|
1524 |
|
|
switch (adr_length[mode]) { |
1525 |
|
|
case 1: |
1526 |
|
|
SAMWriteByte(address++, opcode); |
1527 |
|
|
break; |
1528 |
|
|
|
1529 |
|
|
case 2: |
1530 |
|
|
SAMWriteByte(address++, opcode); |
1531 |
|
|
SAMWriteByte(address++, arg); |
1532 |
|
|
break; |
1533 |
|
|
|
1534 |
|
|
case 3: |
1535 |
|
|
SAMWriteByte(address++, opcode); |
1536 |
|
|
SAMWriteByte(address++, arg & 0xff); |
1537 |
|
|
SAMWriteByte(address++, arg >> 8); |
1538 |
|
|
break; |
1539 |
|
|
|
1540 |
|
|
default: |
1541 |
|
|
error("Internal error"); |
1542 |
|
|
break; |
1543 |
|
|
} |
1544 |
|
|
|
1545 |
|
|
} else |
1546 |
|
|
error("Addressing mode not supported by instruction"); |
1547 |
|
|
|
1548 |
|
|
} else |
1549 |
|
|
error("Unrecognized addressing mode"); |
1550 |
|
|
|
1551 |
|
|
} else |
1552 |
|
|
error("Unknown instruction"); |
1553 |
|
|
|
1554 |
|
|
} else // Input is terminated with a blank line |
1555 |
|
|
done = true; |
1556 |
|
|
} while (!done); |
1557 |
|
|
} |
1558 |
|
|
|
1559 |
|
|
|
1560 |
|
|
/* |
1561 |
|
|
* Find mnemonic code to three letters |
1562 |
|
|
* M_ILLEGAL: No matching mnemonic found |
1563 |
|
|
*/ |
1564 |
|
|
|
1565 |
|
|
static char find_mnemonic(char op1, char op2, char op3) |
1566 |
|
|
{ |
1567 |
|
|
int i; |
1568 |
|
|
|
1569 |
|
|
for (i=0; i<M_MAXIMUM; i++) |
1570 |
|
|
if ((mnem_1[i] == op1) && (mnem_2[i] == op2) && (mnem_3[i] == op3)) |
1571 |
|
|
return i; |
1572 |
|
|
|
1573 |
|
|
return M_ILLEGAL; |
1574 |
|
|
} |
1575 |
|
|
|
1576 |
|
|
|
1577 |
|
|
/* |
1578 |
|
|
* Determine opcode of an instruction given mnemonic and addressing mode |
1579 |
|
|
* true: OK, false: Mnemonic can't have specified addressing mode |
1580 |
|
|
*/ |
1581 |
|
|
|
1582 |
|
|
static bool find_opcode(char mnem, char mode, uint8 *opcode) |
1583 |
|
|
{ |
1584 |
|
|
int i; |
1585 |
|
|
|
1586 |
|
|
for (i=0; i<256; i++) |
1587 |
|
|
if ((mnemonic[i] == mnem) && (adr_mode[i] == mode)) { |
1588 |
|
|
*opcode = i; |
1589 |
|
|
return true; |
1590 |
|
|
} |
1591 |
|
|
|
1592 |
|
|
return false; |
1593 |
|
|
} |
1594 |
|
|
|
1595 |
|
|
|
1596 |
|
|
/* |
1597 |
|
|
* Show/set memory configuration |
1598 |
|
|
* k [config] |
1599 |
|
|
*/ |
1600 |
|
|
|
1601 |
|
|
static void mem_config(void) |
1602 |
|
|
{ |
1603 |
|
|
uint16 con; |
1604 |
|
|
|
1605 |
|
|
if (the_token != T_END) |
1606 |
|
|
if (!expression(&con)) |
1607 |
|
|
return; |
1608 |
|
|
else |
1609 |
|
|
TheCPU->ExtConfig = con; |
1610 |
|
|
else |
1611 |
|
|
con = TheCPU->ExtConfig; |
1612 |
|
|
|
1613 |
|
|
fprintf(fout, "Configuration: %ld\n", con & 7); |
1614 |
|
|
fprintf(fout, "A000-BFFF: %s\n", (con & 3) == 3 ? "Basic" : "RAM"); |
1615 |
|
|
fprintf(fout, "D000-DFFF: %s\n", (con & 3) ? ((con & 4) ? "I/O" : "Char") : "RAM"); |
1616 |
|
|
fprintf(fout, "E000-FFFF: %s\n", (con & 2) ? "Kernal" : "RAM"); |
1617 |
|
|
} |
1618 |
|
|
|
1619 |
|
|
|
1620 |
|
|
/* |
1621 |
|
|
* Fill |
1622 |
|
|
* f start end byte |
1623 |
|
|
*/ |
1624 |
|
|
|
1625 |
|
|
static void fill(void) |
1626 |
|
|
{ |
1627 |
|
|
bool done = false; |
1628 |
|
|
uint16 adr, end_adr, value; |
1629 |
|
|
|
1630 |
|
|
if (!expression(&adr)) |
1631 |
|
|
return; |
1632 |
|
|
if (!expression(&end_adr)) |
1633 |
|
|
return; |
1634 |
|
|
if (!expression(&value)) |
1635 |
|
|
return; |
1636 |
|
|
|
1637 |
|
|
do { |
1638 |
|
|
if (adr == end_adr) done = true; |
1639 |
|
|
|
1640 |
|
|
SAMWriteByte(adr++, value); |
1641 |
|
|
} while (!done); |
1642 |
|
|
} |
1643 |
|
|
|
1644 |
|
|
|
1645 |
|
|
/* |
1646 |
|
|
* Compare |
1647 |
|
|
* c start end dest |
1648 |
|
|
*/ |
1649 |
|
|
|
1650 |
|
|
static void compare(void) |
1651 |
|
|
{ |
1652 |
|
|
bool done = false; |
1653 |
|
|
uint16 adr, end_adr, dest; |
1654 |
|
|
int num = 0; |
1655 |
|
|
|
1656 |
|
|
if (!expression(&adr)) |
1657 |
|
|
return; |
1658 |
|
|
if (!expression(&end_adr)) |
1659 |
|
|
return; |
1660 |
|
|
if (!expression(&dest)) |
1661 |
|
|
return; |
1662 |
|
|
|
1663 |
|
|
do { |
1664 |
|
|
if (adr == end_adr) done = true; |
1665 |
|
|
|
1666 |
|
|
if (SAMReadByte(adr) != SAMReadByte(dest)) { |
1667 |
|
|
fprintf(fout, "%04lx ", adr); |
1668 |
|
|
num++; |
1669 |
|
|
if (!(num & 7)) |
1670 |
|
|
fputc('\n', fout); |
1671 |
|
|
} |
1672 |
|
|
adr++; dest++; |
1673 |
|
|
} while (!done && !aborted()); |
1674 |
|
|
|
1675 |
|
|
if (num & 7) |
1676 |
|
|
fputc('\n', fout); |
1677 |
|
|
fprintf(fout, "%ld byte(s) different\n", num); |
1678 |
|
|
} |
1679 |
|
|
|
1680 |
|
|
|
1681 |
|
|
/* |
1682 |
|
|
* Transfer memory |
1683 |
|
|
* t start end dest |
1684 |
|
|
*/ |
1685 |
|
|
|
1686 |
|
|
static void transfer(void) |
1687 |
|
|
{ |
1688 |
|
|
bool done = false; |
1689 |
|
|
uint16 adr, end_adr, dest; |
1690 |
|
|
|
1691 |
|
|
if (!expression(&adr)) |
1692 |
|
|
return; |
1693 |
|
|
if (!expression(&end_adr)) |
1694 |
|
|
return; |
1695 |
|
|
if (!expression(&dest)) |
1696 |
|
|
return; |
1697 |
|
|
|
1698 |
|
|
if (dest < adr) |
1699 |
|
|
do { |
1700 |
|
|
if (adr == end_adr) done = true; |
1701 |
|
|
SAMWriteByte(dest++, SAMReadByte(adr++)); |
1702 |
|
|
} while (!done); |
1703 |
|
|
else { |
1704 |
|
|
dest += end_adr - adr; |
1705 |
|
|
do { |
1706 |
|
|
if (adr == end_adr) done = true; |
1707 |
|
|
SAMWriteByte(dest--, SAMReadByte(end_adr--)); |
1708 |
|
|
} while (!done); |
1709 |
|
|
} |
1710 |
|
|
} |
1711 |
|
|
|
1712 |
|
|
|
1713 |
|
|
/* |
1714 |
|
|
* Change memory |
1715 |
|
|
* : addr {byte} |
1716 |
|
|
*/ |
1717 |
|
|
|
1718 |
|
|
static void modify(void) |
1719 |
|
|
{ |
1720 |
|
|
uint16 adr, val; |
1721 |
|
|
|
1722 |
|
|
if (!expression(&adr)) |
1723 |
|
|
return; |
1724 |
|
|
|
1725 |
|
|
while (the_token != T_END) |
1726 |
|
|
if (expression(&val)) |
1727 |
|
|
SAMWriteByte(adr++, val); |
1728 |
|
|
else |
1729 |
|
|
return; |
1730 |
|
|
} |
1731 |
|
|
|
1732 |
|
|
|
1733 |
|
|
/* |
1734 |
|
|
* Compute and display expression |
1735 |
|
|
* ? expression |
1736 |
|
|
*/ |
1737 |
|
|
|
1738 |
|
|
static void print_expr(void) |
1739 |
|
|
{ |
1740 |
|
|
uint16 val; |
1741 |
|
|
|
1742 |
|
|
if (!expression(&val)) |
1743 |
|
|
return; |
1744 |
|
|
|
1745 |
|
|
fprintf(fout, "Hex: %04lx\nDec: %lu\n", val, val); |
1746 |
|
|
} |
1747 |
|
|
|
1748 |
|
|
|
1749 |
|
|
/* |
1750 |
|
|
* Redirect output |
1751 |
|
|
* o [file] |
1752 |
|
|
*/ |
1753 |
|
|
|
1754 |
|
|
static void redir_output(void) |
1755 |
|
|
{ |
1756 |
|
|
// Close old file |
1757 |
|
|
if (fout != ferr) { |
1758 |
|
|
fclose(fout); |
1759 |
|
|
fout = ferr; |
1760 |
|
|
return; |
1761 |
|
|
} |
1762 |
|
|
|
1763 |
|
|
// No argument given? |
1764 |
|
|
if (the_token == T_END) |
1765 |
|
|
return; |
1766 |
|
|
|
1767 |
|
|
// Otherwise open file |
1768 |
|
|
if (the_token == T_STRING) { |
1769 |
|
|
if (!(fout = fopen(the_string, "w"))) |
1770 |
|
|
error("Unable to open file"); |
1771 |
|
|
} else |
1772 |
|
|
error("'\"' around file name expected"); |
1773 |
|
|
} |
1774 |
|
|
|
1775 |
|
|
|
1776 |
|
|
/* |
1777 |
|
|
* Display interrupt vectors |
1778 |
|
|
*/ |
1779 |
|
|
|
1780 |
|
|
static void int_vectors(void) |
1781 |
|
|
{ |
1782 |
|
|
fprintf(fout, " IRQ BRK NMI\n"); |
1783 |
|
|
fprintf(fout, "%d : %04lx %04lx %04lx\n", |
1784 |
|
|
access_1541 ? 6502 : 6510, |
1785 |
|
|
SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe), |
1786 |
|
|
SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe), |
1787 |
|
|
SAMReadByte(0xfffb) << 8 | SAMReadByte(0xfffa)); |
1788 |
|
|
|
1789 |
|
|
if (!access_1541 && TheCPU->ExtConfig & 2) |
1790 |
|
|
fprintf(fout, "Kernal: %04lx %04lx %04lx\n", |
1791 |
|
|
SAMReadByte(0x0315) << 8 | SAMReadByte(0x0314), |
1792 |
|
|
SAMReadByte(0x0317) << 8 | SAMReadByte(0x0316), |
1793 |
|
|
SAMReadByte(0x0319) << 8 | SAMReadByte(0x0318)); |
1794 |
|
|
} |
1795 |
|
|
|
1796 |
|
|
|
1797 |
|
|
/* |
1798 |
|
|
* Display state of custom chips |
1799 |
|
|
*/ |
1800 |
|
|
|
1801 |
|
|
static void view_state(void) |
1802 |
|
|
{ |
1803 |
|
|
switch (get_char()) { |
1804 |
|
|
case 'c': // CIA |
1805 |
|
|
view_cia_state(); |
1806 |
|
|
break; |
1807 |
|
|
|
1808 |
|
|
case 's': // SID |
1809 |
|
|
view_sid_state(); |
1810 |
|
|
break; |
1811 |
|
|
|
1812 |
|
|
case 'v': // VIC |
1813 |
|
|
view_vic_state(); |
1814 |
|
|
break; |
1815 |
|
|
|
1816 |
|
|
case 'f': // Floppy |
1817 |
|
|
view_1541_state(); |
1818 |
|
|
break; |
1819 |
|
|
|
1820 |
|
|
default: |
1821 |
|
|
error("Unknown command"); |
1822 |
|
|
break; |
1823 |
|
|
} |
1824 |
|
|
} |
1825 |
|
|
|
1826 |
|
|
static void view_cia_state(void) |
1827 |
|
|
{ |
1828 |
|
|
MOS6526State cs; |
1829 |
|
|
|
1830 |
|
|
switch (get_char()) { |
1831 |
|
|
case '1': |
1832 |
|
|
TheCIA1->GetState(&cs); |
1833 |
|
|
break; |
1834 |
|
|
case '2': |
1835 |
|
|
TheCIA2->GetState(&cs); |
1836 |
|
|
break; |
1837 |
|
|
default: |
1838 |
|
|
error("Unknown command"); |
1839 |
|
|
return; |
1840 |
|
|
} |
1841 |
|
|
|
1842 |
|
|
fprintf(fout, "Timer A : %s\n", cs.cra & 1 ? "On" : "Off"); |
1843 |
|
|
fprintf(fout, " Counter : %04lx Latch: %04lx\n", (cs.ta_hi << 8) | cs.ta_lo, cs.latcha); |
1844 |
|
|
fprintf(fout, " Run mode: %s\n", cs.cra & 8 ? "One-shot" : "Continuous"); |
1845 |
|
|
fprintf(fout, " Input : %s\n", cs.cra & 0x20 ? "CNT" : "Phi2"); |
1846 |
|
|
fprintf(fout, " Output : "); |
1847 |
|
|
if (cs.cra & 2) |
1848 |
|
|
if (cs.cra & 4) |
1849 |
|
|
fprintf(fout, "PB6 Toggle\n\n"); |
1850 |
|
|
else |
1851 |
|
|
fprintf(fout, "PB6 Pulse\n\n"); |
1852 |
|
|
else |
1853 |
|
|
fprintf(fout, "None\n\n"); |
1854 |
|
|
|
1855 |
|
|
fprintf(fout, "Timer B : %s\n", cs.crb & 1 ? "On" : "Off"); |
1856 |
|
|
fprintf(fout, " Counter : %04lx Latch: %04lx\n", (cs.tb_hi << 8) | cs.tb_lo, cs.latchb); |
1857 |
|
|
fprintf(fout, " Run mode: %s\n", cs.crb & 8 ? "One-shot" : "Continuous"); |
1858 |
|
|
fprintf(fout, " Input : "); |
1859 |
|
|
if (cs.crb & 0x40) |
1860 |
|
|
if (cs.crb & 0x20) |
1861 |
|
|
fprintf(fout, "Timer A underflow (CNT high)\n"); |
1862 |
|
|
else |
1863 |
|
|
fprintf(fout, "Timer A underflow\n"); |
1864 |
|
|
else |
1865 |
|
|
if (cs.crb & 0x20) |
1866 |
|
|
fprintf(fout, "CNT\n"); |
1867 |
|
|
else |
1868 |
|
|
fprintf(fout, "Phi2\n"); |
1869 |
|
|
fprintf(fout, " Output : "); |
1870 |
|
|
if (cs.crb & 2) |
1871 |
|
|
if (cs.crb & 4) |
1872 |
|
|
fprintf(fout, "PB7 Toggle\n\n"); |
1873 |
|
|
else |
1874 |
|
|
fprintf(fout, "PB7 Pulse\n\n"); |
1875 |
|
|
else |
1876 |
|
|
fprintf(fout, "None\n\n"); |
1877 |
|
|
|
1878 |
|
|
fprintf(fout, "TOD : %lx%lx:%lx%lx:%lx%lx.%lx %s\n", |
1879 |
|
|
(cs.tod_hr >> 4) & 1, cs.tod_hr & 0x0f, |
1880 |
|
|
(cs.tod_min >> 4) & 7, cs.tod_min & 0x0f, |
1881 |
|
|
(cs.tod_sec >> 4) & 7, cs.tod_sec & 0x0f, |
1882 |
|
|
cs.tod_10ths & 0x0f, cs.tod_hr & 0x80 ? "PM" : "AM"); |
1883 |
|
|
fprintf(fout, "Alarm : %lx%lx:%lx%lx:%lx%lx.%lx %s\n", |
1884 |
|
|
(cs.alm_hr >> 4) & 1, cs.alm_hr & 0x0f, |
1885 |
|
|
(cs.alm_min >> 4) & 7, cs.alm_min & 0x0f, |
1886 |
|
|
(cs.alm_sec >> 4) & 7, cs.alm_sec & 0x0f, |
1887 |
|
|
cs.alm_10ths & 0x0f, cs.alm_hr & 0x80 ? "PM" : "AM"); |
1888 |
|
|
fprintf(fout, "TOD input : %s\n", cs.cra & 0x80 ? "50Hz" : "60Hz"); |
1889 |
|
|
fprintf(fout, "Write to : %s registers\n\n", cs.crb & 0x80 ? "Alarm" : "TOD"); |
1890 |
|
|
|
1891 |
|
|
fprintf(fout, "Serial data : %02lx\n", cs.sdr); |
1892 |
|
|
fprintf(fout, "Serial mode : %s\n\n", cs.cra & 0x40 ? "Output" : "Input"); |
1893 |
|
|
|
1894 |
|
|
fprintf(fout, "Pending int.: "); |
1895 |
|
|
dump_cia_ints(cs.int_data); |
1896 |
|
|
fprintf(fout, "Enabled int.: "); |
1897 |
|
|
dump_cia_ints(cs.int_mask); |
1898 |
|
|
} |
1899 |
|
|
|
1900 |
|
|
static void dump_cia_ints(uint8 i) |
1901 |
|
|
{ |
1902 |
|
|
if (i & 0x1f) { |
1903 |
|
|
if (i & 1) fprintf(fout, "TA "); |
1904 |
|
|
if (i & 2) fprintf(fout, "TB "); |
1905 |
|
|
if (i & 4) fprintf(fout, "Alarm "); |
1906 |
|
|
if (i & 8) fprintf(fout, "Serial "); |
1907 |
|
|
if (i & 0x10) fprintf(fout, "Flag"); |
1908 |
|
|
} else |
1909 |
|
|
fprintf(fout, "None"); |
1910 |
|
|
fputc('\n', fout); |
1911 |
|
|
} |
1912 |
|
|
|
1913 |
|
|
static void view_sid_state(void) |
1914 |
|
|
{ |
1915 |
|
|
MOS6581State ss; |
1916 |
|
|
|
1917 |
|
|
TheSID->GetState(&ss); |
1918 |
|
|
|
1919 |
|
|
fprintf(fout, "Voice 1\n"); |
1920 |
|
|
fprintf(fout, " Frequency : %04lx\n", (ss.freq_hi_1 << 8) | ss.freq_lo_1); |
1921 |
|
|
fprintf(fout, " Pulse Width: %04lx\n", ((ss.pw_hi_1 & 0x0f) << 8) | ss.pw_lo_1); |
1922 |
|
|
fprintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", ss.AD_1 >> 4, ss.AD_1 & 0x0f, ss.SR_1 >> 4, ss.SR_1 & 0x0f); |
1923 |
|
|
fprintf(fout, " Waveform : "); |
1924 |
|
|
dump_sid_waveform(ss.ctrl_1); |
1925 |
|
|
fprintf(fout, " Gate : %s Ring mod.: %s\n", ss.ctrl_1 & 0x01 ? "On " : "Off", ss.ctrl_1 & 0x04 ? "On" : "Off"); |
1926 |
|
|
fprintf(fout, " Test bit : %s Synchron.: %s\n", ss.ctrl_1 & 0x08 ? "On " : "Off", ss.ctrl_1 & 0x02 ? "On" : "Off"); |
1927 |
|
|
fprintf(fout, " Filter : %s\n", ss.res_filt & 0x01 ? "On" : "Off"); |
1928 |
|
|
|
1929 |
|
|
fprintf(fout, "\nVoice 2\n"); |
1930 |
|
|
fprintf(fout, " Frequency : %04lx\n", (ss.freq_hi_2 << 8) | ss.freq_lo_2); |
1931 |
|
|
fprintf(fout, " Pulse Width: %04lx\n", ((ss.pw_hi_2 & 0x0f) << 8) | ss.pw_lo_2); |
1932 |
|
|
fprintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", ss.AD_2 >> 4, ss.AD_2 & 0x0f, ss.SR_2 >> 4, ss.SR_2 & 0x0f); |
1933 |
|
|
fprintf(fout, " Waveform : "); |
1934 |
|
|
dump_sid_waveform(ss.ctrl_2); |
1935 |
|
|
fprintf(fout, " Gate : %s Ring mod.: %s\n", ss.ctrl_2 & 0x01 ? "On " : "Off", ss.ctrl_2 & 0x04 ? "On" : "Off"); |
1936 |
|
|
fprintf(fout, " Test bit : %s Synchron.: %s\n", ss.ctrl_2 & 0x08 ? "On " : "Off", ss.ctrl_2 & 0x02 ? "On" : "Off"); |
1937 |
|
|
fprintf(fout, " Filter : %s\n", ss.res_filt & 0x02 ? "On" : "Off"); |
1938 |
|
|
|
1939 |
|
|
fprintf(fout, "\nVoice 3\n"); |
1940 |
|
|
fprintf(fout, " Frequency : %04lx\n", (ss.freq_hi_3 << 8) | ss.freq_lo_3); |
1941 |
|
|
fprintf(fout, " Pulse Width: %04lx\n", ((ss.pw_hi_3 & 0x0f) << 8) | ss.pw_lo_3); |
1942 |
|
|
fprintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", ss.AD_3 >> 4, ss.AD_3 & 0x0f, ss.SR_3 >> 4, ss.SR_3 & 0x0f); |
1943 |
|
|
fprintf(fout, " Waveform : "); |
1944 |
|
|
dump_sid_waveform(ss.ctrl_3); |
1945 |
|
|
fprintf(fout, " Gate : %s Ring mod.: %s\n", ss.ctrl_3 & 0x01 ? "On " : "Off", ss.ctrl_3 & 0x04 ? "On" : "Off"); |
1946 |
|
|
fprintf(fout, " Test bit : %s Synchron.: %s\n", ss.ctrl_3 & 0x08 ? "On " : "Off", ss.ctrl_3 & 0x02 ? "On" : "Off"); |
1947 |
|
|
fprintf(fout, " Filter : %s Mute : %s\n", ss.res_filt & 0x04 ? "On" : "Off", ss.mode_vol & 0x80 ? "Yes" : "No"); |
1948 |
|
|
|
1949 |
|
|
fprintf(fout, "\nFilters/Volume\n"); |
1950 |
|
|
fprintf(fout, " Frequency: %04lx\n", (ss.fc_hi << 3) | (ss.fc_lo & 0x07)); |
1951 |
|
|
fprintf(fout, " Resonance: %lx\n", ss.res_filt >> 4); |
1952 |
|
|
fprintf(fout, " Mode : "); |
1953 |
|
|
if (ss.mode_vol & 0x70) { |
1954 |
|
|
if (ss.mode_vol & 0x10) fprintf(fout, "Low-pass "); |
1955 |
|
|
if (ss.mode_vol & 0x20) fprintf(fout, "Band-pass "); |
1956 |
|
|
if (ss.mode_vol & 0x40) fprintf(fout, "High-pass"); |
1957 |
|
|
} else |
1958 |
|
|
fprintf(fout, "None"); |
1959 |
|
|
fprintf(fout, "\n Volume : %lx\n", ss.mode_vol & 0x0f); |
1960 |
|
|
} |
1961 |
|
|
|
1962 |
|
|
static void dump_sid_waveform(uint8 wave) |
1963 |
|
|
{ |
1964 |
|
|
if (wave & 0xf0) { |
1965 |
|
|
if (wave & 0x10) fprintf(fout, "Triangle "); |
1966 |
|
|
if (wave & 0x20) fprintf(fout, "Sawtooth "); |
1967 |
|
|
if (wave & 0x40) fprintf(fout, "Rectangle "); |
1968 |
|
|
if (wave & 0x80) fprintf(fout, "Noise"); |
1969 |
|
|
} else |
1970 |
|
|
fprintf(fout, "None"); |
1971 |
|
|
fputc('\n', fout); |
1972 |
|
|
} |
1973 |
|
|
|
1974 |
|
|
static void view_vic_state(void) |
1975 |
|
|
{ |
1976 |
|
|
MOS6569State vs; |
1977 |
|
|
short i; |
1978 |
|
|
|
1979 |
|
|
TheVIC->GetState(&vs); |
1980 |
|
|
|
1981 |
|
|
fprintf(fout, "Raster line : %04lx\n", vs.raster | ((vs.ctrl1 & 0x80) << 1)); |
1982 |
|
|
fprintf(fout, "IRQ raster line : %04lx\n\n", vs.irq_raster); |
1983 |
|
|
|
1984 |
|
|
fprintf(fout, "X scroll : %ld\n", vs.ctrl2 & 7); |
1985 |
|
|
fprintf(fout, "Y scroll : %ld\n", vs.ctrl1 & 7); |
1986 |
|
|
fprintf(fout, "Horizontal border : %ld columns\n", vs.ctrl2 & 8 ? 40 : 38); |
1987 |
|
|
fprintf(fout, "Vertical border : %ld rows\n\n", vs.ctrl1 & 8 ? 25 : 24); |
1988 |
|
|
|
1989 |
|
|
fprintf(fout, "Display mode : "); |
1990 |
|
|
switch (((vs.ctrl1 >> 4) & 6) | ((vs.ctrl2 >> 4) & 1)) { |
1991 |
|
|
case 0: |
1992 |
|
|
fprintf(fout, "Standard text\n"); |
1993 |
|
|
break; |
1994 |
|
|
case 1: |
1995 |
|
|
fprintf(fout, "Multicolor text\n"); |
1996 |
|
|
break; |
1997 |
|
|
case 2: |
1998 |
|
|
fprintf(fout, "Standard bitmap\n"); |
1999 |
|
|
break; |
2000 |
|
|
case 3: |
2001 |
|
|
fprintf(fout, "Multicolor bitmap\n"); |
2002 |
|
|
break; |
2003 |
|
|
case 4: |
2004 |
|
|
fprintf(fout, "ECM text\n"); |
2005 |
|
|
break; |
2006 |
|
|
case 5: |
2007 |
|
|
fprintf(fout, "Invalid text (ECM+MCM)\n"); |
2008 |
|
|
break; |
2009 |
|
|
case 6: |
2010 |
|
|
fprintf(fout, "Invalid bitmap (ECM+BMM)\n"); |
2011 |
|
|
break; |
2012 |
|
|
case 7: |
2013 |
|
|
fprintf(fout, "Invalid bitmap (ECM+BMM+ECM)\n"); |
2014 |
|
|
break; |
2015 |
|
|
} |
2016 |
|
|
fprintf(fout, "Sequencer state : %s\n", vs.display_state ? "Display" : "Idle"); |
2017 |
|
|
fprintf(fout, "Bad line state : %s\n", vs.bad_line ? "Yes" : "No"); |
2018 |
|
|
fprintf(fout, "Bad lines enabled : %s\n", vs.bad_line_enable ? "Yes" : "No"); |
2019 |
|
|
fprintf(fout, "Video counter : %04lx\n", vs.vc); |
2020 |
|
|
fprintf(fout, "Video counter base: %04lx\n", vs.vc_base); |
2021 |
|
|
fprintf(fout, "Row counter : %ld\n\n", vs.rc); |
2022 |
|
|
|
2023 |
|
|
fprintf(fout, "VIC bank : %04lx-%04lx\n", vs.bank_base, vs.bank_base + 0x3fff); |
2024 |
|
|
fprintf(fout, "Video matrix base : %04lx\n", vs.matrix_base); |
2025 |
|
|
fprintf(fout, "Character base : %04lx\n", vs.char_base); |
2026 |
|
|
fprintf(fout, "Bitmap base : %04lx\n\n", vs.bitmap_base); |
2027 |
|
|
|
2028 |
|
|
fprintf(fout, " Spr.0 Spr.1 Spr.2 Spr.3 Spr.4 Spr.5 Spr.6 Spr.7\n"); |
2029 |
|
|
fprintf(fout, "Enabled: "); dump_spr_flags(vs.me); |
2030 |
|
|
fprintf(fout, "Data : %04lx %04lx %04lx %04lx %04lx %04lx %04lx %04lx\n", |
2031 |
|
|
vs.sprite_base[0], vs.sprite_base[1], vs.sprite_base[2], vs.sprite_base[3], |
2032 |
|
|
vs.sprite_base[4], vs.sprite_base[5], vs.sprite_base[6], vs.sprite_base[7]); |
2033 |
|
|
fprintf(fout, "MC : %02lx %02lx %02lx %02lx %02lx %02lx %02lx %02lx\n", |
2034 |
|
|
vs.mc[0], vs.mc[1], vs.mc[2], vs.mc[3], vs.mc[4], vs.mc[5], vs.mc[6], vs.mc[7]); |
2035 |
|
|
|
2036 |
|
|
fprintf(fout, "Mode : "); |
2037 |
|
|
for (i=0; i<8; i++) |
2038 |
|
|
if (vs.mmc & (1<<i)) |
2039 |
|
|
fprintf(fout, "Multi "); |
2040 |
|
|
else |
2041 |
|
|
fprintf(fout, "Std. "); |
2042 |
|
|
|
2043 |
|
|
fprintf(fout, "\nX-Exp. : "); dump_spr_flags(vs.mxe); |
2044 |
|
|
fprintf(fout, "Y-Exp. : "); dump_spr_flags(vs.mye); |
2045 |
|
|
|
2046 |
|
|
fprintf(fout, "Prio. : "); |
2047 |
|
|
for (i=0; i<8; i++) |
2048 |
|
|
if (vs.mdp & (1<<i)) |
2049 |
|
|
fprintf(fout, "Back "); |
2050 |
|
|
else |
2051 |
|
|
fprintf(fout, "Fore "); |
2052 |
|
|
|
2053 |
cebix |
1.3 |
fprintf(fout, "\nSS Coll: "); dump_spr_flags(vs.mm); |
2054 |
|
|
fprintf(fout, "SD Coll: "); dump_spr_flags(vs.md); |
2055 |
|
|
|
2056 |
|
|
fprintf(fout, "\nPending interrupts: "); |
2057 |
cebix |
1.1 |
dump_vic_ints(vs.irq_flag); |
2058 |
|
|
fprintf(fout, "Enabled interrupts: "); |
2059 |
|
|
dump_vic_ints(vs.irq_mask); |
2060 |
|
|
} |
2061 |
|
|
|
2062 |
|
|
static void dump_spr_flags(uint8 f) |
2063 |
|
|
{ |
2064 |
|
|
short i; |
2065 |
|
|
|
2066 |
|
|
for (i=0; i<8; i++) |
2067 |
|
|
if (f & (1<<i)) |
2068 |
|
|
fprintf(fout, "Yes "); |
2069 |
|
|
else |
2070 |
|
|
fprintf(fout, "No "); |
2071 |
|
|
|
2072 |
|
|
fputc('\n', fout); |
2073 |
|
|
} |
2074 |
|
|
|
2075 |
|
|
static void dump_vic_ints(uint8 i) |
2076 |
|
|
{ |
2077 |
|
|
if (i & 0x1f) { |
2078 |
|
|
if (i & 1) fprintf(fout, "Raster "); |
2079 |
|
|
if (i & 2) fprintf(fout, "Spr-Data "); |
2080 |
|
|
if (i & 4) fprintf(fout, "Spr-Spr "); |
2081 |
|
|
if (i & 8) fprintf(fout, "Lightpen"); |
2082 |
|
|
} else |
2083 |
|
|
fprintf(fout, "None"); |
2084 |
|
|
fputc('\n', fout); |
2085 |
|
|
} |
2086 |
|
|
|
2087 |
|
|
static void view_1541_state(void) |
2088 |
|
|
{ |
2089 |
|
|
fprintf(fout, "VIA 1:\n"); |
2090 |
|
|
fprintf(fout, " Timer 1 Counter: %04x Latch: %04x\n", R1541.via1_t1c, R1541.via1_t1l); |
2091 |
|
|
fprintf(fout, " Timer 2 Counter: %04x Latch: %04x\n", R1541.via1_t2c, R1541.via1_t2l); |
2092 |
|
|
fprintf(fout, " ACR: %02x\n", R1541.via1_acr); |
2093 |
|
|
fprintf(fout, " PCR: %02x\n", R1541.via1_pcr); |
2094 |
|
|
fprintf(fout, " Pending interrupts: "); |
2095 |
|
|
dump_via_ints(R1541.via1_ifr); |
2096 |
|
|
fprintf(fout, " Enabled interrupts: "); |
2097 |
|
|
dump_via_ints(R1541.via1_ier); |
2098 |
|
|
|
2099 |
|
|
fprintf(fout, "\nVIA 2:\n"); |
2100 |
|
|
fprintf(fout, " Timer 1 Counter: %04x Latch: %04x\n", R1541.via2_t1c, R1541.via2_t1l); |
2101 |
|
|
fprintf(fout, " Timer 2 Counter: %04x Latch: %04x\n", R1541.via2_t2c, R1541.via2_t2l); |
2102 |
|
|
fprintf(fout, " ACR: %02x\n", R1541.via2_acr); |
2103 |
|
|
fprintf(fout, " PCR: %02x\n", R1541.via2_pcr); |
2104 |
|
|
fprintf(fout, " Pending interrupts: "); |
2105 |
|
|
dump_via_ints(R1541.via2_ifr); |
2106 |
|
|
fprintf(fout, " Enabled interrupts: "); |
2107 |
|
|
dump_via_ints(R1541.via2_ier); |
2108 |
|
|
} |
2109 |
|
|
|
2110 |
|
|
static void dump_via_ints(uint8 i) |
2111 |
|
|
{ |
2112 |
|
|
if (i & 0x7f) { |
2113 |
|
|
if (i & 0x40) fprintf(fout, "T1 "); |
2114 |
|
|
if (i & 0x20) fprintf(fout, "T2 "); |
2115 |
|
|
if (i & 2) fprintf(fout, "CA1 "); |
2116 |
|
|
if (i & 1) fprintf(fout, "CA2 "); |
2117 |
|
|
if (i & 0x10) fprintf(fout, "CB1 "); |
2118 |
|
|
if (i & 8) fprintf(fout, "CB2 "); |
2119 |
|
|
if (i & 4) fprintf(fout, "Serial "); |
2120 |
|
|
} else |
2121 |
|
|
fprintf(fout, "None"); |
2122 |
|
|
fputc('\n', fout); |
2123 |
|
|
} |
2124 |
|
|
|
2125 |
|
|
|
2126 |
|
|
/* |
2127 |
|
|
* Load data |
2128 |
|
|
* l start "file" |
2129 |
|
|
*/ |
2130 |
|
|
|
2131 |
|
|
static void load_data(void) |
2132 |
|
|
{ |
2133 |
|
|
uint16 adr; |
2134 |
|
|
FILE *file; |
2135 |
|
|
int fc; |
2136 |
|
|
|
2137 |
|
|
if (!expression(&adr)) |
2138 |
|
|
return; |
2139 |
|
|
if (the_token == T_END) { |
2140 |
|
|
error("Missing file name"); |
2141 |
|
|
return; |
2142 |
|
|
} |
2143 |
|
|
if (the_token != T_STRING) { |
2144 |
|
|
error("'\"' around file name expected"); |
2145 |
|
|
return; |
2146 |
|
|
} |
2147 |
|
|
|
2148 |
|
|
if (!(file = fopen(the_string, "rb"))) |
2149 |
|
|
error("Unable to open file"); |
2150 |
|
|
else { |
2151 |
|
|
while ((fc = fgetc(file)) != EOF) |
2152 |
|
|
SAMWriteByte(adr++, fc); |
2153 |
|
|
fclose(file); |
2154 |
|
|
} |
2155 |
|
|
} |
2156 |
|
|
|
2157 |
|
|
|
2158 |
|
|
/* |
2159 |
|
|
* Save data |
2160 |
|
|
* s start end "file" |
2161 |
|
|
*/ |
2162 |
|
|
|
2163 |
|
|
static void save_data(void) |
2164 |
|
|
{ |
2165 |
|
|
bool done = false; |
2166 |
|
|
uint16 adr, end_adr; |
2167 |
|
|
FILE *file; |
2168 |
|
|
|
2169 |
|
|
if (!expression(&adr)) |
2170 |
|
|
return; |
2171 |
|
|
if (!expression(&end_adr)) |
2172 |
|
|
return; |
2173 |
|
|
if (the_token == T_END) { |
2174 |
|
|
error("Missing file name"); |
2175 |
|
|
return; |
2176 |
|
|
} |
2177 |
|
|
if (the_token != T_STRING) { |
2178 |
|
|
error("'\"' around file name expected"); |
2179 |
|
|
return; |
2180 |
|
|
} |
2181 |
|
|
|
2182 |
|
|
if (!(file = fopen(the_string, "wb"))) |
2183 |
|
|
error("Unable to create file"); |
2184 |
|
|
else { |
2185 |
|
|
do { |
2186 |
|
|
if (adr == end_adr) done = true; |
2187 |
|
|
|
2188 |
|
|
fputc(SAMReadByte(adr++), file); |
2189 |
|
|
} while (!done); |
2190 |
|
|
fclose(file); |
2191 |
|
|
} |
2192 |
|
|
} |