11#include "registers.h"
2+ #include "decoder.h"
3+ #include <string.h>
4+
5+ static Z80RegId _z80_get_register_id (const char * name ) {
6+ if (!name ) return Z80_REG_INVALID ;
7+
8+ if (!strcmp (name , "a" )) return Z80_REG_A ;
9+ if (!strcmp (name , "b" )) return Z80_REG_B ;
10+ if (!strcmp (name , "c" )) return Z80_REG_C ;
11+ if (!strcmp (name , "d" )) return Z80_REG_D ;
12+ if (!strcmp (name , "e" )) return Z80_REG_E ;
13+ if (!strcmp (name , "h" )) return Z80_REG_H ;
14+ if (!strcmp (name , "l" )) return Z80_REG_L ;
15+
16+ if (!strcmp (name , "bc" )) return Z80_REG_BC ;
17+ if (!strcmp (name , "de" )) return Z80_REG_DE ;
18+ if (!strcmp (name , "hl" )) return Z80_REG_HL ;
19+ if (!strcmp (name , "sp" )) return Z80_REG_SP ;
20+ if (!strcmp (name , "af" )) return Z80_REG_AF ;
21+
22+ if (!strcmp (name , "i" )) return Z80_REG_I ;
23+ if (!strcmp (name , "r" )) return Z80_REG_R ;
24+
25+ if (!strcmp (name , "ix" )) return Z80_REG_IX ;
26+ if (!strcmp (name , "ixh" )) return Z80_REG_IXH ;
27+ if (!strcmp (name , "ixl" )) return Z80_REG_IXL ;
28+ if (!strcmp (name , "iy" )) return Z80_REG_IY ;
29+ if (!strcmp (name , "iyh" )) return Z80_REG_IYH ;
30+ if (!strcmp (name , "iyl" )) return Z80_REG_IYL ;
31+
32+ if (!strcmp (name , "bc'" )) return Z80_REG_SHD_BC ;
33+ if (!strcmp (name , "de'" )) return Z80_REG_SHD_DE ;
34+ if (!strcmp (name , "hl'" )) return Z80_REG_SHD_HL ;
35+ if (!strcmp (name , "af'" )) return Z80_REG_SHD_AF ;
36+
37+ return Z80_REG_INVALID ;
38+ }
39+
40+ static u64 _z80_reg_width_mask (Z80RegId id ) {
41+ switch (id ) {
42+ case Z80_REG_A :
43+ case Z80_REG_B :
44+ case Z80_REG_C :
45+ case Z80_REG_D :
46+ case Z80_REG_E :
47+ case Z80_REG_H :
48+ case Z80_REG_L :
49+ case Z80_REG_IXH :
50+ case Z80_REG_IXL :
51+ case Z80_REG_IYH :
52+ case Z80_REG_IYL :
53+ case Z80_REG_I :
54+ case Z80_REG_R : return 0xFF ; // 8-bit
55+
56+ default : return 0xFFFF ; // BC, DE, HL, SP, AF, IX, IY, shadows: 16-bit
57+ }
58+ }
59+
60+ static Z80RegId _z80_canonical_reg (Z80RegId id ) {
61+ switch (id ) {
62+ case Z80_REG_B :
63+ case Z80_REG_C : return Z80_REG_BC ;
64+
65+ case Z80_REG_D :
66+ case Z80_REG_E : return Z80_REG_DE ;
67+
68+ case Z80_REG_H :
69+ case Z80_REG_L : return Z80_REG_HL ;
70+
71+ case Z80_REG_IXH :
72+ case Z80_REG_IXL : return Z80_REG_IX ;
73+
74+ case Z80_REG_IYH :
75+ case Z80_REG_IYL :
76+ return Z80_REG_IY ;
77+
78+ // A, HL, BC, DE, SP, IX, IY, I, R, shadows: already canonical
79+ default : return id ;
80+ }
81+ }
282
383const char * z80_cc_name (Z80Condition cc ) {
484 switch (cc ) {
@@ -16,7 +96,9 @@ const char* z80_cc_name(Z80Condition cc) {
1696 return "???" ;
1797}
1898
19- const char * z80_reg_name (Z80RegId reg ) {
99+ const char * z80_get_reg_name (RDReg reg , RDProcessor * p ) {
100+ RD_UNUSED (p );
101+
20102 switch (reg ) {
21103 case Z80_REG_I : return "i" ;
22104 case Z80_REG_R : return "r" ;
@@ -52,3 +134,116 @@ const char* z80_reg_name(Z80RegId reg) {
52134
53135 return NULL ;
54136}
137+
138+ bool z80_get_reg_mask (const char * name , RDRegMask * m , RDProcessor * p ) {
139+ RD_UNUSED (p );
140+
141+ Z80RegId id = _z80_get_register_id (name );
142+ if (id == Z80_REG_INVALID ) return false;
143+
144+ switch (id ) {
145+ case Z80_REG_H :
146+ case Z80_REG_B :
147+ case Z80_REG_D :
148+ case Z80_REG_IXH :
149+ case Z80_REG_IYH :
150+ m -> mask = 0xFF00 ;
151+ m -> shift = 8 ;
152+ break ;
153+
154+ case Z80_REG_L :
155+ case Z80_REG_C :
156+ case Z80_REG_E :
157+ case Z80_REG_IXL :
158+ case Z80_REG_IYL : m -> mask = 0x00FF ; break ;
159+
160+ default : m -> mask = RD_REGMASK_FULL ; break ;
161+ }
162+
163+ m -> reg = _z80_canonical_reg (id );
164+ return true;
165+ }
166+
167+ void z80_track_regs (RDContext * ctx , const RDInstruction * instr ) {
168+ const RDOperand * dst = & instr -> operands [0 ];
169+ const RDOperand * src = & instr -> operands [1 ];
170+
171+ switch (instr -> id ) {
172+ case Z80_INSTR_LD : {
173+ if (dst -> kind != RD_OP_REG ) break ;
174+
175+ switch (src -> kind ) {
176+ case RD_OP_IMM :
177+ rd_set_regval_id (ctx , dst -> reg , src -> imm );
178+ break ;
179+
180+ case RD_OP_REG : {
181+ RDRegValue v ;
182+ if (rd_get_regval_id (ctx , src -> reg , & v ))
183+ rd_set_regval_id (ctx , dst -> reg , v );
184+ else
185+ rd_del_regval_id (ctx , dst -> reg );
186+ break ;
187+ }
188+
189+ // memory-sourced (LD r,(HL) / LD rp,(nn) / etc.)
190+ // unknown statically
191+ default : rd_del_regval_id (ctx , dst -> reg ); break ;
192+ }
193+ break ;
194+ }
195+
196+ case Z80_INSTR_INC :
197+ case Z80_INSTR_DEC : {
198+ if (dst -> kind != RD_OP_REG ) break ;
199+ RDRegValue v ;
200+ if (rd_get_regval_id (ctx , dst -> reg , & v )) {
201+ v += (instr -> id == Z80_INSTR_INC ) ? 1 : -1 ;
202+ rd_set_regval_id (ctx , dst -> reg ,
203+ v & _z80_reg_width_mask ((Z80RegId )dst -> reg ));
204+ }
205+ break ;
206+ }
207+
208+ // ADD HL,rp only, ADC/SBC need carry-in, not tracked
209+ case Z80_INSTR_ADD : {
210+ if (dst -> kind != RD_OP_REG || src -> kind != RD_OP_REG ) break ;
211+
212+ RDRegValue a , b ;
213+ if (rd_get_regval_id (ctx , dst -> reg , & a ) &&
214+ rd_get_regval_id (ctx , src -> reg , & b ))
215+ rd_set_regval_id (ctx , dst -> reg , (a + b ) & 0xFFFF );
216+ else
217+ rd_del_regval_id (ctx , dst -> reg );
218+ break ;
219+ }
220+
221+ // ADC/SBC HL,rp: carry flag isn't tracked
222+ case Z80_INSTR_ADC :
223+ case Z80_INSTR_SBC :
224+ // POP value comes from stack, (same conservative call as x86_track_pop)
225+ case Z80_INSTR_POP :
226+ // EX DE,HL / EX (SP),HL swap/stack-load,
227+ // invalidate rather than attempt to swap tracked state
228+ case Z80_INSTR_EX : {
229+ if (dst -> kind == RD_OP_REG ) rd_del_regval_id (ctx , dst -> reg );
230+ if (src -> kind == RD_OP_REG ) rd_del_regval_id (ctx , src -> reg );
231+ break ;
232+ }
233+
234+ default : break ;
235+ }
236+ }
237+
238+ void z80_track_derefs (RDContext * ctx , const RDInstruction * instr ) {
239+ for (int i = 0 ; i < 2 ; i ++ ) {
240+ const RDOperand * op = & instr -> operands [i ];
241+ if (op -> kind != Z80_USEROP_IND_REG ) continue ;
242+
243+ RDRegValue v ;
244+ if (rd_get_regval_id (ctx , op -> reg , & v )) {
245+ rd_add_xref (ctx , instr -> address , v ,
246+ (i == 0 ) ? RD_DR_WRITE : RD_DR_READ );
247+ }
248+ }
249+ }
0 commit comments