home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / misc / emu / Frodo.lha / Frodo / src / SAM.c < prev    next >
C/C++ Source or Header  |  1995-12-10  |  42KB  |  1,769 lines

  1. /*
  2.  *  SAM.c - Simple Assembler and Monitor With Integrated System Explorer
  3.  *
  4.  *  Copyright (C) 1994-1995 by Christian Bauer
  5.  */
  6.  
  7. #include <exec/types.h>
  8. #include <clib/dos_protos.h>
  9. #include <clib/utility_protos.h>
  10.  
  11. #include "SAM.h"
  12. #include "6526.h"
  13. #include "6581.h"
  14. #include "6569.h"
  15.  
  16.  
  17. // Aus 6510.asm
  18. extern UBYTE RA, RX, RY, RP, RPR, RDDR;
  19. extern UWORD RPC, RS;
  20. extern UBYTE SAMReadByte(UWORD address);
  21. extern void SAMWriteByte(UWORD address, UBYTE byte);
  22. extern UBYTE SAMMemConfig;
  23.  
  24.  
  25. // Prototypes
  26. void error(char *s);            // Scanner
  27. BOOL aborted(void);
  28. void read_line(void);
  29. char get_char(void);
  30. void put_back(char c);
  31. enum Token get_token(void);
  32. UWORD get_number(void);
  33.  
  34. BOOL expression(UWORD *number);    // Parser
  35. BOOL term(UWORD *number);
  36. BOOL factor(UWORD *number);
  37. BOOL address_args(void);
  38. BOOL range_args(int def_range);
  39. BOOL instr_args(UWORD *number, char *mode);
  40.  
  41. void help(void);                // Routinen für die Befehle
  42. void display_registers(void);
  43. void memory_dump(void);
  44. void ascii_dump(void);
  45. char conv_from_64(char c);
  46. void screen_dump(void);
  47. char conv_from_scode(char c);
  48. void binary_dump(void);
  49. void sprite_dump(void);
  50. void byte_to_bin(UBYTE byte, char *str);
  51. void disassemble(void);
  52. int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi);
  53. void assemble(void);
  54. char find_mnemonic(char op1, char op2, char op3);
  55. BOOL find_opcode(char mnem, char mode, UBYTE *opcode);
  56. void mem_config(void);
  57. void fill(void);
  58. void compare(void);
  59. void transfer(void);
  60. void modify(void);
  61. void print_expr(void);
  62. void redir_output(void);
  63. void int_vectors(void);
  64. void view_state(void);
  65. void view_cia_state(void);
  66. void dump_cia_ints(UBYTE int);
  67. void view_sid_state(void);
  68. void dump_sid_waveform(UBYTE wave);
  69. void view_vic_state(void);
  70. void dump_spr_flags(UBYTE f);
  71. void dump_vic_ints(UBYTE int);
  72.  
  73.  
  74. // FileHandles für Eingabe, Ausgabe und Fehler
  75. BPTR fin, fout, ferr;
  76.  
  77. // Eingabezeile
  78. #define INPUT_LENGTH 80
  79. char input[INPUT_LENGTH];
  80. char *in_ptr;
  81.  
  82. UWORD address, end_address;
  83.  
  84. // Eingabetoken
  85. enum Token {
  86.   T_NULL,        // Ungültiges Token
  87.   T_END,        // Ende der Zeile
  88.   T_NUMBER,        // Hexadezimalzahl
  89.   T_LPAREN,        // '('
  90.   T_RPAREN,        // ')'
  91.   T_ADD,        // '+'
  92.   T_SUB,        // '-'
  93.   T_MUL,        // '*'
  94.   T_DIV,        // '/'
  95.   T_COMMA,        // ','
  96.   T_IMMED,        // '#'
  97.   T_X,            // 'x'
  98.   T_Y,            // 'y'
  99.   T_PC,            // 'pc'
  100.   T_SP            // 'sp'
  101. };
  102.  
  103. enum Token the_token;
  104. UWORD the_number;    // Enthält die Zahl, wenn the_token==T_NUMBER
  105.  
  106. // Adressierungsarten
  107. enum {
  108.   A_IMPL,
  109.   A_ACCU,    // A
  110.   A_IMM,    // #zz
  111.   A_REL,    // Branches
  112.   A_ZERO,    // zz
  113.   A_ZEROX,    // zz,x
  114.   A_ZEROY,    // zz,y
  115.   A_ABS,    // zzzz
  116.   A_ABSX,    // zzzz,x
  117.   A_ABSY,    // zzzz,y
  118.   A_IND,    // (zzzz)
  119.   A_INDX,    // (zz,x)
  120.   A_INDY    // (zz),y
  121. };
  122.  
  123. // Mnemonics
  124. enum {
  125.   M_ADC, M_AND, M_ASL, M_BCC, M_BCS, M_BEQ, M_BIT, M_BMI, M_BNE, M_BPL,
  126.   M_BRK, M_BVC, M_BVS, M_CLC, M_CLD, M_CLI, M_CLV, M_CMP, M_CPX, M_CPY,
  127.   M_DEC, M_DEX, M_DEY, M_EOR, M_INC, M_INX, M_INY, M_JMP, M_JSR, M_LDA,
  128.   M_LDX, M_LDY, M_LSR, M_NOP, M_ORA, M_PHA, M_PHP, M_PLA, M_PLP, M_ROL,
  129.   M_ROR, M_RTI, M_RTS, M_SBC, M_SEC, M_SED, M_SEI, M_STA, M_STX, M_STY,
  130.   M_TAX, M_TAY, M_TSX, M_TXA, M_TXS, M_TYA,
  131.  
  132.   M_ILLEGAL,  // Ab hier kommen die undokumentierten Opcodes
  133.  
  134.   M_IANC, M_IANE, M_IARR, M_IASR, M_IDCP, M_IISB, M_IJAM, M_INOP, M_ILAS,
  135.   M_ILAX, M_ILXA, M_IRLA, M_IRRA, M_ISAX, M_ISBC, M_ISBX, M_ISHA, M_ISHS,
  136.   M_ISHX, M_ISHY, M_ISLO, M_ISRE,
  137.  
  138.   M_MAXIMUM  // Höchstes Element
  139. };
  140.  
  141. // Zu jedem Opcode das Mnemonic
  142. const char mnemonic[256] = {
  143.   M_BRK , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO,    // 00
  144.   M_PHP , M_ORA , M_ASL , M_IANC, M_INOP, M_ORA, M_ASL , M_ISLO,
  145.   M_BPL , M_ORA , M_IJAM, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO,    // 10
  146.   M_CLC , M_ORA , M_INOP, M_ISLO, M_INOP, M_ORA, M_ASL , M_ISLO,
  147.   M_JSR , M_AND , M_IJAM, M_IRLA, M_BIT , M_AND, M_ROL , M_IRLA,    // 20
  148.   M_PLP , M_AND , M_ROL , M_IANC, M_BIT , M_AND, M_ROL , M_IRLA,
  149.   M_BMI , M_AND , M_IJAM, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA,    // 30
  150.   M_SEC , M_AND , M_INOP, M_IRLA, M_INOP, M_AND, M_ROL , M_IRLA,
  151.   M_RTI , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE,    // 40
  152.   M_PHA , M_EOR , M_LSR , M_IASR, M_JMP , M_EOR, M_LSR , M_ISRE,
  153.   M_BVC , M_EOR , M_IJAM, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE,    // 50
  154.   M_CLI , M_EOR , M_INOP, M_ISRE, M_INOP, M_EOR, M_LSR , M_ISRE,
  155.   M_RTS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA,    // 60
  156.   M_PLA , M_ADC , M_ROR , M_IARR, M_JMP , M_ADC, M_ROR , M_IRRA,
  157.   M_BVS , M_ADC , M_IJAM, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA,    // 70
  158.   M_SEI , M_ADC , M_INOP, M_IRRA, M_INOP, M_ADC, M_ROR , M_IRRA,
  159.   M_INOP, M_STA , M_INOP, M_ISAX, M_STY , M_STA, M_STX , M_ISAX,    // 80
  160.   M_DEY , M_INOP, M_TXA , M_IANE, M_STY , M_STA, M_STX , M_ISAX,
  161.   M_BCC , M_STA , M_IJAM, M_ISHA, M_STY , M_STA, M_STX , M_ISAX,    // 90
  162.   M_TYA , M_STA , M_TXS , M_ISHS, M_ISHY, M_STA, M_ISHX, M_ISHA,
  163.   M_LDY , M_LDA , M_LDX , M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX,    // a0
  164.   M_TAY , M_LDA , M_TAX , M_ILXA, M_LDY , M_LDA, M_LDX , M_ILAX,
  165.   M_BCS , M_LDA , M_IJAM, M_ILAX, M_LDY , M_LDA, M_LDX , M_ILAX,    // b0
  166.   M_CLV , M_LDA , M_TSX , M_ILAS, M_LDY , M_LDA, M_LDX , M_ILAX,
  167.   M_CPY , M_CMP , M_INOP, M_IDCP, M_CPY , M_CMP, M_DEC , M_IDCP,    // c0
  168.   M_INY , M_CMP , M_DEX , M_ISBX, M_CPY , M_CMP, M_DEC , M_IDCP,
  169.   M_BNE , M_CMP , M_IJAM, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP,    // d0
  170.   M_CLD , M_CMP , M_INOP, M_IDCP, M_INOP, M_CMP, M_DEC , M_IDCP,
  171.   M_CPX , M_SBC , M_INOP, M_IISB, M_CPX , M_SBC, M_INC , M_IISB,    // e0
  172.   M_INX , M_SBC , M_NOP , M_ISBC, M_CPX , M_SBC, M_INC , M_IISB,
  173.   M_BEQ , M_SBC , M_IJAM, M_IISB, M_INOP, M_SBC, M_INC , M_IISB,    // f0
  174.   M_SED , M_SBC , M_INOP, M_IISB, M_INOP, M_SBC, M_INC , M_IISB
  175. };
  176.  
  177. // Zu jedem Opcode die Adressierungsart
  178. const char adr_mode[256] = {
  179.   A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 00
  180.   A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  181.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // 10
  182.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  183.   A_ABS , A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 20
  184.   A_IMPL, A_IMM , A_ACCU, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  185.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // 30
  186.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  187.   A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 40
  188.   A_IMPL, A_IMM , A_ACCU, 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,    // 50
  190.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  191.   A_IMPL, A_INDX, A_IMPL, A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 60
  192.   A_IMPL, A_IMM , A_ACCU, A_IMM , A_IND  , A_ABS  , A_ABS  , A_ABS,
  193.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // 70
  194.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  195.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // 80
  196.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  197.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY,    // 90
  198.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY,
  199.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // a0
  200.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  201.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROY, A_ZEROY,    // b0
  202.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSY , A_ABSY,
  203.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // c0
  204.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  205.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // d0
  206.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX,
  207.   A_IMM , A_INDX, A_IMM , A_INDX, A_ZERO , A_ZERO , A_ZERO , A_ZERO,    // e0
  208.   A_IMPL, A_IMM , A_IMPL, A_IMM , A_ABS  , A_ABS  , A_ABS  , A_ABS,
  209.   A_REL , A_INDY, A_IMPL, A_INDY, A_ZEROX, A_ZEROX, A_ZEROX, A_ZEROX,    // f0
  210.   A_IMPL, A_ABSY, A_IMPL, A_ABSY, A_ABSX , A_ABSX , A_ABSX , A_ABSX
  211. };
  212.  
  213. // Zu jedem Mnemonic die Zeichen
  214. const char mnem_1[] = "aaabbbbbbbbbbcccccccdddeiiijjllllnopppprrrrssssssstttttt?aaaadijnlllrrsssssssss";
  215. const char mnem_2[] = "dnscceimnprvvllllmppeeeonnnmsdddsorhhlloottbeeetttaasxxy?nnrscsaoaaxlrabbhhhhlr";
  216. const char mnem_3[] = "cdlcsqtielkcscdivpxycxyrcxypraxyrpaapaplrisccdiaxyxyxasa?cerrpbmpsxaaaxcxasxyoe";
  217.  
  218. // Zu jeder Adressierungsart die Befehlslänge
  219. const char adr_length[] = {1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 2, 2};
  220.  
  221.  
  222. /*
  223.  *  SAM öffnen und handhaben
  224.  */
  225.  
  226. void SAM(void)
  227. {
  228.   BOOL done = FALSE;
  229.   char c;
  230.  
  231.   if (fin = fout = ferr = Open("CON:0/0/640/480/SAM", MODE_NEWFILE)) {
  232.     FPuts(ferr, "\n *** SAM - Simple Assembler and Monitor ***\n ***         Press 'h' for help         ***\n\n");
  233.     display_registers();
  234.  
  235.     address = RPC;
  236.  
  237.     while (!done) {
  238.       Write(ferr, "> ", 2);
  239.       read_line();
  240.       while ((c = get_char()) == ' ') ;
  241.  
  242.       switch (c) {
  243.         case 'a':        // Assemblieren
  244.           get_token();
  245.           assemble();
  246.           break;
  247.  
  248.         case 'b':        // Binär-Dump
  249.           get_token();
  250.           binary_dump();
  251.           break;
  252.  
  253.         case 'c':        // Vergleichen
  254.           get_token();
  255.           compare();
  256.           break;
  257.  
  258.         case 'd':        // Disassemblieren
  259.           get_token();
  260.           disassemble();
  261.           break;
  262.  
  263.         case 'e':       // Interrupt-Vektoren
  264.           int_vectors();
  265.           break;
  266.  
  267.         case 'f':        // Füllen
  268.           get_token();
  269.           fill();
  270.           break;
  271.  
  272.         case 'h':        // Help
  273.           help();
  274.           break;
  275.  
  276.         case 'i':        // ASCII-Dump
  277.           get_token();
  278.           ascii_dump();
  279.           break;
  280.  
  281.         case 'k':        // Speicherkonfiguration
  282.           get_token();
  283.           mem_config();
  284.           break;
  285.  
  286.         case 'm':        // Memory-Dump
  287.           get_token();
  288.           memory_dump();
  289.           break;
  290.  
  291.         case 'n':        // Screen-Code-Dump
  292.           get_token();
  293.           screen_dump();
  294.           break;
  295.  
  296.         case 'o':        // Ausgabe umleiten
  297.           redir_output();
  298.           break;
  299.  
  300.         case 'p':        // Sprite-Dump
  301.           get_token();
  302.           sprite_dump();
  303.           break;
  304.  
  305.         case 'r':        // Register
  306.           display_registers();
  307.           break;
  308.  
  309.         case 't':        // Transfer
  310.           get_token();
  311.           transfer();
  312.           break;
  313.  
  314.         case 'v':        // View machine state
  315.           view_state();
  316.           break;
  317.  
  318.         case 'x':        // Exit
  319.           done = TRUE;
  320.           break;
  321.  
  322.         case ':':        // Ändern
  323.           get_token();
  324.           modify();
  325.           break;
  326.  
  327.         case '?':        // Ausdruck berechnen
  328.           get_token();
  329.           print_expr();
  330.           break;
  331.  
  332.         case '\n':        // Leerzeile
  333.           break;
  334.  
  335.         default:        // Unbekannter Befehl
  336.           error("Unknown command");
  337.           break;
  338.       }
  339.     }
  340.  
  341.     Close(fin);
  342.     if (fout != ferr)
  343.       Close(fout);
  344.   }
  345. }
  346.  
  347.  
  348. /*
  349.  *  Fehlermeldung ausgeben
  350.  */
  351.  
  352. void error(char *s)
  353. {
  354.   FPrintf(ferr, "*** %s\n", s);
  355. }
  356.  
  357.  
  358. /*
  359.  *  CTRL-C gedrückt?
  360.  */
  361.  
  362. #include <dos/dos.h>
  363. #include <clib/exec_protos.h>
  364. BOOL aborted(void)
  365. {
  366.   return SetSignal(0, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
  367. }
  368.  
  369.  
  370. /*
  371.  *  Eine Zeile von der Tastatur lesen
  372.  */
  373.  
  374. void read_line(void)
  375. {
  376.   FGets(fin, in_ptr = input, INPUT_LENGTH);
  377. }
  378.  
  379.  
  380. /*
  381.  *  Ein Zeichen aus der Eingabezeile lesen
  382.  */
  383.  
  384. char get_char(void)
  385. {
  386.   return *in_ptr++;
  387. }
  388.  
  389.  
  390. /*
  391.  *  Zeichen in die Eingabezeile zurückpacken
  392.  */
  393.  
  394. void put_back(char c)
  395. {
  396.   *(--in_ptr) = c;
  397. }
  398.  
  399.  
  400. /*
  401.  *  Scanner: Ein Token aus der Eingabezeile lesen
  402.  */
  403.  
  404. enum Token get_token(void)
  405. {
  406.   char c;
  407.  
  408.   // Leerzeichen überspringen
  409.   while ((c = get_char()) == ' ') ;
  410.  
  411.   switch (ToLower(c)) {
  412.     case '\n':
  413.       return the_token = T_END;
  414.     case '(':
  415.       return the_token = T_LPAREN;
  416.     case ')':
  417.       return the_token = T_RPAREN;
  418.     case '+':
  419.       return the_token = T_ADD;
  420.     case '-':
  421.       return the_token = T_SUB;
  422.     case '*':
  423.       return the_token = T_MUL;
  424.     case '/':
  425.       return the_token = T_DIV;
  426.     case ',':
  427.       return the_token = T_COMMA;
  428.     case '#':
  429.       return the_token = T_IMMED;
  430.     case 'x':
  431.       return the_token = T_X;
  432.     case 'y':
  433.       return the_token = T_Y;
  434.     case 'p':
  435.       if (ToLower(get_char()) == 'c')
  436.         return the_token = T_PC;
  437.       else {
  438.         error("Unrecognized token");
  439.         return the_token = T_NULL;
  440.       }
  441.     case 's':
  442.       if (ToLower(get_char()) == 'p')
  443.         return the_token = T_SP;
  444.       else {
  445.         error("Unrecognized token");
  446.         return the_token = T_NULL;
  447.       }
  448.     case '0': case '1': case '2': case '3': case '4':
  449.     case '5': case '6': case '7': case '8': case '9':
  450.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
  451.       put_back(c);
  452.       the_number = get_number();
  453.       return the_token = T_NUMBER;
  454.     default:
  455.       error("Unrecognized token");
  456.       return the_token = T_NULL;
  457.   }
  458. }
  459.  
  460. UWORD get_number(void)
  461. {
  462.   char c;
  463.   UWORD i = 0;
  464.  
  465.   while (((c = ToLower(get_char())) >= '0') && (c <= '9') || (c >= 'a') && (c <= 'f'))
  466.     if (c < 'a')
  467.       i = (i << 4) + (c - '0');
  468.     else
  469.       i = (i << 4) + (c - 'a' + 10);
  470.  
  471.   put_back(c);
  472.   return i;
  473. }
  474.  
  475.  
  476. /*
  477.  *  expression = term {(ADD | SUB) term}
  478.  *  TRUE: OK, FALSE: Fehler
  479.  */
  480.  
  481. BOOL expression(UWORD *number)
  482. {
  483.   UWORD accu, trm;
  484.  
  485.   if (!term(&accu))
  486.     return FALSE;
  487.  
  488.   for (;;)
  489.     switch (the_token) {
  490.       case T_ADD:
  491.         get_token();
  492.         if (!term(&trm))
  493.           return FALSE;
  494.         accu += trm;
  495.         break;
  496.  
  497.       case T_SUB:
  498.         get_token();
  499.         if (!term(&trm))
  500.           return FALSE;
  501.         accu -= trm;
  502.         break;
  503.  
  504.       default:
  505.         *number = accu;
  506.         return TRUE;
  507.     }
  508. }
  509.  
  510.  
  511. /*
  512.  *  term = factor {(MUL | DIV) factor}
  513.  *  TRUE: OK, FALSE: Fehler
  514.  */
  515.  
  516. BOOL term(UWORD *number)
  517. {
  518.   UWORD accu, fact;
  519.  
  520.   if (!factor(&accu))
  521.     return FALSE;
  522.  
  523.   for (;;)
  524.     switch (the_token) {
  525.       case T_MUL:
  526.         get_token();
  527.         if (!factor(&fact))
  528.           return FALSE;
  529.         accu *= fact;
  530.         break;
  531.  
  532.       case T_DIV:
  533.         get_token();
  534.         if (!factor(&fact))
  535.           return FALSE;
  536.         if (fact == 0) {
  537.           error("Division by 0");
  538.           return FALSE;
  539.         }
  540.         accu /= fact;
  541.         break;
  542.  
  543.       default:
  544.         *number = accu;
  545.         return TRUE;
  546.     }
  547. }
  548.  
  549.  
  550. /*
  551.  *  factor = NUMBER | PC | SP | LPAREN expression RPAREN
  552.  *  TRUE: OK, FALSE: Fehler
  553.  */
  554.  
  555. BOOL factor(UWORD *number)
  556. {
  557.   switch (the_token) {
  558.     case T_NUMBER:
  559.       *number = the_number;
  560.       get_token();
  561.       return TRUE;
  562.  
  563.     case T_PC:
  564.       get_token();
  565.       *number = RPC;
  566.       return TRUE;
  567.  
  568.     case T_SP:
  569.       get_token();
  570.       *number = RS;
  571.       return TRUE;
  572.  
  573.     case T_LPAREN:
  574.       get_token();
  575.       if (expression(number))
  576.         if (the_token == T_RPAREN) {
  577.           get_token();
  578.           return TRUE;
  579.         } else {
  580.           error("Missing ')'");
  581.           return FALSE;
  582.         }
  583.       else {
  584.         error("Error in expression");
  585.         return FALSE;
  586.       }
  587.  
  588.     case T_END:
  589.       error("Required argument missing");
  590.       return FALSE;
  591.  
  592.     default:
  593.       error("'pc', 'sp', '(' or number expected");
  594.       return FALSE;
  595.   }
  596. }
  597.  
  598.  
  599. /*
  600.  *  address_args = [expression] END
  601.  *
  602.  *  Startadresse nach address lesen
  603.  *
  604.  *  TRUE: OK, FALSE: Fehler
  605.  */
  606.  
  607. BOOL address_args(void)
  608. {
  609.   if (the_token == T_END)
  610.     return TRUE;
  611.   else {
  612.     if (!expression(&address))
  613.       return FALSE;
  614.     return the_token == T_END;
  615.   }
  616. }
  617.  
  618.  
  619. /*
  620.  *  range_args = [expression] [[COMMA] expression] END
  621.  *
  622.  *  Startadresse nach address, Endadresse nach end_address lesen
  623.  *
  624.  *  TRUE: OK, FALSE: Fehler
  625.  */
  626.  
  627. BOOL range_args(int def_range)
  628. {
  629.   end_address = address + def_range;
  630.  
  631.   if (the_token == T_END)
  632.     return TRUE;
  633.   else {
  634.     if (!expression(&address))
  635.       return FALSE;
  636.     end_address = address + def_range;
  637.     if (the_token == T_END)
  638.       return TRUE;
  639.     else {
  640.       if (the_token == T_COMMA) get_token();
  641.       if (!expression(&end_address))
  642.         return FALSE;
  643.       return the_token == T_END;
  644.     }
  645.   }
  646. }
  647.  
  648.  
  649. /*
  650.  *  instr_args = END
  651.  *             | IMMED NUMBER END
  652.  *             | NUMBER [COMMA (X | Y)] END
  653.  *             | LPAREN NUMBER (RPAREN [COMMA Y] | COMMA X RPAREN) END
  654.  *
  655.  *  Argumente eines 6510-Befehls lesen, Adresse und Adressierungsart ermitteln
  656.  *
  657.  *  TRUE: OK, FALSE: Fehler
  658.  */
  659.  
  660. BOOL instr_args(UWORD *number, char *mode)
  661. {
  662.   switch (the_token) {
  663.  
  664.     case T_END:
  665.       *mode = A_IMPL;
  666.       return TRUE;
  667.  
  668.     case T_IMMED:
  669.       get_token();
  670.       if (the_token == T_NUMBER) {
  671.         *number = the_number;
  672.         *mode = A_IMM;
  673.         get_token();
  674.         return the_token == T_END;
  675.       } else {
  676.         error("Number expected");
  677.         return FALSE;
  678.       }
  679.  
  680.     case T_NUMBER:
  681.       *number = the_number;
  682.       get_token();
  683.       switch (the_token) {
  684.  
  685.         case T_END:
  686.           if (*number < 0x100)
  687.             *mode = A_ZERO;
  688.           else
  689.             *mode = A_ABS;
  690.           return TRUE;
  691.  
  692.         case T_COMMA:
  693.           get_token();
  694.           switch (the_token) {
  695.  
  696.             case T_X:
  697.               get_token();
  698.               if (*number < 0x100)
  699.                 *mode = A_ZEROX;
  700.               else
  701.                 *mode = A_ABSX;
  702.               return the_token == T_END;
  703.  
  704.             case T_Y:
  705.               get_token();
  706.               if (*number < 0x100)
  707.                 *mode = A_ZEROY;
  708.               else
  709.                 *mode = A_ABSY;
  710.               return the_token == T_END;
  711.  
  712.             default:
  713.               error("Illegal index register");
  714.               return FALSE;
  715.           }
  716.  
  717.         default:
  718.           return FALSE;
  719.       }
  720.  
  721.     case T_LPAREN:
  722.       get_token();
  723.       if (the_token == T_NUMBER) {
  724.         *number = the_number;
  725.         get_token();
  726.         switch (the_token) {
  727.           case T_RPAREN:
  728.             get_token();
  729.             switch (the_token) {
  730.  
  731.               case T_END:
  732.                 *mode = A_IND;
  733.                 return TRUE;
  734.  
  735.               case T_COMMA:
  736.                 get_token();
  737.                 if (the_token == T_Y) {
  738.                   *mode = A_INDY;
  739.                   get_token();
  740.                   return the_token == T_END;
  741.                 } else {
  742.                   error("Only 'y' index register allowed");
  743.                   return FALSE;
  744.                 }
  745.  
  746.               default:
  747.                 error("Illegal characters after ')'");
  748.                 return FALSE;
  749.             }
  750.  
  751.           case T_COMMA:
  752.             get_token();
  753.             if (the_token == T_X) {
  754.               get_token();
  755.               if (the_token == T_RPAREN) {
  756.                 *mode = A_INDX;
  757.                 get_token();
  758.                 return the_token == T_END;
  759.               } else {
  760.                 error("')' expected");
  761.                 return FALSE;
  762.               }
  763.             } else {
  764.               error("Only 'x' index register allowed");
  765.               return FALSE;
  766.             }
  767.  
  768.           default:
  769.             error("')' or ',' expected");
  770.             return FALSE;
  771.         }
  772.       } else {
  773.         error("Number expected");
  774.         return FALSE;
  775.       }
  776.  
  777.     default:
  778.       error("'(', '#' or number expected");
  779.       return FALSE;
  780.   }
  781. }
  782.  
  783.  
  784. /*
  785.  *  Hilfstext anzeigen
  786.  *  ?
  787.  */
  788.  
  789. void help(void)
  790. {
  791.   FPuts(fout, "a [start]         Assemble\n"
  792.               "b [start] [end]   Binary dump\n"
  793.               "c start end dest  Compare memory\n"
  794.               "d [start] [end]   Disassemble\n"
  795.               "e                 Show interrupt vectors\n"
  796.               "f start end byte  Fill memory\n"
  797.               "i [start] [end]   ASCII/PETSCII dump\n"
  798.               "k [config]        Show/set memory configuration\n"
  799.               "m [start] [end]   Memory dump\n"
  800.               "n [start] [end]   Screen code dump\n"
  801.               "o [file]          Redirect output\n"
  802.               "p [start] [end]   Sprite dump\n"
  803.               "r                 Show registers\n"
  804.               "t start end dest  Transfer memory\n"
  805.               "vc1               View CIA 1 state\n"
  806.               "vc2               View CIA 2 state\n"
  807.               "vs                View SID state\n"
  808.               "vv                View VIC state\n"
  809.               "x                 Return to Frodo\n"
  810.               ": addr {byte}     Modify memory\n"
  811.               "? expression      Calculate expression\n");
  812. }
  813.  
  814.  
  815. /*
  816.  *  6510-Register anzeigen
  817.  *  r
  818.  */
  819.  
  820. void display_registers(void)
  821. {
  822.   FPuts(fout, " PC  A  X  Y   SP  DR PR NVDIZC  Instruction\n");
  823.   FPrintf(fout, "%04lx %02lx %02lx %02lx %04lx %02lx %02lx %lc%lc%lc%lc%lc%lc ",
  824.     RPC, RA, RX, RY, RS, RDDR, RPR,
  825.     RP & 0x80 ? '1' : '0', RP & 0x40 ? '1' : '0', RP & 0x08 ? '1' : '0',
  826.     RP & 0x04 ? '1' : '0', RP & 0x02 ? '1' : '0', RP & 0x01 ? '1' : '0');
  827.   disass_line(RPC, SAMReadByte(RPC), SAMReadByte(RPC+1), SAMReadByte(RPC+2));
  828. }
  829.  
  830.  
  831. /*
  832.  *  Memory-Dump
  833.  *  m [start] [end]
  834.  */
  835.  
  836. #define MEMDUMP_BPL 16  // Bytes pro Zeile
  837.  
  838. void memory_dump(void)
  839. {
  840.   BOOL done = FALSE;
  841.   short i;
  842.   UBYTE mem[MEMDUMP_BPL + 2];
  843.   UBYTE byte;
  844.  
  845.   mem[MEMDUMP_BPL] = 0;
  846.  
  847.   if (!range_args(16 * MEMDUMP_BPL - 1))  // 16 Zeilen, wenn keine Endadresse angegeben
  848.     return;
  849.  
  850.   do {
  851.     FPrintf(fout, "%04lx:", address);
  852.     for (i=0; i<MEMDUMP_BPL; i++, address++) {
  853.       if (address == end_address) done = TRUE;
  854.  
  855.       FPrintf(fout, " %02lx", byte = SAMReadByte(address));
  856.       if ((byte >= ' ') && (byte <= '~'))
  857.         mem[i] = conv_from_64(byte);
  858.       else
  859.         mem[i] = '.';
  860.     }
  861.     FPrintf(fout, "  '%s'\n", mem);
  862.   } while (!done && !aborted());
  863. }
  864.  
  865.  
  866. /*
  867.  *  ASCII-Dump
  868.  *  i [start] [end]
  869.  */
  870.  
  871. #define ASCIIDUMP_BPL 64  // Bytes pro Zeile
  872.  
  873. void ascii_dump(void)
  874. {
  875.   BOOL done = FALSE;
  876.   short i;
  877.   UBYTE mem[ASCIIDUMP_BPL + 2];
  878.   UBYTE byte;
  879.  
  880.   mem[ASCIIDUMP_BPL] = 0;
  881.  
  882.   if (!range_args(16 * ASCIIDUMP_BPL - 1))  // 16 Zeilen, wenn keine Endadresse angegeben
  883.     return;
  884.  
  885.   do {
  886.     FPrintf(fout, "%04lx:", address);
  887.     for (i=0; i<ASCIIDUMP_BPL; i++, address++) {
  888.       if (address == end_address) done = TRUE;
  889.  
  890.       byte = SAMReadByte(address);
  891.       if ((byte >= ' ') && (byte <= '~'))
  892.         mem[i] = conv_from_64(byte);
  893.       else
  894.         mem[i] = '.';
  895.     }
  896.     FPrintf(fout, " '%s'\n", mem);
  897.   } while (!done && !aborted());
  898. }
  899.  
  900.  
  901. /*
  902.  *  Umwandlung PETSCII->ASCII
  903.  */
  904.  
  905. char conv_from_64(char c)
  906. {
  907.   if ((c >= 'A') && (c <= 'Z') || (c >= 'a') && (c <= 'z'))
  908.     return c ^ 0x20;
  909.   else
  910.     return c;
  911. }
  912.  
  913.  
  914. /*
  915.  *  Screen-Code-Dump
  916.  *  n [start] [end]
  917.  */
  918.  
  919. #define SCRDUMP_BPL 64  // Bytes pro Zeile
  920.  
  921. void screen_dump(void)
  922. {
  923.   BOOL done = FALSE;
  924.   short i;
  925.   UBYTE mem[SCRDUMP_BPL + 2];
  926.   UBYTE byte;
  927.  
  928.   mem[SCRDUMP_BPL] = 0;
  929.  
  930.   if (!range_args(16 * SCRDUMP_BPL - 1))  // 16 Zeilen, wenn keine Endadresse angegeben
  931.     return;
  932.  
  933.   do {
  934.     FPrintf(fout, "%04lx:", address);
  935.     for (i=0; i<SCRDUMP_BPL; i++, address++) {
  936.       if (address == end_address) done = TRUE;
  937.  
  938.       byte = SAMReadByte(address);
  939.       if (byte < 90)
  940.         mem[i] = conv_from_scode(byte);
  941.       else
  942.         mem[i] = '.';
  943.     }
  944.     FPrintf(fout, " '%s'\n", mem);
  945.   } while (!done && !aborted());
  946. }
  947.  
  948.  
  949. /*
  950.  *  Umwandlung Bildschirmcode->ASCII
  951.  */
  952.  
  953. char conv_from_scode(char c)
  954. {
  955.   c &= 0x7f;
  956.  
  957.   if (c <= 31)
  958.     return c + 64;
  959.   else
  960.     if (c >= 64)
  961.       return c + 32;
  962.     else
  963.       return c;
  964. }
  965.  
  966.  
  967. /*
  968.  *  Binär-Dump
  969.  *  b [start] [end]
  970.  */
  971.  
  972. void binary_dump(void)
  973. {
  974.   BOOL done = FALSE;
  975.   char bin[10];
  976.  
  977.   bin[8] = 0;
  978.  
  979.   if (!range_args(7))  // 8 Zeilen, wenn keine Endadresse angegeben
  980.     return;
  981.  
  982.   do {
  983.     if (address == end_address) done = TRUE;
  984.  
  985.     byte_to_bin(SAMReadByte(address), bin);
  986.     FPrintf(fout, "%04lx: %s\n", address++, bin);
  987.   } while (!done && !aborted());
  988. }
  989.  
  990.  
  991. /*
  992.  *  Sprite-Daten-Dump
  993.  *  p [start] [end]
  994.  */
  995.  
  996. void sprite_dump(void)
  997. {
  998.   BOOL done = FALSE;
  999.   short i;
  1000.   char bin[10];
  1001.  
  1002.   bin[8] = 0;
  1003.  
  1004.   if (!range_args(21 * 3 - 1))  // 21 Zeilen, wenn keine Endadresse angegeben
  1005.     return;
  1006.  
  1007.   do {
  1008.     FPrintf(fout, "%04lx: ", address);
  1009.     for (i=0; i<3; i++, address++) {
  1010.       if (address == end_address) done = TRUE;
  1011.  
  1012.       byte_to_bin(SAMReadByte(address), bin);
  1013.       FPrintf(fout, "%s", bin);
  1014.     }
  1015.     FPutC(fout, '\n');
  1016.   } while (!done && !aborted());
  1017. }
  1018.  
  1019.  
  1020. /*
  1021.  *  Ein Byte in Binärfolge umwandeln
  1022.  */
  1023.  
  1024. void byte_to_bin(UBYTE byte, char *str)
  1025. {
  1026.   short i;
  1027.  
  1028.   for (i=0; i<8; i++, byte<<=1)
  1029.     if (byte & 0x80)
  1030.       str[i] = '#';
  1031.     else
  1032.       str[i] = '.';
  1033. }
  1034.  
  1035.  
  1036. /*
  1037.  *  Disassemblieren
  1038.  *  d [start] [end]
  1039.  */
  1040.  
  1041. void disassemble(void)
  1042. {
  1043.   BOOL done = FALSE;
  1044.   short i;
  1045.   UBYTE op[3];
  1046.   UWORD adr;
  1047.  
  1048.   if (!range_args(31))  // 32 Bytes, wenn keine Endadresse angegeben
  1049.     return;
  1050.  
  1051.   do {
  1052.     FPrintf(fout, "%04lx:", adr = address);
  1053.     for (i=0; i<3; i++, adr++) {
  1054.       if (adr == end_address) done = TRUE;
  1055.       op[i] = SAMReadByte(adr);
  1056.     }
  1057.     address += disass_line(address, op[0], op[1], op[2]);
  1058.   } while (!done && !aborted());
  1059. }
  1060.  
  1061.  
  1062. /*
  1063.  *  Einen Befehl disassemblieren, Länge zurückgeben
  1064.  */
  1065.  
  1066. int disass_line(UWORD adr, UBYTE op, UBYTE lo, UBYTE hi)
  1067. {
  1068.   char mode = adr_mode[op], mnem = mnemonic[op];
  1069.  
  1070.   // Befehlsbytes hexadezimal ausgeben
  1071.   switch (adr_length[mode]) {
  1072.     case 1:
  1073.       FPrintf(fout, " %02lx       ", op);
  1074.       break;
  1075.  
  1076.     case 2:
  1077.       FPrintf(fout, " %02lx %02lx    ", op, lo);
  1078.       break;
  1079.  
  1080.     case 3:
  1081.       FPrintf(fout, " %02lx %02lx %02lx ", op, lo, hi);
  1082.       break;
  1083.   }
  1084.  
  1085.   // Undokumentierte Opcodes mit Stern markieren
  1086.   if (mnem > M_ILLEGAL)
  1087.     FPutC(fout, '*');
  1088.   else
  1089.     FPutC(fout, ' ');
  1090.  
  1091.   // Mnemonic ausgeben
  1092.   FPrintf(fout, "%lc%lc%lc ", mnem_1[mnem], mnem_2[mnem], mnem_3[mnem]);
  1093.  
  1094.   // Argument ausgeben
  1095.   switch (mode) {
  1096.     case A_IMPL:
  1097.       break;
  1098.  
  1099.     case A_ACCU:
  1100.       FPuts(fout, "a");
  1101.       break;
  1102.  
  1103.     case A_IMM:
  1104.       FPrintf(fout, "#%02lx", lo);
  1105.       break;
  1106.  
  1107.     case A_REL:
  1108.       FPrintf(fout, "%04lx", ((adr + 2) + (BYTE)lo) & 0xffff);
  1109.       break;
  1110.  
  1111.     case A_ZERO:
  1112.       FPrintf(fout, "%02lx", lo);
  1113.       break;
  1114.  
  1115.     case A_ZEROX:
  1116.       FPrintf(fout, "%02lx,x", lo);
  1117.       break;
  1118.  
  1119.     case A_ZEROY:
  1120.       FPrintf(fout, "%02lx,y", lo);
  1121.       break;
  1122.  
  1123.     case A_ABS:
  1124.       FPrintf(fout, "%04lx", (hi << 8) | lo);
  1125.       break;
  1126.  
  1127.     case A_ABSX:
  1128.       FPrintf(fout, "%04lx,x", (hi << 8) | lo);
  1129.       break;
  1130.  
  1131.     case A_ABSY:
  1132.       FPrintf(fout, "%04lx,y", (hi << 8) | lo);
  1133.       break;
  1134.  
  1135.     case A_IND:
  1136.       FPrintf(fout, "(%04lx)", (hi << 8) | lo);
  1137.       break;
  1138.  
  1139.     case A_INDX:
  1140.       FPrintf(fout, "(%02lx,x)", lo);
  1141.       break;
  1142.  
  1143.     case A_INDY:
  1144.       FPrintf(fout, "(%02lx),y", lo);
  1145.       break;
  1146.   }
  1147.  
  1148.   FPutC(fout, '\n');
  1149.   return adr_length[mode];
  1150. }
  1151.  
  1152.  
  1153. /*
  1154.  *  Assemblieren
  1155.  *  a [start]
  1156.  */
  1157.  
  1158. void assemble(void)
  1159. {
  1160.   BOOL done = FALSE;
  1161.   char c1, c2, c3;
  1162.   char mnem, mode;
  1163.   UBYTE opcode;
  1164.   UWORD arg;
  1165.   WORD rel;
  1166.  
  1167.   // Parameter lesen
  1168.   if (!address_args())
  1169.     return;
  1170.  
  1171.   do {
  1172.     FPrintf(fout, "%04lx> ", address);
  1173.     read_line();
  1174.  
  1175.     c1 = ToLower(get_char());
  1176.     c2 = ToLower(get_char());
  1177.     c3 = ToLower(get_char());
  1178.  
  1179.     if (c1 != '\n') {
  1180.  
  1181.       if ((mnem = find_mnemonic(c1, c2, c3)) != M_ILLEGAL) {
  1182.  
  1183.         get_token();
  1184.         if (instr_args(&arg, &mode)) {
  1185.  
  1186.           // Ggf. A_IMPL -> A_ACCU
  1187.           if ((mode == A_IMPL) && find_opcode(mnem, A_ACCU, &opcode))
  1188.             mode = A_ACCU;
  1189.  
  1190.           // Relative Adressierung getrennt behandeln
  1191.           if (((mode == A_ABS) || (mode == A_ZERO)) && find_opcode(mnem, A_REL, &opcode)) {
  1192.             mode = A_REL;
  1193.             rel = arg - (address + 2) & 0xffff;
  1194.             if ((rel < -128) || (rel > 127)) {
  1195.               error("Branch too long");
  1196.               continue;
  1197.             } else
  1198.               arg = rel & 0xff;
  1199.           }
  1200.  
  1201.           if (find_opcode(mnem, mode, &opcode)) {
  1202.  
  1203.             // Disassemblierte Zeile ausgeben
  1204.             FPrintf(fout, "\v%04lx:", address);
  1205.             disass_line(address, opcode, arg & 0xff, arg >> 8);
  1206.  
  1207.             switch (adr_length[mode]) {
  1208.               case 1:
  1209.                 SAMWriteByte(address++, opcode);
  1210.                 break;
  1211.  
  1212.               case 2:
  1213.                 SAMWriteByte(address++, opcode);
  1214.                 SAMWriteByte(address++, arg);
  1215.                 break;
  1216.  
  1217.               case 3:
  1218.                 SAMWriteByte(address++, opcode);
  1219.                 SAMWriteByte(address++, arg & 0xff);
  1220.                 SAMWriteByte(address++, arg >> 8);
  1221.                 break;
  1222.  
  1223.               default:
  1224.                 error("Internal error");
  1225.                 break;
  1226.             }
  1227.  
  1228.           } else    // Adressierungsart paßt nicht zum Befehl
  1229.             error("Addressing mode not supported by instruction");
  1230.  
  1231.         } else    // Nicht erkannte Adressierungsart
  1232.           error("Unrecognized addressing mode");
  1233.  
  1234.       } else        // Mnemonic nicht gefunden
  1235.         error("Unknown instruction");
  1236.  
  1237.     } else            // Leerzeile beendet die Eingabe
  1238.       done = TRUE;
  1239.   } while (!done);
  1240. }
  1241.  
  1242.  
  1243. /*
  1244.  *  Zu drei Buchstaben den passenden Mnemonic-Code finden
  1245.  *  M_ILLEGAL: Kein passendes Mnemonic gefunden
  1246.  */
  1247.  
  1248. char find_mnemonic(char op1, char op2, char op3)
  1249. {
  1250.   int i;
  1251.   char c1, c2, c3;
  1252.  
  1253.   for (i=0; i<M_MAXIMUM; i++)
  1254.     if ((mnem_1[i] == op1) && (mnem_2[i] == op2) && (mnem_3[i] == op3))
  1255.       return i;
  1256.  
  1257.   return M_ILLEGAL;
  1258. }
  1259.  
  1260.  
  1261. /*
  1262.  *  Opcode eines Befehls ermitteln, Mnemonic und Adressierungsart gegeben
  1263.  *  TRUE: OK, FALSE: Mnemonic kommt mit dieser Adressierungsart nicht vor
  1264.  */
  1265.  
  1266. BOOL find_opcode(char mnem, char mode, UBYTE *opcode)
  1267. {
  1268.   int i;
  1269.  
  1270.   for (i=0; i<256; i++)
  1271.     if ((mnemonic[i] == mnem) && (adr_mode[i] == mode)) {
  1272.       *opcode = i;
  1273.       return TRUE;
  1274.     }
  1275.  
  1276.   return FALSE;
  1277. }
  1278.  
  1279.  
  1280. /*
  1281.  *  Speicherkonfiguration anzeigen/setzen
  1282.  *  k [config]
  1283.  */
  1284.  
  1285. void mem_config(void)
  1286. {
  1287.   UWORD con;
  1288.  
  1289.   if (the_token != T_END)
  1290.     if (!expression(&con))
  1291.       return;
  1292.     else
  1293.       SAMMemConfig = con;
  1294.   else
  1295.     con = SAMMemConfig;
  1296.  
  1297.   FPrintf(fout, "Configuration: %ld\n", con & 7);
  1298.   FPrintf(fout, "A000-BFFF: %s\n", (con & 3) == 3 ? "Basic" : "RAM");
  1299.   FPrintf(fout, "D000-DFFF: %s\n", (con & 3) ? ((con & 4) ? "I/O" : "Char") : "RAM");
  1300.   FPrintf(fout, "E000-FFFF: %s\n", (con & 2) ? "Kernal" : "RAM");
  1301. }
  1302.  
  1303.  
  1304. /*
  1305.  *  Füllen
  1306.  *  k start end byte
  1307.  */
  1308.  
  1309. void fill(void)
  1310. {
  1311.   BOOL done = FALSE;
  1312.   UWORD adr, end_adr, value;
  1313.  
  1314.   if (!expression(&adr))
  1315.     return;
  1316.   if (!expression(&end_adr))
  1317.     return;
  1318.   if (!expression(&value))
  1319.     return;
  1320.  
  1321.   do {
  1322.     if (adr == end_adr) done = TRUE;
  1323.  
  1324.     SAMWriteByte(adr++, value);
  1325.   } while (!done);
  1326. }
  1327.  
  1328.  
  1329. /*
  1330.  *  Vergleichen
  1331.  *  c start end dest
  1332.  */
  1333.  
  1334. void compare(void)
  1335. {
  1336.   BOOL done = FALSE;
  1337.   UWORD adr, end_adr, dest;
  1338.   int num = 0;
  1339.  
  1340.   if (!expression(&adr))
  1341.     return;
  1342.   if (!expression(&end_adr))
  1343.     return;
  1344.   if (!expression(&dest))
  1345.     return;
  1346.  
  1347.   do {
  1348.     if (adr == end_adr) done = TRUE;
  1349.  
  1350.     if (SAMReadByte(adr) != SAMReadByte(dest)) {
  1351.       FPrintf(fout, "%04lx ", adr);
  1352.       num++;
  1353.       if (!(num & 7))
  1354.         FPutC(fout, '\n');
  1355.     }
  1356.     adr++; dest++;
  1357.   } while (!done && !aborted());
  1358.  
  1359.   if (num & 7)
  1360.     FPutC(fout, '\n');
  1361.   FPrintf(fout, "%ld byte(s) different\n", num);
  1362. }
  1363.  
  1364.  
  1365. /*
  1366.  *  Kopieren
  1367.  *  t start end dest
  1368.  */
  1369.  
  1370. void transfer(void)
  1371. {
  1372.   BOOL done = FALSE;
  1373.   UWORD adr, end_adr, dest;
  1374.  
  1375.   if (!expression(&adr))
  1376.     return;
  1377.   if (!expression(&end_adr))
  1378.     return;
  1379.   if (!expression(&dest))
  1380.     return;
  1381.  
  1382.   if (dest < adr)
  1383.     do {
  1384.       if (adr == end_adr) done = TRUE;
  1385.       SAMWriteByte(dest++,SAMReadByte(adr++));
  1386.     } while (!done);
  1387.   else {
  1388.     dest += end_adr - adr;
  1389.     do {
  1390.       if (adr == end_adr) done = TRUE;
  1391.       SAMWriteByte(dest--,SAMReadByte(end_adr--));
  1392.     } while (!done);
  1393.   }
  1394. }
  1395.  
  1396.  
  1397. /*
  1398.  *  Speicher ändern
  1399.  *  : addr {byte}
  1400.  */
  1401.  
  1402. void modify(void)
  1403. {
  1404.   UWORD adr, val;
  1405.  
  1406.   if (!expression(&adr))
  1407.     return;
  1408.  
  1409.   while (the_token != T_END)
  1410.     if (expression(&val))
  1411.       SAMWriteByte(adr++, val);
  1412.     else
  1413.       return;
  1414. }
  1415.  
  1416.  
  1417. /*
  1418.  *  Ausdruck berechnen und anzeigen
  1419.  *  ? expression
  1420.  */
  1421.  
  1422. void print_expr(void)
  1423. {
  1424.   UWORD val;
  1425.  
  1426.   if (!expression(&val))
  1427.     return;
  1428.  
  1429.   FPrintf(fout, "Hex: %04lx\nDec: %lu\n", val, val);
  1430. }
  1431.  
  1432.  
  1433. /*
  1434.  *  Ausgabe umleiten
  1435.  *  o [file]
  1436.  */
  1437.  
  1438. void redir_output(void)
  1439. {
  1440.   char c;
  1441.   char filename[INPUT_LENGTH];
  1442.   char *p = filename;
  1443.  
  1444.   // Alte Datei schließen
  1445.   if (fout != ferr) {
  1446.     Close(fout);
  1447.     fout = ferr;
  1448.     return;
  1449.   }
  1450.  
  1451.   // Leerzeichen überspringen
  1452.   while ((c = get_char()) == ' ') ;
  1453.  
  1454.   if (c == '\n')
  1455.     return;
  1456.  
  1457.   do {
  1458.     *p++ = c;
  1459.   } while ((c = get_char()) != '\n');
  1460.   *p++ = 0;
  1461.  
  1462.   if (!(fout = Open(filename, MODE_NEWFILE)))
  1463.     error("Unable to open file");
  1464. }
  1465.  
  1466.  
  1467. /*
  1468.  *  Interrupt-Vektoren anzeigen
  1469.  */
  1470.  
  1471. void int_vectors(void)
  1472. {
  1473.   FPuts(fout, "        IRQ  BRK  NMI\n");
  1474.   FPrintf(fout, "6510  : %04lx %04lx %04lx\n",
  1475.     SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe),
  1476.     SAMReadByte(0xffff) << 8 | SAMReadByte(0xfffe),
  1477.     SAMReadByte(0xfffb) << 8 | SAMReadByte(0xfffa));
  1478.  
  1479.   if (SAMMemConfig & 2)
  1480.     FPrintf(fout, "Kernal: %04lx %04lx %04lx\n",
  1481.       SAMReadByte(0x0315) << 8 | SAMReadByte(0x0314),
  1482.       SAMReadByte(0x0317) << 8 | SAMReadByte(0x0316),
  1483.       SAMReadByte(0x0319) << 8 | SAMReadByte(0x0318));
  1484. }
  1485.  
  1486.  
  1487. /*
  1488.  *  Zustand der Customchips anzeigen
  1489.  */
  1490.  
  1491. void view_state(void)
  1492. {
  1493.   switch (get_char()) {
  1494.     case 'c':        // CIA
  1495.       view_cia_state();
  1496.       break;
  1497.  
  1498.     case 's':        // SID
  1499.       view_sid_state();
  1500.       break;
  1501.  
  1502.     case 'v':        // VIC
  1503.       view_vic_state();
  1504.       break;
  1505.  
  1506.     default:
  1507.       error("Unknown command");
  1508.       break;
  1509.   }
  1510. }
  1511.  
  1512. void view_cia_state(void)
  1513. {
  1514.   CIADump cd;
  1515.  
  1516.   switch (get_char()) {
  1517.     case '1':
  1518.       GetCIA1Dump(&cd);
  1519.       break;
  1520.     case '2':
  1521.       GetCIA2Dump(&cd);
  1522.       break;
  1523.     default:
  1524.       error("Unknown command");
  1525.       return;
  1526.   }
  1527.  
  1528.   FPrintf(fout, "Timer A  : %s\n", cd.cra & 1 ? "On" : "Off");
  1529.   FPrintf(fout, " Counter : %04lx  Latch: %04lx\n", (cd.ta_hi << 8) | cd.ta_lo, (cd.ltcha_hi << 8) | cd.ltcha_lo);
  1530.   FPrintf(fout, " Run mode: %s\n", cd.cra & 8 ? "One-shot" : "Continuous");
  1531.   FPrintf(fout, " Input   : %s\n", cd.cra & 0x20 ? "CNT" : "ø2");
  1532.   FPuts(fout, " Output  : ");
  1533.   if (cd.cra & 4)
  1534.     if (cd.cra & 8)
  1535.       FPuts(fout, "PB6 Toggle\n\n");
  1536.     else
  1537.       FPuts(fout, "PB6 Pulse\n\n");
  1538.   else
  1539.     FPuts(fout, "None\n\n");
  1540.  
  1541.   FPrintf(fout, "Timer B  : %s\n", cd.crb & 1 ? "On" : "Off");
  1542.   FPrintf(fout, " Counter : %04lx  Latch: %04lx\n", (cd.tb_hi << 8) | cd.tb_lo, (cd.ltchb_hi << 8) | cd.ltchb_lo);
  1543.   FPrintf(fout, " Run mode: %s\n", cd.crb & 8 ? "One-shot" : "Continuous");
  1544.   FPuts(fout, " Input   : ");
  1545.   if (cd.crb & 0x40)
  1546.     if (cd.crb & 0x20)
  1547.       FPuts(fout, "Timer A underflow (CNT high)\n");
  1548.     else
  1549.       FPuts(fout, "Timer A underflow\n");
  1550.   else
  1551.     if (cd.crb & 0x20)
  1552.       FPuts(fout, "CNT\n");
  1553.     else
  1554.       FPuts(fout, "ø2\n");
  1555.   FPuts(fout, " Output  : ");
  1556.   if (cd.crb & 4)
  1557.     if (cd.crb & 8)
  1558.       FPuts(fout, "PB7 Toggle\n\n");
  1559.     else
  1560.       FPuts(fout, "PB7 Pulse\n\n");
  1561.   else
  1562.     FPuts(fout, "None\n\n");
  1563.  
  1564.   FPrintf(fout, "TOD         : %lx%lx:%lx%lx:%lx%lx.%lx %s\n",
  1565.     (cd.tod_hr >> 4) & 1, cd.tod_hr & 0x0f,
  1566.     (cd.tod_min >> 4) & 7, cd.tod_min & 0x0f,
  1567.     (cd.tod_sec >> 4) & 7, cd.tod_sec & 0x0f,
  1568.     cd.tod_10ths & 0x0f, cd.tod_hr & 0x80 ? "PM" : "AM");
  1569.   FPrintf(fout, "Alarm       : %lx%lx:%lx%lx:%lx%lx.%lx %s\n",
  1570.     (cd.alm_hr >> 4) & 1, cd.alm_hr & 0x0f,
  1571.     (cd.alm_min >> 4) & 7, cd.alm_min & 0x0f,
  1572.     (cd.alm_sec >> 4) & 7, cd.alm_sec & 0x0f,
  1573.     cd.alm_10ths & 0x0f, cd.alm_hr & 0x80 ? "PM" : "AM");
  1574.   FPrintf(fout, "TOD input   : %s\n", cd.cra & 0x80 ? "50Hz" : "60Hz");
  1575.   FPrintf(fout, "Write to    : %s registers\n\n", cd.crb & 0x80 ? "Alarm" : "TOD");
  1576.  
  1577.   FPrintf(fout, "Serial data : %02lx\n", cd.sdr);
  1578.   FPrintf(fout, "Serial mode : %s\n\n", cd.cra & 0x40 ? "Output" : "Input");
  1579.  
  1580.   FPuts(fout, "Pending int.: ");
  1581.   dump_cia_ints(cd.int_data);
  1582.   FPuts(fout, "Enabled int.: ");
  1583.   dump_cia_ints(cd.int_mask);
  1584. }
  1585.  
  1586. void dump_cia_ints(UBYTE int)
  1587. {
  1588.   if (int & 0x1f) {
  1589.     if (int & 1) FPuts(fout, "TA ");
  1590.     if (int & 2) FPuts(fout, "TB ");
  1591.     if (int & 4) FPuts(fout, "Alarm ");
  1592.     if (int & 8) FPuts(fout, "Serial ");
  1593.     if (int & 0x10) FPuts(fout, "Flag");
  1594.   } else
  1595.     FPuts(fout, "None");
  1596.   FPutC(fout, '\n');
  1597. }
  1598.  
  1599. void view_sid_state(void)
  1600. {
  1601.   SIDDump sd;
  1602.  
  1603.   GetSIDDump(&sd);
  1604.  
  1605.   FPuts(fout, "Voice 1\n");
  1606.   FPrintf(fout, " Frequency  : %04lx\n", (sd.freq_hi_1 << 8) | sd.freq_lo_1);
  1607.   FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_1 & 0x0f) << 8) | sd.pw_lo_1);
  1608.   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);
  1609.   FPuts(fout, " Waveform   : ");
  1610.   dump_sid_waveform(sd.ctrl_1);
  1611.   FPrintf(fout, " Gate       : %s  Ring mod.: %s\n", sd.ctrl_1 & 0x01 ? "On " : "Off", sd.ctrl_1 & 0x04 ? "On" : "Off");
  1612.   FPrintf(fout, " Test bit   : %s  Synchron.: %s\n", sd.ctrl_1 & 0x08 ? "On " : "Off", sd.ctrl_1 & 0x02 ? "On" : "Off");
  1613.   FPrintf(fout, " Filter     : %s\n", sd.res_filt & 0x01 ? "On" : "Off");
  1614.  
  1615.   FPuts(fout, "\nVoice 2\n");
  1616.   FPrintf(fout, " Frequency  : %04lx\n", (sd.freq_hi_2 << 8) | sd.freq_lo_2);
  1617.   FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_2 & 0x0f) << 8) | sd.pw_lo_2);
  1618.   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);
  1619.   FPuts(fout, " Waveform   : ");
  1620.   dump_sid_waveform(sd.ctrl_2);
  1621.   FPrintf(fout, " Gate       : %s  Ring mod.: %s\n", sd.ctrl_2 & 0x01 ? "On " : "Off", sd.ctrl_2 & 0x04 ? "On" : "Off");
  1622.   FPrintf(fout, " Test bit   : %s  Synchron.: %s\n", sd.ctrl_2 & 0x08 ? "On " : "Off", sd.ctrl_2 & 0x02 ? "On" : "Off");
  1623.   FPrintf(fout, " Filter     : %s\n", sd.res_filt & 0x02 ? "On" : "Off");
  1624.  
  1625.   FPuts(fout, "\nVoice 3\n");
  1626.   FPrintf(fout, " Frequency  : %04lx\n", (sd.freq_hi_3 << 8) | sd.freq_lo_3);
  1627.   FPrintf(fout, " Pulse Width: %04lx\n", ((sd.pw_hi_3 & 0x0f) << 8) | sd.pw_lo_3);
  1628.   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);
  1629.   FPuts(fout, " Waveform   : ");
  1630.   dump_sid_waveform(sd.ctrl_3);
  1631.   FPrintf(fout, " Gate       : %s  Ring mod.: %s\n", sd.ctrl_3 & 0x01 ? "On " : "Off", sd.ctrl_3 & 0x04 ? "On" : "Off");
  1632.   FPrintf(fout, " Test bit   : %s  Synchron.: %s\n", sd.ctrl_3 & 0x08 ? "On " : "Off", sd.ctrl_3 & 0x02 ? "On" : "Off");
  1633.   FPrintf(fout, " Filter     : %s  Mute     : %s\n", sd.res_filt & 0x04 ? "On" : "Off", sd.mode_vol & 0x80 ? "Yes" : "No");
  1634.  
  1635.   FPuts(fout, "\nFilters/Volume\n");
  1636.   FPrintf(fout, " Frequency: %04lx\n", (sd.fc_hi << 3) | (sd.fc_lo & 0x07));
  1637.   FPrintf(fout, " Resonance: %lx\n", sd.res_filt >> 4);
  1638.   FPuts(fout, " Mode     : ");
  1639.   if (sd.mode_vol & 0x70) {
  1640.     if (sd.mode_vol & 0x10) FPuts(fout, "Low-pass ");
  1641.     if (sd.mode_vol & 0x20) FPuts(fout, "Band-pass ");
  1642.     if (sd.mode_vol & 0x40) FPuts(fout, "High-pass");
  1643.   } else
  1644.     FPuts(fout, "None");
  1645.   FPrintf(fout, "\n Volume   : %lx\n", sd.mode_vol & 0x0f);
  1646. }
  1647.  
  1648. void dump_sid_waveform(UBYTE wave)
  1649. {
  1650.   if (wave & 0xf0) {
  1651.     if (wave & 0x10) FPuts(fout, "Triangle ");
  1652.     if (wave & 0x20) FPuts(fout, "Sawtooth ");
  1653.     if (wave & 0x40) FPuts(fout, "Rectangle ");
  1654.     if (wave & 0x80) FPuts(fout, "Noise");
  1655.   } else
  1656.     FPuts(fout, "None");
  1657.   FPutC(fout, '\n');
  1658. }
  1659.  
  1660. void view_vic_state(void)
  1661. {
  1662.   VICDump vd;
  1663.   short i;
  1664.  
  1665.   GetVICDump(&vd);
  1666.  
  1667.   FPrintf(fout, "Raster line       : %04lx\n", vd.raster | ((vd.ctrl1 & 0x80) << 1));
  1668.   FPrintf(fout, "IRQ raster line   : %04lx\n\n", vd.irq_raster);
  1669.  
  1670.   FPrintf(fout, "X scroll          : %ld\n", vd.ctrl2 & 7);
  1671.   FPrintf(fout, "Y scroll          : %ld\n", vd.ctrl1 & 7);
  1672.   FPrintf(fout, "Horizontal border : %ld columns\n", vd.ctrl2 & 8 ? 40 : 38);
  1673.   FPrintf(fout, "Vertical border   : %ld rows\n\n", vd.ctrl1 & 8 ? 25 : 24);
  1674.  
  1675.   FPuts(fout, "Display mode      : ");
  1676.   switch (((vd.ctrl1 >> 5) & 3) | ((vd.ctrl2 >> 2) & 4)) {
  1677.     case 0:
  1678.       FPuts(fout, "Standard text\n");
  1679.       break;
  1680.     case 1:
  1681.       FPuts(fout, "Multicolor text\n");
  1682.       break;
  1683.     case 2:
  1684.       FPuts(fout, "Standard bitmap\n");
  1685.       break;
  1686.     case 3:
  1687.       FPuts(fout, "Multicolor bitmap\n");
  1688.       break;
  1689.     case 4:
  1690.       FPuts(fout, "ECM text\n");
  1691.       break;
  1692.     case 5:
  1693.       FPuts(fout, "Invalid text (ECM+MCM)\n");
  1694.       break;
  1695.     case 6:
  1696.       FPuts(fout, "Invalid bitmap (ECM+BMM)\n");
  1697.       break;
  1698.     case 7:
  1699.       FPuts(fout, "Invalid bitmap (ECM+BMM+ECM)\n");
  1700.       break;
  1701.   }
  1702.   FPrintf(fout, "Sequencer state   : %s\n", vd.idle_state ? "Idle" : "Display");
  1703.   FPrintf(fout, "Bad line state    : %s\n", vd.bad_line ? "Yes" : "No");
  1704.   FPrintf(fout, "Bad lines enabled : %s\n", vd.bad_line_enable ? "Yes" : "No");
  1705.   FPrintf(fout, "Video counter     : %04lx\n", vd.vc);
  1706.   FPrintf(fout, "Video counter base: %04lx\n", vd.vcbase);
  1707.   FPrintf(fout, "Row counter       : %ld\n\n", vd.rc);
  1708.  
  1709.   FPrintf(fout, "VIC bank          : %04lx-%04lx\n", vd.bank_base, vd.bank_base + 0x3fff);
  1710.   FPrintf(fout, "Video matrix base : %04lx\n", vd.matrix_base);
  1711.   FPrintf(fout, "Character base    : %04lx\n", vd.char_base);
  1712.   FPrintf(fout, "Bitmap base       : %04lx\n\n", vd.bitmap_base);
  1713.  
  1714.   FPrintf(fout, "         Spr.0  Spr.1  Spr.2  Spr.3  Spr.4  Spr.5  Spr.6  Spr.7\n");
  1715.   FPuts(fout, "Enabled: "); dump_spr_flags(vd.me);
  1716.   FPrintf(fout, "Data   : %04lx   %04lx   %04lx   %04lx   %04lx   %04lx   %04lx   %04lx\n",
  1717.     vd.sprite_base[0], vd.sprite_base[1], vd.sprite_base[2], vd.sprite_base[3],
  1718.     vd.sprite_base[4], vd.sprite_base[5], vd.sprite_base[6], vd.sprite_base[7]);
  1719.   FPrintf(fout, "MC     : %02lx     %02lx     %02lx     %02lx     %02lx     %02lx     %02lx     %02lx\n",
  1720.     vd.mc[0], vd.mc[1], vd.mc[2], vd.mc[3], vd.mc[4], vd.mc[5], vd.mc[6], vd.mc[7]);
  1721.  
  1722.   FPuts(fout, "Mode   : ");
  1723.   for (i=0; i<8; i++)
  1724.     if (vd.mmc & (1<<i))
  1725.       FPuts(fout, "Multi  ");
  1726.     else
  1727.       FPuts(fout, "Std.   ");
  1728.  
  1729.   FPuts(fout, "\nX-Exp. : "); dump_spr_flags(vd.mxe);
  1730.   FPuts(fout, "Y-Exp. : "); dump_spr_flags(vd.mye);
  1731.  
  1732.   FPuts(fout, "Prio.  : ");
  1733.   for (i=0; i<8; i++)
  1734.     if (vd.mdp & (1<<i))
  1735.       FPuts(fout, "Back   ");
  1736.     else
  1737.       FPuts(fout, "Fore   ");
  1738.  
  1739.   FPuts(fout, "\n\nPending interrupts: ");
  1740.   dump_vic_ints(vd.irq_flag);
  1741.   FPuts(fout, "Enabled interrupts: ");
  1742.   dump_vic_ints(vd.irq_mask);
  1743. }
  1744.  
  1745. void dump_spr_flags(UBYTE f)
  1746. {
  1747.   short i;
  1748.  
  1749.   for (i=0; i<8; i++)
  1750.     if (f & (1<<i))
  1751.       FPuts(fout, "Yes    ");
  1752.     else
  1753.       FPuts(fout, "No     ");
  1754.  
  1755.   FPutC(fout, '\n');
  1756. }
  1757.  
  1758. void dump_vic_ints(UBYTE int)
  1759. {
  1760.   if (int & 0x1f) {
  1761.     if (int & 1) FPuts(fout, "Raster ");
  1762.     if (int & 2) FPuts(fout, "Spr-Data ");
  1763.     if (int & 4) FPuts(fout, "Spr-Spr ");
  1764.     if (int & 8) FPuts(fout, "Lightpen");
  1765.   } else
  1766.     FPuts(fout, "None");
  1767.   FPutC(fout, '\n');
  1768. }
  1769.