diff --git a/constants.h b/constants.h new file mode 100644 index 0000000..9ecfdc9 --- /dev/null +++ b/constants.h @@ -0,0 +1,38 @@ +#pragma once +#include "parser.h" + +void register_constants() { + parser_register_constant("ink_red", 0x00); + parser_register_constant("ink_lime", 0x01); + parser_register_constant("ink_blue", 0x02); + parser_register_constant("ink_magenta", 0x03); + parser_register_constant("ink_yellow", 0x04); + parser_register_constant("ink_cyan", 0x05); + parser_register_constant("ink_white", 0x06); + parser_register_constant("ink_black", 0x07); + parser_register_constant("ink_brown", 0x08); + parser_register_constant("ink_green", 0x09); + parser_register_constant("ink_navy", 0x0A); + parser_register_constant("ink_purple", 0x0B); + parser_register_constant("ink_gold", 0x0C); + parser_register_constant("ink_teal", 0x0D); + parser_register_constant("ink_gray", 0x0E); + parser_register_constant("ink_black2", 0x0F); + + parser_register_constant("paper_red", 0x00); + parser_register_constant("paper_lime", 0x10); + parser_register_constant("paper_blue", 0x20); + parser_register_constant("paper_magenta", 0x30); + parser_register_constant("paper_yellow", 0x40); + parser_register_constant("paper_cyan", 0x50); + parser_register_constant("paper_white", 0x60); + parser_register_constant("paper_black", 0x70); + parser_register_constant("paper_brown", 0x80); + parser_register_constant("paper_green", 0x90); + parser_register_constant("paper_navy", 0xA0); + parser_register_constant("paper_purple", 0xB0); + parser_register_constant("paper_gold", 0xC0); + parser_register_constant("paper_teal", 0xD0); + parser_register_constant("paper_gray", 0xE0); + parser_register_constant("paper_black2", 0xF0); +} diff --git a/main.cpp b/main.cpp index ac6f038..fc10df9 100644 --- a/main.cpp +++ b/main.cpp @@ -4,6 +4,35 @@ #include "vdp.h" #include +#define BTN_ANY 0 +#define BTN_UP 1 +#define BTN_DOWN 2 +#define BTN_LEFT 3 +#define BTN_RIGHT 4 +#define BTN_A 5 +#define BTN_B 6 +#define BTN_MENU 7 + +bool anykey = false; +unsigned char data_in; + +void input_data_in(const unsigned char& value) { + data_in = value; +} + +unsigned char input_data_out() { + const Uint8* keys = SDL_GetKeyboardState(nullptr); + switch (data_in) { + case BTN_ANY: return anykey; break; + case BTN_UP: return keys[SDL_SCANCODE_UP]; break; + case BTN_DOWN: return keys[SDL_SCANCODE_DOWN]; break; + case BTN_LEFT: return keys[SDL_SCANCODE_LEFT]; break; + case BTN_RIGHT: return keys[SDL_SCANCODE_RIGHT]; break; + case BTN_A: return keys[SDL_SCANCODE_RCTRL]; break; + case BTN_B: return keys[SDL_SCANCODE_RSHIFT]; break; + case BTN_MENU: return keys[SDL_SCANCODE_RETURN]; break; + }; +} int main(int argc, char** argv) { @@ -11,22 +40,26 @@ int main(int argc, char** argv) { vdp_init(); vm_register_out_port(10, vdp_data_out); vm_register_out_port(11, vdp_cmd_out); + vm_register_out_port(20, input_data_in); + vm_register_in_port(21, input_data_out); static bool should_quit = false; static SDL_Event sdlEvent; SDL_Scancode just_pressed; + //Uint32 ticks = SDL_GetTicks(); while (!should_quit) { just_pressed = SDL_SCANCODE_UNKNOWN; while (SDL_PollEvent(&sdlEvent)) { if (sdlEvent.type == SDL_QUIT) { should_quit = true; break; } else if (sdlEvent.type == SDL_KEYDOWN) { - //anyKey = true; + anykey = true; just_pressed = sdlEvent.key.keysym.scancode; if (sdlEvent.key.keysym.scancode == SDL_SCANCODE_ESCAPE) { should_quit = true; } } } vm_step(); + //if (SDL_GetTicks() - ticks >= 15) { vdp_flip(); ticks = SDL_GetTicks(); } } vdp_quit(); diff --git a/parser.cpp b/parser.cpp index bc3b5a6..f3924f6 100644 --- a/parser.cpp +++ b/parser.cpp @@ -9,6 +9,7 @@ #define MAX_LABELS 256 #define MAX_EXTERNAL_FUNCTIONS 256 #define MAX_IDENTIFIER_LENGTH 40 +#define MAX_CONSTANTS 256 struct t_label { char name[MAX_IDENTIFIER_LENGTH]; @@ -33,6 +34,11 @@ struct t_string { int num_references = 1; }; +struct t_constant { + char name[MAX_IDENTIFIER_LENGTH]; + byte value; +}; + static byte* code; // [MAX_CODE_SIZE]; static word codepos = 0; @@ -57,6 +63,9 @@ static int num_strings = 0; static bool parser_finished = false; +static t_constant constants[MAX_CONSTANTS]; +static int num_constants; + /****************************************************************************************/ /* GENERIC FUNCTIONS */ /****************************************************************************************/ @@ -119,11 +128,27 @@ static int get_variable_index(const char* string, const int array_size = 1) { else { variables = newvar; } - return newvar->index; + return newvar->index + 0xC000; } static bool is_variable_array() { return variable_is_array; } +/****************************************************************************************/ +/* CONSTANT MANAGEMENT */ +/****************************************************************************************/ +void parser_register_constant(const char* name, const unsigned char value) { + strcpy(constants[num_constants].name, name); + constants[num_constants++].value = value; +} + +static const int get_constant(const char* name) { + for (int i = 0; i < num_constants; i++) { + if (strcmp(constants[i].name, name) == 0) + return constants[i].value; + } + return -1; +} + /****************************************************************************************/ /* LABEL MANAGEMENT */ /****************************************************************************************/ @@ -167,7 +192,7 @@ static void register_label_address(const char* string) { i++; } } - num_known_labels++; + //num_known_labels++; } static void generate_anonymous_labelname(char* dest) { @@ -206,6 +231,14 @@ static void append_strings() { static void parse_expression(); static void parse_statements(); +static void parse_strleft(); +static void parse_str(); +static void parse_chr(); + +static void parse_strlen(); +static void parse_keypressed(); +static void parse_anykey(); + #define EXPECT(X, Y) if (tkn_get_token() != X) { parser_finished = true; error_raise(Y); return; } static void parse_concat_atom() { @@ -227,6 +260,9 @@ static void parse_concat_atom() { tkn_next(); return; } + if (tkn_get_token() == TOKEN_STRLEFT) { tkn_next(); parse_strleft(); return; } + if (tkn_get_token() == TOKEN_STR) { tkn_next(); parse_str(); return; } + if (tkn_get_token() == TOKEN_CHR) { tkn_next(); parse_chr(); return; } parser_finished = true; error_raise("Syntax error"); return; } @@ -248,6 +284,13 @@ static void parse_expr_atom() { return; } if (tkn_get_token() == TOKEN_IDENTIFIER) { + int constvalue = get_constant(tkn_get_string()); + if (constvalue != -1) { + emmit(OP_PUSH); + emmit(constvalue); + tkn_next(); + return; + } int ivar = get_variable_index(tkn_get_string()); if (is_variable_array()) { tkn_next(); EXPECT(TOKEN_LPAR, "Expected array index"); @@ -282,6 +325,10 @@ static void parse_expr_atom() { tkn_next(); return; } + if (tkn_get_token() == TOKEN_STRLEN) { tkn_next(); parse_strlen(); return; } + if (tkn_get_token() == TOKEN_KEYPRESSED) { tkn_next(); parse_keypressed(); return; } + if (tkn_get_token() == TOKEN_ANYKEY) { tkn_next(); parse_anykey(); return; } + parser_finished = true; error_raise("Syntax error"); return; } @@ -339,6 +386,17 @@ static void parse_expression() { } } +static void parse_const() { + EXPECT(TOKEN_IDENTIFIER, "Expected identifier"); + char constname[40]; + strcpy(constname, tkn_get_string()); + tkn_next(); EXPECT(TOKEN_EQ, "Expected '='"); + tkn_next(); EXPECT(TOKEN_NUMBER, "Expected integer constant"); + int constvalue = tkn_get_value(); + parser_register_constant(constname, constvalue); + tkn_next(); +} + static void parse_dim() { EXPECT(TOKEN_IDENTIFIER, "Expected variable"); char varname[40]; @@ -674,9 +732,22 @@ static void parse_border() { emmit_w(get_label_address("_sys_vdp_border")); } +static void parse_clrscr() { + emmit(OP_JSR); + emmit_w(get_label_address("_sys_vdp_clrscr")); +} + +static void parse_wait() { + parse_expression(); + emmit(OP_SLEEP); +} + + static void parse_statements() { while (!parser_finished) { switch (tkn_get_token()) { + case TOKEN_CONST: + tkn_next(); parse_const(); break; case TOKEN_DIM: tkn_next(); parse_dim(); break; case TOKEN_LET: @@ -704,16 +775,16 @@ static void parse_statements() { case TOKEN_REM: tkn_next(); break; - case TOKEN_STRLEFT: - tkn_next(); parse_strleft(); break; - case TOKEN_STRLEN: - tkn_next(); parse_strlen(); break; + //case TOKEN_STRLEFT: <--- Parsed in parse_concat_atom + // tkn_next(); parse_strleft(); break; + //case TOKEN_STRLEN: <--- Parsed in parse_expr_atom + // tkn_next(); parse_strlen(); break; case TOKEN_DEBUG: tkn_next(); parse_debug(); break; - case TOKEN_CHR: - tkn_next(); parse_chr(); break; - case TOKEN_STR: - tkn_next(); parse_str(); break; + //case TOKEN_CHR: + // tkn_next(); parse_chr(); break; <--- Parsed in parse_concat_atom + //case TOKEN_STR: + // tkn_next(); parse_str(); break; <--- Parsed in parse_concat_atom case TOKEN_SETSPRITE: tkn_next(); parse_setsprite(); break; case TOKEN_PUTSPRITE: @@ -726,16 +797,20 @@ static void parse_statements() { tkn_next(); parse_putchar(); break; case TOKEN_SETCHAR: tkn_next(); parse_setchar(); break; - case TOKEN_KEYPRESSED: - tkn_next(); parse_keypressed(); break; - case TOKEN_ANYKEY: - tkn_next(); parse_anykey(); break; + //case TOKEN_KEYPRESSED: <--- Parsed in parse_expr_atom + // tkn_next(); parse_keypressed(); break; + //case TOKEN_ANYKEY: <--- Parsed in parse_expr_atom + // tkn_next(); parse_anykey(); break; case TOKEN_UPDATESCR: tkn_next(); parse_updatescr(); break; case TOKEN_COLOR: tkn_next(); parse_color(); break; case TOKEN_BORDER: tkn_next(); parse_border(); break; + case TOKEN_CLRSCR: + tkn_next(); parse_clrscr(); break; + case TOKEN_WAIT: + tkn_next(); parse_wait(); break; case TOKEN_IDENTIFIER: for (int i = 0; i < num_external_functions; i++) { @@ -781,6 +856,10 @@ void parser_parse(const char* buffer, byte* mem) { parse_statements(); append_strings(); + FILE *f = fopen("test.bin", "wb"); + fwrite(mem, codepos, 1, f); + fclose(f); + //return code; } diff --git a/parser.h b/parser.h index f43086b..c3b64bf 100644 --- a/parser.h +++ b/parser.h @@ -78,3 +78,4 @@ void parser_parse(const char* buffer, unsigned char* mem); const int parser_get_codesize(); const int parser_get_memory_usage(); void parser_register_external_function(const char* name, const int num_parameters); +void parser_register_constant(const char* name, const unsigned char value); \ No newline at end of file diff --git a/rom.lbl b/rom.lbl index 37a390c..5dbc3f5 100644 Binary files a/rom.lbl and b/rom.lbl differ diff --git a/test.bas b/test.bas index 422b424..6186cb2 100644 --- a/test.bas +++ b/test.bas @@ -1,21 +1,24 @@ -locate 2 1 -print "HOLA JAILERS" -border 5 -spr = 250 -setsprite 0 spr 0 -x = 0 -dx = 1 -count = 5 + border INK_BLACK + color INK_WHITE + PAPER_BLACK + clrscr + locate 4 2 print chr &h87, chr &h85, chr &h87, chr &h85, chr &h87, chr &h85, chr &h87, chr &h81 + locate 4 3 print chr &h85, chr &h85, chr &h85, chr &h85, chr &h85, chr &h85, chr &h85, chr &h84 + locate 4 4 print chr &h87, chr &h81, chr &h8D, chr &h85, chr &h85, chr &h85, chr &h8D, chr &h85 + locate 3 8 print "PRESS SPACE" + updatescr + x = 0 + dx = 1 + setsprite 0 &HF9 INK_RED peiv: -putsprite 0 x 60 -updatescr -x = x + dx -if x = 128 then dx = -1 end -if x = 8 then dx = 1 end -dec count -if count = 0 then - count = 5 - if spr = 250 then spr = 251 else spr = 250 end - setsprite 0 spr 1 -end -goto peiv \ No newline at end of file + putsprite 0 x 40 + putsprite 0 x 40 + putsprite 0 x 40 + updatescr + if anykey then goto continuar end + goto peiv +continuar: + clrscr + locate 0 0 print "Ok" + updatescr +ttt: + goto ttt \ No newline at end of file diff --git a/tokenizer.cpp b/tokenizer.cpp index ba40913..8c641ad 100644 --- a/tokenizer.cpp +++ b/tokenizer.cpp @@ -1,4 +1,5 @@ #include "tokenizer.h" +#include "error.h" static bool streq(const char* a, const char* b) { while (*a != 0 && *b != 0) { @@ -42,6 +43,7 @@ t_token_op tkn_tokens[] = { { "not", TOKEN_NOT }, { "mod", TOKEN_MOD }, { "dim", TOKEN_DIM }, + { "const", TOKEN_CONST }, { "inc", TOKEN_INC }, { "dec", TOKEN_DEC }, { "strleft", TOKEN_STRLEFT }, @@ -60,8 +62,12 @@ t_token_op tkn_tokens[] = { { "updatescr", TOKEN_UPDATESCR }, { "color", TOKEN_COLOR }, { "border", TOKEN_BORDER }, + { "clrscr", TOKEN_CLRSCR }, + { "wait", TOKEN_WAIT }, }; +static char hex_digit(const char digit) { return digit - (digit < 57 ? 48 : 55); } + #define CCHR *ptr #define NEXT if(*ptr==10){line++;row=0;}else{row++;};ptr++ @@ -80,7 +86,7 @@ static void tkn_do_next() { if (CCHR == 34) { NEXT; while (CCHR != 0 && CCHR != 34) { *id = CCHR; id++; NEXT; } - if (CCHR == 0) { current_token = TOKEN_ERROR; return; } + if (CCHR == 0) { current_token = TOKEN_ERROR; error_raise("Unexpected end of file."); return; } *id = 0; NEXT; current_token = TOKEN_STRING; return; } @@ -122,6 +128,27 @@ static void tkn_do_next() { if (CCHR == '%') { NEXT; current_token = TOKEN_MOD; return; } if (CCHR == 39) { NEXT; current_token = TOKEN_REM; while (CCHR != 0 && CCHR != 10) { NEXT; }; return; } + if (CCHR == '&') { + NEXT; + if ((CCHR | 32) == 'h') { + NEXT; + if ((CCHR >= 48 && CCHR <= 57) || (CCHR >= 65 && CCHR <= 70)) { + do { value = (value << 4) + hex_digit(CCHR); NEXT; } while ((CCHR >= 48 && CCHR <= 57) || (CCHR >= 65 && CCHR <= 70)); + current_token = TOKEN_NUMBER; return; + } + } + if ((CCHR | 32) == 'b') { + NEXT; + if (CCHR == 48 || CCHR == 49) { + do { value = (value << 1) + (CCHR-48); NEXT; } while (CCHR == 48 || CCHR == 49); + current_token = TOKEN_NUMBER; return; + } + } + current_token = TOKEN_ERROR; + error_raise("Syntax error"); + return; + } + // if no match, it's an error current_token = TOKEN_ERROR; return; } diff --git a/tokenizer.h b/tokenizer.h index 54f6bc2..9904db8 100644 --- a/tokenizer.h +++ b/tokenizer.h @@ -11,6 +11,7 @@ enum t_tokentype { TOKEN_IDENTIFIER, TOKEN_LABEL, TOKEN_DIM, + TOKEN_CONST, TOKEN_LET, TOKEN_IF, @@ -66,6 +67,8 @@ enum t_tokentype { TOKEN_UPDATESCR, TOKEN_COLOR, TOKEN_BORDER, + TOKEN_CLRSCR, + TOKEN_WAIT, }; void tkn_init(const char* buffer); diff --git a/vbvm.vcxproj b/vbvm.vcxproj index e3faf46..70777dc 100644 --- a/vbvm.vcxproj +++ b/vbvm.vcxproj @@ -88,6 +88,7 @@ + diff --git a/vbvm.vcxproj.filters b/vbvm.vcxproj.filters index c28762b..1c443c9 100644 --- a/vbvm.vcxproj.filters +++ b/vbvm.vcxproj.filters @@ -62,5 +62,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/vdp.cpp b/vdp.cpp index 42f6c81..39beb3d 100644 --- a/vdp.cpp +++ b/vdp.cpp @@ -13,6 +13,7 @@ #define VDP_CMD_FLIP 6 #define VDP_CMD_COLOR 7 #define VDP_CMD_BORDER 8 +#define VDP_CMD_CLRSCR 9 struct t_sprite { Uint8 x = 0; @@ -96,7 +97,7 @@ void vdp_quit() { SDL_Quit(); } -static void flip() { +void vdp_flip() { Uint8* sb = screen_buffer; Uint8* sm = screen_map; Uint8* sc = screen_color; @@ -191,7 +192,7 @@ void vdp_cmd_out(const unsigned char& value) { sprites[n].col = data_stack[data_stack_pos - 3] & 0xF; break; case VDP_CMD_FLIP: - flip(); break; + vdp_flip(); break; case VDP_CMD_COLOR: color = data_stack[0]; break; @@ -199,6 +200,10 @@ void vdp_cmd_out(const unsigned char& value) { border = data_stack[0] & 0xF; SDL_SetRenderDrawColor(sdlRenderer, palette[border][0], palette[border][1], palette[border][2], palette[border][3]); break; + case VDP_CMD_CLRSCR: + for (int i = 0; i < 16 * 12; i++) screen_map[i] = 32; + for (int i = 0; i < 16 * 12; i++) screen_color[i] = color; + break; } data_stack_pos = 0; } diff --git a/vdp.h b/vdp.h index 2d5ac40..1344a00 100644 --- a/vdp.h +++ b/vdp.h @@ -2,7 +2,7 @@ void vdp_init(); void vdp_quit(); - +void vdp_flip(); void vdp_data_out(const unsigned char& value); void vdp_cmd_out(const unsigned char& value); unsigned char vdp_in(); diff --git a/vm.cpp b/vm.cpp index 726b9ec..5e2f633 100644 --- a/vm.cpp +++ b/vm.cpp @@ -3,6 +3,8 @@ #include #include "parser.h" #include "error.h" +#include "constants.h" +#include // For SDL_Delay #define MAX_EXTERNAL_CALLS 256 #define MAX_DATA_STACK 256 @@ -116,30 +118,22 @@ static void load_rom() { } static void load_program(const char* filename) { -/* FILE *f = fopen(filename, "rb"); - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - fread(mem, fsize, 1, f); - fclose(f);*/ FILE *f = fopen(filename, "rb"); fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); //same as rewind(f); - char *program = (char*)malloc(fsize + 1); fread(program, fsize, 1, f); fclose(f); - program[fsize] = 0; - //unsigned char* rawCode = + register_constants(); + parser_parse(program, mem); free(program); if (error_raised()) { error_print(); - //getchar(); } else { printf("Compilation complete!\nProgram size: %d bytes\nMemory usage: %d bytes\n", parser_get_codesize(), parser_get_memory_usage()); @@ -240,7 +234,7 @@ const int vm_step() { case OP_GEQ: stack_push(vm_datastack, stack_pop(vm_datastack) >= stack_pop(vm_datastack)); vm_cycles++; break; case OP_IN: stack_push(vm_datastack, in_ports[vm_program[vm_pc++]]()); vm_cycles++; break; case OP_OUT: out_ports[vm_program[vm_pc++]](stack_pop(vm_datastack)); vm_cycles++; break; - case OP_SLEEP: sleeping = true; vm_cycles++; break; + case OP_SLEEP: SDL_Delay(stack_pop(vm_datastack) * 1000); vm_cycles++; break; } return vm_cycles; }