Add code generator to assembler, re compile colors.dat with assembler
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a27b55..3c57c91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,15 @@
include_directories(nuklear)
+include(TestBigEndian)
+test_big_endian(BIG_ENDIAN)
+
+if (${BIG_ENDIAN})
+ add_compile_definitions(BIG_ENDIAN)
+else()
+ add_compile_definitions(LITTLE_ENDIAN)
+endif()
+
subdirs(as)
if (${GEN_INSTRUCTIONS_HEADER})
diff --git a/as/CMakeLists.txt b/as/CMakeLists.txt
index 70638fe..7a7b6a5 100644
--- a/as/CMakeLists.txt
+++ b/as/CMakeLists.txt
@@ -2,4 +2,15 @@
project(6502 VERSION 0.1.0 LANGUAGES C)
+include(TestBigEndian)
+test_big_endian(BIG_ENDIAN)
+
+
+if (${BIG_ENDIAN})
+ add_compile_definitions(BIG_ENDIAN)
+else()
+ add_compile_definitions(LITTLE_ENDIAN)
+endif()
+
+
add_executable(6502-as main.c as.h as.c map.h map.c hash.c hash.c)
diff --git a/as/as.c b/as/as.c
index 2ff5c36..1d72d97 100644
--- a/as/as.c
+++ b/as/as.c
@@ -4,6 +4,8 @@
#include "../mnemonics.h"
#include "map.h"
+#include <endian.h>
+#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
@@ -20,6 +22,8 @@
#define ERR "\033[31m"
#define RESET "\033[0m"
+#define MAX_LEN (0xFFFF - 0x600)
+#define MAX_INSTS (MAX_LEN / 2)
typedef struct
{
@@ -35,6 +39,13 @@
};
} inst_t;
+typedef struct ll_node
+{
+ struct ll_node *last;
+ char name[32];
+ uint16_t addr;
+} ll_node_t;
+
// Normal strtok() counts 2 seperators as one, ie asdf\n\njlk is 2 lines.
// This functions counts that as 3 lines, and will return an empty line in between.
char *strtok_fix(char *string, const char *token)
@@ -65,6 +76,12 @@
return pos;
}
+void putshort(uint16_t a, FILE *out)
+{
+ uint16_t le = htole16(a);
+ fwrite(&le, sizeof(uint16_t), 1, out);
+}
+
void print_inst(inst_t *arg)
{
char *arg_types =
@@ -150,6 +167,7 @@
(*code)++;
return start;
}
+ printf(">> lkl: **code == %c %x\n", **code, **code);
*code = start;
@@ -302,13 +320,13 @@
{
inst->arg_type = ARG_16;
inst->long_arg = num;
- return true;
+ return ws_end(&code);
}
else if ((lbl = parse_label_name(&code)))
{
inst->arg_type = ARG_ABS;
strncpy(inst->label, lbl, 32);
- return true;
+ return ws_end(&code);
}
break;
@@ -339,7 +357,7 @@
inst->arg_type = ARG_16;
inst->long_arg = num;
- return true;
+ return ws_end(&code);
case AM_AX:
case AM_ZPX:
@@ -359,14 +377,17 @@
inst->arg_type = ARG_8;
inst->byte_arg = num8;
}
+ printf("Parsing AM_* worked, now parsing ,\n");
if (!skip(&code, ","))
return false;
skip_ws(&code);
-
- if (tolower(*code) != (am == AM_AY || am == AM_ZPY ? 'y' : 'x'))
+ printf(", worked yup\n");
+ char reg = (am == AM_AY || am == AM_ZPY ? 'y' : 'x');
+ printf("reg is %c, *code is %c %x\n", reg, tolower(*code), tolower(*code));
+ if (tolower(*code) != reg)
return false;
-
+ (code)++;
return ws_end(&code);
case AM_ZIX:
@@ -413,15 +434,30 @@
return false;
}
+// Since program counter can never be < $600, return 0 on failure
+uint16_t ll_find(ll_node_t *head, char *name)
+{
+ ll_node_t *last = head;
+ while (last)
+ {
+ head = last;
+ if (!strcasecmp(head->name, name))
+ return head->addr;
+ last = head->last;
+ }
+ return 0;
+}
+
uint32_t assemble(char *code, FILE *out)
{
- uintptr_t num_insts = 0,
- pc = 0x600;
+ uint16_t num_insts = 0;
+ uint16_t pc = 0x600;
uint32_t line_no = 1;
- map_t *labels = new_map();
+ ll_node_t *last_node = NULL;
char *line,
*orig_line,
*line_start;
+ inst_t **insts = calloc(sizeof(inst_t), MAX_INSTS);
printf("Assembling File\n");
printf("%s\n", code);
@@ -435,10 +471,11 @@
if (*line == 0)
goto end_of_line;
- printf("line %d: \033[36m%.12s\033[0m\n", line_no, line);
skip_ws(&line);
-
+
+ printf("line %d: \033[36m%.12s\033[0m\n", line_no, line);
+
if (is_eol(*line))
{
printf("skip_ws() brought us to EOL\n");
@@ -446,26 +483,30 @@
}
char *label = parse_label(&line);
+ printf(">> label == %.5s %p\n", label, label);
skip_ws(&code);
- if (is_eol(*line))
- goto end_of_line;
+ //if (is_eol(*line))
+ // goto end_of_line;
char *mn = parse_inst(&line);
- printf(" skipping %d ", skip_ws(&line));
- //printf("\033[33m%s\033[0m\n", line);
bool no_argument = false;
- printf("eol is %c ($%x)\n", *line, *line);
if (is_eol(*line))
{
no_argument = true;
- printf("... no argument\n");
}
int32_t mnemonic = -1;
if (label)
{
- map_set(labels, label, (void *)pc);
- printf("Set label %s at $%lx\n", label, pc);
+ printf("Storing label %s\n", label);
+ ll_node_t *head = malloc(sizeof(ll_node_t));
+ head->last = last_node;
+ strncpy(head->name, label, 32);
+ // strncpy won't zero the last byte if its over 32 bytes long
+ head->name[31] = 0;
+ head->addr = pc;
+ last_node = head;
+ printf("Set label %s at $%x\n", label, pc);
}
if (mn)
@@ -479,39 +520,113 @@
MNEMONICS
{
printf(ERR "Could not parse instruction on line %d\n%s\n" RESET, line_no, orig_line);
+ free(line_start);
goto cleanup;
}
#undef MN
printf("Got instruction %s %d\n", mn, mnemonic);
- inst_t arg;
+ inst_t *arg = malloc(sizeof(inst_t));
+ arg->line = line_no;
// printf("Parsing '%s'\n", line);
#define INST(_mn, am, op, len) \
if ((no_argument && (_mn == AM_IMP || _mn == AM_ACC)) \
- || (mnemonic == _mn && parse_arg(line, am, &arg))) \
+ || (mnemonic == _mn && parse_arg(line, am, arg))) \
{ \
- arg.opcode = op; \
+ printf("AM_ succeeded: %s\n", #am); \
+ arg->opcode = op; \
pc += len; \
- print_inst(&arg); \
+ print_inst(arg); \
} \
else
INSTRUCTIONS
{
printf("\033[31mCould not be parsed: %s '%s'\033[0m\n", mn, line);
+ free(line_start);
+ goto cleanup;
}
#undef INST
+
+ insts[num_insts++] = arg;
}
end_of_line:
line_no++;
- printf("Line is %d\n", line_no);
orig_line = strtok_fix(NULL, "\n");
free(line_start);
}
+ // Generate machine code
+ for (int i = 0, curr_pc = 0x600; insts[i]; i++)
+ {
+ putc(insts[i]->opcode, out);
+
+ switch (insts[i]->arg_type)
+ {
+ case ARG_8:
+ putc(insts[i]->byte_arg, out);
+ curr_pc += 2;
+ break;
+ case ARG_16:
+ putshort(insts[i]->long_arg, out);
+ curr_pc += 3;
+ break;
+ case ARG_8REL:
+ putc(insts[i]->rel_arg, out);
+ curr_pc += 2;
+ break;
+ case ARG_ABS:
+ {
+ uint16_t lbl;
+ if (!(lbl = ll_find(last_node, insts[i]->label)))
+ {
+ printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
+ goto cleanup;
+ }
+ curr_pc += 3;
+
+ putshort(lbl, out);
+ break;
+ }
+ case ARG_REL:
+ {
+ uint16_t lbl;
+ if (!(lbl = ll_find(last_node, insts[i]->label)))
+ {
+ printf(ERR "Error on line %d: label '%s' is not defined" RESET "\n", insts[i]->line, insts[i]->label);
+ goto cleanup;
+ }
+ curr_pc += 2;
+ int16_t diff = lbl - curr_pc;
+ printf("ARG_REL, pc (after) == %x, diff = %d\n", curr_pc, diff);
+ if ((diff < 0 ? -diff : diff) > 0xFF)
+ {
+ printf(ERR "Error on line %d: label '%s' is too far away for a relative jump" RESET "\n", insts[i]->line, insts[i]->label);
+ printf("pc == %hx, label is at %hx\n", curr_pc, lbl);
+ goto cleanup;
+ }
+ putshort((uint8_t) diff, out);
+ break;
+ }
+ default:
+ curr_pc++;
+ }
+ }
+
cleanup:
- free_map(labels);
+ printf("-----\n");
+ printf("At end, there are %d instructions\n", num_insts);
+ while (last_node)
+ {
+ ll_node_t *curr_node = last_node;
+ last_node = curr_node->last;
+ free(curr_node);
+ }
+ for (int i = 0; insts[i]; i++)
+ free(insts[i]);
+ free(insts);
+ fflush(out);
return num_insts;
}
diff --git a/as/map.c b/as/map.c
index e990af9..bbb4aa7 100644
--- a/as/map.c
+++ b/as/map.c
@@ -70,7 +70,7 @@
{
map_node val =
{
- malloc(strlen(k)),
+ malloc(strlen(k) + 1),
v,
1,
h,
diff --git a/as/test/colors.s b/as/test/colors.s
new file mode 100644
index 0000000..3c705be
--- /dev/null
+++ b/as/test/colors.s
@@ -0,0 +1,13 @@
+;;; Shows some nice colors on the screen
+
+ LDY #$0
+loop:
+ TYA
+ STA $200, Y
+ STA $300, Y
+ STA $400, Y
+ STA $500, Y
+ INY
+ CMP #$ff
+ BCC loop
+ BRK
diff --git a/colors.dat b/colors.dat
index aea5970..33989da 100644
--- a/colors.dat
+++ b/colors.dat
Binary files differ
diff --git a/cpu.c b/cpu.c
index ef544a7..6363fe6 100644
--- a/cpu.c
+++ b/cpu.c
@@ -42,7 +42,7 @@
#ifdef LITTLE_ENDIAN
return b << 8 | a;
#else
- return a << 8 | b;
+ return le16toh(a << 8 | b);
#endif
}