In order to handle breakpoints functionality of step, next, and continue, it is necessary to know 1) how long the current instruction is and 2) whether and how it branches.

So I coded up a quick function that takes a pointer to a location and returns 1) 1-4 in the lower 3 bits with instruction length, 2 bits with the branch type (absolute, relative, return, and jp (hl)), one bit to indicate the branch is conditional, and one bit for instructions that always branch away and will never get to the next instruction.

Note that the ‘rst’ and ‘halt’ commands don’t have branch information. Anyone wanting to try to use this code will want to add that if they need it.

Here it is:

  1 // The following are found in pBranchInfo
  2 #define BRANCH_CALL     (0x08)
  3 // relative to pc + (int8_t)(opcode+1) ALWAYS or COND
  4 #define BRANCH_REL      (0x20)
  5 // absolute to (void*)(opcode+1) ALWAYS or COND
  6 #define BRANCH_ABS      (0x10)
  7 // return to (void*)(sp-2) ALWAYS or COND
  8 #define BRANCH_RET      (0x30)
  9 // to (hl) // ALWAYS but never COND
 10 #define BRANCH_HL       (0x00)
 11 // conditional--bp necessary after instruction
 12 #define BRANCH_COND     (0x40)
 13 // always--will never got to pc+length--certain to branch
 14 #define BRANCH_ALWAYS   (0x80)
 15 
 16 
 17 struct InstLen
 18 {
 19     uint8_t mask;
 20     uint8_t value;
 21     uint8_t data;
 22 };
 23 
 24 static const struct InstLen scan00[] =
 25 {
 26     // ld rr, **
 27     {
 28         0xcf, 0x01, 3
 29     },
 30     // ld (hl)/a <-> **
 31     {
 32         0xe7, 0x22, 3
 33     },
 34     // ld r, *
 35     {
 36         0xc7, 0x06, 2
 37     },
 38     // jr f, *
 39     {
 40         0xe7, 0x20, 2 | BRANCH_REL | BRANCH_COND
 41     },
 42     // djnz *
 43     {
 44         0xff, 0x10, 2 | BRANCH_REL | BRANCH_COND
 45     },
 46     // jr *
 47     {
 48         0xff, 0x18, 2 | BRANCH_REL | BRANCH_ALWAYS
 49     },
 50 };
 51 
 52 static const struct InstLen scan11[] =
 53 {
 54     // ret f (not detault b/c branch)
 55     {
 56         0xc7, 0xc0, 1 | BRANCH_RET | BRANCH_COND
 57     },
 58     // ret (not detault b/c branch)
 59     {
 60         0xff, 0xc9, 1 | BRANCH_RET | BRANCH_ALWAYS
 61     },
 62     // jp (hl)
 63     {
 64         0xff, 0xe9, 1 | BRANCH_HL | BRANCH_ALWAYS
 65     },
 66     // jp f, **
 67     {
 68         0xc7, 0xc2, 3 | BRANCH_ABS | BRANCH_COND
 69     },
 70     // call f, **
 71     {
 72         0xc7, 0xc4, 3 | BRANCH_ABS | BRANCH_COND | BRANCH_CALL
 73     },
 74     // jp **
 75     {
 76         0xff, 0xc3, 3 | BRANCH_ABS | BRANCH_ALWAYS
 77     },
 78     // call **
 79     {
 80         0xff, 0xcd, 3 | BRANCH_ABS | BRANCH_CALL
 81     },
 82     // arith *, *
 83     {
 84         0xc7, 0xc6, 2
 85     },
 86     // out/in(*), a
 87     {
 88         0xf7, 0xd3, 2
 89     },
 90     // bit op
 91     {
 92         0xff, 0xcb, 2
 93     }
 94 };
 95 
 96 static const struct InstLen scanED[] =
 97 {
 98     // ld (rr) <-> **
 99     {
100         0xc7, 0x43, 4
101     }
102 };
103 
104 static const struct InstLen scanDDFD[] =
105 {
106     // ld ix, **
107     {
108         0xff, 0x21, 4
109     },
110     // ld ix <-> (**)
111     {
112         0xf7, 0x22, 4
113     },
114     // ld (ix+*), * order dep
115     {
116         0xff, 0x36, 4
117     },
118     // various
119     {
120         0x07, 0x06, 3
121     },
122     // ld (ix+*), r
123     {
124         0xb8, 0x30, 3
125     },
126     // bit ops
127     {
128         0xff, 0xcb, 3
129     },
130 };
131 
132 // Returns the length in the first 3 bits and the BRANCH_* bits in the upper 5 bits
133 uint8_t z80InstructionLength(uint8_t* start)
134 {
135     uint8_t opcode = *start++;
136     const struct InstLen* scanner;
137     int i;
138     uint8_t length;
139     uint8_t instructionLength = 1;
140 
141     if ((opcode & 0x80) == 0)
142     {
143         if ((opcode & 0x40) == 0)
144         {
145             scanner = scan00;
146             length = sizeof(scan00) / sizeof(scan00[0]);
147         }
148         else
149         {
150             return 1;
151         }
152     }
153     else
154     {
155         if ((opcode & 0x40) == 0)
156         {
157             return 1;
158         }
159         else
160         {
161             if ((opcode & 0xdf) == 0xdd)
162             {
163                 scanner = scanDDFD;
164                 length = sizeof(scanDDFD) / sizeof(scanDDFD[0]);
165                 instructionLength = 2;
166                 opcode = *start++;
167             }
168             else if (opcode == 0xed)
169             {
170                 scanner = scanED;
171                 length = sizeof(scanED) / sizeof(scanED[0]);
172                 instructionLength = 2;
173                 opcode = *start++;
174             }
175             else
176             {
177                 scanner = scan11;
178                 length = sizeof(scan11) / sizeof(scan11[0]);
179             }
180         }
181     }
182     for (i = 0; i < length; i++)
183     {
184         const struct InstLen* scan = &scanner[i];
185         if ((scan->mask & opcode) == scan->value)
186         {
187             instructionLength = scan->data;
188             break;
189         }
190     }
191     return instructionLength;
192 }