home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / debugger.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  30.9 KB  |  1,455 lines

  1.  
  2. /*
  3.     ==========
  4.     DEBUGGER.C
  5.     ==========
  6. */
  7.  
  8.  
  9. #include <stdio.h>
  10.  
  11. #include "v9t9_common.h"
  12. #include "9900.h"
  13. #include "9900st.h"
  14. #include "memory.h"
  15. #include "vdp.h"
  16. #include "grom.h"
  17. #include "speech.h"
  18. #include "system.h"
  19. #include "debugger.h"
  20.  
  21. #define _L LOG_CPU
  22.  
  23. static char *
  24. decR(char *buf, int val)
  25. {
  26.     *buf++ = 'R';
  27.     if (val >= 10) {
  28.         *buf++ = '1';
  29.         val -= 10;
  30.     }
  31.     *buf++ = (val + '0');
  32.     return buf;
  33. }
  34.  
  35. #define NO_DOMAIN    (mem_domain)(-1)
  36.  
  37. static Memory views[MEMORY_VIEW_COUNT];
  38. int debugger_memory_view_size[MEMORY_VIEW_COUNT] = { 16, 16, 16, 16, 16 };
  39. bool debugger_operand_view_verbose = true;
  40.  
  41. static u16 register_view;
  42.  
  43. static void
  44. instruction_decode(u16 op, u16 pc, u16 wp, u16 st,
  45.                    Instruction *ins);
  46.  
  47. static      u8
  48. MEMORY_READ_MM_BYTE(u16 x)
  49. {
  50.     x &= 0x9c02;
  51.  
  52.     return x == 0x8800 ? domain_read_byte(md_video, vdp_mmio_get_addr()) :
  53.         x == 0x8802 ? vdp_mmio_get_status() :
  54.         x == 0x9000 ? domain_read_byte(md_speech, speech_mmio_get_addr()) :
  55.         x == 0x9800 ? domain_read_byte(md_graphics, grom_mmio_get_addr()) :
  56.         x == 0x9802 ? grom_mmio_get_addr_byte() : 
  57.         0;
  58. }
  59.  
  60. #define flatmem(x)         (byteop ? flatmem8(x)&0xff : flatmem16(x)&0xffff)
  61. #define flatmem8(x)     (((x)>=0x8400 && (x)<0xa000 ? MEMORY_READ_MM_BYTE(x) : memory_read_byte(x))&0xff)
  62. #define flatmem16(x)     (((x)>=0x8400 && (x)<0xa000 ? MEMORY_READ_MM_BYTE(x)<<8 : memory_read_word(x))&0xffff)
  63.  
  64. /*
  65.  *    Complete an operand by fixing up val and ea as needed.
  66.  *
  67.  *    addr is the address of the PC.
  68.  */
  69. static void
  70. operand_complete(Operand *op, u16 *addr)
  71. {
  72.     switch (op->type)
  73.     {
  74.     case OP_NONE:    
  75.         break;
  76.     case OP_REG:    // Rx
  77.         op->ea = (op->val<<1) + wp;
  78.         break;
  79.     case OP_IND:    // *Rx
  80.     case OP_INC:    // *Rx+
  81.         op->ea = flatmem16((op->val<<1) + wp);
  82.         break;
  83.     case OP_ADDR:    // @>xxxx or @>xxxx(Rx)
  84.         op->ea = op->immed = MEMORY_READ_WORD(*addr); *addr += 2;
  85.         if (op->val != 0) {
  86.             op->ea += flatmem16((op->val<<1) + wp);
  87.         }
  88.         break;
  89.     case OP_IMMED:    // immediate
  90.         op->ea = *addr;
  91.         op->immed = MEMORY_READ_WORD(*addr); *addr += 2;
  92.         break;
  93.     case OP_CNT:    // shift count
  94.         break;
  95.     case OP_OFFS:    // offset from R12
  96.         op->ea = flatmem16((12<<1) + wp) + op->val;
  97.         break;
  98.     case OP_JUMP:    // jump target
  99.         op->val <<= 1;                // byte -> word
  100.         op->ea = op->val + *addr;
  101.         break;
  102.     case OP_STATUS:    // status word
  103.         break;
  104.     case OP_INST:
  105.         break;        // can't handle here
  106.     }
  107. }
  108.  
  109. /*
  110.  *    Print out an operand into a disassembler operand
  111.  */
  112. char *
  113. debugger_instruction_operand_print(Operand *op, char *buffer)
  114. {
  115.     switch (op->type) 
  116.     {
  117.     case OP_REG:
  118.         sprintf(buffer, "R%d", op->val);
  119.         break;
  120.  
  121.     case OP_IND:
  122.         sprintf(buffer, "*R%d", op->val);
  123.         break;
  124.  
  125.     case OP_ADDR:
  126.         if (op->val == 0) {
  127.             sprintf(buffer, "@>%04X", op->immed);
  128.         } else {
  129.             sprintf(buffer, "@>%04X(R%d)", op->immed, op->val);
  130.         }
  131.         break;
  132.  
  133.     case OP_INC:
  134.         sprintf(buffer, "*R%d+", op->val);
  135.         break;
  136.  
  137.     case OP_IMMED:
  138.         sprintf(buffer, ">%04X", op->immed);
  139.         break;
  140.  
  141.     case OP_CNT:
  142.         sprintf(buffer, "%d", op->val);
  143.         break;
  144.  
  145.     case OP_OFFS:
  146.         sprintf(buffer, ">%s%02X",
  147.                 (op->val & 0x8000) ? "-" : "", 
  148.                 (op->val & 0x8000) ? -op->val : op->val);
  149.         break;
  150.  
  151.     case OP_JUMP:
  152.         sprintf(buffer, "$+>%04X", op->val);
  153.         break;
  154.  
  155.     case OP_STATUS:        // not real operands
  156.     case OP_INST:        
  157.     default:
  158.         return 0L;
  159.     }
  160.  
  161.     return buffer;
  162. }
  163.  
  164. /*
  165.  *    Print value of operand to buffer
  166.  *
  167.  *    verbose==true means to print extra info
  168.  *    after==true means this operand as the destination of 
  169.  *    previous instruction
  170.  */
  171. char *
  172. debugger_operand_value_print(Instruction *inst, Operand *op, 
  173.                              bool verbose, bool after, 
  174.                              char *buffer)
  175. {
  176.     const char *equ = after ? ":=" : "=";
  177.  
  178.     // is operand not a destination?
  179.     if (after && !op->dest)
  180.         return NULL;
  181.  
  182.     // if source operand is killed, we don't care to see it
  183.     if (!after && op->dest == OP_DEST_KILLED)
  184.         return NULL;
  185.  
  186.     // ignore this operand?
  187.     if (op->ignore)
  188.         return NULL;
  189.  
  190.     switch (op->type) 
  191.     {
  192.     case OP_REG:
  193.         if (inst->opcode >= 0x3800 && inst->opcode < 0x3C00)
  194.         {
  195.             // MPY uses two adjacent registers
  196.             if (after)
  197.                 if (verbose)
  198.                     sprintf(buffer, "R%d,R%d%s>%04X%04X",
  199.                             op->val, op->val+1, equ,
  200.                             flatmem16(op->ea), 
  201.                             flatmem16(op->ea + 2));
  202.                 else
  203.                     sprintf(buffer, ">%04X%04X",
  204.                             flatmem16(op->ea), 
  205.                             flatmem16(op->ea + 2));
  206.             else
  207.                 if (verbose)
  208.                     sprintf(buffer, "R%d%s>%04X", 
  209.                             op->val, equ, flatmem16(op->ea));
  210.                 else
  211.                     sprintf(buffer, ">%04X", flatmem16(op->ea));
  212.         }
  213.         else if (inst->opcode >= 0x3C00 && inst->opcode < 0x4000)
  214.         {
  215.             // DIV uses two adjacent registers
  216.             if (!after)
  217.                 if (verbose)
  218.                     sprintf(buffer, "R%d,R%d%s>%04X%04X",
  219.                             op->val, op->val+1, equ,
  220.                             flatmem16(op->ea), 
  221.                             flatmem16(op->ea + 2));
  222.                 else
  223.                     sprintf(buffer, ">%04X%04X",
  224.                             flatmem16(op->ea), 
  225.                             flatmem16(op->ea + 2));
  226.  
  227.             else
  228.                 if (verbose)
  229.                     sprintf(buffer, "qR%d%s>%04X,rR%d%s>%04X",
  230.                             op->val, equ, flatmem16(op->ea),
  231.                             op->val+1, equ, flatmem16(op->ea + 2));
  232.                 else
  233.                     sprintf(buffer, "Q>%04X R>%04X",
  234.                             flatmem16(op->ea),
  235.                             flatmem16(op->ea + 2));
  236.         }
  237.         else
  238.         {
  239.             if (op->byteop)
  240.                 if (verbose)
  241.                     sprintf(buffer, "R%d%s>%02X", 
  242.                             op->val, equ, flatmem8(op->ea));
  243.                 else
  244.                     sprintf(buffer, ">%02X", flatmem8(op->ea));
  245.             else
  246.                 if (verbose)
  247.                     sprintf(buffer, "R%d%s>%04X", 
  248.                             op->val, equ, flatmem16(op->ea));
  249.                 else
  250.                     sprintf(buffer, ">%04X", flatmem16(op->ea));
  251.         }
  252.         break;
  253.  
  254.     case OP_INC:
  255.     case OP_IND:
  256.         if (after) 
  257.         {
  258.             if (op->byteop)
  259.                 if (verbose)
  260.                     sprintf(buffer, "R%d%s>%02X", 
  261.                             op->val, equ, flatmem8(op->ea));
  262.                 else
  263.                     sprintf(buffer, ">%02X", flatmem8(op->ea));
  264.             else 
  265.                 if (verbose)
  266.                     sprintf(buffer, "R%d%s>%04X", 
  267.                             op->val, equ, flatmem16(op->ea));
  268.                 else
  269.                     sprintf(buffer, ">%04X", flatmem16(op->ea));
  270.             break;
  271.         }
  272.         // else show address
  273.  
  274.     case OP_ADDR:
  275.         if (op->byteop)
  276.             if (verbose)
  277.                 // if address points to a register, point this out
  278.                 if (op->ea >= inst->wp && op->ea < inst->wp+32)
  279.                     sprintf(buffer, "%c%d%s>%02X", 
  280.                             (op->ea&1) ? 'r' : 'R', // low or high byte
  281.                             (op->ea - inst->wp)>>1,
  282.                             equ,
  283.                             flatmem8(op->ea));
  284.                 else
  285.                     sprintf(buffer, ">%04X%s>%02X", 
  286.                             op->ea, equ,
  287.                             flatmem8(op->ea));
  288.             else
  289.                 sprintf(buffer, ">%02X", flatmem8(op->ea));
  290.         else
  291.             if (verbose)
  292.                 // if address points to a register, point this out
  293.                 if (op->ea >= inst->wp && op->ea < inst->wp+32)
  294.                     sprintf(buffer, "R%d%s>%04X", 
  295.                             (op->ea - inst->wp)>>1,
  296.                             equ,
  297.                             flatmem16(op->ea));
  298.                 else
  299.                     sprintf(buffer, ">%04X%s>%04X", 
  300.                             op->ea, equ,
  301.                             flatmem16(op->ea));
  302.             else
  303.                 sprintf(buffer, ">%04X", flatmem16(op->ea));
  304.         break;
  305.  
  306. /*
  307.     case OP_IMMED:
  308.         sprintf(buffer, ">%04X",op->immed);
  309.         break;    
  310.  
  311.     case OP_CNT:
  312.         sprintf(buffer, ">%04X",op->val);
  313.         break;
  314. */
  315.  
  316.     case OP_OFFS:
  317.     case OP_JUMP:
  318.         sprintf(buffer, ">%04X",op->ea);
  319.         break;
  320.  
  321.     case OP_STATUS:
  322.         sprintf(buffer, "<%s%s%s%s%s%s%s|%x>",
  323.                        (inst->status&ST_L) ? "L" : "",
  324.                        (inst->status&ST_A) ? "A" : "",
  325.                        (inst->status&ST_E) ? "E" : "",
  326.                        (inst->status&ST_C) ? "C" : "",
  327.                        (inst->status&ST_O) ? "O" : "",
  328.                        (inst->status&ST_P) ? "P" : "",
  329.                        (inst->status&ST_X) ? "X" : "",
  330.                        inst->status&ST_INTLEVEL);
  331.         break;
  332.  
  333.     case OP_INST:
  334.         {
  335.             // sub-instruction!
  336.             Instruction xinst;
  337.             char op1[32], *op1ptr, op2[32], *op2ptr;
  338.             instruction_decode(op->val, 
  339.                                inst->pc, inst->wp, inst->status, 
  340.                                &xinst);
  341.             if (verbose)
  342.             {
  343.                 op1ptr = debugger_instruction_operand_print(&xinst.op1, op1);
  344.                 op2ptr = debugger_instruction_operand_print(&xinst.op2, op2);
  345.                 sprintf(buffer, "(>%04X %s %s%s%s)",
  346.                         xinst.opcode,
  347.                         xinst.name,
  348.                         op1ptr ? op1ptr : "",
  349.                         op2ptr ? "," : "",
  350.                         op2ptr ? op2ptr : "");
  351.             } 
  352.             else
  353.             {
  354.                 sprintf(buffer, "(>%04X %s)",
  355.                         xinst.opcode,
  356.                         xinst.name);
  357.             } 
  358.         }
  359.         break;
  360.  
  361.     default:
  362.         return 0L;
  363.     }
  364.  
  365.     return buffer;
  366. }
  367.  
  368.  
  369. /*
  370.  *    Decode an instruction with opcode 'op' at 'addr'
  371.  *    into 'ins'
  372.  */
  373. static void
  374. instruction_decode(u16 op, u16 pc, u16 wp, u16 st,
  375.                    Instruction *ins)
  376. {
  377.     Instruction    inst;
  378.  
  379.     memset(&inst, 0, sizeof(inst));
  380.  
  381.     inst.opcode = op;
  382.     inst.name = "????";
  383.     inst.op1.type = inst.op2.type = OP_NONE;
  384.  
  385.     inst.pc = pc;
  386.     inst.wp = wp;
  387.     inst.status = st;
  388.  
  389.     // Collect the instruction name
  390.     // and operand structure.
  391.  
  392.     pc += 2;    // point to operands
  393.  
  394.     // Initially, inst.op?.val is incomplete, and is whatever
  395.     // raw data from the opcode we can decode;
  396.     // inst.op?.ea is that of the instruction or immediate
  397.     // if the operand needs it.
  398.    
  399.     // after decoding the instruction, we complete
  400.     // the operand, making inst.op?.val and inst.op?.ea valid.
  401.  
  402.     if (op < 0x200)                // data
  403.     {
  404.         inst.op1.type = OP_IMMED;
  405.         pc -= 2;                  // instruction itself is value
  406.         inst.name = "DATA";
  407.  
  408.     } else if (op < 0x2a0) {
  409.         inst.op1.type = OP_REG;
  410.         inst.op1.val = op & 15;
  411.         inst.op1.dest = true;
  412.         inst.op2.type = OP_IMMED;
  413.         switch ((op & 0x1e0) >> 5) 
  414.         {
  415.         case 0:        inst.name = "LI  ";    
  416.             inst.op1.dest = OP_DEST_KILLED;
  417.             break;
  418.         case 1:        inst.name = "AI  ";    break;
  419.         case 2:        inst.name = "ANDI";    break;
  420.         case 3:        inst.name = "ORI ";    break;
  421.         case 4:        inst.name = "CI  ";    
  422.             inst.op1.dest = false; break;
  423.         }
  424.  
  425.     } else if (op < 0x2e0) {
  426.         inst.op1.type = OP_REG;
  427.         inst.op1.val = op & 15;
  428.         inst.op1.dest = OP_DEST_KILLED;
  429.         switch ((op & 0x1e0) >> 5) 
  430.         {
  431.         case 5:        inst.name = "STWP";    break;
  432.         case 6:        inst.name = "STST";
  433.             inst.op2.type = OP_STATUS;
  434.             inst.op2.val = st;
  435.             break;
  436.         }
  437.  
  438.     } else if (op < 0x320) {
  439.         inst.op1.type = OP_IMMED;
  440.  
  441.         switch ((op & 0x1e0) >> 5) {
  442.         case 7:        inst.name = "LWPI";    break;
  443.         case 8:        inst.name = "LIMI";    break;
  444.         }
  445.  
  446.     } else if (op < 0x400) {
  447.         switch ((op & 0x1e0) >> 5) {
  448.         case 10:    inst.name = "IDLE";    break;
  449.         case 11:    inst.name = "RSET";    break;
  450.         case 12:    inst.name = "RTWP";
  451.             inst.op1.type = OP_STATUS;
  452.             inst.op1.val = st;
  453.             break;
  454.         case 13:    inst.name = "CKON";    break;
  455.         case 14:    inst.name = "CKOF";    break;
  456.         case 15:    inst.name = "LREX";    break;
  457.         }
  458.  
  459.     } else if (op < 0x800) {
  460.         inst.op1.type = (op & 0x30) >> 4;
  461.         inst.op1.val = op & 15;
  462.         inst.op1.dest = true;
  463.  
  464.         switch ((op & 0x3c0) >> 6) 
  465.         {
  466.         case 0:        inst.name = "BLWP";    
  467.             inst.op1.dest = false;
  468.             inst.op1.ignore = true;
  469.             break;
  470.         case 1:        inst.name = "B   ";    
  471.             inst.op1.dest = false;
  472.             inst.op1.ignore = true;
  473.             break;
  474.         case 2:        inst.name = "X   ";
  475.             inst.op1.dest = false;
  476.             inst.op2.type = OP_INST;
  477.             break;
  478.         case 3:        inst.name = "CLR ";    
  479.             inst.op1.dest = OP_DEST_KILLED;
  480.             break;
  481.         case 4:        inst.name = "NEG ";    break;
  482.         case 5:        inst.name = "INV ";    break;
  483.         case 6:        inst.name = "INC ";    break;
  484.         case 7:        inst.name = "INCT";    break;
  485.         case 8:        inst.name = "DEC ";    break;
  486.         case 9:        inst.name = "DECT";    break;
  487.         case 10:    inst.name = "BL  ";    
  488.             inst.op1.dest = false;
  489.             inst.op1.ignore = true;
  490.             break;
  491.         case 11:    inst.name = "SWPB";    break;
  492.         case 12:    inst.name = "SETO";    
  493.             inst.op1.dest = OP_DEST_KILLED;
  494.             break;
  495.         case 13:    inst.name = "ABS ";    break;
  496.         }
  497.  
  498.     } else if (op < 0xc00) {
  499.         inst.op1.type = OP_REG;
  500.         inst.op1.val = op & 15;
  501.         inst.op1.dest = true;
  502.         inst.op2.type = OP_CNT;
  503.         inst.op2.val = (op & 0xf0) >> 4;
  504.  
  505.         // shift of zero comes from R0
  506.         if (inst.op2.val == 0) {
  507.             inst.op2.type = OP_REG;
  508.             inst.op2.val = 0;
  509.         }
  510.  
  511.         switch ((op & 0x700) >> 8) 
  512.         {
  513.         case 0:        inst.name = "SRA ";    break;
  514.         case 1:        inst.name = "SRL ";    break;
  515.         case 2:        inst.name = "SLA ";    break;
  516.         case 3:        inst.name = "SRC ";    break;
  517.         }
  518.  
  519.     } else if (op < 0x1000) {
  520.         switch ((op & 0x7e0) >> 5) {
  521.             // !!! extended instructions
  522.         }
  523.  
  524.     } else if (op < 0x2000) {
  525.         if (op < 0x1d00) {
  526.             inst.op1.type = OP_JUMP;
  527.             inst.op1.val = ((s8) (op & 0xff));
  528.             inst.op2.type = OP_STATUS;
  529.             inst.op2.val = st;
  530.         } else {
  531.             inst.op1.type = OP_OFFS;
  532.             inst.op1.val = ((s8) (op & 0xff));
  533.         }
  534.  
  535.         switch ((op & 0xf00) >> 8) {
  536.         case 0:        inst.name = "JMP ";     break;
  537.         case 1:        inst.name = "JLT ";    break;
  538.         case 2:        inst.name = "JLE ";    break;
  539.         case 3:        inst.name = "JEQ ";    break;
  540.         case 4:        inst.name = "JHE ";    break;
  541.         case 5:        inst.name = "JGT ";    break;
  542.         case 6:        inst.name = "JNE ";    break;
  543.         case 7:        inst.name = "JNC ";    break;
  544.         case 8:        inst.name = "JOC ";    break;
  545.         case 9:        inst.name = "JNO ";    break;
  546.         case 10:    inst.name = "JL  ";    break;
  547.         case 11:    inst.name = "JH  ";    break;
  548.         case 12:    inst.name = "JOP ";    break;
  549.         case 13:    inst.name = "SBO ";    break;
  550.         case 14:    inst.name = "SBZ ";    break;
  551.         case 15:    inst.name = "TB  ";    break;
  552.         }
  553.  
  554.     } else if (op < 0x4000 && !(op >= 0x3000 && op < 0x3800)) {
  555.         inst.op1.type = (op & 0x30) >> 4;
  556.         inst.op1.val = (op & 15);
  557.         inst.op1.dest = false;
  558.         inst.op2.type = OP_REG;
  559.         inst.op2.val = (op & 0x3c0) >> 6;
  560.         inst.op2.dest = true;
  561.  
  562.         switch ((op & 0x1c00) >> 10) {
  563.         case 0:        inst.name = "COC ";    
  564.             inst.op2.dest = false;
  565.             break;
  566.         case 1:        inst.name = "CZC ";
  567.             inst.op2.dest = false;
  568.             break;
  569.         case 2:        inst.name = "XOR ";    break;
  570.         case 3:        inst.name = "XOP ";    break;
  571.         case 6:        inst.name = "MPY ";    
  572. //            inst.op2.type = OP_MPY;
  573.             break;
  574.         case 7:        inst.name = "DIV ";
  575. //            inst.op2.type = OP_DIV;
  576.             break;
  577.         }
  578.  
  579.     } else if (op >= 0x3000 && op < 0x3800) {
  580.         inst.op1.type = (op & 0x30) >> 4;
  581.         inst.op1.val = (op & 15);
  582.         inst.op2.type = OP_CNT;
  583.         inst.op2.val = (op & 0x3c0) >> 6;
  584.         if (inst.op2.val == 0) inst.op2.val = 16;
  585.         inst.op1.byteop = (inst.op2.val <= 8);
  586.  
  587.         inst.name = (op < 0x3400 ? "LDCR" : "STCR");
  588.         inst.op1.dest = (op >= 0x3400);
  589.  
  590.     } else {
  591.         inst.op1.type = (op & 0x30) >> 4;
  592.         inst.op1.val = (op & 15);
  593.         inst.op2.type = (op & 0x0c00) >> 10;
  594.         inst.op2.val = (op & 0x3c0) >> 6;
  595.         inst.op2.dest = true;
  596.         inst.op1.byteop = inst.op2.byteop = ((op & 0x1000) != 0);
  597.  
  598.         switch ((op & 0xf000) >> 12) {
  599.         case 4:        inst.name = "SZC ";    break;
  600.         case 5:        inst.name = "SZCB";    break;
  601.         case 6:        inst.name = "S   ";    break;
  602.         case 7:        inst.name = "SB  ";    break;
  603.         case 8:        inst.name = "C   ";    
  604.             inst.op2.dest = false;
  605.             break;
  606.         case 9:        inst.name = "CB  ";    
  607.             inst.op2.dest = false;
  608.             break;
  609.         case 10:    inst.name = "A   ";    break;
  610.         case 11:    inst.name = "AB  ";    break;
  611.         case 12:    inst.name = "MOV ";    
  612.             inst.op2.dest = OP_DEST_KILLED;
  613.             break;
  614.         case 13:    inst.name = "MOVB";    
  615.             inst.op2.dest = OP_DEST_KILLED;
  616.             break;
  617.         case 14:    inst.name = "SOC ";    break;
  618.         case 15:    inst.name = "SOCB";    break;
  619.         }
  620.     }
  621.  
  622.     // Figure out the ea for the operands
  623.     operand_complete(&inst.op1, &pc);
  624.     operand_complete(&inst.op2, &pc);
  625.  
  626.     // And the instruction for X
  627.     if (inst.op2.type == OP_INST) {
  628.         inst.op2.val = MEMORY_READ_WORD(inst.op1.ea);
  629.     }
  630.  
  631.     *ins = inst;
  632. }
  633.  
  634. /*
  635.  *    Tell if the operand has any effect on a register;
  636.  *    return a bitmap for each
  637.  */
  638. static void
  639. derive_register_access(Instruction *inst, Operand *op, 
  640.                        int *read, int *written)
  641. {
  642.     switch (op->type)
  643.     {
  644.     case OP_REG:
  645.         if (op->dest != OP_DEST_KILLED)
  646.             *read |= (1 << op->val);
  647.         if (op->dest)
  648.             *written |= (1 << op->val);
  649.  
  650.         // multiply writes two registers
  651.         if ((inst->opcode >= 0x3800 && inst->opcode < 0x3C00) 
  652.             && op->dest)
  653.             *written |= (1 << (op->val+1));
  654.  
  655.         // divide reads and writes two registers
  656.         if (inst->opcode >= 0x3C00 && inst->opcode < 0x4000) {
  657.             if (op->dest)
  658.                 *read |= (1 << (op->val+1));
  659.             else
  660.                 *written |= (1 << (op->val+1));
  661.         }
  662.         break;
  663.  
  664.     case OP_IND:
  665.     case OP_ADDR:
  666.     case OP_INC:
  667.         if (op->type != OP_ADDR || op->val != 0)
  668.             *read |= (1 << op->val);
  669.        
  670.         if (op->type == OP_INC)
  671.             *written |= (1 << op->val);
  672.  
  673.         // memory write to register?
  674.         if (op->ea >= inst->wp && op->ea < inst->wp + 32) {
  675.             if (op->dest != OP_DEST_KILLED)
  676.                 *read |= (1 << ((op->ea - inst->wp) >> 1));
  677.             if (op->dest)
  678.                 *written |= (1 << ((op->ea - inst->wp) >> 1));
  679.         }
  680.         break;
  681.  
  682.     case OP_INST:
  683.         {
  684.             Instruction xinst;
  685.             instruction_decode(op->val, 
  686.                                inst->pc, inst->wp, inst->status,
  687.                                &xinst);
  688.  
  689.             // watch out for recursion
  690.             if (xinst.op1.type != OP_INST
  691.                 && xinst.op2.type != OP_INST) 
  692.             {
  693.                 derive_register_access(&xinst, &xinst.op1, read, written);
  694.                 derive_register_access(&xinst, &xinst.op2, read, written);
  695.             } 
  696.             else 
  697.             {
  698.                 // panic
  699.                 *read = *written = -1;
  700.             }
  701.         }
  702.         break;
  703.     }
  704. }
  705.  
  706. /*
  707.  *    Update register view according to effects of 
  708.  *    previously executed instruction, including change to WP,
  709.  *    reads and writes to register.
  710.  */
  711. static void
  712. register_update_view(Instruction *inst, u16 wp)
  713. {
  714.     int reg;
  715.     int read, written;
  716.     u16 regs[16];
  717.  
  718.     // is new register set changing?
  719.  
  720.     if (wp != register_view) {
  721.         register_view = wp;
  722.  
  723.         for (reg = 0; reg < 16; reg++) {
  724.             regs[reg] = MEMORY_READ_WORD((reg<<1) + register_view);
  725.         }
  726.         report_status(STATUS_CPU_REGISTER_VIEW, register_view, regs);
  727.  
  728.         // don't bother reporting effects of previous instruction
  729.         return;
  730.     }
  731.  
  732.     // report accessed registers from prevous instruction
  733.  
  734.     read = written = 0;
  735.     derive_register_access(inst, &inst->op1, &read, &written);
  736.     derive_register_access(inst, &inst->op2, &read, &written);
  737.  
  738.     for (reg = 0; reg < 16; reg++) {
  739.         if (written & (1 << reg)) {
  740.             report_status(
  741.                 STATUS_CPU_REGISTER_WRITE,
  742.                 reg, MEMORY_READ_WORD((reg<<1) + inst->wp));
  743.         } else if (read & (1 << reg)) {
  744.             report_status(
  745.                 STATUS_CPU_REGISTER_READ,
  746.                 reg, MEMORY_READ_WORD((reg<<1) + inst->wp));
  747.         }
  748.     }
  749. }
  750.  
  751. void
  752. debugger_register_clear_view(void)
  753. {
  754.     u16 regs[16];
  755.     int reg;
  756.  
  757.     for (reg = 0; reg < 16; reg++) {
  758.         regs[reg] = MEMORY_READ_WORD((reg<<1) + register_view);
  759.     }
  760.     report_status(STATUS_CPU_REGISTER_VIEW, register_view, regs);
  761. }
  762.  
  763. static char *hexstr = "0123456789ABCDEF";
  764.  
  765. static char *
  766. hex2(char *buf, u8 val)
  767. {
  768.     *buf++ = hexstr[(val & 0xf0) >> 4];
  769.     *buf++ = hexstr[val & 0xf];
  770.     return buf;
  771. }
  772.  
  773. static char *
  774. hex4(char *buf, u16 val)
  775. {
  776.     *buf++ = hexstr[(val & 0xf000) >> 12];
  777.     *buf++ = hexstr[(val & 0xf00) >> 8];
  778.     *buf++ = hexstr[(val & 0xf0) >> 4];
  779.     *buf++ = hexstr[val & 0xf];
  780.     return buf;
  781. }
  782.  
  783. /*
  784.  *    Setup a memory view, returning a bool telling
  785.  *    whether the view changed.
  786.  */
  787. static bool
  788. memory_view_setup(Memory *s, MemoryView view, u16 addr, int len)
  789. {
  790.     bool changed = false;
  791.     mem_domain dmn;
  792.     u8 *mem;
  793.     mrstruct *area;
  794.  
  795.     s->which = view;
  796.     s->addr = addr;
  797.     s->len = len;
  798.  
  799.     if (debugger_memory_view_size[s->which] <= 0) {
  800.         debugger_memory_view_size[s->which] = 16;
  801.     }
  802.  
  803.     // get base address fixed at multiple of view size
  804.     if ((s->addr < s->base || 
  805.         s->addr + len >= s->base + debugger_memory_view_size[s->which]) 
  806.         || s->base % debugger_memory_view_size[s->which]) 
  807.     {
  808.         s->base = s->addr - (s->addr % debugger_memory_view_size[s->which]);
  809.         changed = true;
  810.     }
  811.     
  812.     // if not enough room for operand, fudge base address
  813.     if (s->base + debugger_memory_view_size[s->which] < s->addr + len) 
  814.     {
  815.         s->base = s->addr;
  816.         changed = true;
  817.     }
  818.  
  819.     // set up memory pointer
  820.     dmn = (view == MEMORY_VIEW_VIDEO) ? md_video :
  821.         (view == MEMORY_VIEW_GRAPHICS) ? md_graphics :
  822.         (view == MEMORY_VIEW_SPEECH) ? md_speech : md_cpu;
  823.  
  824.     //mem = FLAT_MEMORY_PTR(dmn, s->base);
  825.     area = THE_AREA(dmn, s->base);
  826.     if (area->areamemory)
  827.         mem = area->areamemory + (s->base & (AREASIZE-1));
  828.     else
  829.         mem = zeroes;
  830.  
  831.  
  832.     if (mem != s->mem)
  833.         changed = true;
  834.  
  835.     s->mem = mem;
  836.  
  837.     return changed;
  838. }
  839.  
  840. /*
  841.  *    For a given address reference, select a view for the
  842.  *    type of memory it is referencing.
  843.  */
  844.  
  845. INLINE int memory_distance(u16 a, u16 b)
  846. {
  847.     return (a < 0x8000 && b < 0x8000) ? a - b :
  848.         (a < 0x8000 && b >= 0x8000) ? a - (0x10000 - b) :
  849.         (a >= 0x8000 && b < 0x8000) ? (0x10000 - a) - b :
  850.         (0x10000 - a) - (0x10000 - b);
  851. }
  852.  
  853. static Memory *
  854. memory_view_get(u16 addr, int len, bool dest, Memory *using, bool *changed)
  855. {
  856.     MemoryView    view = dest ? MEMORY_VIEW_CPU_2 : MEMORY_VIEW_CPU_1;
  857.     Memory       *s;
  858.  
  859.     // !!! warning, this assumes a 99/4A with this memory
  860.     // configuration
  861.     if (addr >= 0x8400 && addr < 0xa000) {
  862.         addr &= 0x9c02;
  863.  
  864.         switch (addr) {
  865.         case 0x8800:
  866.         case 0x8c00:
  867.         case 0x8c02:
  868.             if (!vdp_mmio_addr_is_complete())
  869.                 return 0L;
  870.             addr = vdp_mmio_get_addr();
  871.             view = MEMORY_VIEW_VIDEO;
  872.             break;
  873.         case 0x9000:
  874.         case 0x9400:
  875.             if (!speech_mmio_addr_is_complete())
  876.                 return 0L;
  877.             addr = speech_mmio_get_addr();
  878.             view = MEMORY_VIEW_SPEECH;
  879.             break;
  880.         case 0x9800:
  881.         case 0x9802:
  882.         case 0x9c00:
  883.         case 0x9c02:
  884.             if (!grom_mmio_addr_is_complete())
  885.                 return 0L;
  886.             addr = grom_mmio_get_addr();
  887.             view = MEMORY_VIEW_GRAPHICS;
  888.             break;
  889.         }
  890.     }
  891.  
  892.     // divide cpu views 1 and 2 into source and
  893.     // destination, or, based on distance from previous view
  894.  
  895.     if (view == MEMORY_VIEW_CPU_1 || view == MEMORY_VIEW_CPU_2) {
  896.         int dist1 = memory_distance(views[MEMORY_VIEW_CPU_1].addr, addr);
  897.         int dist2 = memory_distance(views[MEMORY_VIEW_CPU_2].addr, addr);
  898.  
  899.         if (dist1 > dist2 + 32 ||
  900.             (views[MEMORY_VIEW_CPU_1].coverage > 
  901.              views[MEMORY_VIEW_CPU_2].coverage + 32))
  902.             view = MEMORY_VIEW_CPU_2;
  903.         else if (dist2 > dist1 + 32 ||
  904.                  (views[MEMORY_VIEW_CPU_2].coverage > 
  905.                   views[MEMORY_VIEW_CPU_1].coverage + 32))
  906.             view = MEMORY_VIEW_CPU_1;
  907.  
  908.         views[view].coverage++;
  909.     }
  910.  
  911.  
  912.     // setup the view info
  913.     s = &views[view];
  914.  
  915.     *changed = memory_view_setup(s, view, addr, len);
  916.  
  917.     return s;
  918. }
  919.  
  920. /*
  921.  *    Update views of memory according to effect of
  922.  *    previous instruction
  923.  */
  924. static void
  925. memory_update_views(Instruction *inst)
  926. {
  927.     Memory     *view1 = 0L, *view2 = 0L;
  928.     bool view1changed, view2changed;
  929.  
  930.     // pick a view for each memory operand
  931.  
  932.     if (OP_IS_MEMORY(inst->op1)) {
  933.         view1 = memory_view_get(inst->op1.ea, 
  934.                                 inst->op1.byteop ? 1 : 2,
  935.                                 inst->op1.dest,
  936.                                 NULL,
  937.                                 &view1changed);
  938.     }
  939.  
  940.     if (OP_IS_MEMORY(inst->op2)) {
  941.         view2 = memory_view_get(inst->op2.ea,
  942.                                 inst->op2.byteop ? 1 : 2,
  943.                                 inst->op2.dest,
  944.                                 view1,
  945.                                 &view2changed);
  946.     }
  947.  
  948.     // don't show the same one twice
  949.  
  950.     if (view1 && view1 == view2)
  951.         view2 = 0L;
  952.  
  953.     // update each view
  954.  
  955.     if (view1) {
  956.         if (view1changed)
  957.             report_status(STATUS_MEMORY_VIEW, view1);
  958.  
  959.         report_status(inst->op1.dest ? 
  960.                       STATUS_MEMORY_WRITE :
  961.                       STATUS_MEMORY_READ, view1);
  962.     }
  963.  
  964.     if (view2) {
  965.         if (view2changed)
  966.             report_status(STATUS_MEMORY_VIEW, view2);
  967.  
  968.         report_status(inst->op2.dest ? 
  969.                       STATUS_MEMORY_WRITE :
  970.                       STATUS_MEMORY_READ, view2);
  971.     }
  972. }
  973.  
  974. static u16
  975. memory_view_real_address(Memory *s)
  976. {
  977.     switch (s->which) 
  978.     {
  979.     case MEMORY_VIEW_VIDEO:
  980.         s->len = 1;
  981.         if (vdp_mmio_addr_is_complete())
  982.             s->addr = vdp_mmio_get_addr();
  983.         return true;
  984.     case MEMORY_VIEW_GRAPHICS:
  985.         s->len = 1;
  986.         if (grom_mmio_addr_is_complete())
  987.             s->addr = grom_mmio_get_addr();
  988.         return true;
  989.     case MEMORY_VIEW_SPEECH:
  990.         s->len = 1;
  991.         if (speech_mmio_addr_is_complete())
  992.             s->addr = speech_mmio_get_addr();
  993.         return true;
  994.     }
  995.     return false;
  996. }
  997.  
  998. void
  999. debugger_memory_clear_views(void)
  1000. {
  1001.     MemoryView view;
  1002.     Memory *s;
  1003.     bool memory_mapped;
  1004.  
  1005.     for (view = MEMORY_VIEW_CPU_1;
  1006.          view < MEMORY_VIEW_COUNT;
  1007.          view++)
  1008.     {  
  1009.         s = &views[view];
  1010.         memory_mapped = memory_view_real_address(s);
  1011.         memory_view_setup(s, view, s->addr, 0);
  1012.         report_status(STATUS_MEMORY_VIEW, s);
  1013.     }
  1014. }
  1015.  
  1016. /*
  1017.  *    Update view of instruction.  When a previous instruction
  1018.  *    is being viewed, we send any destination operands changed.
  1019.  *    For a current instruction, we preview the values of the operands
  1020.  *    and send those, as well as a disassembly.
  1021.  */
  1022. static void
  1023. instruction_update_view(Instruction *inst, bool after)
  1024. {
  1025.     char hex[16];
  1026.     char disasm[64];
  1027.     char op1[32], *op1ptr;
  1028.     char op2[32], *op2ptr;
  1029.  
  1030.     if (!after) {
  1031.         // tell about the system registers
  1032.         report_status(STATUS_CPU_PC, inst->pc);
  1033.         report_status(STATUS_CPU_WP, inst->wp);
  1034.         report_status(STATUS_CPU_STATUS, inst->status);
  1035.  
  1036.         // get hex representation of instruction
  1037.         sprintf(hex, "%04X=%04X", inst->pc, inst->opcode);
  1038.         
  1039.         // get disassembly with operand representations
  1040.         op1ptr = debugger_instruction_operand_print(&inst->op1, op1);
  1041.         op2ptr = debugger_instruction_operand_print(&inst->op2, op2);
  1042.         if (!op1ptr) {
  1043.             op1ptr = op2ptr;
  1044.             op2ptr = 0L;
  1045.         }
  1046.         sprintf(disasm, "%s%s%s",
  1047.                 op1ptr ? op1ptr : "",
  1048.                 op2ptr ? "," : "",
  1049.                 op2ptr ? op2ptr : "");
  1050.  
  1051.         // get operand values
  1052.         op1ptr = debugger_operand_value_print(
  1053.                     inst, 
  1054.                     &inst->op1,
  1055.                     debugger_operand_view_verbose,
  1056.                     false /*after*/,
  1057.                     op1);
  1058.  
  1059.         op2ptr = debugger_operand_value_print(
  1060.                     inst, 
  1061.                     &inst->op2,
  1062.                     debugger_operand_view_verbose,
  1063.                     false /*after*/,
  1064.                     op2);
  1065.  
  1066.         if (!op1ptr) {                             
  1067.             op1ptr = op2ptr;
  1068.             op2ptr = 0L;
  1069.         }
  1070.  
  1071.         // send it to frontend
  1072.         report_status(STATUS_CPU_INSTRUCTION,
  1073.                       inst,
  1074.                       hex,
  1075.                       disasm,
  1076.                       op1ptr,
  1077.                       op2ptr);
  1078.     } else {
  1079.         // afterwards, show destination operands
  1080.     
  1081.         // get operand values
  1082.         op1ptr = debugger_operand_value_print(
  1083.                     inst, 
  1084.                     &inst->op1,
  1085.                     debugger_operand_view_verbose,
  1086.                     true /*after*/,
  1087.                     op1);
  1088.  
  1089.         op2ptr = debugger_operand_value_print(
  1090.                     inst, 
  1091.                     &inst->op2,
  1092.                     debugger_operand_view_verbose,
  1093.                     true /*after*/,
  1094.                     op2);
  1095.  
  1096.         if (!op1ptr) {                             
  1097.             op1ptr = op2ptr;
  1098.             op2ptr = 0L;
  1099.         }
  1100.  
  1101.         // send it to frontend
  1102.         report_status(STATUS_CPU_INSTRUCTION_LAST,
  1103.                       inst,
  1104.                       op1ptr,
  1105.                       op2ptr);
  1106.     }
  1107. }
  1108.  
  1109. void
  1110. debugger_instruction_clear_view(void)
  1111. {
  1112.     // send refresh signal to frontend
  1113.     report_status(STATUS_CPU_INSTRUCTION_LAST,
  1114.                   0L,
  1115.                   0L,
  1116.                   0L);
  1117. }
  1118.  
  1119. /*
  1120.  *    Utility for status reporters.  Given the slot, it writes a one-line hex dump to
  1121.  *    the given buffer, and sets start/astart and end/aend to point to the extent
  1122.  *    of the last memory access within the buffer.  (These will be spaces.)
  1123.  *
  1124.  *    addr_separator: char appearing between address and bytes
  1125.  *    byte_separator: char appearing between each hex byte
  1126.  *    ascii_separator: char appearing between hex field and ascii field
  1127.  *    line_separator: char appearing between lines, and at end
  1128.  */    
  1129. void
  1130. debugger_hex_dump_line(Memory * slot, int offset, int length,
  1131.                        char addr_separator, char byte_separator, 
  1132.                        char ascii_separator, char line_separator,
  1133.                        char *buffer, int bufsz,
  1134.                        char **start, char **end,
  1135.                        char **astart, char **aend)
  1136. {
  1137.     char       *dumpptr = buffer, *asciiptr = dumpptr + 6+length*3;
  1138.     u16         idx, addr;
  1139.     u8          *bytes;
  1140.  
  1141.     if (asciiptr + length + 1 >= buffer + bufsz)
  1142.     {
  1143.         length = debugger_hex_dump_chars_to_bytes(bufsz-1);
  1144.         asciiptr = dumpptr + 6+length*3;
  1145.         my_assert(asciiptr + length < buffer + bufsz);
  1146.     }
  1147.  
  1148.     *dumpptr = 0;
  1149.     *start = *end = *astart = *aend = 0L;
  1150.  
  1151.     bytes = slot->mem + offset;
  1152.     addr = slot->base + offset;
  1153.  
  1154.     *dumpptr++ = MEMORY_VIEW_TOKEN(slot->which);
  1155.     dumpptr = hex4(dumpptr, addr);
  1156.     *dumpptr++ = addr_separator;
  1157.  
  1158.     if (slot->len
  1159.         && addr > slot->addr
  1160.         && addr < slot->addr + slot->len) 
  1161.     {
  1162.         *start = dumpptr;
  1163.         *astart = asciiptr;
  1164.     }
  1165.  
  1166.     idx = 0;
  1167.     while (idx < length) {
  1168.         u8          ch;
  1169.  
  1170.         if (slot->len && addr + idx == slot->addr) {
  1171.             *start = dumpptr;
  1172.             *astart = asciiptr;
  1173.         }
  1174.  
  1175.         ch = bytes[idx];
  1176.  
  1177.         dumpptr = hex2(dumpptr, ch);
  1178.         *asciiptr++ = isprint(ch) ? ch : '.';
  1179.         idx++;
  1180.  
  1181.         if (slot->len && addr + idx == slot->addr + slot->len) {
  1182.             *end = dumpptr;
  1183.             *aend = asciiptr;
  1184.         }
  1185.         if (idx  < length)
  1186.             *dumpptr++ = byte_separator;
  1187.     }
  1188.  
  1189.     if (slot->len
  1190.         && addr + length > slot->addr 
  1191.         && addr + length < slot->addr + slot->len)
  1192.     {
  1193.         *end = dumpptr;
  1194.         *aend = asciiptr;
  1195.     }
  1196.  
  1197.     *dumpptr++ = ascii_separator;
  1198.     *asciiptr++ = line_separator;
  1199.     *asciiptr = 0;
  1200. }
  1201.  
  1202. /*
  1203.  *    How long will this text be?
  1204.  */
  1205. int 
  1206. debugger_hex_dump_bytes_to_chars(int bytes)
  1207. {
  1208.     return bytes * 4 + 6 + 1 + 1;
  1209. }
  1210.  
  1211. /*
  1212.  *    How many bytes fit in this length?
  1213.  */
  1214. int 
  1215. debugger_hex_dump_chars_to_bytes(int chars)
  1216. {
  1217.     return (chars - 6 - 1 - 1) / 4;
  1218. }
  1219.  
  1220. /*
  1221.  *    Breakpoint manager
  1222.  */
  1223.  
  1224. typedef struct bkpt {
  1225.     u16 pc;            // location of bkpt
  1226.     struct bkpt *next;
  1227. } bkpt;
  1228.  
  1229. static bkpt    *breakpoints;
  1230.  
  1231. // check to see if the address matches a breakpoint
  1232. int 
  1233. debugger_check_breakpoint(u16 pc)
  1234. {
  1235.     bkpt *ptr = breakpoints;
  1236.     while (ptr)
  1237.         if (ptr->pc == pc)
  1238.             return 1;
  1239.         else
  1240.             ptr = ptr->next;
  1241.     return 0;
  1242. }
  1243.  
  1244. // add the address to the list of breakpoints
  1245. static void
  1246. debugger_set_breakpoint(u16 pc)
  1247. {
  1248.     bkpt *ptr;
  1249.  
  1250.     if (debugger_check_breakpoint(pc))
  1251.         return;
  1252.  
  1253.     ptr = (bkpt *)xmalloc(sizeof(bkpt));
  1254.     ptr->pc = pc;
  1255.     ptr->next = breakpoints;
  1256.     breakpoints = ptr;
  1257. }
  1258.  
  1259. // remove the address from the list of breakpoints
  1260. static void
  1261. debugger_reset_breakpoint(u16 pc)
  1262. {
  1263.     bkpt *ptr, *prev;
  1264.  
  1265.     prev = 0L;
  1266.     ptr = breakpoints;
  1267.     while (ptr && ptr->pc != pc)
  1268.     {
  1269.         prev = ptr;
  1270.         ptr = ptr->next;
  1271.     }
  1272.  
  1273.     if (!ptr) return;
  1274.  
  1275.     if (prev)
  1276.         prev->next = ptr->next;
  1277.     else
  1278.         breakpoints = ptr->next;
  1279. }
  1280.  
  1281. DECL_SYMBOL_ACTION(debugger_breakpoint)
  1282. {
  1283.     if (task == csa_READ) {
  1284.         static bkpt *list;
  1285.  
  1286.         if (!iter) list = breakpoints;
  1287.  
  1288.         if (list == 0L)
  1289.             return 0;
  1290.         
  1291.         command_arg_set_num(SYM_ARG_1st, list->pc);
  1292.         list = list->next;
  1293.     } else {
  1294.         int val;
  1295.  
  1296.         command_arg_get_num(SYM_ARG_1st, &val);
  1297.         debugger_set_breakpoint(val);
  1298.     }
  1299.     return 1;
  1300. }
  1301.  
  1302. DECL_SYMBOL_ACTION(debugger_clear_breakpoint)
  1303. {
  1304.     int val;
  1305.  
  1306.     command_arg_get_num(SYM_ARG_1st, &val);
  1307.     debugger_reset_breakpoint(val);
  1308.     return 1;
  1309. }
  1310.  
  1311.  
  1312. DECL_SYMBOL_ACTION(debugger_list_breakpoints)
  1313. {
  1314.     static bkpt *list;
  1315.  
  1316.     list = breakpoints;
  1317.  
  1318.     logger(_L|LOG_USER, "Active breakpoints:\n");
  1319.     if (list == 0L)
  1320.     {
  1321.         logger(_L|LOG_USER, "\t<none>\n");
  1322.         return 1;
  1323.     }
  1324.         
  1325.     while (list)
  1326.     {
  1327.         logger(_L|LOG_USER, "\t>%04X\n", list->pc);
  1328.         list = list->next;
  1329.     }
  1330.     return 1;
  1331. }
  1332.  
  1333.  
  1334. /*
  1335.  *    Entry point for debugger backend, entered before every instruction
  1336.  *    executed when ST_DEBUG is set in the stateflag.
  1337.  */
  1338.  
  1339. static Instruction last;
  1340. static bool last_valid;
  1341.  
  1342. void
  1343. debugger(void)
  1344. {
  1345.     Instruction inst;
  1346.  
  1347.     report_status(STATUS_DEBUG_REFRESH);
  1348.  
  1349.     // Show effects of previous instruction
  1350.     if (last_valid) {
  1351.         memory_update_views(&last);
  1352.         register_update_view(&last, wp);
  1353.         instruction_update_view(&last, true /*after*/);
  1354.     } else {
  1355.         debugger_memory_clear_views();
  1356.         debugger_register_clear_view();
  1357.         debugger_instruction_clear_view();
  1358.     }
  1359.  
  1360.     // Get a status word for this instruction
  1361.     statusto9900();
  1362.  
  1363.     // Decode the current instruction
  1364.     instruction_decode(MEMORY_READ_WORD(pc), 
  1365.                        pc, wp, status, 
  1366.                        &inst);
  1367.  
  1368.     if (last.pc != inst.pc) {
  1369.         // Show current instruction
  1370.         instruction_update_view(&inst, false /*after*/);
  1371.     }
  1372.  
  1373.     // Save instruction
  1374.     last = inst;
  1375.     last_valid = true;
  1376. }
  1377.  
  1378. void
  1379. debugger_init(void)
  1380. {
  1381.     command_symbol_table *debugcommands =
  1382.       command_symbol_table_new("Debugger Options",
  1383.                                  "These commands control the debugger",
  1384.  
  1385.          command_symbol_new("BreakPoint",
  1386.                             "Add a breakpoint at the given PC",
  1387.                             c_DYNAMIC|c_SESSION_ONLY,
  1388.                             debugger_breakpoint,
  1389.                             RET_FIRST_ARG,
  1390.                             command_arg_new_num
  1391.                             ("address",
  1392.                              "PC address at which to break",
  1393.                              NULL /* action */ ,
  1394.                              NEW_ARG_NUM(u16),
  1395.                              NULL /* next */ )
  1396.                             ,
  1397.  
  1398.          command_symbol_new("ClearBreakPoint",
  1399.                             "Remove breakpoint at the given PC",
  1400.                             c_STATIC|c_DONT_SAVE,
  1401.                             debugger_clear_breakpoint,
  1402.                             RET_FIRST_ARG,
  1403.                             command_arg_new_num
  1404.                             ("address",
  1405.                              "PC address of breakpoint",
  1406.                              NULL /* action */ ,
  1407.                              NEW_ARG_NUM(u16),
  1408.                              NULL /* next */ )
  1409.                             ,
  1410.  
  1411.          command_symbol_new("ListBreakPoints",
  1412.                             "List active breakpoints",
  1413.                             c_STATIC|c_DONT_SAVE,
  1414.                             debugger_list_breakpoints,
  1415.                             NULL /*ret*/,
  1416.                             NULL /*args*/,
  1417.  
  1418.         NULL /*next*/))),
  1419.       NULL /* sub */,
  1420.     NULL /* next */
  1421.     );
  1422.  
  1423.     command_symbol_table_add_subtable(universe, debugcommands);
  1424.  
  1425.     memset((void *)&views, 0, sizeof(views));
  1426.     register_view = 0;
  1427. }
  1428.  
  1429. /*
  1430.  *    Force next update to refresh all status items
  1431.  */
  1432. void 
  1433. debugger_refresh(void)
  1434. {
  1435.     last_valid = false;
  1436. }
  1437.  
  1438. void 
  1439. debugger_enable(bool enable)
  1440. {
  1441.     if (enable) {
  1442.         system_debugger_enabled(true);
  1443.         if (!(stateflag & ST_DEBUG)) {
  1444.             stateflag |= ST_DEBUG | ST_SINGLESTEP;
  1445.             debugger_refresh();
  1446.             debugger();
  1447.         }
  1448.     } else if (!enable && (stateflag & ST_DEBUG)) {
  1449.         stateflag &= ~ST_DEBUG;
  1450.         system_debugger_enabled(false);
  1451.         debugger_refresh();
  1452.     }
  1453. }
  1454.  
  1455.