Rizin
unix-like reverse engineering framework and cli tools
lh5801.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2014 jn
2 // SPDX-License-Identifier: LGPL-3.0-only
3 
4 /*
5  * This disassembler is based on the "SHARP PC-1500/A Systemhandbuch"
6  * (system manual) as published by Günter Holtkötter GmbH.
7  *
8  * An english version is available at
9  * http://www.pc1500.com/technical_reference_manual.html.
10  */
11 
12 #include "lh5801.h"
13 #include <stdio.h>
14 #include <string.h>
15 #include <rz_types.h>
16 
17 #define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0]))
18 
19 const struct lh5801_insn_class_desc
21  [LH5801_INSNC_ADC] = { "adc", "add with carry" },
22  [LH5801_INSNC_ADI] = { "adi", "add immediate" },
23  [LH5801_INSNC_DCA] = { "dca", "decimal add" },
24  [LH5801_INSNC_ADR] = { "adr", "add Rreg" },
25  [LH5801_INSNC_SBC] = { "sbc", "subtract with carry" },
26  [LH5801_INSNC_SBI] = { "sbi", "subtract immediate" },
27  [LH5801_INSNC_DCS] = { "dcs", "decimal subtract" },
28  [LH5801_INSNC_AND] = { "and", "and accumulator" },
29  [LH5801_INSNC_ANI] = { "ani", "and immediate" },
30  [LH5801_INSNC_ORA] = { "ora", "or accumulator" },
31  [LH5801_INSNC_ORI] = { "ori", "or immediate" },
32  [LH5801_INSNC_EOR] = { "eor", "exclusive or" },
33  [LH5801_INSNC_EAI] = { "eai", "exclusive or accumulator, immediate" },
34  [LH5801_INSNC_INC] = { "inc", "increment" },
35  [LH5801_INSNC_DEC] = { "dec", "decrement" },
36  [LH5801_INSNC_CPA] = { "cpa", "compare accumulator" },
37  [LH5801_INSNC_CPI] = { "cpi", "compare immediate" },
38  [LH5801_INSNC_BIT] = { "bit", "bit test" },
39  [LH5801_INSNC_BII] = { "bii", "bit test immediate" },
40  [LH5801_INSNC_LDA] = { "lda", "load accumulator" },
41  [LH5801_INSNC_LDE] = { "lde", "load and decrement" },
42  [LH5801_INSNC_LIN] = { "lin", "load and increment" },
43  [LH5801_INSNC_LDI] = { "ldi", "load immediate" },
44  [LH5801_INSNC_LDX] = { "ldx", "load Xreg" },
45  [LH5801_INSNC_STA] = { "sta", "store accumulator" },
46  [LH5801_INSNC_SDE] = { "sde", "store and decrement" },
47  [LH5801_INSNC_SIN] = { "sin", "store and increment" },
48  [LH5801_INSNC_STX] = { "stx", "store Xreg" },
49  [LH5801_INSNC_PSH] = { "psh", "push" },
50  [LH5801_INSNC_POP] = { "pop", "pop" },
51  [LH5801_INSNC_ATT] = { "att", "accumulator to t (status register)" },
52  [LH5801_INSNC_TTA] = { "tta", "t (status register) to accumulator" },
53  [LH5801_INSNC_TIN] = { "tin", "transfer and increment" },
54  [LH5801_INSNC_CIN] = { "cin", "compare and increment" },
55  [LH5801_INSNC_ROL] = { "rol", "rotate left" },
56  [LH5801_INSNC_ROR] = { "ror", "rotate right" },
57  [LH5801_INSNC_SHL] = { "shl", "shift left" },
58  [LH5801_INSNC_SHR] = { "shr", "shift right" },
59  [LH5801_INSNC_DRL] = { "drl", "digit rotate left" },
60  [LH5801_INSNC_DRR] = { "drr", "digit rotate right" },
61  [LH5801_INSNC_AEX] = { "aex", "exchange accumulator" },
62  [LH5801_INSNC_SEC] = { "sec", "set carry flag" },
63  [LH5801_INSNC_REC] = { "rec", "reset carry flag" },
64  [LH5801_INSNC_CDV] = { "cdv", "clear divider" },
65  [LH5801_INSNC_ATP] = { "atp", "accumulator to port" },
66  [LH5801_INSNC_SPU] = { "spu", "set PU" },
67  [LH5801_INSNC_RPU] = { "rpu", "reset PU" },
68  [LH5801_INSNC_SPV] = { "spv", "set PV" },
69  [LH5801_INSNC_RPV] = { "rpv", "reset PV" },
70  [LH5801_INSNC_SDP] = { "sdp", "set display" },
71  [LH5801_INSNC_RDP] = { "rdp", "reset display" },
72  [LH5801_INSNC_ITA] = { "ita", "IN to accumulator" },
73  [LH5801_INSNC_SIE] = { "sie", "set interrupt enable" },
74  [LH5801_INSNC_RIE] = { "rie", "reset interrupt enable" },
75  [LH5801_INSNC_AM0] = { "am0", "accumulator to tm and 0" },
76  [LH5801_INSNC_AM1] = { "am1", "accumulator to tm and 1" },
77  [LH5801_INSNC_NOP] = { "nop", "no operation" },
78  [LH5801_INSNC_HLT] = { "hlt", "halt" },
79  [LH5801_INSNC_OFF] = { "off", "\"off\", reset BF" },
80  [LH5801_INSNC_JMP] = { "jmp", "jump" },
81  [LH5801_INSNC_BCH] = { "bch", "unconditional branch" },
82  [LH5801_INSNC_BCC] = { "bcc", "conditional branch" },
83  [LH5801_INSNC_LOP] = { "lop", "loop" },
84  [LH5801_INSNC_SJP] = { "sjp", "subroutine jump (aka. call)" },
85  [LH5801_INSNC_VEJ] = { "vej", "vector subroutine jump, short format" },
86  [LH5801_INSNC_VMJ] = { "vmj", "vector subroutine jump, long format" },
87  [LH5801_INSNC_VCC] = { "vcc", "conditional vector subroutine jump" },
88  [LH5801_INSNC_RTN] = { "rtn", "return from subroutine" },
89  [LH5801_INSNC_RTI] = { "rti", "return from interrupt" }
90  };
91 
92 /* These flags describe an instruction variant's properties with regard to
93  * encoding and printing */
95  /* An instruction can contain up to three immediate data bytes. */
101 
102  /* Instructions may either require an 0xFD prefix, require its absence,
103  * or behave differently if it is found. */
106  LH5801_IFMT_FD_MOD = 2 << 2, /* FD_MEM */
107  LH5801_IFMT_FD_MASK = 3 << 2, /* ^- also take care of (ij) */
108 
109  /* Some instructions encode access registers */
110  LH5801_IFMT_RREG = 1 << 4, /* X,Y or U, encoded by two bits */
111  LH5801_IFMT_AREG = 2 << 4, /* accumulator */
112  LH5801_IFMT_SREG = 3 << 4, /* stack pointer */
113  LH5801_IFMT_PREG = 4 << 4, /* program counter */
115 
116  /* Branch and vector jump instructions may have a three-bit condition
117  * code. */
119 
120  /* Branch instructions may point forward or backward. */
121  LH5801_IFMT_BCH = 1 << 8,
122 
123  /* The short vector jump instruction (VEJ) */
124  LH5801_IFMT_VEJ = 1 << 9,
125 
126  /* Register access modes: full, low/high half, or memory pointed to */
128  LH5801_IFMT_RLOW = 1 << 10,
129  LH5801_IFMT_RHIGH = 2 << 10,
130  LH5801_IFMT_RMEM = 3 << 10, /* <-- should be removed, see above */
132 };
133 
134 #define LH5801_IFMT_IMMS(f) ((f)&LH5801_IFMT_IMM_MASK)
135 #define LH5801_IFMT_RMODE(f) ((f)&LH5801_IFMT_RMODE_MASK)
136 
137 static bool lh5801_ifmt_fd_matches(enum lh5801_insn_format fmt, int fd) {
138  switch (fmt & LH5801_IFMT_FD_MASK) {
139  case LH5801_IFMT_FD_NO: return !fd;
140  case LH5801_IFMT_FD_YES: return fd;
141  case LH5801_IFMT_FD_MOD: return true;
142  default: return false;
143  }
144 }
145 
146 /* Instruction (variant) description. */
148  ut8 iclass; /* enum lh5801_insn_class */
149 
150  /* The common bits in this format */
152 
153  ut16 format; /* enum lh5801_insn_format */
154 };
155 
156 const struct lh5801_insn_desc lh5801_insn_descs[] = {
157  {
158  /* adc rl*/
161  .opcode = 0x02,
162  },
163  {
164  /* adc rh*/
165  .iclass = LH5801_INSNC_ADC,
167  .opcode = 0x82,
168  },
169  {
170  /* adc (r) */
171  .iclass = LH5801_INSNC_ADC,
173  .opcode = 0x03,
174  },
175  {
176  /* adc (0000h) */
177  .iclass = LH5801_INSNC_ADC,
179  .opcode = 0xa3,
180  },
181  { /* adi a, 00h */
182  .iclass = LH5801_INSNC_ADI,
184  .opcode = 0xb3 },
185  {
186  /* adi (r), 00h */
187  .iclass = LH5801_INSNC_ADI,
189  .opcode = 0x4f,
190  },
191  { /* adi (0000h), 00h */
192  .iclass = LH5801_INSNC_ADI,
194  .opcode = 0xef },
195  {
196  /* dca (r) */
197  .iclass = LH5801_INSNC_DCA,
199  .opcode = 0x8c,
200  },
201  {
202  /* adr r */
203  .iclass = LH5801_INSNC_ADR,
205  .opcode = 0xca,
206  },
207  { /* sbc rl */
208  .iclass = LH5801_INSNC_SBC,
210  .opcode = 0x00 },
211  { /* sbc rh */
212  .iclass = LH5801_INSNC_SBC,
214  .opcode = 0x80 },
215  { /* sbc (r) */
216  .iclass = LH5801_INSNC_SBC,
218  .opcode = 0x01 },
219  { /* sbc (0000h) */
220  .iclass = LH5801_INSNC_SBC,
222  .opcode = 0xa1 },
223  { /* sbi a, 00h */
224  .iclass = LH5801_INSNC_SBI,
226  .opcode = 0xb1 },
227  { /* dcs (r) */
228  .iclass = LH5801_INSNC_DCS,
230  .opcode = 0x0c },
231  { /* and (r) */
232  .iclass = LH5801_INSNC_AND,
234  .opcode = 0x09 },
235  { /* and (0000h) */
236  .iclass = LH5801_INSNC_AND,
238  .opcode = 0xa9 },
239  { /* ani a, 00h */
240  .iclass = LH5801_INSNC_ANI,
242  .opcode = 0xb9 },
243  { /* ani (r), 00h */
244  .iclass = LH5801_INSNC_ANI,
246  .opcode = 0x49 },
247  { /* ani (0000h), 00h */
248  .iclass = LH5801_INSNC_ANI,
250  .opcode = 0xe9 },
251  { /* ora (r) */
252  .iclass = LH5801_INSNC_ORA,
254  .opcode = 0x0b },
255  { /* ora (0000h) */
256  .iclass = LH5801_INSNC_ORA,
258  .opcode = 0xab },
259  { /* ori a, 00h */
260  .iclass = LH5801_INSNC_ORI,
262  .opcode = 0xbb },
263  { /* ori (r), 00h */
264  .iclass = LH5801_INSNC_ORI,
266  .opcode = 0x4b },
267  { /* ori (0000h), 00h */
268  .iclass = LH5801_INSNC_ORI,
270  .opcode = 0xeb },
271  { /* eor (r) */
272  .iclass = LH5801_INSNC_EOR,
274  .opcode = 0x0d },
275  { /* eor (0000h) */
276  .iclass = LH5801_INSNC_EOR,
278  .opcode = 0xad },
279  { /* eai 00h */
280  .iclass = LH5801_INSNC_EAI,
281  .format = LH5801_IFMT_IMM1,
282  .opcode = 0xbd },
283  {
284  /* inc a */
285  .iclass = LH5801_INSNC_INC,
286  .format = LH5801_IFMT_AREG,
287  .opcode = 0xdd,
288  },
289  {
290  /* inc rl */
291  .iclass = LH5801_INSNC_INC,
293  .opcode = 0x40,
294  },
295  {
296  /* inc rh */
297  .iclass = LH5801_INSNC_INC,
299  .opcode = 0x40,
300  },
301  { /* inc r */
302  .iclass = LH5801_INSNC_INC,
303  .format = LH5801_IFMT_RREG,
304  .opcode = 0x44 },
305  {
306  /* dec a */
307  .iclass = LH5801_INSNC_DEC,
308  .format = LH5801_IFMT_AREG,
309  .opcode = 0xdf,
310  },
311  {
312  /* dec rl */
313  .iclass = LH5801_INSNC_DEC,
315  .opcode = 0x42,
316  },
317  {
318  /* dec rh */
319  .iclass = LH5801_INSNC_DEC,
321  .opcode = 0x42,
322  },
323  { /* dec r */
324  .iclass = LH5801_INSNC_DEC,
325  .format = LH5801_IFMT_RREG,
326  .opcode = 0x46 },
327  { /* cpa rl */
328  .iclass = LH5801_INSNC_CPA,
330  .opcode = 0x06 },
331  { /* cpa rh */
332  .iclass = LH5801_INSNC_CPA,
334  .opcode = 0x86 },
335  { /* cpa (r) */
336  .iclass = LH5801_INSNC_CPA,
338  .opcode = 0x07 },
339  { /* cpa (0000h) */
340  .iclass = LH5801_INSNC_CPA,
342  .opcode = 0xa7 },
343  { /* cpi rl,00h */
344  .iclass = LH5801_INSNC_CPI,
346  .opcode = 0x4e },
347  { /* cpi rh,00h */
348  .iclass = LH5801_INSNC_CPI,
350  .opcode = 0x4c },
351  { /* cpi a,00h */
352  .iclass = LH5801_INSNC_CPI,
354  .opcode = 0xb7 },
355  { /* bit (r) */
356  .iclass = LH5801_INSNC_BIT,
358  .opcode = 0x0f },
359  { /* bit (0000h) */
360  .iclass = LH5801_INSNC_BIT,
362  .opcode = 0xaf },
363  { /* bii a, 00h */
364  .iclass = LH5801_INSNC_BII,
366  .opcode = 0xbf },
367  { /* bii (r), 00h */
368  .iclass = LH5801_INSNC_BII,
370  .opcode = 0x4d },
371  { /* bii (0000h), 00h */
372  .iclass = LH5801_INSNC_BII,
374  .opcode = 0xed },
375  {
376  /* lda rl */
377  .iclass = LH5801_INSNC_LDA,
379  .opcode = 0x04,
380  },
381  {
382  /* lda rh */
383  .iclass = LH5801_INSNC_LDA,
385  .opcode = 0x84,
386  },
387  {
388  /* lda (r) */
389  .iclass = LH5801_INSNC_LDA,
391  .opcode = 0x05,
392  },
393  {
394  /* lda (0000h) */
395  .iclass = LH5801_INSNC_LDA,
397  .opcode = 0xa5,
398  },
399  {
400  /* lde r */
401  .iclass = LH5801_INSNC_LDE,
402  .format = LH5801_IFMT_RREG,
403  .opcode = 0x47,
404  },
405  {
406  /* lin r */
407  .iclass = LH5801_INSNC_LIN,
408  .format = LH5801_IFMT_RREG,
409  .opcode = 0x45,
410  },
411  {
412  /* ldi rl, 00h */
413  .iclass = LH5801_INSNC_LDI,
415  .opcode = 0x4a,
416  },
417  {
418  /* ldi rh, 00h */
419  .iclass = LH5801_INSNC_LDI,
421  .opcode = 0x48,
422  },
423  { /* ldi a, 00h */
424  .iclass = LH5801_INSNC_LDI,
426  .opcode = 0xb5 },
427  { /* ldi s, 0000h */
428  .iclass = LH5801_INSNC_LDI,
430  .opcode = 0xaa },
431  {
432  /* ldx r */
433  .iclass = LH5801_INSNC_LDX,
435  .opcode = 0x08,
436  },
437  {
438  /* ldx s */
439  .iclass = LH5801_INSNC_LDX,
441  .opcode = 0x48,
442  },
443  { /* ldx p */
444  .iclass = LH5801_INSNC_LDX,
446  .opcode = 0x58 },
447  { /* sta rl */
448  .iclass = LH5801_INSNC_STA,
450  .opcode = 0x0a },
451  { /* sta rh */
452  .iclass = LH5801_INSNC_STA,
454  .opcode = 0x08 },
455  { /* sta (r) */
456  .iclass = LH5801_INSNC_STA,
458  .opcode = 0x0e },
459  { /* sta (0000h) */
460  .iclass = LH5801_INSNC_STA,
462  .opcode = 0xae },
463  { /* sde r */
464  .iclass = LH5801_INSNC_SDE,
465  .format = LH5801_IFMT_RREG,
466  .opcode = 0x43 },
467  { /* sin r */
468  .iclass = LH5801_INSNC_SIN,
469  .format = LH5801_IFMT_RREG,
470  .opcode = 0x41 },
471  { /* stx r */
472  .iclass = LH5801_INSNC_STX,
474  .opcode = 0x4a },
475  { /* stx s */
476  .iclass = LH5801_INSNC_STX,
478  .opcode = 0x4e },
479  { /* stx p */
480  .iclass = LH5801_INSNC_STX,
482  .opcode = 0x5e },
483  { /* psh a */
484  .iclass = LH5801_INSNC_PSH,
486  .opcode = 0xc8 },
487  { /* psh r */
488  .iclass = LH5801_INSNC_PSH,
490  .opcode = 0x88 },
491  { /* pop a */
492  .iclass = LH5801_INSNC_POP,
494  .opcode = 0x8a },
495  { /* pop r */
496  .iclass = LH5801_INSNC_POP,
498  .opcode = 0x0a },
499  { /* att */
500  .iclass = LH5801_INSNC_ATT,
501  .format = LH5801_IFMT_FD_YES,
502  .opcode = 0xec },
503  { /* tta */
504  .iclass = LH5801_INSNC_TTA,
505  .format = LH5801_IFMT_FD_YES,
506  .opcode = 0xaa },
507  { /* tin */
508  .iclass = LH5801_INSNC_TIN,
509  .format = 0,
510  .opcode = 0xf5 },
511  { /* cin */
512  .iclass = LH5801_INSNC_CIN,
513  .format = 0,
514  .opcode = 0xf7 },
515  { /* rol */
516  /* FIXME:
517  * In the technical reference manual rol is encoded as 0xd8
518  * (vej d8h) in one table and 0xdd (inc a) in another. The
519  * actual encoding of rol should be used instead.
520  */
521  .iclass = LH5801_INSNC_ROL,
522  .format = 0,
523  .opcode = 0xdd },
524  { /* ror */
525  .iclass = LH5801_INSNC_ROR,
526  .format = 0,
527  .opcode = 0xd1 },
528  { /* shl */
529  .iclass = LH5801_INSNC_SHL,
530  .format = 0,
531  .opcode = 0xd9 },
532  { /* shr */
533  .iclass = LH5801_INSNC_SHR,
534  .format = 0,
535  .opcode = 0xd5 },
536  { /* drl (x) */
537  .iclass = LH5801_INSNC_DRL,
538  .format = 0, // LH5801_IFMT_XREG|LH5801_IFMT_RMEM|LH5801_IFMT_FD_MOD,
539  .opcode = 0xd7 },
540  { /* drr (x) */
541  .iclass = LH5801_INSNC_DRR,
542  .format = 0, // LH5801_IFMT_XREG|LH5801_IFMT_RMEM|LH5801_IFMT_FD_MOD,
543  .opcode = 0xd3 },
544  { /* aex */
545  .iclass = LH5801_INSNC_AEX,
546  .format = 0,
547  .opcode = 0xf1 },
548  { /* am0 */
549  .iclass = LH5801_INSNC_AM0,
550  .format = LH5801_IFMT_FD_YES,
551  .opcode = 0xce },
552  { /* am1 */
553  .iclass = LH5801_INSNC_AM1,
554  .format = LH5801_IFMT_FD_YES,
555  .opcode = 0xde },
556  { /* cdv */
557  .iclass = LH5801_INSNC_CDV,
558  .format = LH5801_IFMT_FD_YES,
559  .opcode = 0x8e },
560  { /* atp */
561  .iclass = LH5801_INSNC_ATP,
562  .format = LH5801_IFMT_FD_YES,
563  .opcode = 0xcc },
564  { /* sdp */
565  .iclass = LH5801_INSNC_SDP,
566  .format = LH5801_IFMT_FD_YES,
567  .opcode = 0xc1 },
568  { /* rdp */
569  .iclass = LH5801_INSNC_RDP,
570  .format = LH5801_IFMT_FD_YES,
571  .opcode = 0xc0 },
572  { /* spu */
573  .iclass = LH5801_INSNC_SPU,
574  .format = 0,
575  .opcode = 0xe1 },
576  { /* rpu */
577  .iclass = LH5801_INSNC_RPU,
578  .format = 0,
579  .opcode = 0xe3 },
580  { /* spv */
581  .iclass = LH5801_INSNC_SPV,
582  .format = 0,
583  .opcode = 0xa8 },
584  { /* rpv */
585  .iclass = LH5801_INSNC_RPV,
586  .format = 0,
587  .opcode = 0xb8 },
588  { /* ita */
589  .iclass = LH5801_INSNC_ITA,
590  .format = LH5801_IFMT_FD_YES,
591  .opcode = 0xba },
592  { /* rie */
593  .iclass = LH5801_INSNC_RIE,
594  .format = LH5801_IFMT_FD_YES,
595  .opcode = 0xbe },
596  { /* sie */
597  .iclass = LH5801_INSNC_SIE,
598  .format = LH5801_IFMT_FD_YES,
599  .opcode = 0x81 },
600  { /* hlt */
601  .iclass = LH5801_INSNC_HLT,
602  .format = LH5801_IFMT_FD_YES,
603  .opcode = 0xb1 },
604  { /* off */
605  .iclass = LH5801_INSNC_OFF,
606  .format = LH5801_IFMT_FD_YES,
607  .opcode = 0x4c },
608  { /* nop */
609  .iclass = LH5801_INSNC_NOP,
610  .format = 0,
611  .opcode = 0x38 },
612  { /* sec */
613  .iclass = LH5801_INSNC_SEC,
614  .format = 0,
615  .opcode = 0xfb },
616  { /* rec */
617  .iclass = LH5801_INSNC_REC,
618  .format = 0,
619  .opcode = 0xf9 },
620  { /* jmp 0000h */
621  .iclass = LH5801_INSNC_JMP,
622  .format = LH5801_IFMT_IMM2,
623  .opcode = 0xba },
624  { /* bch ±00h */
625  .iclass = LH5801_INSNC_BCH,
626  .format = LH5801_IFMT_BCH | LH5801_IFMT_IMM1,
627  .opcode = 0x8e },
628  { /* bcc ±00h */
629  .iclass = LH5801_INSNC_BCC,
631  .opcode = 0x81 },
632  { /* lop 02h */
633  .iclass = LH5801_INSNC_LOP,
634  .format = LH5801_IFMT_IMM1,
635  .opcode = 0x88 },
636  {
637  /* sjp 0000h */
638  .iclass = LH5801_INSNC_SJP,
639  .format = LH5801_IFMT_IMM2,
640  .opcode = 0xbe,
641  },
642  { /* vej c0h */
643  .iclass = LH5801_INSNC_VEJ,
644  .format = LH5801_IFMT_VEJ,
645  .opcode = 0xc0 },
646  { /* vcc 00h */
647  .iclass = LH5801_INSNC_VCC,
649  .opcode = 0xc1 },
650  { /* vmj 00h */
651  /* FIXME:
652  * This instruction is documented in the technical reference
653  * manual, but when decoded in the same way as bcc, it looks
654  * like vvr (vector jump if overflow is reset).
655  * It should be tested what the hardware does on vmj with the
656  * overflow bit set.
657  */
658  .iclass = LH5801_INSNC_VMJ,
659  .format = LH5801_IFMT_IMM1,
660  .opcode = 0xcd },
661  { /* rtn */
662  .iclass = LH5801_INSNC_RTN,
663  .format = 0,
664  .opcode = 0x9a },
665  { /* rti */
666  .iclass = LH5801_INSNC_RTI,
667  .format = 0,
668  .opcode = 0x8a }
669 };
670 
671 /* Decodes one instruction.
672  * returns -1 on invalid instructions, the length on valid instructions,
673  * and 0 when decoding wasn't possible due to a too small length */
674 int lh5801_decode(struct lh5801_insn *insn, const ut8 *buf, int len) {
675  int fd = (buf[0] == 0xfd);
676  int type = -1;
677  unsigned i;
678  struct lh5801_insn_desc desc;
679 
680  if (fd) {
681  buf++;
682  len--;
683  }
684 
685  if (len == 0)
686  return 0;
687 
688  /* Find the correct opcode */
689  for (i = 0; i < ARRAY_LENGTH(lh5801_insn_descs); i++) {
690  ut8 byte = *buf;
691  unsigned fmt;
692  unsigned ifmt_reg;
693 
695  fmt = desc.format;
696  ifmt_reg = fmt & LH5801_IFMT_REG_MASK;
697 
698  if (!lh5801_ifmt_fd_matches(fmt, fd))
699  continue;
700 
701  /* Ignore instructions referencing the register number 3. */
702  if (ifmt_reg == LH5801_IFMT_RREG && (byte >> 4) % 4 == 3)
703  continue;
704 
705  /* Reduce the opcode byte to the relevant bits */
706  if (ifmt_reg == LH5801_IFMT_RREG)
707  byte &= 0xcf; /* xxRRxxxx */
708  if (fmt & LH5801_IFMT_COND)
709  byte &= 0xf1; /* xxxxCCCx */
710  if (fmt & LH5801_IFMT_BCH)
711  byte &= 0xef; /* xxxSxxxx */
712 
713  if (byte == desc.opcode) {
714  type = i;
715  break;
716  }
717 
718  /* The short vector subroutine jump instructions require
719  * special treatment. */
720  if (fmt & LH5801_IFMT_VEJ) {
721  if (!(byte & 1) && byte >= 0xc0 && byte <= 0xf6) {
722  type = i;
723  break;
724  }
725  }
726  }
727  if (type == -1)
728  return -1;
729 
730  /* fill the insn structure. */
731  insn->iclass = desc.iclass;
732  insn->type = type;
733  insn->fd = fd;
734  insn->opcode = buf[0];
735  switch (LH5801_IFMT_IMMS(desc.format)) {
736  case 3: insn->imm[2] = buf[3]; // fallthrough
737  case 2: insn->imm[1] = buf[2]; // fallthrough
738  case 1: insn->imm[0] = buf[1]; // fallthrough
739  }
740 
741  /* return the instruction length */
742  return fd + 1 + LH5801_IFMT_IMMS(desc.format);
743 }
744 
745 /* Print the accessed register. Buf must point to a buffer of at least eight
746  * bytes. Only the return value should be used. */
747 static char *print_reg(char *buf, const struct lh5801_insn *insn) {
748  const struct lh5801_insn_desc desc = lh5801_insn_descs[insn->type];
749  unsigned regnr = (insn->opcode >> 4) & 3;
750  const char names[] = "xyu";
751  char *saved_buf = buf;
752 
753  /* Handle A, S, and P, before handling R */
754  switch (desc.format & LH5801_IFMT_REG_MASK) {
755  case LH5801_IFMT_AREG: return "a";
756  case LH5801_IFMT_SREG: return "s";
757  case LH5801_IFMT_PREG: return "p";
758  }
759 
760  if (regnr == 3)
761  return "invalid";
762  else
763  switch (LH5801_IFMT_RMODE(desc.format)) {
764  case LH5801_IFMT_RFULL:
765  buf[0] = names[regnr];
766  buf[1] = '\0';
767  break;
768  case LH5801_IFMT_RLOW:
769  case LH5801_IFMT_RHIGH:
770  buf[0] = names[regnr];
771  buf[1] = (desc.format & LH5801_IFMT_RLOW) ? 'l' : 'h';
772  buf[2] = '\0';
773  break;
774  case LH5801_IFMT_RMEM:
775  if (desc.format & LH5801_IFMT_FD_MOD) {
776  if (insn->fd)
777  *(buf++) = '#';
778  buf[0] = '(';
779  buf[1] = names[regnr];
780  buf[2] = ')';
781  buf[3] = '\0';
782  } else {
783  return NULL;
784  }
785  break;
786  default:
787  return NULL;
788  }
789  return saved_buf;
790 }
791 
792 void lh5801_print_insn(char *out, int size, const struct lh5801_insn *insn) {
793  const struct lh5801_insn_class_desc *iclass =
795  const struct lh5801_insn_desc desc = lh5801_insn_descs[insn->type];
796  const char *mnem = iclass->mnem;
797  char mnembuf[4];
798  char regbuf[8];
799 
800  /* Conditional instructions have special mnemonics. */
801  if (desc.format & LH5801_IFMT_COND) {
802  mnembuf[0] = mnem[0]; /* the first character is the same. */
803  mnembuf[1] = "chzv"[(insn->opcode >> 2) % 4]; /* which flag */
804  mnembuf[2] = (insn->opcode & 2) ? 's' : 'r'; /* set or reset */
805  mnembuf[3] = '\0';
806  mnem = mnembuf;
807  }
808 
809  /*
810  * operand print modes:
811  * IMM0: rl/rh, REG|LOW, REG|HIGH
812  * r, REG
813  * (r), REG|MEM -> would MEM imply FD_MOD?
814  * s,p S, P
815  * vej i VEJ
816  * IMM1: IMM0,i IMM1
817  * a,i ACCU
818  * IMM2: ij (jump)
819  * (ij)
820  * s,ij (ldi)
821  * IMM3: (ij),k
822  */
823 
825  case LH5801_IFMT_VEJ:
826  snprintf(out, size, "%s %02xh", mnem, insn->opcode);
827  break;
828  case LH5801_IFMT_IMM0:
829  snprintf(out, size, "%s", mnem);
830  break;
835  snprintf(out, size, "%s %s", mnem, print_reg(regbuf, insn));
836  break;
837  case LH5801_IFMT_IMM1:
838  snprintf(out, size, "%s %02xh", mnem, insn->imm[0]);
839  break;
844  snprintf(out, size, "%s %s, %02xh", mnem,
845  print_reg(regbuf, insn), insn->imm[0]);
846  break;
848  snprintf(out, size, "%s %c%02xh", mnem,
849  (insn->opcode & 0x10) ? '-' : '+', insn->imm[0]);
850  break;
851  case LH5801_IFMT_IMM2:
852  if (desc.format & LH5801_IFMT_FD_MOD) {
853  snprintf(out, size, "%s %s(%02x%02xh)", mnem,
854  insn->fd ? "#" : "",
855  insn->imm[0], insn->imm[1]);
856  } else {
857  snprintf(out, size, "%s %02x%02xh", mnem,
858  insn->imm[0], insn->imm[1]);
859  }
860  break;
861  case LH5801_IFMT_IMM3:
862  if (desc.format & LH5801_IFMT_FD_MOD) {
863  snprintf(out, size, "%s %s(%02x%02xh), %02xh", mnem,
864  insn->fd ? "#" : "",
865  insn->imm[0], insn->imm[1], insn->imm[2]);
866  } else {
867  snprintf(out, size, "imm3 invalid format");
868  }
869  break;
870  default:
871  snprintf(out, size, "%s, BUG: unknown format 0x%x -> 0x%x",
872  mnem, desc.format,
873  desc.format & ~LH5801_IFMT_RMODE_MASK &
875  }
876 }
size_t len
Definition: 6502dis.c:15
#define mnem(n, mn)
lzma_index ** i
Definition: index.h:629
const char * desc
Definition: bin_vsf.c:19
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
#define NULL
Definition: cris-opc.c:27
uint16_t ut16
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
static char * print_reg(char *buf, const struct lh5801_insn *insn)
Definition: lh5801.c:747
#define LH5801_IFMT_RMODE(f)
Definition: lh5801.c:135
const struct lh5801_insn_desc lh5801_insn_descs[]
Definition: lh5801.c:156
const struct lh5801_insn_class_desc lh5801_insn_class_descs[LH5801_INSNC_NUMBER]
Definition: lh5801.c:20
static bool lh5801_ifmt_fd_matches(enum lh5801_insn_format fmt, int fd)
Definition: lh5801.c:137
void lh5801_print_insn(char *out, int size, const struct lh5801_insn *insn)
Definition: lh5801.c:792
int lh5801_decode(struct lh5801_insn *insn, const ut8 *buf, int len)
Definition: lh5801.c:674
lh5801_insn_format
Definition: lh5801.c:94
@ LH5801_IFMT_IMM3
Definition: lh5801.c:99
@ LH5801_IFMT_PREG
Definition: lh5801.c:113
@ LH5801_IFMT_IMM_MASK
Definition: lh5801.c:100
@ LH5801_IFMT_RMODE_MASK
Definition: lh5801.c:131
@ LH5801_IFMT_RFULL
Definition: lh5801.c:127
@ LH5801_IFMT_RHIGH
Definition: lh5801.c:129
@ LH5801_IFMT_RLOW
Definition: lh5801.c:128
@ LH5801_IFMT_VEJ
Definition: lh5801.c:124
@ LH5801_IFMT_SREG
Definition: lh5801.c:112
@ LH5801_IFMT_IMM2
Definition: lh5801.c:98
@ LH5801_IFMT_REG_MASK
Definition: lh5801.c:114
@ LH5801_IFMT_FD_YES
Definition: lh5801.c:105
@ LH5801_IFMT_RREG
Definition: lh5801.c:110
@ LH5801_IFMT_FD_NO
Definition: lh5801.c:104
@ LH5801_IFMT_BCH
Definition: lh5801.c:121
@ LH5801_IFMT_FD_MOD
Definition: lh5801.c:106
@ LH5801_IFMT_FD_MASK
Definition: lh5801.c:107
@ LH5801_IFMT_IMM1
Definition: lh5801.c:97
@ LH5801_IFMT_AREG
Definition: lh5801.c:111
@ LH5801_IFMT_RMEM
Definition: lh5801.c:130
@ LH5801_IFMT_COND
Definition: lh5801.c:118
@ LH5801_IFMT_IMM0
Definition: lh5801.c:96
#define ARRAY_LENGTH(a)
Definition: lh5801.c:17
#define LH5801_IFMT_IMMS(f)
Definition: lh5801.c:134
@ LH5801_INSNC_DCS
Definition: lh5801.h:21
@ LH5801_INSNC_PSH
Definition: lh5801.h:43
@ LH5801_INSNC_TIN
Definition: lh5801.h:47
@ LH5801_INSNC_ADC
Definition: lh5801.h:15
@ LH5801_INSNC_SPU
Definition: lh5801.h:60
@ LH5801_INSNC_POP
Definition: lh5801.h:44
@ LH5801_INSNC_RPV
Definition: lh5801.h:63
@ LH5801_INSNC_CPA
Definition: lh5801.h:30
@ LH5801_INSNC_SIE
Definition: lh5801.h:67
@ LH5801_INSNC_ATP
Definition: lh5801.h:59
@ LH5801_INSNC_BIT
Definition: lh5801.h:32
@ LH5801_INSNC_TTA
Definition: lh5801.h:46
@ LH5801_INSNC_AM1
Definition: lh5801.h:70
@ LH5801_INSNC_AM0
Definition: lh5801.h:69
@ LH5801_INSNC_DEC
Definition: lh5801.h:29
@ LH5801_INSNC_NUMBER
Definition: lh5801.h:85
@ LH5801_INSNC_JMP
Definition: lh5801.h:74
@ LH5801_INSNC_RTN
Definition: lh5801.h:82
@ LH5801_INSNC_SPV
Definition: lh5801.h:62
@ LH5801_INSNC_REC
Definition: lh5801.h:57
@ LH5801_INSNC_LDI
Definition: lh5801.h:37
@ LH5801_INSNC_SDE
Definition: lh5801.h:40
@ LH5801_INSNC_DCA
Definition: lh5801.h:17
@ LH5801_INSNC_BCH
Definition: lh5801.h:75
@ LH5801_INSNC_RIE
Definition: lh5801.h:68
@ LH5801_INSNC_LOP
Definition: lh5801.h:77
@ LH5801_INSNC_ATT
Definition: lh5801.h:45
@ LH5801_INSNC_LIN
Definition: lh5801.h:36
@ LH5801_INSNC_VMJ
Definition: lh5801.h:80
@ LH5801_INSNC_VCC
Definition: lh5801.h:81
@ LH5801_INSNC_ANI
Definition: lh5801.h:23
@ LH5801_INSNC_SBI
Definition: lh5801.h:20
@ LH5801_INSNC_DRR
Definition: lh5801.h:54
@ LH5801_INSNC_CIN
Definition: lh5801.h:48
@ LH5801_INSNC_LDE
Definition: lh5801.h:35
@ LH5801_INSNC_SJP
Definition: lh5801.h:78
@ LH5801_INSNC_OFF
Definition: lh5801.h:73
@ LH5801_INSNC_ITA
Definition: lh5801.h:66
@ LH5801_INSNC_RDP
Definition: lh5801.h:65
@ LH5801_INSNC_STA
Definition: lh5801.h:39
@ LH5801_INSNC_LDA
Definition: lh5801.h:34
@ LH5801_INSNC_ORA
Definition: lh5801.h:24
@ LH5801_INSNC_SEC
Definition: lh5801.h:56
@ LH5801_INSNC_AND
Definition: lh5801.h:22
@ LH5801_INSNC_SDP
Definition: lh5801.h:64
@ LH5801_INSNC_RTI
Definition: lh5801.h:83
@ LH5801_INSNC_HLT
Definition: lh5801.h:72
@ LH5801_INSNC_VEJ
Definition: lh5801.h:79
@ LH5801_INSNC_ROR
Definition: lh5801.h:50
@ LH5801_INSNC_ADI
Definition: lh5801.h:16
@ LH5801_INSNC_ADR
Definition: lh5801.h:18
@ LH5801_INSNC_ROL
Definition: lh5801.h:49
@ LH5801_INSNC_CPI
Definition: lh5801.h:31
@ LH5801_INSNC_ORI
Definition: lh5801.h:25
@ LH5801_INSNC_SBC
Definition: lh5801.h:19
@ LH5801_INSNC_LDX
Definition: lh5801.h:38
@ LH5801_INSNC_INC
Definition: lh5801.h:28
@ LH5801_INSNC_SIN
Definition: lh5801.h:41
@ LH5801_INSNC_EAI
Definition: lh5801.h:27
@ LH5801_INSNC_SHL
Definition: lh5801.h:51
@ LH5801_INSNC_NOP
Definition: lh5801.h:71
@ LH5801_INSNC_AEX
Definition: lh5801.h:55
@ LH5801_INSNC_SHR
Definition: lh5801.h:52
@ LH5801_INSNC_BII
Definition: lh5801.h:33
@ LH5801_INSNC_DRL
Definition: lh5801.h:53
@ LH5801_INSNC_BCC
Definition: lh5801.h:76
@ LH5801_INSNC_EOR
Definition: lh5801.h:26
@ LH5801_INSNC_CDV
Definition: lh5801.h:58
@ LH5801_INSNC_STX
Definition: lh5801.h:42
@ LH5801_INSNC_RPU
Definition: lh5801.h:61
uint8_t ut8
Definition: lh5801.h:11
int type
Definition: mipsasm.c:17
ut8 fd
Definition: lh5801.h:103
ut8 type
Definition: lh5801.h:102
ut8 opcode
Definition: lh5801.h:104
ut8 iclass
Definition: lh5801.h:101
ut8 imm[3]
Definition: lh5801.h:105
Definition: names.h:123
static const z80_opcode fd[]
Definition: z80_tab.h:997