230 lines
6.5 KiB
C
230 lines
6.5 KiB
C
#include "../common/types.h"
|
|
#include "../common/opcodeInfo.h"
|
|
#include "../common/buffer.h"
|
|
#include "../common/sourceFile.h"
|
|
#include "assembler.h"
|
|
#include "assemblerConfig.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define error(...) fprintf(stderr, __VA_ARGS__)
|
|
int main(int argc, char** argv) {
|
|
//BEGIN variable definitions
|
|
int sourceFile=-1, outputFile=-1, configFile=-1;
|
|
buffer_t sourceBuffer, outputBuffer, configBuffer, infoBuffer;
|
|
int sourceLen, configLen, outputPos;
|
|
assembler_config_t config;
|
|
source_file_t header;
|
|
mapping_t mapping;
|
|
assembler_t assembler;
|
|
int hasConfig;
|
|
//END variable definitions
|
|
|
|
//BEGIN check usage
|
|
argc--;
|
|
if(argc!=2&&argc!=3) {
|
|
error("Usage: %s <source> <output> [config]\n", argv[0]);
|
|
return 1;
|
|
} else {
|
|
printf("Using %d arguments\n", argc);
|
|
}
|
|
hasConfig=argc==3;
|
|
//END check usage
|
|
|
|
//BEGIN open the files
|
|
sourceFile=File_open(argv[1], FILE_OPEN_read);
|
|
outputFile=File_open(argv[2], FILE_OPEN_write|FILE_OPEN_create);
|
|
if(hasConfig) configFile=File_open(argv[3], FILE_OPEN_read);
|
|
//END open the files
|
|
|
|
//BEGIN check if opening the files went well
|
|
if(sourceFile==-1) {
|
|
error("ERR: Couldn't open input file %s\n", argv[1]);
|
|
return 1;
|
|
}
|
|
if(outputFile==-1) {
|
|
error("ERR: Couldn't open output file %s\n", argv[2]);
|
|
return 1;
|
|
}
|
|
if(hasConfig&&configFile==-1) {
|
|
error("ERR: Couldn't open config file %s\n", argv[3]);
|
|
return 1;
|
|
}
|
|
//END check if opening the files went well
|
|
|
|
//BEGIN read the source file
|
|
sourceLen=File_length(sourceFile);
|
|
if(!allocBuffer(&sourceBuffer, sourceLen)) {
|
|
error("ERR: Failed to allocate memory for reading source file\n");
|
|
return 1;
|
|
}
|
|
File_read(sourceFile, 0, sourceBuffer.data, sourceLen);
|
|
File_close(sourceFile);
|
|
printf("Successfully loaded source file in memory\n");
|
|
//END read the source file
|
|
|
|
//BEGIN read the config file
|
|
if(hasConfig) {
|
|
configLen=File_length(configFile);
|
|
if(!allocBuffer(&configBuffer, configLen)) {
|
|
error("ERR: Failed to allocate memory for reading config file\n");
|
|
return 1;
|
|
}
|
|
File_read(configFile, 0, configBuffer.data, configLen);
|
|
File_close(configFile);
|
|
printf("Successfully loaded config file in memory\n");
|
|
}
|
|
//END read the config file
|
|
|
|
//BEGIN allocate the output and info buffer
|
|
if(!allocBuffer(&outputBuffer, 256)) {
|
|
error("ERR: Failed to allocate memory for output buffer\n");
|
|
return 1;
|
|
}
|
|
outputBuffer.size=0;
|
|
outputPos=0;
|
|
if(!allocBuffer(&infoBuffer, 256)) {
|
|
error("ERR: Failed to allocate memory for info buffer\n");
|
|
return 1;
|
|
}
|
|
infoBuffer.size=0;
|
|
//END allocate the output and info buffer
|
|
|
|
//BEGIN read the config
|
|
if(hasConfig) {
|
|
if(!readConfig(&configBuffer, &config)) {
|
|
error("ERR: Error while reading config file\n");
|
|
return 1;
|
|
}
|
|
freeBuffer(&configBuffer);
|
|
printf("Successfully read the config\n");
|
|
}
|
|
//END read the config
|
|
|
|
//BEGIN assemble the code
|
|
printf("Preparing to assemble the code\n");
|
|
|
|
//setup the assembler struct
|
|
if(hasConfig) assembler.offset=config.codeOffset;
|
|
else assembler.offset=0x0000;
|
|
assembler.pos=0;
|
|
assembler.line=1;
|
|
assembler.col=1;
|
|
assembler.labelCount=0;
|
|
assembler.in=&sourceBuffer;
|
|
assembler.out=&outputBuffer;
|
|
assembler.stdout=&infoBuffer;
|
|
|
|
//register opcodes
|
|
Opcode_registerOpcodes();
|
|
|
|
//assemble the code
|
|
if(!Assembler_assemble(&assembler)) {
|
|
error("ERR: Failed to assemble the code\n");
|
|
toStringBuffer(&infoBuffer);
|
|
error("%s", (char*) infoBuffer.data);
|
|
return 1;
|
|
}
|
|
|
|
//print information
|
|
printf("Successfully assembled the code\n");
|
|
toStringBuffer(&infoBuffer);
|
|
printf("%s", (char*) infoBuffer.data);
|
|
freeBuffer(&infoBuffer);
|
|
//END assemble the code
|
|
|
|
//BEGIN compute the header
|
|
//we hash the source file and push source version
|
|
printf("Computing hash\n");
|
|
header.magic=MAGIC;
|
|
header.hash=strsuml((char*) sourceBuffer.data, sourceBuffer.size);
|
|
header.version=SOURCE_VERSION;
|
|
freeBuffer(&sourceBuffer);
|
|
|
|
if(hasConfig) {
|
|
//add the header
|
|
printf("Injecting config\n");
|
|
header.entryPoint=config.entryPoint;
|
|
header.mappings=config.mappingCount;
|
|
File_write(outputFile, outputPos, &header, HEADER_LENGTH);
|
|
outputPos+=HEADER_LENGTH;
|
|
|
|
for(int i=0; i<config.mappingCount; i++) {
|
|
//read the mapping and add it
|
|
printf("Adding mapping %d\n", i);
|
|
assembler_mapping_t map=config.mappings[i];
|
|
mapping.offset=map.offset;
|
|
mapping.length=map.length;
|
|
mapping.type=map.type;
|
|
mapping.access=map.access;
|
|
File_write(outputFile, outputPos, &mapping, MAPPING_LENGTH);
|
|
outputPos+=MAPPING_LENGTH;
|
|
|
|
//write the filename if we have one
|
|
if(mapping.type==MAPPING_TYPE_file||mapping.type==MAPPING_TYPE_file_raw) {
|
|
//name length
|
|
big_endian_int_t bei={.value=map.filenameLen};
|
|
File_write(outputFile, outputPos, &bei, sizeof(bei));
|
|
outputPos+=sizeof(bei);
|
|
|
|
//name itself
|
|
File_write(outputFile, outputPos, &map.filename, map.filenameLen);
|
|
outputPos+=map.filenameLen;
|
|
}
|
|
}
|
|
} else {
|
|
//we start at 0 in a regular script, and have 3 mappings
|
|
printf("Injecting default config\n");
|
|
header.entryPoint=0x0000;
|
|
header.mappings=3;
|
|
File_write(outputFile, outputPos, &header, HEADER_LENGTH);
|
|
outputPos+=HEADER_LENGTH;
|
|
|
|
//we map the ROM at offset 0x0000
|
|
printf("Mapping the ROM at %.4x\n", 0x0000);
|
|
mapping.offset=0x0000;
|
|
mapping.length=outputBuffer.size;
|
|
mapping.type=MAPPING_TYPE_rom;
|
|
mapping.access=MAPPING_ACCESS_r|MAPPING_ACCESS_x;
|
|
File_write(outputFile, outputPos, &mapping, MAPPING_LENGTH);
|
|
outputPos+=MAPPING_LENGTH;
|
|
|
|
//we map 1kB of RAM at offset 0x10000
|
|
printf("Mapping 1kB of RAM at %.4x\n", 0x10000);
|
|
mapping.offset=0x10000;
|
|
mapping.length=1024;
|
|
mapping.type=MAPPING_TYPE_ram;
|
|
mapping.access=MAPPING_ACCESS_r|MAPPING_ACCESS_w;
|
|
File_write(outputFile, outputPos, &mapping, MAPPING_LENGTH);
|
|
outputPos+=MAPPING_LENGTH;
|
|
|
|
//we map the stack at offset 0x20000
|
|
printf("Mapping the stack at %.4x\n", 0x20000);
|
|
mapping.offset=0x20000;
|
|
mapping.length=-1;
|
|
mapping.type=MAPPING_TYPE_stack;
|
|
mapping.access=MAPPING_ACCESS_r|MAPPING_ACCESS_w;
|
|
File_write(outputFile, outputPos, &mapping, MAPPING_LENGTH);
|
|
outputPos+=MAPPING_LENGTH;
|
|
}
|
|
printf("Written header to disk\n");
|
|
//END compute the header
|
|
|
|
//BEGIN add the code
|
|
if(!File_write(outputFile, outputPos, outputBuffer.data, outputBuffer.size)) {
|
|
error("ERR: Cannot write to output file\n");
|
|
return 1;
|
|
}
|
|
outputPos+=outputBuffer.size;
|
|
if(!File_truncate(outputFile, outputPos)) {
|
|
error("ERR: Cannot truncate output file\n");
|
|
return 1;
|
|
}
|
|
freeBuffer(&outputBuffer);
|
|
File_close(outputFile);
|
|
printf("Successfully assembled the code\n");
|
|
//END add the code
|
|
|
|
return 0;
|
|
}
|