371 lines
8.7 KiB
C
371 lines
8.7 KiB
C
#include "./assembler.h"
|
|
#include "../emu/cpu_const.h"
|
|
#include "../emu/cpu_human.h"
|
|
#include "./asm_const.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
// i apologise for the next three functions, they are written very werirdly,
|
|
// and are not as readable as they coudld be, sorry
|
|
// the rough flow for each is just to loop along a string until you
|
|
// encounter a specific char, or a non space / tab char
|
|
//
|
|
// again i apologise for the unreadability, they use way to many
|
|
// goto's, but should be pretty efficient.
|
|
|
|
char *FindNextChar(char *data, char toFind, bool careAboutNull)
|
|
{
|
|
begin:
|
|
switch (*data)
|
|
{
|
|
case '\0':
|
|
if (careAboutNull)
|
|
{
|
|
fprintf(stderr, "FOUND NULL CHAR BEFORE CHAR TO FIND\n");
|
|
exit(-1);
|
|
}
|
|
|
|
goto final;
|
|
default:
|
|
if (*data == toFind)
|
|
{
|
|
final:
|
|
return data;
|
|
}
|
|
|
|
data++;
|
|
goto begin;
|
|
}
|
|
}
|
|
|
|
char *FindNextNonSpaceChar(char *data, bool careAboutNull)
|
|
{
|
|
begin:
|
|
switch(*data)
|
|
{
|
|
case '\0':
|
|
if (careAboutNull)
|
|
{
|
|
fprintf(stderr, "FOUND NULL CHAR BEFORE NON SPACE / TAB CHAR\n");
|
|
exit(-1);
|
|
}
|
|
|
|
goto final;
|
|
case ' ':
|
|
case '\t':
|
|
data++;
|
|
goto begin;
|
|
default:
|
|
final:
|
|
return data;
|
|
}
|
|
}
|
|
|
|
char *FindNextSpaceChar(char *data, bool careAboutNull)
|
|
{
|
|
begin:
|
|
switch(*data)
|
|
{
|
|
case '\0':
|
|
if (careAboutNull)
|
|
{
|
|
fprintf(stderr, "FOUND NULL CHAR BEFORE NON SPACE / TAB CHAR\n");
|
|
exit(-1);
|
|
}
|
|
case ' ':
|
|
case '\t':
|
|
return data;
|
|
default:
|
|
data++;
|
|
goto begin;
|
|
}
|
|
}
|
|
|
|
AsmInstructionArray *InterpretAssembly(char *data)
|
|
{
|
|
char *d = data;
|
|
AsmInstructionArray *asmIA = malloc(sizeof(AsmInstructionArray));
|
|
asmIA->length = 0;
|
|
asmIA->instruction = malloc(sizeof(AsmInstruction) * ARRAY_SNAP_SIZE);
|
|
uint32_t cSize = 0, mSize = ARRAY_SNAP_SIZE;
|
|
|
|
int gfususc = 0;
|
|
|
|
while (true)
|
|
{
|
|
loopStart:
|
|
printf("asmiloop: %d\n", gfususc++);
|
|
|
|
if (cSize == mSize)
|
|
{
|
|
mSize += ARRAY_SNAP_SIZE;
|
|
asmIA->instruction = realloc(asmIA->instruction, sizeof(AsmInstruction) * mSize);
|
|
}
|
|
|
|
AsmInstruction current = asmIA->instruction[cSize];
|
|
|
|
d = FindNextNonSpaceChar(d, false);
|
|
|
|
if (*d == '\0')
|
|
goto final;
|
|
if (*d == '\n')
|
|
{
|
|
d++;
|
|
goto loopStart;
|
|
}
|
|
|
|
if (*(FindNextSpaceChar(d, true) - 1) == ':')
|
|
{
|
|
size_t l = (FindNextSpaceChar(d, true) - 1) - d;
|
|
memcpy(¤t.label, d, l);
|
|
current.label[l] = '\0';
|
|
|
|
d = FindNextNonSpaceChar(d, true);
|
|
}
|
|
else
|
|
{
|
|
current.label[0] = '\0';
|
|
}
|
|
|
|
memcpy(¤t.instruction, d, sizeof(char) * 3);
|
|
current.instruction[3] = '\0';
|
|
|
|
d = FindNextNonSpaceChar(d, false);
|
|
|
|
if (*d == '\0')
|
|
goto final;
|
|
if (*d == '\n')
|
|
{
|
|
d++;
|
|
goto loopEnd;
|
|
}
|
|
|
|
char *comma = FindNextChar(d + 3, ',', true),
|
|
*nline = FindNextChar(d + 3, '\n', true);
|
|
|
|
bool a2 = comma < nline;
|
|
char *eoA1 = a2 ? comma : nline;
|
|
size_t s = eoA1 - (d + 3);
|
|
memcpy(¤t.arg1, d + 3, s);
|
|
current.arg1[s] = '\0';
|
|
|
|
if (!a2)
|
|
goto loopEnd;
|
|
|
|
d = FindNextNonSpaceChar(eoA1 + 1, true);
|
|
s = nline - d;
|
|
memcpy(¤t.arg2, d, s);
|
|
current.arg2[s] = '\0';
|
|
d = nline + 1;
|
|
|
|
printf("l: %s, i: %s, a1: %s, a2: %s\n", current.label, current.instruction, current.arg1, current.arg2);
|
|
|
|
loopEnd:
|
|
cSize++;
|
|
}
|
|
|
|
final:
|
|
asmIA->instruction = realloc(asmIA->instruction, cSize);
|
|
asmIA->length = cSize;
|
|
|
|
return asmIA;
|
|
}
|
|
|
|
AsmLabelArray *GenerateLabels(AsmInstructionArray *assembly)
|
|
{
|
|
AsmLabelArray *labels = malloc(sizeof(AsmLabelArray));
|
|
uint32_t cSize = 0, mSize = ARRAY_SNAP_SIZE;
|
|
labels->labels = malloc(sizeof(AsmLabel) * ARRAY_SNAP_SIZE);
|
|
|
|
for (int i = 0; i < assembly->length; i++)
|
|
{
|
|
if (cSize == mSize)
|
|
{
|
|
mSize += ARRAY_SNAP_SIZE;
|
|
labels->labels = realloc(labels->labels, mSize);
|
|
}
|
|
|
|
if (assembly->instruction[0].label[0] == '\0')
|
|
continue;
|
|
|
|
labels->labels[cSize].location = i;
|
|
strcpy(labels->labels[cSize].label, assembly->instruction[0].label);
|
|
|
|
cSize++;
|
|
}
|
|
|
|
labels->labels = realloc(labels->labels, cSize);
|
|
labels->length = cSize;
|
|
|
|
return labels;
|
|
}
|
|
|
|
uint16_t *BinaryInstructionToBin(BinaryInstruction instruction)
|
|
{
|
|
uint16_t *bin = malloc(sizeof(uint16_t) * 3);
|
|
|
|
bin[0] = instruction.instruction +
|
|
(instruction.arg1Info << 12) +
|
|
(instruction.arg2Info << 14);
|
|
|
|
bin[1] = instruction.arg1;
|
|
bin[2] = instruction.arg2;
|
|
|
|
return bin;
|
|
}
|
|
|
|
static void just() {
|
|
|
|
}
|
|
|
|
int WhereIn2DCharArray(int x, int y, char array[25][4], char* val)
|
|
{
|
|
for (int i = 0; i < x; i++)
|
|
{
|
|
if (strcmp(array[i], val) == 0)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void ParseArgument(char *argData, AsmLabelArray *labels, uint16_t labelOffset,
|
|
ArgumentInfo *argInfoOut, uint16_t *argOut)
|
|
{
|
|
bool pointer, value, label;
|
|
pointer = argData[0] == '*'; // location in ram / pointer in register
|
|
if (pointer)
|
|
argData++;
|
|
|
|
value = argData[0] >= '0' && argData[0] <= '9';
|
|
|
|
label = !value && argData[0] == '[';
|
|
|
|
if (!pointer && !value) // value in register / label
|
|
{
|
|
if (label)
|
|
{
|
|
*argInfoOut = value;
|
|
|
|
// todo: something here probably??
|
|
}
|
|
else
|
|
{
|
|
*argInfoOut = valueInRegister;
|
|
|
|
// todo: something here probably??
|
|
}
|
|
}
|
|
else if (!pointer && value) // value
|
|
{
|
|
*argInfoOut = value;
|
|
|
|
uint16_t modval = 0, total = 0;
|
|
|
|
switch (argData[1])
|
|
{
|
|
case 'x':
|
|
case 'X':
|
|
modval = 16;
|
|
argData += 2;
|
|
break;
|
|
case 'b':
|
|
case 'B':
|
|
modval = 2;
|
|
argData += 2;
|
|
break;
|
|
default:
|
|
modval = 10;
|
|
break;
|
|
}
|
|
|
|
for (char *a = argData; a < FindNextSpaceChar(argData, true); a++)
|
|
{
|
|
total *= modval;
|
|
|
|
switch(*a)
|
|
{
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
just();
|
|
total += '0' - *a;
|
|
break;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
total += 10 + ('a' - *a);
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
total += 10 + ('A' - *a);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "FATAL CHARACTER IN NUMBER STREAM\n");
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
*argOut = total;
|
|
}
|
|
else if (pointer && !value) // pointer in register
|
|
{
|
|
*argInfoOut = pointerInRegister;
|
|
|
|
|
|
}
|
|
else
|
|
{
|
|
fprintf(stderr, "FATAL ARGUMENT INFO\n");
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
uint16_t *CompileAsembly(AsmInstructionArray *assembly, AsmLabelArray *labels)
|
|
{
|
|
uint16_t *ret = malloc(sizeof(uint16_t) * UINT16_MAX);
|
|
uint16_t cSize = 0;
|
|
|
|
for (int i = 0; i < assembly->length; i++)
|
|
{
|
|
printf("cabii: %d\n", i);
|
|
|
|
BinaryInstruction binaryIns;
|
|
|
|
int instruction = WhereIn2DCharArray(LEN(CpuInstructionsHumanReadable),
|
|
LEN(CpuInstructionsHumanReadable[0]),
|
|
CpuInstructionsHumanReadable,
|
|
assembly->instruction[i].instruction);
|
|
|
|
if (instruction < 0)
|
|
{
|
|
fprintf(stderr, "INSTRUCTION NOT FOUND\n");
|
|
exit(-1);
|
|
}
|
|
|
|
binaryIns.instruction = instruction;
|
|
|
|
cSize++;
|
|
}
|
|
|
|
ret = realloc(ret, cSize);
|
|
return ret;
|
|
}
|