/* * SAM.c - Simple Assembler and Monitor With Integrated System Explorer * * Copyright (C) 1994-1996 by Christian Bauer */ #include #include #include #include "SAM.h" #include "6526.h" #include "6581.h" #include "6569.h" // Aus 6510.asm extern UBYTE RA, RX, RY, RP, RPR, RDDR; extern UWORD RPC, RS; extern UBYTE SAMReadByte(UWORD address); extern void SAMWriteByte(UWORD address, UBYTE byte); extern UBYTE SAMMemConfig; // Prototypes void error(char *s); // Scanner BOOL aborted(void); void read_line(void); char get_char(void); void put_back(char c); enum Token get_token(void); enum RegToken get_reg_token(void); UWORD get_number(void); enum Token get_string(char *str); BOOL expression(UWORD *number); // Parser BOOL term(UWORD *number); BOOL factor(UWORD *number); BOOL address_args(void); BOOL range_args(int def_range); BOOL instr_args(UWORD *number, char *mode); void help(void); // Routinen für die Befehle void registers(void); void display_registers(void); void memory_dump(void); void ascii_dump(void); char conv_from_64(char c); void screen_dump(void); char conv_from_scode(char c); void binary_dump(void); void sprite_dump(void); void byte_to_bin(UBYTE byte, char *str); void disassemble(void); int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi); void assemble(void); char find_mnemonic(char op1, char op2, char op3); BOOL find_opcode(char mnem, char mode, UBYTE *opcode); void mem_config(void); void fill(void); void compare(void); void transfer(void); void modify(void); void print_expr(void); void redir_output(void); void int_vectors(void); void view_state(void); void view_cia_state(void); void dump_cia_ints(UBYTE int); void view_sid_state(void); void dump_sid_waveform(UBYTE wave); void view_vic_state(void); void dump_spr_flags(UBYTE f); void dump_vic_ints(UBYTE int); void load_data(void); void save_data(void); // FileHandles für Eingabe, Ausgabe und Fehler BPTR fin, fout, ferr; // Eingabezeile #define INPUT_LENGTH 80 char input[INPUT_LENGTH]; char *in_ptr; UWORD address, end_address; // Eingabetoken enum Token { T_NULL, // Ungültiges Token T_END, // Ende der Zeile T_NUMBER, // Hexadezimalzahl T_STRING, // In "" eingeschlossener String T_LPAREN, // '(' T_RPAREN, // ')' T_ADD, // '+' T_SUB, // '-' T_MUL, // '*' T_DIV, // '/' T_COMMA, // ',' T_IMMED, // '#' T_X, // 'x' T_Y, // 'y' T_PC, // 'pc' T_SP // 'sp' }; // Registernamen enum RegToken { RT_NULL, // Ungültiges Token RT_END, // Ende der Zeile RT_A, // 'a' RT_X, // 'x' RT_Y, // 'y' RT_PC, // 'pc' RT_SP, // 'sp' RT_DR, // 'dr' RT_PR // 'pr' }; enum Token the_token; // Auch RegToken für get_reg_token UWORD the_number; // Enthält die Zahl, wenn the_token==T_NUMBER char the_string[INPUT_LENGTH]; // Enthält den String, wenn the_token==T_STRING // Adressierungsarten enum { A_IMPL, A_ACCU, // A A_IMM, // #zz A_REL, // Branches A_ZERO, // zz A_ZEROX, // zz,x A_ZEROY, // zz,y A_ABS, // zzzz A_ABSX, // zzzz,x A_ABSY, // zzzz,y A_IND, // (zzzz) A_INDX, // (zz,x) A_INDY // (zz),y }; // Mnemonics enum { M_ADC, M_AND, M_ASL, M_BCC, M_BCS, M_BEQ, M_BIT, M_BMI, M_BNE, M_BPL, M_BRK, M_BVC, M_BVS, M_CLC, M_CLD, M_CLI, M_CLV, M_CMP, M_CPX, M_CPY, M_DEC, M_DEX, M_DEY, M_EOR, M_INC, M_INX, M_INY, M_JMP, M_JSR, M_LDA, M_LDX, M_LDY, M_LSR, M_NOP, M_ORA, M_PHA, M_PHP, M_PLA, M_PLP, M_ROL, M_ROR, M_RTI, M_RTS, M_SBC, M_SEC, M_SED, M_SEI, M_STA, M_STX, M_STY, M_TAX, M_TAY, M_TSX, M_TXA, M_TXS, M_TYA, M_ILLEGAL, // Ab hier kommen die undokumentierten Opcodes M_IANC, M_IANE, M_IARR, M_IASR, M_IDCP, M_IISB, M_IJAM, M_INOP, M_ILAS, M_ILAX, M_ILXA, M_IRLA, M_IRRA, M_ISAX, M_ISBC, M_ISBX, M_ISHA, M_ISHS, M_ISHX, M_ISHY, M_ISLO, M_ISRE, M_MAXIMUM // Höchstes Element }; // Zu jedem Opcode das Mnemonic const char mnemonic[256] = { M_BRK , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, // 00 M_PHP , M_ORA , M_ASL , M_IANC, M_INOP, M_ORA, M_ASL , M_ISLO, M_BPL , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, // 10 M_CLC , M_ORA , M_INOP, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO, M_JSR , M_AND , M_IJAM, M_IRLA, M_BIT , M_AND, M_ROL , M_IRLA, // 20 M_PLP , M_AND , M_ROL , M_IANC, M_BIT , M_AND, M_ROL , M_IRLA, M_BMI , M_AND , M_IJAM, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA, // 30 M_SEC , M_AND , M_INOP, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA, M_RTI , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, // 40 M_PHA , M_EOR , M_LSR , M_IASR, M_JMP , M_EOR, M_LSR , M_ISRE, M_BVC , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, // 50 M_CLI , M_EOR , M_INOP, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE, M_RTS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, // 60 M_PLA , M_ADC , M_ROR , M_IARR, M_JMP , M_ADC, M_ROR , M_IRRA, M_BVS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, // 70 M_SEI , M_ADC , M_INOP, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA, M_INOP, M_STA , M_INOP, M_ISAX, M_STY , M_STA, M_STX , M_ISAX, // 80 M_DEY , M_INOP, M_TXA , M_IANE, M_STY , M_STA, M_STX , M_ISAX, M_BCC , M_STA , M_IJAM, M_ISHA, M_STY , M_STA, M_STX , M_ISAX, // 90 M_TYA , M_STA , M_TXS , M_ISHS, M_ISHY, M_STA, M_ISHX, M_ISHA, M_LDY , M_LDA , M_LDX , M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX, // a0 M_TAY , M_LDA , M_TAX , M_ILXA, M_LDY , M_LDA, M_LDX , M_ILAX, M_BCS , M_LDA , M_IJAM, M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX, // b0 M_CLV , M_LDA , M_TSX , M_ILAS, M_LDY , M_LDA, M_LDX , M_ILAX, M_CPY , M_CMP , M_INOP, M_IDCP, M_CPY , M_CMP, M_DEC , M_IDCP, // c0 M_INY , M_CMP , M_DEX , M_ISBX, M_CPY , M_CMP, M_DEC , M_IDCP, M_BNE , M_CMP , M_IJAM, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP, // d0 M_CLD , M_CMP , M_INOP, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP, M_CPX , M_SBC , M_INOP, M_IISB, M_CPX , M_SBC, M_INC , M_IISB, // e0 M_INX , M_SBC , M_NOP , M_ISBC, M_CPX , M_SBC, M_INC , M_IISB, M_BEQ , M_SBC , M_IJAM, M_IISB, M_INOP, M_SBC, M_INC , M_IISB, // f0 M_SED , M_SBC , M_INOP, M_IISB, M_INOP, M_SBC, M_INC , M_IISB }; // Zu jedem Opcode die Adressierungsart const char adr_mode[256] = { A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 00 A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 10 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, A_ABS , A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 20 A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 30 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 40 A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 50 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 60 A_IMPL, A_IMM , A_ACCU, A_IMM , A_IND , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // 70 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // 80 A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY, // 90 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY, A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // a0 A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY, // b0 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY, A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // c0 A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // d0 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX, A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO, // e0 A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS , A_ABS , A_ABS , A_ABS, A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX, // f0 A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX }; // Zu jedem Mnemonic die Zeichen const char mnem_1[] = "aaabbbbbbbbbbcccccccdddeiiijjllllnopppprrrrssssssstttttt?aaaadijnlllrrsssssssss"; const char mnem_2[] = "dnscceimnprvvllllmppeeeonnnmsdddsorhhlloottbeeetttaasxxy?nnrscsaoaaxlrabbhhhhlr"; const char mnem_3[] = "cdlcsqtielkcscdivpxycxyrcxypraxyrpaapaplrisccdiaxyxyxasa?cerrpbmpsxaaaxcxasxyoe"; // Zu jeder Adressierungsart die Befehlslänge const char adr_length[] = {1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2}; /* * SAM öffnen und handhaben */ void SAM(void) { BOOL done = FALSE; char c; if (fin = fout = ferr = Open("CON:0/0/640/480/SAM", MODE_NEWFILE)) { FPuts(ferr, "\n *** SAM - Simple Assembler and Monitor ***\n *** Press 'h' for help ***\n\n"); display_registers(); address = RPC; while (!done) { Write(ferr, "> ", 2); read_line(); while ((c = get_char()) == ' ') ; switch (c) { case 'a': // Assemblieren get_token(); assemble(); break; case 'b': // Binär-Dump get_token(); binary_dump(); break; case 'c': // Vergleichen get_token(); compare(); break; case 'd': // Disassemblieren get_token(); disassemble(); break; case 'e': // Interrupt-Vektoren int_vectors(); break; case 'f': // Füllen get_token(); fill(); break; case 'h': // Help help(); break; case 'i': // ASCII-Dump get_token(); ascii_dump(); break; case 'k': // Speicherkonfiguration get_token(); mem_config(); break; case 'l': // Daten laden get_token(); load_data(); break; case 'm': // Memory-Dump get_token(); memory_dump(); break; case 'n': // Screen-Code-Dump get_token(); screen_dump(); break; case 'o': // Ausgabe umleiten get_token(); redir_output(); break; case 'p': // Sprite-Dump get_token(); sprite_dump(); break; case 'r': // Register get_reg_token(); registers(); break; case 's': // Daten speichern get_token(); save_data(); break; case 't': // Transfer get_token(); transfer(); break; case 'v': // View machine state view_state(); break; case 'x': // Exit done = TRUE; break; case ':': // Ändern get_token(); modify(); break; case '?': // Ausdruck berechnen get_token(); print_expr(); break; case '\n': // Leerzeile break; default: // Unbekannter Befehl error("Unknown command"); break; } } Close(fin); if (fout != ferr) Close(fout); } } /* * Fehlermeldung ausgeben */ void error(char *s) { FPrintf(ferr, "*** %s\n", s); } /* * CTRL-C gedrückt? */ #include #include BOOL aborted(void) { return SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C; } /* * Eine Zeile von der Tastatur lesen */ void read_line(void) { FGets(fin, in_ptr = input, INPUT_LENGTH); } /* * Ein Zeichen aus der Eingabezeile lesen */ char get_char(void) { return *in_ptr++; } /* * Zeichen in die Eingabezeile zurückpacken */ void put_back(char c) { *(--in_ptr) = c; } /* * Scanner: Ein Token aus der Eingabezeile lesen */ enum Token get_token(void) { char c; // Leerzeichen überspringen while ((c = get_char()) == ' ') ; switch (ToLower(c)) { case '\n': return the_token = T_END; case '(': return the_token = T_LPAREN; case ')': return the_token = T_RPAREN; case '+': return the_token = T_ADD; case '-': return the_token = T_SUB; case '*': return the_token = T_MUL; case '/': return the_token = T_DIV; case ',': return the_token = T_COMMA; case '#': return the_token = T_IMMED; case 'x': return the_token = T_X; case 'y': return the_token = T_Y; case 'p': if (ToLower(get_char()) == 'c') return the_token = T_PC; else { error("Unrecognized token"); return the_token = T_NULL; } case 's': if (ToLower(get_char()) == 'p') return the_token = T_SP; else { error("Unrecognized token"); return the_token = T_NULL; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': put_back(c); the_number = get_number(); return the_token = T_NUMBER; case '"': return the_token = get_string(the_string); default: error("Unrecognized token"); return the_token = T_NULL; } } enum RegToken get_reg_token(void) { char c; // Leerzeichen überspringen while ((c = get_char()) == ' ') ; switch (ToLower(c)) { case '\n': return the_token = RT_END; case 'a': return the_token = RT_A; case 'd': if (ToLower(get_char()) == 'r') return the_token = RT_DR; else { error("Unrecognized token"); return the_token = RT_NULL; } case 'p': if ((c = ToLower(get_char())) == 'c') return the_token = RT_PC; else if (c == 'r') return the_token = RT_PR; else { error("Unrecognized token"); return the_token = RT_NULL; } case 's': if (ToLower(get_char()) == 'p') return the_token = RT_SP; else { error("Unrecognized token"); return the_token = RT_NULL; } case 'x': return the_token = RT_X; case 'y': return the_token = RT_Y; default: error("Unrecognized token"); return the_token = RT_NULL; } } UWORD get_number(void) { char c; UWORD i = 0; while (((c = ToLower(get_char())) >= '0') && (c <= '9') || (c >= 'a') && (c <= 'f')) if (c < 'a') i = (i << 4) + (c - '0'); else i = (i << 4) + (c - 'a' + 10); put_back(c); return i; } enum Token get_string(char *str) { char c; while ((c = get_char()) != '\n') { if (c == '"') { *str = 0; return T_STRING; } *str++ = c; } error("Unterminated string"); return T_NULL; } /* * expression = term {(ADD | SUB) term} * TRUE: OK, FALSE: Fehler */ BOOL expression(UWORD *number) { UWORD accu, trm; if (!term(&accu)) return FALSE; for (;;) switch (the_token) { case T_ADD: get_token(); if (!term(&trm)) return FALSE; accu += trm; break; case T_SUB: get_token(); if (!term(&trm)) return FALSE; accu -= trm; break; default: *number = accu; return TRUE; } } /* * term = factor {(MUL | DIV) factor} * TRUE: OK, FALSE: Fehler */ BOOL term(UWORD *number) { UWORD accu, fact; if (!factor(&accu)) return FALSE; for (;;) switch (the_token) { case T_MUL: get_token(); if (!factor(&fact)) return FALSE; accu *= fact; break; case T_DIV: get_token(); if (!factor(&fact)) return FALSE; if (fact == 0) { error("Division by 0"); return FALSE; } accu /= fact; break; default: *number = accu; return TRUE; } } /* * factor = NUMBER | PC | SP | LPAREN expression RPAREN * TRUE: OK, FALSE: Fehler */ BOOL factor(UWORD *number) { switch (the_token) { case T_NUMBER: *number = the_number; get_token(); return TRUE; case T_PC: get_token(); *number = RPC; return TRUE; case T_SP: get_token(); *number = RS; return TRUE; case T_LPAREN: get_token(); if (expression(number)) if (the_token == T_RPAREN) { get_token(); return TRUE; } else { error("Missing ')'"); return FALSE; } else { error("Error in expression"); return FALSE; } case T_END: error("Required argument missing"); return FALSE; default: error("'pc', 'sp', '(' or number expected"); return FALSE; } } /* * address_args = [expression] END * * Startadresse nach address lesen * * TRUE: OK, FALSE: Fehler */ BOOL address_args(void) { if (the_token == T_END) return TRUE; else { if (!expression(&address)) return FALSE; return the_token == T_END; } } /* * range_args = [expression] [[COMMA] expression] END * * Startadresse nach address, Endadresse nach end_address lesen * * TRUE: OK, FALSE: Fehler */ BOOL range_args(int def_range) { end_address = address + def_range; if (the_token == T_END) return TRUE; else { if (!expression(&address)) return FALSE; end_address = address + def_range; if (the_token == T_END) return TRUE; else { if (the_token == T_COMMA) get_token(); if (!expression(&end_address)) return FALSE; return the_token == T_END; } } } /* * instr_args = END * | IMMED NUMBER END * | NUMBER [COMMA (X | Y)] END * | LPAREN NUMBER (RPAREN [COMMA Y] | COMMA X RPAREN) END * * Argumente eines 6510-Befehls lesen, Adresse und Adressierungsart ermitteln * * TRUE: OK, FALSE: Fehler */ BOOL instr_args(UWORD *number, char *mode) { switch (the_token) { case T_END: *mode = A_IMPL; return TRUE; case T_IMMED: get_token(); if (the_token == T_NUMBER) { *number = the_number; *mode = A_IMM; get_token(); return the_token == T_END; } else { error("Number expected"); return FALSE; } case T_NUMBER: *number = the_number; get_token(); switch (the_token) { case T_END: if (*number < 0x100) *mode = A_ZERO; else *mode = A_ABS; return TRUE; case T_COMMA: get_token(); switch (the_token) { case T_X: get_token(); if (*number < 0x100) *mode = A_ZEROX; else *mode = A_ABSX; return the_token == T_END; case T_Y: get_token(); if (*number < 0x100) *mode = A_ZEROY; else *mode = A_ABSY; return the_token == T_END; default: error("Illegal index register"); return FALSE; } default: return FALSE; } case T_LPAREN: get_token(); if (the_token == T_NUMBER) { *number = the_number; get_token(); switch (the_token) { case T_RPAREN: get_token(); switch (the_token) { case T_END: *mode = A_IND; return TRUE; case T_COMMA: get_token(); if (the_token == T_Y) { *mode = A_INDY; get_token(); return the_token == T_END; } else { error("Only 'y' index register allowed"); return FALSE; } default: error("Illegal characters after ')'"); return FALSE; } case T_COMMA: get_token(); if (the_token == T_X) { get_token(); if (the_token == T_RPAREN) { *mode = A_INDX; get_token(); return the_token == T_END; } else { error("')' expected"); return FALSE; } } else { error("Only 'x' index register allowed"); return FALSE; } default: error("')' or ',' expected"); return FALSE; } } else { error("Number expected"); return FALSE; } default: error("'(', '#' or number expected"); return FALSE; } } /* * Hilfstext anzeigen * ? */ void help(void) { FPuts(fout, "a [start] Assemble\n" "b [start] [end] Binary dump\n" "c start end dest Compare memory\n" "d [start] [end] Disassemble\n" "e Show interrupt vectors\n" "f start end byte Fill memory\n" "i [start] [end] ASCII/PETSCII dump\n" "k [config] Show/set memory configuration\n" "l start \"file\" Load data\n" "m [start] [end] Memory dump\n" "n [start] [end] Screen code dump\n" "o [\"file\"] Redirect output\n" "p [start] [end] Sprite dump\n" "r [reg value] Show/set registers\n" "s start end \"file\" Save data\n" "t start end dest Transfer memory\n" "vc1 View CIA 1 state\n" "vc2 View CIA 2 state\n" "vs View SID state\n" "vv View VIC state\n" "x Return to Frodo\n" ": addr {byte} Modify memory\n" "? expression Calculate expression\n"); } /* * 6510-Register anzeigen/ändern * r [reg value] */ void registers(void) { enum RegToken the_reg; UWORD value; if (the_token != RT_END) switch (the_reg = the_token) { case RT_A: case RT_X: case RT_Y: case RT_PC: case RT_SP: case RT_DR: case RT_PR: get_token(); if (!expression(&value)) return; switch (the_reg) { case RT_A: RA = value; break; case RT_X: RX = value; break; case RT_Y: RY = value; break; case RT_PC: RPC = value; break; case RT_SP: RS = (value & 0xff) | 0x0100; break; case RT_DR: RDDR = value; break; case RT_PR: RPR = value; break; } break; default: return; } display_registers(); } void display_registers(void) { FPuts(fout, " PC A X Y SP DR PR NVDIZC Instruction\n"); FPrintf(fout, "%04lx %02lx %02lx %02lx %04lx %02lx %02lx %lc%lc%lc%lc%lc%lc ", RPC, RA, RX, RY, RS, RDDR, RPR, RP & 0x80 ? '1' : '0', RP & 0x40 ? '1' : '0', RP & 0x08 ? '1' : '0', RP & 0x04 ? '1' : '0', RP & 0x02 ? '1' : '0', RP & 0x01 ? '1' : '0'); disass_line(RPC, SAMReadByte(RPC), SAMReadByte(RPC+1), SAMReadByte(RPC+2)); } /* * Memory-Dump * m [start] [end] */ #define MEMDUMP_BPL 16 // Bytes pro Zeile void memory_dump(void) { BOOL done = FALSE; short i; UBYTE mem[MEMDUMP_BPL + 2]; UBYTE byte; mem[MEMDUMP_BPL] = 0; if (!range_args(16 * MEMDUMP_BPL - 1)) // 16 Zeilen, wenn keine Endadresse angegeben return; do { FPrintf(fout, "%04lx:", address); for (i=0; i= ' ') && (byte <= '~')) mem[i] = conv_from_64(byte); else mem[i] = '.'; } FPrintf(fout, " '%s'\n", mem); } while (!done && !aborted()); } /* * ASCII-Dump * i [start] [end] */ #define ASCIIDUMP_BPL 64 // Bytes pro Zeile void ascii_dump(void) { BOOL done = FALSE; short i; UBYTE mem[ASCIIDUMP_BPL + 2]; UBYTE byte; mem[ASCIIDUMP_BPL] = 0; if (!range_args(16 * ASCIIDUMP_BPL - 1)) // 16 Zeilen, wenn keine Endadresse angegeben return; do { FPrintf(fout, "%04lx:", address); for (i=0; i= ' ') && (byte <= '~')) mem[i] = conv_from_64(byte); else mem[i] = '.'; } FPrintf(fout, " '%s'\n", mem); } while (!done && !aborted()); } /* * Umwandlung PETSCII->ASCII */ char conv_from_64(char c) { if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z')) return c ^ 0x20; else return c; } /* * Screen-Code-Dump * n [start] [end] */ #define SCRDUMP_BPL 64 // Bytes pro Zeile void screen_dump(void) { BOOL done = FALSE; short i; UBYTE mem[SCRDUMP_BPL + 2]; UBYTE byte; mem[SCRDUMP_BPL] = 0; if (!range_args(16 * SCRDUMP_BPL - 1)) // 16 Zeilen, wenn keine Endadresse angegeben return; do { FPrintf(fout, "%04lx:", address); for (i=0; iASCII */ char conv_from_scode(char c) { c &= 0x7f; if (c <= 31) return c + 64; else if (c >= 64) return c + 32; else return c; } /* * Binär-Dump * b [start] [end] */ void binary_dump(void) { BOOL done = FALSE; char bin[10]; bin[8] = 0; if (!range_args(7)) // 8 Zeilen, wenn keine Endadresse angegeben return; do { if (address == end_address) done = TRUE; byte_to_bin(SAMReadByte(address), bin); FPrintf(fout, "%04lx: %s\n", address++, bin); } while (!done && !aborted()); } /* * Sprite-Daten-Dump * p [start] [end] */ void sprite_dump(void) { BOOL done = FALSE; short i; char bin[10]; bin[8] = 0; if (!range_args(21 * 3 - 1)) // 21 Zeilen, wenn keine Endadresse angegeben return; do { FPrintf(fout, "%04lx: ", address); for (i=0; i<3; i++, address++) { if (address == end_address) done = TRUE; byte_to_bin(SAMReadByte(address), bin); FPrintf(fout, "%s", bin); } FPutC(fout, '\n'); } while (!done && !aborted()); } /* * Ein Byte in Binärfolge umwandeln */ void byte_to_bin(UBYTE byte, char *str) { short i; for (i=0; i<8; i++, byte<<=1) if (byte & 0x80) str[i] = '#'; else str[i] = '.'; } /* * Disassemblieren * d [start] [end] */ void disassemble(void) { BOOL done = FALSE; short i; UBYTE op[3]; UWORD adr; if (!range_args(31)) // 32 Bytes, wenn keine Endadresse angegeben return; do { FPrintf(fout, "%04lx:", adr = address); for (i=0; i<3; i++, adr++) { if (adr == end_address) done = TRUE; op[i] = SAMReadByte(adr); } address += disass_line(address, op[0], op[1], op[2]); } while (!done && !aborted()); } /* * Einen Befehl disassemblieren, Länge zurückgeben */ int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi) { char mode = adr_mode[op], mnem = mnemonic[op]; // Befehlsbytes hexadezimal ausgeben switch (adr_length[mode]) { case 1: FPrintf(fout, " %02lx ", op); break; case 2: FPrintf(fout, " %02lx %02lx ", op, lo); break; case 3: FPrintf(fout, " %02lx %02lx %02lx ", op, lo, hi); break; } // Undokumentierte Opcodes mit Stern markieren if (mnem > M_ILLEGAL) FPutC(fout, '*'); else FPutC(fout, ' '); // Mnemonic ausgeben FPrintf(fout, "%lc%lc%lc ", mnem_1[mnem], mnem_2[mnem], mnem_3[mnem]); // Argument ausgeben switch (mode) { case A_IMPL: break; case A_ACCU: FPuts(fout, "a"); break; case A_IMM: FPrintf(fout, "#%02lx", lo); break; case A_REL: FPrintf(fout, "%04lx", ((adr + 2) + (BYTE)lo) & 0xffff); break; case A_ZERO: FPrintf(fout, "%02lx", lo); break; case A_ZEROX: FPrintf(fout, "%02lx,x", lo); break; case A_ZEROY: FPrintf(fout, "%02lx,y", lo); break; case A_ABS: FPrintf(fout, "%04lx", (hi << 8) | lo); break; case A_ABSX: FPrintf(fout, "%04lx,x", (hi << 8) | lo); break; case A_ABSY: FPrintf(fout, "%04lx,y", (hi << 8) | lo); break; case A_IND: FPrintf(fout, "(%04lx)", (hi << 8) | lo); break; case A_INDX: FPrintf(fout, "(%02lx,x)", lo); break; case A_INDY: FPrintf(fout, "(%02lx),y", lo); break; } FPutC(fout, '\n'); return adr_length[mode]; } /* * Assemblieren * a [start] */ void assemble(void) { BOOL done = FALSE; char c1, c2, c3; char mnem, mode; UBYTE opcode; UWORD arg; WORD rel; // Parameter lesen if (!address_args()) return; do { FPrintf(fout, "%04lx> ", address); read_line(); c1 = ToLower(get_char()); c2 = ToLower(get_char()); c3 = ToLower(get_char()); if (c1 != '\n') { if ((mnem = find_mnemonic(c1, c2, c3)) != M_ILLEGAL) { get_token(); if (instr_args(&arg, &mode)) { // Ggf. A_IMPL -> A_ACCU if ((mode == A_IMPL) && find_opcode(mnem, A_ACCU, &opcode)) mode = A_ACCU; // Relative Adressierung getrennt behandeln if (((mode == A_ABS) || (mode == A_ZERO)) && find_opcode(mnem, A_REL, &opcode)) { mode = A_REL; rel = arg - (address + 2) & 0xffff; if ((rel < -128) || (rel > 127)) { error("Branch too long"); continue; } else arg = rel & 0xff; } if (find_opcode(mnem, mode, &opcode)) { // Disassemblierte Zeile ausgeben FPrintf(fout, "\v%04lx:", address); disass_line(address, opcode, arg & 0xff, arg >> 8); switch (adr_length[mode]) { case 1: SAMWriteByte(address++, opcode); break; case 2: SAMWriteByte(address++, opcode); SAMWriteByte(address++, arg); break; case 3: SAMWriteByte(address++, opcode); SAMWriteByte(address++, arg & 0xff); SAMWriteByte(address++, arg >> 8); break; default: error("Internal error"); break; } } else // Adressierungsart paßt nicht zum Befehl error("Addressing mode not supported by instruction"); } else // Nicht erkannte Adressierungsart error("Unrecognized addressing mode"); } else // Mnemonic nicht gefunden error("Unknown instruction"); } else // Leerzeile beendet die Eingabe done = TRUE; } while (!done); } /* * Zu drei Buchstaben den passenden Mnemonic-Code finden * M_ILLEGAL: Kein passendes Mnemonic gefunden */ char find_mnemonic(char op1, char op2, char op3) { int i; char c1, c2, c3; for (i=0; i> 4) & 1, cd.tod_hr & 0x0f, (cd.tod_min >> 4) & 7, cd.tod_min & 0x0f, (cd.tod_sec >> 4) & 7, cd.tod_sec & 0x0f, cd.tod_10ths & 0x0f, cd.tod_hr & 0x80 ? "PM" : "AM"); FPrintf(fout, "Alarm : %lx%lx:%lx%lx:%lx%lx.%lx %s\n", (cd.alm_hr >> 4) & 1, cd.alm_hr & 0x0f, (cd.alm_min >> 4) & 7, cd.alm_min & 0x0f, (cd.alm_sec >> 4) & 7, cd.alm_sec & 0x0f, cd.alm_10ths & 0x0f, cd.alm_hr & 0x80 ? "PM" : "AM"); FPrintf(fout, "TOD input : %s\n", cd.cra & 0x80 ? "50Hz" : "60Hz"); FPrintf(fout, "Write to : %s registers\n\n", cd.crb & 0x80 ? "Alarm" : "TOD"); FPrintf(fout, "Serial data : %02lx\n", cd.sdr); FPrintf(fout, "Serial mode : %s\n\n", cd.cra & 0x40 ? "Output" : "Input"); FPuts(fout, "Pending int.: "); dump_cia_ints(cd.int_data); FPuts(fout, "Enabled int.: "); dump_cia_ints(cd.int_mask); } void dump_cia_ints(UBYTE int) { if (int & 0x1f) { if (int & 1) FPuts(fout, "TA "); if (int & 2) FPuts(fout, "TB "); if (int & 4) FPuts(fout, "Alarm "); if (int & 8) FPuts(fout, "Serial "); if (int & 0x10) FPuts(fout, "Flag"); } else FPuts(fout, "None"); FPutC(fout, '\n'); } void view_sid_state(void) { SIDDump sd; GetSIDDump(&sd); FPuts(fout, "Voice 1\n"); FPrintf(fout, " Frequency : %04lx\n", (sd.freq_hi_1 << 8) | sd.freq_lo_1); FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_1 & 0x0f) << 8) | sd.pw_lo_1); FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_1 >> 4, sd.AD_1 & 0x0f, sd.SR_1 >> 4, sd.SR_1 & 0x0f); FPuts(fout, " Waveform : "); dump_sid_waveform(sd.ctrl_1); FPrintf(fout, " Gate : %s Ring mod.: %s\n", sd.ctrl_1 & 0x01 ? "On " : "Off", sd.ctrl_1 & 0x04 ? "On" : "Off"); FPrintf(fout, " Test bit : %s Synchron.: %s\n", sd.ctrl_1 & 0x08 ? "On " : "Off", sd.ctrl_1 & 0x02 ? "On" : "Off"); FPrintf(fout, " Filter : %s\n", sd.res_filt & 0x01 ? "On" : "Off"); FPuts(fout, "\nVoice 2\n"); FPrintf(fout, " Frequency : %04lx\n", (sd.freq_hi_2 << 8) | sd.freq_lo_2); FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_2 & 0x0f) << 8) | sd.pw_lo_2); FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_2 >> 4, sd.AD_2 & 0x0f, sd.SR_2 >> 4, sd.SR_2 & 0x0f); FPuts(fout, " Waveform : "); dump_sid_waveform(sd.ctrl_2); FPrintf(fout, " Gate : %s Ring mod.: %s\n", sd.ctrl_2 & 0x01 ? "On " : "Off", sd.ctrl_2 & 0x04 ? "On" : "Off"); FPrintf(fout, " Test bit : %s Synchron.: %s\n", sd.ctrl_2 & 0x08 ? "On " : "Off", sd.ctrl_2 & 0x02 ? "On" : "Off"); FPrintf(fout, " Filter : %s\n", sd.res_filt & 0x02 ? "On" : "Off"); FPuts(fout, "\nVoice 3\n"); FPrintf(fout, " Frequency : %04lx\n", (sd.freq_hi_3 << 8) | sd.freq_lo_3); FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_3 & 0x0f) << 8) | sd.pw_lo_3); FPrintf(fout, " Env. (ADSR): %lx %lx %lx %lx\n", sd.AD_3 >> 4, sd.AD_3 & 0x0f, sd.SR_3 >> 4, sd.SR_3 & 0x0f); FPuts(fout, " Waveform : "); dump_sid_waveform(sd.ctrl_3); FPrintf(fout, " Gate : %s Ring mod.: %s\n", sd.ctrl_3 & 0x01 ? "On " : "Off", sd.ctrl_3 & 0x04 ? "On" : "Off"); FPrintf(fout, " Test bit : %s Synchron.: %s\n", sd.ctrl_3 & 0x08 ? "On " : "Off", sd.ctrl_3 & 0x02 ? "On" : "Off"); FPrintf(fout, " Filter : %s Mute : %s\n", sd.res_filt & 0x04 ? "On" : "Off", sd.mode_vol & 0x80 ? "Yes" : "No"); FPuts(fout, "\nFilters/Volume\n"); FPrintf(fout, " Frequency: %04lx\n", (sd.fc_hi << 3) | (sd.fc_lo & 0x07)); FPrintf(fout, " Resonance: %lx\n", sd.res_filt >> 4); FPuts(fout, " Mode : "); if (sd.mode_vol & 0x70) { if (sd.mode_vol & 0x10) FPuts(fout, "Low-pass "); if (sd.mode_vol & 0x20) FPuts(fout, "Band-pass "); if (sd.mode_vol & 0x40) FPuts(fout, "High-pass"); } else FPuts(fout, "None"); FPrintf(fout, "\n Volume : %lx\n", sd.mode_vol & 0x0f); } void dump_sid_waveform(UBYTE wave) { if (wave & 0xf0) { if (wave & 0x10) FPuts(fout, "Triangle "); if (wave & 0x20) FPuts(fout, "Sawtooth "); if (wave & 0x40) FPuts(fout, "Rectangle "); if (wave & 0x80) FPuts(fout, "Noise"); } else FPuts(fout, "None"); FPutC(fout, '\n'); } void view_vic_state(void) { VICDump vd; short i; GetVICDump(&vd); FPrintf(fout, "Raster line : %04lx\n", vd.raster | ((vd.ctrl1 & 0x80) << 1)); FPrintf(fout, "IRQ raster line : %04lx\n\n", vd.irq_raster); FPrintf(fout, "X scroll : %ld\n", vd.ctrl2 & 7); FPrintf(fout, "Y scroll : %ld\n", vd.ctrl1 & 7); FPrintf(fout, "Horizontal border : %ld columns\n", vd.ctrl2 & 8 ? 40 : 38); FPrintf(fout, "Vertical border : %ld rows\n\n", vd.ctrl1 & 8 ? 25 : 24); FPuts(fout, "Display mode : "); switch (((vd.ctrl1 >> 5) & 3) | ((vd.ctrl2 >> 2) & 4)) { case 0: FPuts(fout, "Standard text\n"); break; case 1: FPuts(fout, "Multicolor text\n"); break; case 2: FPuts(fout, "Standard bitmap\n"); break; case 3: FPuts(fout, "Multicolor bitmap\n"); break; case 4: FPuts(fout, "ECM text\n"); break; case 5: FPuts(fout, "Invalid text (ECM+MCM)\n"); break; case 6: FPuts(fout, "Invalid bitmap (ECM+BMM)\n"); break; case 7: FPuts(fout, "Invalid bitmap (ECM+BMM+ECM)\n"); break; } FPrintf(fout, "Sequencer state : %s\n", vd.idle_state ? "Idle" : "Display"); FPrintf(fout, "Bad line state : %s\n", vd.bad_line ? "Yes" : "No"); FPrintf(fout, "Bad lines enabled : %s\n", vd.bad_line_enable ? "Yes" : "No"); FPrintf(fout, "Video counter : %04lx\n", vd.vc); FPrintf(fout, "Video counter base: %04lx\n", vd.vcbase); FPrintf(fout, "Row counter : %ld\n\n", vd.rc); FPrintf(fout, "VIC bank : %04lx-%04lx\n", vd.bank_base, vd.bank_base + 0x3fff); FPrintf(fout, "Video matrix base : %04lx\n", vd.matrix_base); FPrintf(fout, "Character base : %04lx\n", vd.char_base); FPrintf(fout, "Bitmap base : %04lx\n\n", vd.bitmap_base); FPrintf(fout, " Spr.0 Spr.1 Spr.2 Spr.3 Spr.4 Spr.5 Spr.6 Spr.7\n"); FPuts(fout, "Enabled: "); dump_spr_flags(vd.me); FPrintf(fout, "Data : %04lx %04lx %04lx %04lx %04lx %04lx %04lx %04lx\n", vd.sprite_base[0], vd.sprite_base[1], vd.sprite_base[2], vd.sprite_base[3], vd.sprite_base[4], vd.sprite_base[5], vd.sprite_base[6], vd.sprite_base[7]); FPrintf(fout, "MC : %02lx %02lx %02lx %02lx %02lx %02lx %02lx %02lx\n", vd.mc[0], vd.mc[1], vd.mc[2], vd.mc[3], vd.mc[4], vd.mc[5], vd.mc[6], vd.mc[7]); FPuts(fout, "Mode : "); for (i=0; i<8; i++) if (vd.mmc & (1<= 0) SAMWriteByte(adr++, fc); Close(file); } } /* * Daten speichern * s start end "file" */ void save_data(void) { BOOL done = FALSE; UWORD adr, end_adr; BPTR file; if (!expression(&adr)) return; if (!expression(&end_adr)) return; if (the_token == T_END) { error("Missing file name"); return; } if (the_token != T_STRING) { error("'\"' around file name expected"); return; } if (!(file = Open(the_string, MODE_NEWFILE))) error("Unable to create file"); else { do { if (adr == end_adr) done = TRUE; FPutC(file, SAMReadByte(adr++)); } while (!done); Close(file); } }