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