Compare commits

...

2 Commits

Author SHA1 Message Date
ee162a70ed jump 2025-03-12 12:57:42 +05:00
b9fa669fd1 fixed bugs 2025-03-12 12:57:16 +05:00
16 changed files with 136 additions and 80 deletions

2
.vscode/launch.json vendored
View File

@ -7,7 +7,7 @@
"request": "launch", "request": "launch",
"program": "${workspaceFolder}/bin/tcpu", "program": "${workspaceFolder}/bin/tcpu",
"windows": { "program": "${workspaceFolder}/bin/tcpu.exe" }, "windows": { "program": "${workspaceFolder}/bin/tcpu.exe" },
"args": [ "-c", "../examples/s.tasm", "o.bin", "--debug" ], "args": [ "-c", "../examples/conditional_jump.tasm", "o.bin", "--debug", "-i", "o.bin" ],
"cwd": "${workspaceFolder}/bin", "cwd": "${workspaceFolder}/bin",
"preLaunchTask": "build_exec_dbg", "preLaunchTask": "build_exec_dbg",
"stopAtEntry": false, "stopAtEntry": false,

View File

@ -1,2 +1,9 @@
# TODO List # TODO List
- add negative number arguments support
- change section binary format:
1. code
2. exit instruction with code ERR_U_FORGOT_TO_CALL_EXIT
3. data
- add padding to compilation
- arguments validation for each instruction - arguments validation for each instruction
- VM debug mode

View File

@ -0,0 +1,32 @@
/*
Example of behavior change depending on some condition
*/
.main:
movc ax 1
movc bx 2
gt cx ax bx
jnz @true cx
jz @false cx
.true:
const8 true.msg "true\n"
movc cx @true.msg
movc dx #true.msg
jmp @print
.false
const8 false.msg "false\n"
movc cx @false.msg
movc dx #false.msg
jmp @print
.print:
movc ax 1
movc bx 1
sys
jmp @end
.end:
movc ax 0
exit

View File

@ -1,12 +1,7 @@
/* /*
Example of graphical application Example of self-repeating code section
*/ */
.main: .main:
//TODO loop example
le
gt
eq
jif
jel
exit exit

View File

@ -4,7 +4,7 @@
.data: .data:
// named array of 8-bit values // named array of 8-bit values
const8 msg "Hello, World :3\n\0" const8 msg "Hello, World"
.main: .main:
movc ax 1; // sys_write movc ax 1; // sys_write

View File

@ -27,6 +27,8 @@ void BinaryObject_construct(BinaryObject* ptr){
ptr->section_list = List_CompiledSection_alloc(64); ptr->section_list = List_CompiledSection_alloc(64);
HashMap_CompiledSectionPtr_alloc(&ptr->section_map); HashMap_CompiledSectionPtr_alloc(&ptr->section_map);
HashMap_ConstDataProps_alloc(&ptr->const_data_map); HashMap_ConstDataProps_alloc(&ptr->const_data_map);
ptr->main_section = NULL;
ptr->total_size = 0;
} }
void BinaryObject_free(BinaryObject* ptr){ void BinaryObject_free(BinaryObject* ptr){

View File

@ -57,6 +57,7 @@ HashMap_declare(CompiledSectionPtr);
typedef struct BinaryObject { typedef struct BinaryObject {
List_CompiledSection section_list; List_CompiledSection section_list;
HashMap_CompiledSectionPtr section_map; HashMap_CompiledSectionPtr section_map;
NULLABLE(CompiledSection*) main_section;
HashMap_ConstDataProps const_data_map; HashMap_ConstDataProps const_data_map;
u32 total_size; u32 total_size;
} BinaryObject; } BinaryObject;

View File

@ -124,6 +124,9 @@ static bool compileSection(Compiler* cmp, Section* sec){
} }
static bool compileBinary(Compiler* cmp){ static bool compileBinary(Compiler* cmp){
returnErrorIf_auto(cmp->state != CompilerState_Parsing);
cmp->state = CompilerState_Compiling;
for(u32 i = 0; i < cmp->ast.sections.len; i++){ for(u32 i = 0; i < cmp->ast.sections.len; i++){
SectionPtr sec = &cmp->ast.sections.data[i]; SectionPtr sec = &cmp->ast.sections.data[i];
if(!compileSection(cmp, sec)){ if(!compileSection(cmp, sec)){
@ -137,6 +140,7 @@ static bool compileBinary(Compiler* cmp){
if(main_sec_ptrptr == NULL){ if(main_sec_ptrptr == NULL){
returnError("no 'main' section was defined"); returnError("no 'main' section was defined");
} }
cmp->binary.main_section = *main_sec_ptrptr;
// create linked list of CompiledSection where main is the first // create linked list of CompiledSection where main is the first
CompiledSection* prev_sec = *main_sec_ptrptr; CompiledSection* prev_sec = *main_sec_ptrptr;
@ -160,6 +164,8 @@ static bool compileBinary(Compiler* cmp){
returnError("duplicate named data '%s'", str_copy(cd.name).data); returnError("duplicate named data '%s'", str_copy(cd.name).data);
} }
} }
prev_sec = sec;
} }
// insert calculated offsets into sections // insert calculated offsets into sections
@ -194,26 +200,16 @@ static bool compileBinary(Compiler* cmp){
} }
static bool writeBinaryFile(Compiler* cmp, FILE* f){ static bool writeBinaryFile(Compiler* cmp, FILE* f){
returnErrorIf_auto(cmp->state != CompilerState_Parsing); returnErrorIf_auto(cmp->state != CompilerState_Compiling);
cmp->state = CompilerState_Compiling;
if(!compileBinary(cmp)){ CompiledSection* sec = cmp->binary.main_section;
return false;
}
CompiledSection** main_sec_ptrptr = HashMap_CompiledSectionPtr_tryGetPtr(&cmp->binary.section_map, STR("main"));
if(main_sec_ptrptr == NULL){
returnError("no 'main' section was defined");
}
CompiledSection* sec = *main_sec_ptrptr;
while(sec){ while(sec){
fwrite(sec->bytes.data, 1, sec->bytes.len, f); fwrite(sec->bytes.data, 1, sec->bytes.len, f);
fflush(f);
sec = sec->next; sec = sec->next;
} }
//TODO: print warnings for unused sections //TODO: print warnings for unused sections
return true; return true;
} }
@ -289,6 +285,7 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
if(debug_log) if(debug_log)
printf("===================================[parsing]===================================\n"); printf("===================================[parsing]===================================\n");
success = Compiler_parse(cmp); success = Compiler_parse(cmp);
if (debug_log){ if (debug_log){
printf("-------------------------------------[AST]-------------------------------------\n"); printf("-------------------------------------[AST]-------------------------------------\n");
for(u32 i = 0; i < cmp->ast.sections.len; i++){ for(u32 i = 0; i < cmp->ast.sections.len; i++){
@ -309,6 +306,7 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
Operation* op = &sec->code.data[j]; Operation* op = &sec->code.data[j];
const Instruction* instr = Instruction_getByOpcode(op->opcode); const Instruction* instr = Instruction_getByOpcode(op->opcode);
if(instr == NULL){ if(instr == NULL){
fclose(f);
returnError("unknown opcode: %i", op->opcode) returnError("unknown opcode: %i", op->opcode)
} }
@ -352,6 +350,7 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
} }
} }
} }
if(!success){ if(!success){
fclose(f); fclose(f);
return false; return false;
@ -359,6 +358,25 @@ bool Compiler_compile(Compiler* cmp, cstr source_file_name, cstr out_file_name,
if(debug_log) if(debug_log)
printf("==================================[compiling]==================================\n"); printf("==================================[compiling]==================================\n");
success = compileBinary(cmp);
if(debug_log){
for(u32 i = 0; i < cmp->binary.section_list.len; i++){
CompiledSection* sec = &cmp->binary.section_list.data[i];
str tmpstr = str_copy(sec->name);
printf("compiled section '%s' to %u bytes with offset 0x%x\n", tmpstr.data, sec->bytes.len, sec->offset);
free(tmpstr.data);
}
}
if(!success){
fclose(f);
return false;
}
if(debug_log)
printf("----------------------------[writing output to file]---------------------------\n");
success = writeBinaryFile(cmp, f); success = writeBinaryFile(cmp, f);
fclose(f); fclose(f);
if(success){ if(success){

View File

@ -130,7 +130,7 @@ static void readArguments(Compiler* cmp){
// string argument reading // string argument reading
if(quot != '\0'){ if(quot != '\0'){
if(c == quot && cmp->code.data[cmp->pos - 1] != '\\'){ if(c == quot && (cmp->code.data[cmp->pos - 1] != '\\' || cmp->code.data[cmp->pos - 2] == '\\')){
quot = '\0'; quot = '\0';
} }
else if(c == '\r' || c == '\n'){ else if(c == '\r' || c == '\n'){

View File

@ -44,6 +44,7 @@ static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
c = src.data[i]; c = src.data[i];
if(c == '\\'){ if(c == '\\'){
escaped = !escaped; escaped = !escaped;
if(escaped)
continue; continue;
} }
@ -69,11 +70,17 @@ static NULLABLE(str) resolveEscapeSequences(Compiler* cmp, str src){
case 'e': case 'e':
StringBuilder_append_char(&sb, '\e'); StringBuilder_append_char(&sb, '\e');
break; break;
case '"':
case '\'':
StringBuilder_append_char(&sb, c);
break;
default: default:
setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i); setError_unexpectedTokenChar(cmp->tokens.data[cmp->tok_i], i);
StringBuilder_free(&sb); StringBuilder_free(&sb);
return str_null; return str_null;
} }
escaped = false;
} }
return StringBuilder_getStr(&sb); return StringBuilder_getStr(&sb);

View File

@ -0,0 +1,40 @@
#include "impl_macros.h"
// JUMP [destination address]
i32 JMP_impl(VM* vm){
u32 dst_addr = 0;
readVar(dst_addr);
vm->current_pos = dst_addr;
return sizeof(dst_addr);
}
// JNZ [destination address] [condition register]
i32 JNZ_impl(VM* vm){
u32 dst_addr = 0;
readVar(dst_addr);
u8 cond_register_i = 0;
readRegisterVar(cond_register_i);
if(vm->registers.array[cond_register_i].u32v0 != 0){
vm->current_pos = dst_addr;
}
return sizeof(dst_addr) + sizeof(cond_register_i);
}
// JZ [destination address] [condition register]
i32 JZ_impl(VM* vm){
u32 dst_addr = 0;
readVar(dst_addr);
u8 cond_register_i = 0;
readRegisterVar(cond_register_i);
if(vm->registers.array[cond_register_i].u32v0 == 0){
vm->current_pos = dst_addr;
}
return sizeof(dst_addr) + sizeof(cond_register_i);
}

View File

@ -22,7 +22,7 @@ i32 NAME##_impl (VM* vm) {\
vm->registers.array[src_register_i].u64v = OPERATOR vm->registers.array[src_register_i].u64v;\ vm->registers.array[src_register_i].u64v = OPERATOR vm->registers.array[src_register_i].u64v;\
break;\ break;\
}\ }\
return sizeof(src_register_i) + sizeof(value_size);\ return sizeof(src_register_i) /*+ sizeof(value_size)*/;\
} }
#define logicalOperator2Impl(NAME, OPERATOR)\ #define logicalOperator2Impl(NAME, OPERATOR)\
@ -48,7 +48,7 @@ i32 NAME##_impl (VM* vm) {\
vm->registers.array[dst_register_i].u64v OPERATOR##= vm->registers.array[src_register_i].u64v;\ vm->registers.array[dst_register_i].u64v OPERATOR##= vm->registers.array[src_register_i].u64v;\
break;\ break;\
}\ }\
return sizeof(dst_register_i) + sizeof(src_register_i) + sizeof(value_size);\ return sizeof(dst_register_i) + sizeof(src_register_i) /*+ sizeof(value_size)*/;\
} }
#define logicalOperator3Impl(NAME, OPERATOR)\ #define logicalOperator3Impl(NAME, OPERATOR)\
@ -75,7 +75,7 @@ i32 NAME##_impl (VM* vm) {\
vm->registers.array[dst_register_i].u64v = vm->registers.array[src0_register_i].u64v OPERATOR vm->registers.array[src1_register_i].u64v;\ vm->registers.array[dst_register_i].u64v = vm->registers.array[src0_register_i].u64v OPERATOR vm->registers.array[src1_register_i].u64v;\
break;\ break;\
}\ }\
return sizeof(dst_register_i) + sizeof(src0_register_i) + sizeof(src1_register_i) + sizeof(value_size);\ return sizeof(dst_register_i) + sizeof(src0_register_i) + sizeof(src1_register_i) /*+ sizeof(value_size)*/;\
} }
logicalOperator3Impl(EQ, ==) logicalOperator3Impl(EQ, ==)

View File

@ -23,7 +23,7 @@ i32 NAME##_impl (VM* vm) {\
vm->registers.array[dst_register_i].u64v OPERATOR##= vm->registers.array[src_register_i].u64v;\ vm->registers.array[dst_register_i].u64v OPERATOR##= vm->registers.array[src_register_i].u64v;\
break;\ break;\
}\ }\
return sizeof(dst_register_i) + sizeof(src_register_i) + sizeof(value_size);\ return sizeof(dst_register_i) + sizeof(src_register_i) /*+ sizeof(value_size)*/;\
} }
/// ADD [dst_register] [src_register] /// ADD [dst_register] [src_register]

View File

@ -27,8 +27,8 @@ i32 XOR_impl(VM* vm);
i32 AND_impl(VM* vm); i32 AND_impl(VM* vm);
i32 JMP_impl(VM* vm); i32 JMP_impl(VM* vm);
i32 JIF_impl(VM* vm); i32 JNZ_impl(VM* vm);
i32 JEL_impl(VM* vm); i32 JZ_impl(VM* vm);
Array_declare(Instruction); Array_declare(Instruction);
@ -59,8 +59,8 @@ static const Array_Instruction instructions_array = ARRAY(Instruction, {
Instruction_construct(AND), Instruction_construct(AND),
Instruction_construct(JMP), Instruction_construct(JMP),
Instruction_construct(JIF), Instruction_construct(JNZ),
Instruction_construct(JEL), Instruction_construct(JZ),
}); });
const Instruction* Instruction_getByOpcode(Opcode opcode){ const Instruction* Instruction_getByOpcode(Opcode opcode){

View File

@ -32,8 +32,8 @@ typedef enum __attribute__((__packed__)) Opcode {
Opcode_AND, Opcode_AND,
Opcode_JMP, Opcode_JMP,
Opcode_JIF, Opcode_JNZ,
Opcode_JEL, Opcode_JZ,
} Opcode; } Opcode;
typedef struct Instruction { typedef struct Instruction {

View File

@ -10,53 +10,7 @@
i32 compileSources(cstr source_file, cstr out_file, bool debug_log); i32 compileSources(cstr source_file, cstr out_file, bool debug_log);
i32 bootFromImage(cstr image_file); i32 bootFromImage(cstr image_file);
#define assert_sdl(EXPR) if(!(EXPR)) { printf("assert failed: %s\nSDL_Error: %s\n", #EXPR, SDL_GetError()); return false; }
bool test_display(){
Display* display = Display_create(STR("le display"), 1600, 900, DisplayFlags_Default);
assert_sdl(display != NULL);
i64 fps = 60;
i64 nsec_per_frame = 1e9 / fps;
for(u32 i = 0; i < 600; i++){
static i64 last_frame_time = 0;
i64 current_frame_time = SDL_GetTicksNS();
i64 delta_time = current_frame_time - last_frame_time;
last_frame_time = current_frame_time;
SDL_Event event;
while(SDL_PollEvent(&event)) {
if(event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED){
printfe("event WINDOW_CLOSE");
return 0;
}
if(event.type == SDL_EVENT_QUIT){
printfe("event QUIT");
return 0;
}
}
assert_sdl(Display_setDrawingColor(display, ColorRGBA_create(200, 200, 200, 255)));
assert_sdl(Display_clear(display));
assert_sdl(Display_setDrawingColor(display, ColorRGBA_create(240, 40, 40, 255)));
assert_sdl(Display_fillRect(display, Rect_create(i, i, 64, 64)));
assert_sdl(Display_swapBuffers(display));
i64 time_ellapsed = SDL_GetTicksNS() - last_frame_time;
i64 delay = nsec_per_frame - time_ellapsed;
if (delay > 0) {
SDL_DelayNS(delay);
}
}
Display_destroy(display);
return true;
}
i32 main(const i32 argc, cstr* argv){ i32 main(const i32 argc, cstr* argv){
test_display();
return 0;
if(argc < 2){ if(argc < 2){
printfe("ERROR: no arguments provided. Use --help to know more.\n"); printfe("ERROR: no arguments provided. Use --help to know more.\n");
return 1; return 1;