2021-01-29 15:14:37 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
Copyright (c) 2021 Devine Lu Linvega
|
|
|
|
|
|
|
|
Permission to use, copy, modify, and distribute this software for any
|
|
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
WITH REGARD TO THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef unsigned char Uint8;
|
2021-02-04 15:22:08 -05:00
|
|
|
typedef unsigned short Uint16;
|
2021-01-29 15:14:37 -05:00
|
|
|
|
2021-01-29 16:59:16 -05:00
|
|
|
typedef struct {
|
2021-02-04 00:53:56 -05:00
|
|
|
int ptr;
|
2021-02-04 15:22:08 -05:00
|
|
|
Uint8 data[65536];
|
2021-01-29 16:59:16 -05:00
|
|
|
} Program;
|
|
|
|
|
2021-01-31 00:31:49 -05:00
|
|
|
typedef struct {
|
2021-02-04 15:22:08 -05:00
|
|
|
Uint16 addr;
|
|
|
|
char name[64];
|
2021-01-31 00:31:49 -05:00
|
|
|
} Label;
|
|
|
|
|
|
|
|
int labelslen;
|
|
|
|
Label labels[256];
|
2021-01-30 17:25:48 -05:00
|
|
|
|
2021-02-01 23:21:27 -05:00
|
|
|
/* clang-format off */
|
|
|
|
|
2021-02-06 13:39:13 -05:00
|
|
|
char ops[][4] = {
|
2021-02-01 23:21:27 -05:00
|
|
|
"BRK", "RTS", "LIT", "POP", "DUP", "SWP", "OVR", "ROT",
|
2021-02-04 00:53:56 -05:00
|
|
|
"JMU", "JSU", "JMC", "JSC", "EQU", "NEQ", "GTH", "LTH",
|
2021-02-04 15:22:08 -05:00
|
|
|
"AND", "ORA", "ROL", "ROR", "ADD", "SUB", "MUL", "DIV",
|
2021-02-06 13:39:13 -05:00
|
|
|
"LDR", "STR", "PEK", "POK", "---", "---", "---", "---"
|
2021-02-04 15:22:08 -05:00
|
|
|
};
|
2021-02-01 23:21:27 -05:00
|
|
|
|
|
|
|
/* clang-format on */
|
2021-01-29 20:49:10 -05:00
|
|
|
|
2021-01-29 16:59:16 -05:00
|
|
|
Program p;
|
|
|
|
|
|
|
|
#pragma mark - Helpers
|
|
|
|
|
|
|
|
int
|
|
|
|
scmp(char *a, char *b) /* string compare */
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
while(a[i] == b[i])
|
|
|
|
if(!a[i++])
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-01-31 00:31:49 -05:00
|
|
|
char *
|
|
|
|
scpy(char *src, char *dst, int len) /* string copy */
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
while((dst[i] = src[i]) && i < len - 2)
|
|
|
|
i++;
|
|
|
|
dst[i + 1] = '\0';
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2021-02-01 23:21:27 -05:00
|
|
|
int
|
|
|
|
slen(char *s) /* string length */
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
while(s[i] && s[++i])
|
|
|
|
;
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2021-01-29 20:49:10 -05:00
|
|
|
char *
|
|
|
|
suca(char *s) /* string to uppercase */
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
char c;
|
|
|
|
while((c = s[i]))
|
|
|
|
s[i++] = c >= 'a' && c <= 'z' ? c - ('a' - 'A') : c;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2021-01-30 17:25:48 -05:00
|
|
|
int
|
2021-02-04 15:22:08 -05:00
|
|
|
sihx(char *s) /* string is hexadecimal */
|
2021-01-30 17:25:48 -05:00
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
char c;
|
|
|
|
while((c = s[i++]))
|
2021-01-31 00:31:49 -05:00
|
|
|
if(!(c >= '0' && c <= '9') && !(c >= 'a' && c <= 'f') && !(c >= 'A' && c <= 'F'))
|
2021-01-30 17:25:48 -05:00
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-01-29 16:59:16 -05:00
|
|
|
int
|
|
|
|
shex(char *s) /* string to num */
|
|
|
|
{
|
|
|
|
int n = 0, i = 0;
|
|
|
|
char c;
|
|
|
|
while((c = s[i++]))
|
|
|
|
if(c >= '0' && c <= '9')
|
|
|
|
n = n * 16 + (c - '0');
|
2021-01-30 17:25:48 -05:00
|
|
|
else if(c >= 'A' && c <= 'F')
|
|
|
|
n = n * 16 + 10 + (c - 'A');
|
2021-01-31 00:31:49 -05:00
|
|
|
else if(c >= 'a' && c <= 'f')
|
2021-02-05 13:51:45 -05:00
|
|
|
n = n * 16 + 10 + (c - 'a');
|
2021-01-29 16:59:16 -05:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2021-02-04 15:22:08 -05:00
|
|
|
int
|
|
|
|
iscomment(char *w, int *skip)
|
2021-01-30 17:25:48 -05:00
|
|
|
{
|
2021-02-04 15:22:08 -05:00
|
|
|
if(w[0] == ')') {
|
|
|
|
*skip = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(w[0] == '(') *skip = 1;
|
|
|
|
if(*skip) return 1;
|
|
|
|
return 0;
|
2021-01-30 17:25:48 -05:00
|
|
|
}
|
|
|
|
|
2021-02-04 15:22:08 -05:00
|
|
|
#pragma mark - I/O
|
|
|
|
|
2021-02-01 23:21:27 -05:00
|
|
|
void
|
2021-02-04 15:22:08 -05:00
|
|
|
pushbyte(Uint8 b, int lit)
|
2021-02-01 23:21:27 -05:00
|
|
|
{
|
2021-02-04 15:22:08 -05:00
|
|
|
if(lit) {
|
|
|
|
pushbyte(0x02, 0);
|
|
|
|
pushbyte(0x01, 0);
|
|
|
|
}
|
|
|
|
p.data[p.ptr++] = b;
|
2021-02-01 23:21:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-02-04 15:22:08 -05:00
|
|
|
pushshort(Uint16 s, int lit)
|
2021-02-01 23:21:27 -05:00
|
|
|
{
|
2021-02-04 15:22:08 -05:00
|
|
|
if(lit) {
|
|
|
|
pushbyte(0x02, 0);
|
|
|
|
pushbyte(0x02, 0);
|
2021-02-01 23:21:27 -05:00
|
|
|
}
|
2021-02-04 15:22:08 -05:00
|
|
|
pushbyte((s >> 8) & 0xff, 0);
|
|
|
|
pushbyte(s & 0xff, 0);
|
2021-02-01 23:21:27 -05:00
|
|
|
}
|
|
|
|
|
2021-02-05 14:57:37 -05:00
|
|
|
void
|
|
|
|
pushword(char *w)
|
|
|
|
{
|
|
|
|
int i = slen(w);
|
|
|
|
pushbyte(0x02, 0);
|
|
|
|
pushbyte(slen(w), 0);
|
|
|
|
while(i > 0)
|
|
|
|
pushbyte(w[--i], 0);
|
|
|
|
}
|
|
|
|
|
2021-01-31 00:31:49 -05:00
|
|
|
Label *
|
|
|
|
findlabel(char *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < labelslen; ++i)
|
|
|
|
if(scmp(labels[i].name, s))
|
|
|
|
return &labels[i];
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-02-06 13:39:13 -05:00
|
|
|
Uint8
|
|
|
|
findop(char *s)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 32; ++i) {
|
|
|
|
int m = 0;
|
|
|
|
if(ops[i][0] != s[0]) continue;
|
|
|
|
if(ops[i][1] != s[1]) continue;
|
|
|
|
if(ops[i][2] != s[2]) continue;
|
|
|
|
while(s[3 + m]) {
|
|
|
|
char c = s[3 + m];
|
|
|
|
if(c == '^') i |= (1 << 5); /* mode: 16 bits */
|
2021-02-07 12:01:40 -05:00
|
|
|
if(c == '~') i |= (1 << 6); /* mode: signed */
|
|
|
|
if(c == '&') i |= (1 << 7); /* mode: unused */
|
2021-02-06 13:39:13 -05:00
|
|
|
m++;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-02-04 15:22:08 -05:00
|
|
|
#pragma mark - Parser
|
2021-01-31 00:31:49 -05:00
|
|
|
|
2021-01-30 17:25:48 -05:00
|
|
|
int
|
2021-02-04 15:22:08 -05:00
|
|
|
error(char *name, char *id)
|
2021-01-30 17:25:48 -05:00
|
|
|
{
|
2021-02-05 23:18:30 -05:00
|
|
|
printf("Error: %s[%s]\n", name, id);
|
2021-02-04 16:49:03 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2021-02-04 18:23:04 -05:00
|
|
|
makelabel(char *id, Uint16 addr)
|
2021-02-04 16:49:03 -05:00
|
|
|
{
|
|
|
|
Label *l;
|
|
|
|
if(findlabel(id))
|
|
|
|
return error("Label duplicate", id);
|
|
|
|
l = &labels[labelslen++];
|
|
|
|
scpy(id, l->name, 64);
|
|
|
|
l->addr = addr;
|
|
|
|
printf("New label: %s[0x%02x]\n", l->name, l->addr);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-02-05 13:51:45 -05:00
|
|
|
int
|
|
|
|
makeconst(char *id, FILE *f)
|
|
|
|
{
|
|
|
|
char wv[64];
|
|
|
|
fscanf(f, "%s", wv);
|
|
|
|
return makelabel(id, shex(wv));
|
|
|
|
}
|
|
|
|
|
2021-02-04 00:53:56 -05:00
|
|
|
int
|
2021-01-29 15:14:37 -05:00
|
|
|
pass1(FILE *f)
|
|
|
|
{
|
2021-02-04 18:23:04 -05:00
|
|
|
int skip = 0, vars = 0;
|
|
|
|
Uint16 addr = 0;
|
2021-02-04 15:22:08 -05:00
|
|
|
char w[64];
|
|
|
|
while(fscanf(f, "%s", w) == 1) {
|
|
|
|
if(iscomment(w, &skip)) continue;
|
2021-02-05 13:51:45 -05:00
|
|
|
if(w[0] == '@' && !makelabel(w + 1, addr))
|
2021-02-04 16:49:03 -05:00
|
|
|
return error("Pass1 failed", w);
|
|
|
|
if(w[0] == ';' && !makelabel(w + 1, vars++))
|
|
|
|
return error("Pass1 failed", w);
|
2021-02-05 13:51:45 -05:00
|
|
|
if(w[0] == ':') {
|
|
|
|
if(!makeconst(w + 1, f))
|
|
|
|
return error("Pass1 failed", w);
|
|
|
|
else
|
|
|
|
continue;
|
|
|
|
}
|
2021-02-04 15:22:08 -05:00
|
|
|
/* move addr ptr */
|
|
|
|
if(findop(w) || scmp(w, "BRK"))
|
|
|
|
addr += 1;
|
2021-02-05 13:51:45 -05:00
|
|
|
else if(w[0] == '|')
|
2021-02-04 18:23:04 -05:00
|
|
|
addr = shex(w + 1);
|
2021-02-05 13:51:45 -05:00
|
|
|
else if(w[0] == '@')
|
2021-02-04 15:22:08 -05:00
|
|
|
addr += 0;
|
|
|
|
else if(w[0] == ';')
|
|
|
|
addr += 0;
|
|
|
|
else if(w[0] == '.')
|
|
|
|
addr += 2;
|
2021-02-05 14:57:37 -05:00
|
|
|
else if(w[0] == '"')
|
2021-02-05 17:01:34 -05:00
|
|
|
addr += slen(w + 1) + 2;
|
2021-02-04 15:22:08 -05:00
|
|
|
else if(w[0] == ',')
|
2021-02-05 23:18:30 -05:00
|
|
|
addr += 2 + (sihx(w + 1) && slen(w + 1) == 2 ? 1 : 2);
|
2021-02-04 15:22:08 -05:00
|
|
|
else
|
2021-02-04 16:49:03 -05:00
|
|
|
return error("Unknown label", w);
|
2021-01-30 17:25:48 -05:00
|
|
|
}
|
|
|
|
rewind(f);
|
2021-02-04 15:22:08 -05:00
|
|
|
return 1;
|
2021-01-30 17:25:48 -05:00
|
|
|
}
|
|
|
|
|
2021-02-04 15:22:08 -05:00
|
|
|
int
|
2021-01-30 17:25:48 -05:00
|
|
|
pass2(FILE *f)
|
|
|
|
{
|
|
|
|
int skip = 0;
|
2021-02-04 15:22:08 -05:00
|
|
|
char w[64];
|
|
|
|
while(fscanf(f, "%s", w) == 1) {
|
2021-02-01 14:58:47 -05:00
|
|
|
Uint8 op = 0;
|
2021-01-31 00:31:49 -05:00
|
|
|
Label *l;
|
2021-02-05 13:51:45 -05:00
|
|
|
if(w[0] == '@') continue;
|
2021-02-04 15:22:08 -05:00
|
|
|
if(w[0] == ';') continue;
|
2021-02-05 23:18:30 -05:00
|
|
|
if(iscomment(w, &skip)) continue;
|
2021-02-05 13:51:45 -05:00
|
|
|
if(w[0] == '|')
|
2021-02-04 15:22:08 -05:00
|
|
|
p.ptr = shex(w + 1);
|
2021-02-05 13:51:45 -05:00
|
|
|
else if(w[0] == ':')
|
|
|
|
fscanf(f, "%s", w);
|
2021-02-05 14:57:37 -05:00
|
|
|
else if(w[0] == '"')
|
|
|
|
pushword(w + 1);
|
2021-02-04 15:22:08 -05:00
|
|
|
else if((l = findlabel(w + 1)))
|
|
|
|
pushshort(l->addr, w[0] == ',');
|
2021-02-06 13:39:13 -05:00
|
|
|
else if((op = findop(w)) || scmp(w, "BRK"))
|
|
|
|
pushbyte(op, 0);
|
2021-02-04 15:22:08 -05:00
|
|
|
else if(sihx(w + 1) && slen(w + 1) == 2)
|
|
|
|
pushbyte(shex(w + 1), w[0] == ',');
|
|
|
|
else if(sihx(w + 1) && slen(w + 1) == 4)
|
|
|
|
pushshort(shex(w + 1), w[0] == ',');
|
2021-02-01 23:21:27 -05:00
|
|
|
else
|
2021-02-04 16:49:03 -05:00
|
|
|
return error("Unknown label", w);
|
2021-01-29 15:14:37 -05:00
|
|
|
}
|
2021-02-04 15:22:08 -05:00
|
|
|
return 1;
|
2021-01-29 15:14:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
if(argc < 3)
|
2021-02-04 15:22:08 -05:00
|
|
|
return error("Input", "Missing");
|
2021-01-29 15:14:37 -05:00
|
|
|
if(!(f = fopen(argv[1], "r")))
|
2021-02-04 15:22:08 -05:00
|
|
|
return error("Open", "Failed");
|
|
|
|
if(!pass1(f) || !pass2(f))
|
|
|
|
return error("Assembly", "Failed");
|
2021-01-29 16:59:16 -05:00
|
|
|
fwrite(p.data, sizeof(p.data), 1, fopen(argv[2], "wb"));
|
|
|
|
fclose(f);
|
2021-02-04 18:23:04 -05:00
|
|
|
printf("Assembled %s.\n", argv[2]);
|
2021-01-29 15:14:37 -05:00
|
|
|
return 0;
|
|
|
|
}
|