Rizin
unix-like reverse engineering framework and cli tools
lh5801.c File Reference
#include "lh5801.h"
#include <stdio.h>
#include <string.h>
#include <rz_types.h>

Go to the source code of this file.

Classes

struct  lh5801_insn_desc
 

Macros

#define ARRAY_LENGTH(a)   (sizeof(a) / sizeof((a)[0]))
 
#define LH5801_IFMT_IMMS(f)   ((f)&LH5801_IFMT_IMM_MASK)
 
#define LH5801_IFMT_RMODE(f)   ((f)&LH5801_IFMT_RMODE_MASK)
 

Enumerations

enum  lh5801_insn_format {
  LH5801_IFMT_IMM0 = 0 , LH5801_IFMT_IMM1 , LH5801_IFMT_IMM2 , LH5801_IFMT_IMM3 ,
  LH5801_IFMT_IMM_MASK = 3 , LH5801_IFMT_FD_NO = 0 , LH5801_IFMT_FD_YES = 1 << 2 , LH5801_IFMT_FD_MOD = 2 << 2 ,
  LH5801_IFMT_FD_MASK = 3 << 2 , LH5801_IFMT_RREG = 1 << 4 , LH5801_IFMT_AREG = 2 << 4 , LH5801_IFMT_SREG = 3 << 4 ,
  LH5801_IFMT_PREG = 4 << 4 , LH5801_IFMT_REG_MASK = 7 << 4 , LH5801_IFMT_COND = 1 << 7 , LH5801_IFMT_BCH = 1 << 8 ,
  LH5801_IFMT_VEJ = 1 << 9 , LH5801_IFMT_RFULL = 0 , LH5801_IFMT_RLOW = 1 << 10 , LH5801_IFMT_RHIGH = 2 << 10 ,
  LH5801_IFMT_RMEM = 3 << 10 , LH5801_IFMT_RMODE_MASK = 3 << 10
}
 

Functions

static bool lh5801_ifmt_fd_matches (enum lh5801_insn_format fmt, int fd)
 
int lh5801_decode (struct lh5801_insn *insn, const ut8 *buf, int len)
 
static char * print_reg (char *buf, const struct lh5801_insn *insn)
 
void lh5801_print_insn (char *out, int size, const struct lh5801_insn *insn)
 

Variables

const struct lh5801_insn_class_desc lh5801_insn_class_descs [LH5801_INSNC_NUMBER]
 
const struct lh5801_insn_desc lh5801_insn_descs []
 

Macro Definition Documentation

◆ ARRAY_LENGTH

#define ARRAY_LENGTH (   a)    (sizeof(a) / sizeof((a)[0]))

Definition at line 17 of file lh5801.c.

◆ LH5801_IFMT_IMMS

#define LH5801_IFMT_IMMS (   f)    ((f)&LH5801_IFMT_IMM_MASK)

Definition at line 134 of file lh5801.c.

◆ LH5801_IFMT_RMODE

#define LH5801_IFMT_RMODE (   f)    ((f)&LH5801_IFMT_RMODE_MASK)

Definition at line 135 of file lh5801.c.

Enumeration Type Documentation

◆ lh5801_insn_format

Enumerator
LH5801_IFMT_IMM0 
LH5801_IFMT_IMM1 
LH5801_IFMT_IMM2 
LH5801_IFMT_IMM3 
LH5801_IFMT_IMM_MASK 
LH5801_IFMT_FD_NO 
LH5801_IFMT_FD_YES 
LH5801_IFMT_FD_MOD 
LH5801_IFMT_FD_MASK 
LH5801_IFMT_RREG 
LH5801_IFMT_AREG 
LH5801_IFMT_SREG 
LH5801_IFMT_PREG 
LH5801_IFMT_REG_MASK 
LH5801_IFMT_COND 
LH5801_IFMT_BCH 
LH5801_IFMT_VEJ 
LH5801_IFMT_RFULL 
LH5801_IFMT_RLOW 
LH5801_IFMT_RHIGH 
LH5801_IFMT_RMEM 
LH5801_IFMT_RMODE_MASK 

Definition at line 94 of file lh5801.c.

94  {
95  /* An instruction can contain up to three immediate data bytes. */
96  LH5801_IFMT_IMM0 = 0,
101 
102  /* Instructions may either require an 0xFD prefix, require its absence,
103  * or behave differently if it is found. */
104  LH5801_IFMT_FD_NO = 0,
105  LH5801_IFMT_FD_YES = 1 << 2,
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 */
114  LH5801_IFMT_REG_MASK = 7 << 4,
115 
116  /* Branch and vector jump instructions may have a three-bit condition
117  * code. */
118  LH5801_IFMT_COND = 1 << 7,
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 */
127  LH5801_IFMT_RFULL = 0,
128  LH5801_IFMT_RLOW = 1 << 10,
129  LH5801_IFMT_RHIGH = 2 << 10,
130  LH5801_IFMT_RMEM = 3 << 10, /* <-- should be removed, see above */
131  LH5801_IFMT_RMODE_MASK = 3 << 10,
132 };
@ 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

Function Documentation

◆ lh5801_decode()

int lh5801_decode ( struct lh5801_insn insn,
const ut8 buf,
int  len 
)

Definition at line 674 of file lh5801.c.

674  {
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 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
const char * desc
Definition: bin_vsf.c:19
voidpf void * buf
Definition: ioapi.h:138
const struct lh5801_insn_desc lh5801_insn_descs[]
Definition: lh5801.c:156
static bool lh5801_ifmt_fd_matches(enum lh5801_insn_format fmt, int fd)
Definition: lh5801.c:137
#define ARRAY_LENGTH(a)
Definition: lh5801.c:17
#define LH5801_IFMT_IMMS(f)
Definition: lh5801.c:134
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
static const z80_opcode fd[]
Definition: z80_tab.h:997

References ARRAY_LENGTH, desc, lh5801_insn::fd, fd, i, lh5801_insn::iclass, lh5801_insn::imm, len, LH5801_IFMT_BCH, LH5801_IFMT_COND, lh5801_ifmt_fd_matches(), LH5801_IFMT_IMMS, LH5801_IFMT_REG_MASK, LH5801_IFMT_RREG, LH5801_IFMT_VEJ, lh5801_insn_descs, lh5801_insn::opcode, lh5801_insn::type, and type.

Referenced by disassemble().

◆ lh5801_ifmt_fd_matches()

static bool lh5801_ifmt_fd_matches ( enum lh5801_insn_format  fmt,
int  fd 
)
static

Definition at line 137 of file lh5801.c.

137  {
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 }

References fd, LH5801_IFMT_FD_MASK, LH5801_IFMT_FD_MOD, LH5801_IFMT_FD_NO, and LH5801_IFMT_FD_YES.

Referenced by lh5801_decode().

◆ lh5801_print_insn()

void lh5801_print_insn ( char *  out,
int  size,
const struct lh5801_insn insn 
)

Definition at line 792 of file lh5801.c.

792  {
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 }
#define mnem(n, mn)
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
voidpf void uLong size
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
static char * print_reg(char *buf, const struct lh5801_insn *insn)
Definition: lh5801.c:747
const struct lh5801_insn_class_desc lh5801_insn_class_descs[LH5801_INSNC_NUMBER]
Definition: lh5801.c:20

References desc, lh5801_insn::fd, lh5801_insn_desc::iclass, lh5801_insn::iclass, lh5801_insn::imm, LH5801_IFMT_AREG, LH5801_IFMT_BCH, LH5801_IFMT_COND, LH5801_IFMT_FD_MASK, LH5801_IFMT_FD_MOD, LH5801_IFMT_IMM0, LH5801_IFMT_IMM1, LH5801_IFMT_IMM2, LH5801_IFMT_IMM3, LH5801_IFMT_PREG, LH5801_IFMT_RMODE_MASK, LH5801_IFMT_RREG, LH5801_IFMT_SREG, LH5801_IFMT_VEJ, lh5801_insn_class_descs, lh5801_insn_descs, mnem, lh5801_insn::opcode, out, print_reg(), snprintf, and lh5801_insn::type.

Referenced by disassemble().

◆ print_reg()

static char* print_reg ( char *  buf,
const struct lh5801_insn insn 
)
static

Definition at line 747 of file lh5801.c.

747  {
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 }
#define NULL
Definition: cris-opc.c:27
#define LH5801_IFMT_RMODE(f)
Definition: lh5801.c:135
Definition: names.h:123

References desc, lh5801_insn::fd, LH5801_IFMT_AREG, LH5801_IFMT_FD_MOD, LH5801_IFMT_PREG, LH5801_IFMT_REG_MASK, LH5801_IFMT_RFULL, LH5801_IFMT_RHIGH, LH5801_IFMT_RLOW, LH5801_IFMT_RMEM, LH5801_IFMT_RMODE, LH5801_IFMT_SREG, lh5801_insn_descs, NULL, lh5801_insn::opcode, and lh5801_insn::type.

Referenced by lh5801_print_insn().

Variable Documentation

◆ lh5801_insn_class_descs

const struct lh5801_insn_class_desc lh5801_insn_class_descs[LH5801_INSNC_NUMBER]

Definition at line 1 of file lh5801.c.

Referenced by lh5801_print_insn().

◆ lh5801_insn_descs

const struct lh5801_insn_desc lh5801_insn_descs[]

Definition at line 137 of file lh5801.c.

Referenced by lh5801_decode(), lh5801_print_insn(), and print_reg().