r16/asm/assembler.c

371 lines
8.7 KiB
C
Raw Permalink Normal View History

2024-04-22 13:05:10 +00:00
#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>
2024-04-24 11:29:32 +00:00
#include <stdbool.h>
#include <string.h>
2024-04-22 13:05:10 +00:00
2024-04-24 11:29:32 +00:00
// 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)
2024-04-22 13:05:10 +00:00
{
2024-04-24 11:29:32 +00:00
begin:
switch (*data)
{
case '\0':
if (careAboutNull)
{
fprintf(stderr, "FOUND NULL CHAR BEFORE CHAR TO FIND\n");
exit(-1);
}
2024-04-22 13:05:10 +00:00
2024-04-24 11:29:32 +00:00
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));
2024-12-17 10:09:20 +00:00
asmIA->length = 0;
2024-04-24 12:02:18 +00:00
asmIA->instruction = malloc(sizeof(AsmInstruction) * ARRAY_SNAP_SIZE);
2024-12-17 10:09:20 +00:00
uint32_t cSize = 0, mSize = ARRAY_SNAP_SIZE;
2024-12-10 10:50:54 +00:00
int gfususc = 0;
2024-04-22 13:05:10 +00:00
2024-04-24 11:29:32 +00:00
while (true)
{
2024-12-10 10:50:54 +00:00
loopStart:
printf("asmiloop: %d\n", gfususc++);
2024-04-24 11:29:32 +00:00
if (cSize == mSize)
{
2024-04-24 12:02:18 +00:00
mSize += ARRAY_SNAP_SIZE;
2024-12-10 10:50:54 +00:00
asmIA->instruction = realloc(asmIA->instruction, sizeof(AsmInstruction) * mSize);
2024-04-24 11:29:32 +00:00
}
2024-12-10 10:50:54 +00:00
AsmInstruction current = asmIA->instruction[cSize];
2024-04-24 11:29:32 +00:00
d = FindNextNonSpaceChar(d, false);
if (*d == '\0')
goto final;
if (*d == '\n')
{
d++;
goto loopStart;
}
if (*(FindNextSpaceChar(d, true) - 1) == ':')
{
2024-12-17 10:09:20 +00:00
size_t l = (FindNextSpaceChar(d, true) - 1) - d;
memcpy(&current.label, d, l);
current.label[l] = '\0';
2024-04-24 11:29:32 +00:00
d = FindNextNonSpaceChar(d, true);
}
else
{
current.label[0] = '\0';
}
2024-12-17 10:09:20 +00:00
memcpy(&current.instruction, d, sizeof(char) * 3);
current.instruction[3] = '\0';
2024-04-24 11:29:32 +00:00
d = FindNextNonSpaceChar(d, false);
if (*d == '\0')
goto final;
if (*d == '\n')
{
d++;
goto loopEnd;
}
2024-12-17 10:09:20 +00:00
char *comma = FindNextChar(d + 3, ',', true),
*nline = FindNextChar(d + 3, '\n', true);
2024-04-24 11:29:32 +00:00
bool a2 = comma < nline;
char *eoA1 = a2 ? comma : nline;
2024-12-17 10:09:20 +00:00
size_t s = eoA1 - (d + 3);
memcpy(&current.arg1, d + 3, s);
current.arg1[s] = '\0';
2024-04-24 11:29:32 +00:00
if (!a2)
goto loopEnd;
d = FindNextNonSpaceChar(eoA1 + 1, true);
2024-12-17 10:09:20 +00:00
s = nline - d;
memcpy(&current.arg2, d, s);
current.arg2[s] = '\0';
2024-04-24 11:29:32 +00:00
d = nline + 1;
2024-12-17 10:09:20 +00:00
printf("l: %s, i: %s, a1: %s, a2: %s\n", current.label, current.instruction, current.arg1, current.arg2);
2024-04-24 11:29:32 +00:00
loopEnd:
cSize++;
}
final:
asmIA->instruction = realloc(asmIA->instruction, cSize);
asmIA->length = cSize;
return asmIA;
2024-04-24 12:02:18 +00:00
}
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);
2024-04-24 12:02:18 +00:00
}
if (assembly->instruction[0].label[0] == '\0')
continue;
labels->labels[cSize].location = i;
strcpy(labels->labels[cSize].label, assembly->instruction[0].label);
2024-04-24 12:02:18 +00:00
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;
}
2024-12-17 10:09:20 +00:00
static void just() {
}
2024-12-10 11:03:41 +00:00
int WhereIn2DCharArray(int x, int y, char array[25][4], char* val)
2024-04-25 19:40:09 +00:00
{
for (int i = 0; i < x; i++)
{
if (strcmp(array[i], val) == 0)
return i;
}
return -1;
}
2024-04-26 12:31:55 +00:00
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;
2024-12-17 10:09:20 +00:00
// todo: something here probably??
2024-04-26 12:31:55 +00:00
}
else
{
*argInfoOut = valueInRegister;
2024-12-17 10:09:20 +00:00
// todo: something here probably??
2024-04-26 12:31:55 +00:00
}
}
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':
2024-12-17 10:09:20 +00:00
just();
2024-04-26 12:31:55 +00:00
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);
}
}
2024-04-24 12:02:18 +00:00
uint16_t *CompileAsembly(AsmInstructionArray *assembly, AsmLabelArray *labels)
{
uint16_t *ret = malloc(sizeof(uint16_t) * UINT16_MAX);
2024-04-25 19:40:09 +00:00
uint16_t cSize = 0;
for (int i = 0; i < assembly->length; i++)
{
2024-12-17 10:09:20 +00:00
printf("cabii: %d\n", i);
BinaryInstruction binaryIns;
2024-04-25 19:40:09 +00:00
int instruction = WhereIn2DCharArray(LEN(CpuInstructionsHumanReadable),
2024-12-10 11:03:41 +00:00
LEN(CpuInstructionsHumanReadable[0]),
2024-04-25 19:40:09 +00:00
CpuInstructionsHumanReadable,
assembly->instruction[i].instruction);
if (instruction < 0)
{
fprintf(stderr, "INSTRUCTION NOT FOUND\n");
exit(-1);
}
binaryIns.instruction = instruction;
cSize++;
}
2024-04-24 12:02:18 +00:00
2024-04-25 19:40:09 +00:00
ret = realloc(ret, cSize);
return ret;
2024-04-24 12:02:18 +00:00
}