WIP: lut based instructions
authorLukas Krickl <lukas@krickl.dev>
Wed, 22 Nov 2023 21:24:41 +0000 (22:24 +0100)
committerLukas Krickl <lukas@krickl.dev>
Wed, 22 Nov 2023 21:24:41 +0000 (22:24 +0100)
src/ulas.c

index 9307b15be8afa18cf10a21102032f4a11da611d4..613034bd09a22a7567bba06ddb17d3dc2f3f266d 100644 (file)
@@ -1400,110 +1400,86 @@ int ulas_asmregisr8(enum ulas_asmregs reg) {
 }
 
 // all instructions
+// when name is NULL list ended
 const struct ulas_instr ULASINSTRS[] = {
     {"nop", {0}, {0x00, 0}},
-    {"ld", {ULAS_REG_B, ',', ULAS_REG_B, 0}, {0x40, 0}}};
+    {"ld", {ULAS_REG_B, ',', ULAS_REG_B, 0}, {0x40, 0}},
+    {NULL}};
 
-// adds an instruction that only comparse names
-#define ULAS_STATICINSTR(name, n, ...)                                         \
-  if (strncmp(ulas.tok.buf, (name), ulas.tok.maxlen) == 0) {                   \
-    const unsigned char t[] = {__VA_ARGS__};                                   \
-    memcpy(dst, t, n);                                                         \
-    return n;                                                                  \
-  }
-
-// parses <instruction> r8, r8
-int ulas_ld(char *dst, unsigned long max, const char **line, unsigned long n) {
-  if (strncmp(ulas.tok.buf, "ld", ulas.tok.maxlen) != 0) {
-    return 0;
-  }
-
-  enum ulas_asmregs reg = -1;
-  // lookup tables for first r8 base instruction
-  char instrs_r8lut[] = {0x40, 0x48, 0x50, 0x58, 0x60, 0x68, -1, 0x78};
-
-  // first token: can either be
-  //  - r8
-  //  - r16
-  //  - [
-  if (ulas_tok(&ulas.tok, line, n) == -1) {
+// assembles an instruction, writes bytes into dst
+// returns bytes written or -1 on error
+int ulas_asminstr(char *dst, unsigned long max, const char **line,
+                  unsigned long n) {
+  const char *start = *line;
+  if (max < 4) {
+    ULASPANIC("Instruction buffer is too small!");
     return -1;
   }
 
-  // decide which load instruction we have here
-  if (strncmp(ulas.tok.buf, "[", ulas.tok.maxlen) == 0) {
-    // ld [r16], a
-  } else if ((reg = ulas_asmstrreg(ulas.tok.buf, ulas.tok.maxlen)) != -1) {
-    int base_instr = -1;
-    if (!ulas_asmregisr8(reg)) {
-      // TODO: reg16
-    } else {
-      // reg8
-      base_instr = instrs_r8lut[reg];
-    }
+  // TODO: check for symbol token here... if so add it
+  // and skip to the next token
 
-    // need one , here
-    if (ulas_tok(&ulas.tok, line, n) == -1 ||
-        strncmp(ulas.tok.buf, ",", ulas.tok.maxlen) != 0) {
-      return -1;
-    }
+  const struct ulas_instr *instrs = ULASINSTRS;
 
-    // the second param has to be either an expression or a r8
+  int written = 0;
+  while (instrs->name && written == 0) {
+    *line = start;
     if (ulas_tok(&ulas.tok, line, n) == -1) {
+      ULASERR("Expected label or instruction\n");
       return -1;
     }
-    if ((reg = ulas_asmstrreg(ulas.tok.buf, ulas.tok.maxlen)) == -1) {
-      // TODO: not a reg, expression!
-    } else if (!ulas_asmregisr8(reg)) {
-      // r16 is not allowed
-      ULASERR("Expected r8\n");
-      return -1;
-    } else {
-      // r8
-      dst[0] = base_instr + reg;
-      return 1;
+
+    // check for instruction name first
+    if (strncmp(ulas.tok.buf, instrs->name, ulas.tok.maxlen) != 0) {
+      goto skip;
     }
-  }
 
-  // if nothing matches... we have an error at this point
-  return -1;
-}
+    // expression results in order they appear
+    int exprres[ULAS_INSTRDATMAX];
+    memset(&exprres, 0, sizeof(int) * ULAS_INSTRDATMAX);
 
-// assembles an instruction, writes bytes into dst
-// returns bytes written or -1 on error
-int ulas_asminstr(char *dst, unsigned long max, const char **line,
-                  unsigned long n) {
-  const char *start = *line;
-  if (max < 4) {
-    ULASPANIC("Instruction buffer is too small!");
-    return -1;
-  }
+    // then check for each single token...
+    short *tok = instrs->tokens;
+    int i = 0;
+    while (tok[i]) {
+      if (ulas_tok(&ulas.tok, line, n) == -1) {
+        goto skip;
+      }
 
-  if (ulas_tok(&ulas.tok, line, n) == -1) {
-    ULASERR("Expected label or instruction\n");
-    return -1;
-  }
+      char *regstr = NULL;
+      if ((regstr = ulas_asmregstr(tok[i]))) {
+        if (strncmp(regstr, ulas.tok.buf, ulas.tok.maxlen) != 0) {
+          goto skip;
+        }
+      } else if (tok[i] == ULAS_E8 || tok[i] == ULAS_E16) {
+      } else {
+        char c[2] = {tok[i], '\0'};
+        if (strncmp(ulas.tok.buf, c, ulas.tok.maxlen) != 0) {
+          goto skip;
+        }
+      }
 
-  // TODO: check for symbol token here... if so add it
-  // and skip to the next token
+      i++;
+    }
 
-  int towrt = 0;
+    // we are good to go!
+    char *dat = instrs->data;
+    while (dat[written]) {
+      dst[written] = dat[written];
+      written++;
+    }
 
-  // misc / control
-  ULAS_STATICINSTR("nop", 1, 0x00);
-  ULAS_STATICINSTR("halt", 1, 0x76);
-  ULAS_STATICINSTR("stop", 2, 0x10, 0x00);
-  ULAS_STATICINSTR("di", 1, 0xF3);
-  ULAS_STATICINSTR("ei", 1, 0xFB);
+  skip:
+    instrs++;
+  }
 
-  // 8 bit loads
-  if ((towrt = ulas_ld(dst, max, line, n)) > 0) {
-    return towrt;
+  if (!written) {
+    ulas_trimend('\n', (char *)start, n);
+    ULASERR("Invalid instruction: %s\n", start);
+    return -1;
   }
 
-  ulas_trimend('\n', (char *)start, n);
-  ULASERR("Invalid instruction '%s'\n", start);
-  return -1;
+  return written;
 }
 
 #undef ULAS_STATICINSTR