old-computer-simulator

godot game
git clone git://git.evenfri.pw/old-computer-simulator.git
Log | Files | Refs

commit ef873235e84af879f075d75c54c1c89c2c39f00b
parent d8117dc8d37b7c00da929384ece4693be57d12a8
Author: evenfri <evenfri@4plt.ch>
Date:   Tue, 27 Oct 2026 21:22:39 +0800

PATCH

Diffstat:
DPxPlus_IBM_VGA8.ttf | 0
DPxPlus_IBM_VGA8.ttf.import | 36------------------------------------
Aemulator/dat.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Memulator/emu.h | 49++++++++++++++++++++++++-------------------------
Memulator/emu.so | 0
Memulator/main.c | 307+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mmain.tscn | 24++++++++++++++++++++++--
7 files changed, 308 insertions(+), 164 deletions(-)

diff --git a/PxPlus_IBM_VGA8.ttf b/PxPlus_IBM_VGA8.ttf Binary files differ. diff --git a/PxPlus_IBM_VGA8.ttf.import b/PxPlus_IBM_VGA8.ttf.import @@ -1,36 +0,0 @@ -[remap] - -importer="font_data_dynamic" -type="FontFile" -uid="uid://bq48lr0d5eg8h" -path="res://.godot/imported/PxPlus_IBM_VGA8.ttf-4eae0e9f40467468ccc4ab703e6e051f.fontdata" - -[deps] - -source_file="res://PxPlus_IBM_VGA8.ttf" -dest_files=["res://.godot/imported/PxPlus_IBM_VGA8.ttf-4eae0e9f40467468ccc4ab703e6e051f.fontdata"] - -[params] - -Rendering=null -antialiasing=1 -generate_mipmaps=false -disable_embedded_bitmaps=true -multichannel_signed_distance_field=false -msdf_pixel_range=8 -msdf_size=48 -allow_system_fallback=true -force_autohinter=false -modulate_color_glyphs=false -hinting=3 -subpixel_positioning=4 -keep_rounding_remainders=true -oversampling=0.0 -Fallbacks=null -fallbacks=[] -Compress=null -compress=true -preload=[] -language_support={} -script_support={} -opentype_features={} diff --git a/emulator/dat.h b/emulator/dat.h @@ -0,0 +1,56 @@ +#ifndef DAT_H +#define DAT_H + +#define MEMORY_SIZE 65536 + +#define REG_A 0b111 +#define REG_B 0b000 +#define REG_C 0b001 +#define REG_D 0b010 +#define REG_E 0b011 +#define REG_H 0b100 +#define REG_L 0b101 +#define REG_M 0b110 + +#define OP_ZZ 0b00 +#define OP_MV 0b01 +#define OP_ALU 0b10 +#define OP_OO 0b11 + +#define OP_ALU_ADD 0b000 +#define OP_ALU_ADC 0b001 +#define OP_ALU_SUB 0b010 +#define OP_ALU_SBB 0b011 +#define OP_ALU_ANA 0b100 +#define OP_ALU_XRA 0b101 +#define OP_ALU_ORA 0b110 +#define OP_ALU_CMP 0b111 + +#define OP_INC 0b100 +#define OP_DEC 0b101 + +#define OP_JMP 0b011 +#define OP_J 0b010 +#define OP_JNZ 0b000 +#define OP_JZ 0b001 + +#define F_CY 0 /* carry */ +#define F_P 1 /* parity */ +#define F_AC 2 /* auxiliary carry */ +#define F_Z 3 /* zero */ +#define F_S 4 /* sign */ + +typedef struct { + uint8_t mem[MEMORY_SIZE]; + uint8_t a; + uint8_t b; + uint8_t c; + uint8_t d; + uint8_t e; + uint8_t h; + uint8_t l; + uint16_t pc; + uint8_t f; +} emu_t; + +#endif /* DAT_H */ diff --git a/emulator/emu.h b/emulator/emu.h @@ -6,19 +6,7 @@ #include <stdio.h> #include <string.h> -#define reg_a 0b111 -#define reg_b 0b000 -#define reg_c 0b001 -#define reg_d 0b010 -#define reg_e 0b011 -#define reg_h 0b100 -#define reg_l 0b101 -#define reg_m 0b110 - -#define op_n 0b00 -#define op_mv 0b01 -#define op_sum_a 0b10 -#define op_jmp 0b11 +#include "dat.h" #if defined(__GNUC__) || defined(__clang__) #define EXPORT __attribute__((visibility("default"))) @@ -26,25 +14,37 @@ #define EXPORT #endif -typedef struct emulator emulator; typedef unsigned char byte; +#define FLAG_SET(e, bit) ((e)->f |= (1u << (bit))) +#define FLAG_CLR(e, bit) ((e)->f &= ~(1u << (bit))) +#define FLAG_GET(e, bit) (((e)->f >> (bit)) & 1u) +#define FLAG_PUT(e, bit, v) \ + ((e)->f = (v) ? ((e)->f | (1u << (bit))) \ + : ((e)->f & ~(1u << (bit)))) + +static inline int parity_even(uint8_t x) { + int ones = 0; + for (int i = 0; i < 8; i++) ones += (x >> i) & 1; + return (ones & 1) == 0; +} + #ifdef __cplusplus extern "C" { #endif -EXPORT emulator* emu_create(void); -EXPORT int emu_load_program(emulator *e, const char *filename); -EXPORT void emu_destroy(emulator *e); -EXPORT int emu_step(emulator *e); -EXPORT void emu_mem_write(emulator *e, uint16_t addr, byte val); -EXPORT byte emu_mem_read(emulator *e, uint16_t addr); -EXPORT int emu_get_pc(emulator *e); -EXPORT void emu_set_pc(emulator *e, int pc); -EXPORT byte emu_get_reg(emulator *e, byte c); +EXPORT emu_t* emu_create(void); +EXPORT int emu_load_program(emu_t *e, const char *filename); +EXPORT void emu_destroy(emu_t *e); +EXPORT int emu_step(emu_t *e); +EXPORT void emu_mem_write(emu_t *e, uint16_t addr, byte val); +EXPORT byte emu_mem_read(emu_t *e, uint16_t addr); +EXPORT int emu_get_pc(emu_t *e); +EXPORT void emu_set_pc(emu_t *e, int pc); +EXPORT byte emu_get_reg(emu_t *e, byte c); #ifdef __cplusplus } #endif -#endif /* emu_h */ -\ No newline at end of file +#endif /* emu_h */ diff --git a/emulator/emu.so b/emulator/emu.so Binary files differ. diff --git a/emulator/main.c b/emulator/main.c @@ -1,135 +1,240 @@ #include "emu.h" -struct emulator { - byte memory[65536]; - byte a; - byte b; - byte c; - byte d; - byte e; - byte h; - byte l; - int pc; -}; - -static void set_reg(emulator *e, byte c, byte val) { - switch (c) { - case reg_a: e->a = val; break; - case reg_b: e->b = val; break; - case reg_c: e->c = val; break; - case reg_d: e->d = val; break; - case reg_e: e->e = val; break; - case reg_h: e->h = val; break; - case reg_l: e->l = val; break; - case reg_m: - { - uint16_t hl = ((uint16_t)e->h << 8) | e->l; - e->memory[hl] = val; - break; - } - } +static void set_zsp(emu_t *e, uint8_t res) { + FLAG_PUT(e, F_Z, res == 0); + FLAG_PUT(e, F_S, (res & 0x80) != 0); + FLAG_PUT(e, F_P, parity_even(res)); } -emulator* emu_create(void) { - emulator* e = malloc(sizeof(emulator)); - memset(e, 0, sizeof(emulator)); - return e; -} - -int emu_load_program(emulator *e, const char *filename) { - FILE *f = fopen(filename, "rb"); - if (!f) return 1; - - size_t bytes_read = fread(e->memory, 1, sizeof(e->memory), f); - - fclose(f); - if (bytes_read == 0) { - return 1; +uint8_t emu_set(emu_t *e, uint8_t r, uint8_t v) { + switch (r) { + case REG_A: e->a = v; break; + case REG_B: e->b = v; break; + case REG_C: e->c = v; break; + case REG_D: e->d = v; break; + case REG_E: e->e = v; break; + case REG_H: e->h = v; break; + case REG_L: e->l = v; break; + case REG_M: + { + uint16_t hl = ((uint16_t)e->h << 8) | e->l; + e->mem[hl] = v; + break; + } + default: return 0; } - e->pc = 0; return 0; } -void emu_destroy(emulator *e) { free(e); } - -int emu_get_pc(emulator *e) { - return e->pc; -} - -void emu_set_pc(emulator *e, int pc) { - e->pc = pc; +uint8_t emu_get(emu_t *e, uint8_t r) { + switch (r) { + case REG_A: return e->a; + case REG_B: return e->b; + case REG_C: return e->c; + case REG_D: return e->d; + case REG_E: return e->e; + case REG_H: return e->h; + case REG_L: return e->l; + case REG_M: + { + uint16_t hl = ((uint16_t)e->h << 8) | e->l; + return e->mem[hl]; + } + default: return 0; + } } -int emu_step(emulator *e) { - byte instr = e->memory[e->pc]; +int emu_execute(emu_t *e, uint8_t i) { /* parse instr */ - byte part1 = (instr >> 6) & 0x03; /* 0b[00]000000 */ - byte dst = (instr >> 3) & 0x07; /* 0b00[000]000 */ - byte src = instr & 0x07; /* 0b00000[000] */ + uint8_t part1 = (i >> 6) & 0x03; /* [00]000000 */ + uint8_t dst = (i >> 3) & 0x07; /* 00[000]000 */ + uint8_t src = i & 0x07; /* 00000[000] */ switch (part1) { - case op_mv: - /* instr = 0b01110110 hlt */ - if (dst == reg_m && src == reg_m) { + case OP_MV: + /* 01110110: hlt */ + if (dst == REG_M && src == REG_M) { return 1; } - set_reg(e, dst, emu_get_reg(e, src)); + emu_set(e, dst, emu_get(e, src)); e->pc++; break; - case op_n: - if (src == 0b110) { - set_reg(e, dst, e->memory[e->pc+1]); - e->pc += 2; - } else if (src == reg_d) { - uint16_t addr = (uint16_t)e->memory[e->pc + 1] | - ((uint16_t)e->memory[e->pc + 2] << 8); - - if (dst == reg_a) { - e->a = e->memory[addr]; - } else if (dst == reg_m) { - e->memory[addr] = e->a; + + case OP_ZZ: + { + if (src == 0b110) { + /* MVI r, data */ + emu_set(e, dst, e->mem[e->pc + 1]); + e->pc += 2; + } else if (src == REG_D) { + uint16_t addr = (uint16_t)e->mem[e->pc + 1] | + ((uint16_t)e->mem[e->pc + 2] << 8); + if (dst == REG_A) { + e->a = e->mem[addr]; + } else if (dst == REG_M) { + e->mem[addr] = e->a; + } + e->pc += 3; + } else if (src == OP_INC) { + uint8_t val = emu_get(e, dst) + 1; + emu_set(e, dst, val); + set_zsp(e, val); + e->pc++; + } else if (src == OP_DEC) { + uint8_t val = emu_get(e, dst) - 1; + emu_set(e, dst, val); + set_zsp(e, val); + e->pc++; + } else { + e->pc++; } - e->pc += 3; - } else { - e->pc++; + break; + } + + case OP_ALU: + switch (dst) { + case OP_ALU_ADD: + emu_set(e, REG_A, emu_get(e, REG_A) + emu_get(e, src)); + set_zsp(e, emu_get(e, REG_A)); + break; + + case OP_ALU_SUB: + emu_set(e, REG_A, emu_get(e, REG_A) - emu_get(e, src)); + set_zsp(e, emu_get(e, REG_A)); + break; + + case OP_ALU_CMP: + { + uint8_t a = emu_get(e, REG_A); + uint8_t b = emu_get(e, src); + unsigned r = a - b; + uint8_t res = (uint8_t)r; + + FLAG_PUT(e, F_CY, a < b); + FLAG_PUT(e, F_AC, ((a ^ b ^ res) & 0x10) != 0); + + set_zsp(e, res); + break; + } } - break; - case op_sum_a: - e->pc++; - break; - case op_jmp: e->pc++; break; + + case OP_OO: + { + switch (src) { + case REG_M: + { + uint8_t imm = e->mem[e->pc + 1]; + if (dst == OP_ALU_ADD) { + emu_set(e, REG_A, emu_get(e, REG_A) + imm); + set_zsp(e, emu_get(e, REG_A)); + } else if (dst == OP_ALU_SUB) { + emu_set(e, REG_A, emu_get(e, REG_A) - imm); + set_zsp(e, emu_get(e, REG_A)); + } + e->pc += 2; + } + break; + + case OP_JMP: + { + uint16_t addr = (uint16_t)e->mem[e->pc + 1] | + ((uint16_t)e->mem[e->pc + 2] << 8); + e->pc = addr; + } + break; + + case OP_J: + { + bool jump = false; + if (dst == OP_JNZ) jump = (FLAG_GET(e, F_Z) == 0); + else if (dst == OP_JZ) jump = (FLAG_GET(e, F_Z) != 0); + + if (jump) { + uint16_t addr = (uint16_t)e->mem[e->pc + 1] | + ((uint16_t)e->mem[e->pc + 2] << 8); + e->pc = addr; + } else { + e->pc += 3; + } + } + break; + + default: + e->pc++; + break; + } + break; + } + default: return 1; } - return 0; } -void emu_mem_write(emulator *e, uint16_t addr, byte val) { - e->memory[addr] = val; +void emu_start(emu_t *e) { + int running = 1; + e->pc = 0; + + while (running) { + uint8_t instr = e->mem[e->pc]; + int res = emu_execute(e, instr); + if (res != 0) break; + } } -byte emu_mem_read(emulator *e, uint16_t addr) { - return e->memory[addr]; +EXPORT emu_t* emu_create(void) { + emu_t *e = (emu_t*)calloc(1, sizeof(emu_t)); + return e; } -byte emu_get_reg(emulator *e, byte c) { - switch (c) { - case reg_a: return e->a; - case reg_b: return e->b; - case reg_c: return e->c; - case reg_d: return e->d; - case reg_e: return e->e; - case reg_h: return e->h; - case reg_l: return e->l; - case reg_m: - { - uint16_t hl = ((uint16_t)e->h << 8) | e->l; - return e->memory[hl]; - } - default: return 0; +EXPORT void emu_destroy(emu_t *e) { + if (e) { + free(e); + } +} + +EXPORT int emu_load_program(emu_t *e, const char *filename) { + if (!e || !filename) return -1; + + FILE *f = fopen(filename, "rb"); + if (!f) return -1; + + size_t n = fread(e->mem, 1, MEMORY_SIZE, f); + fclose(f); + + return (n > 0) ? 0 : -1; +} + +EXPORT int emu_step(emu_t *e) { + if (!e) return 1; + uint8_t instr = e->mem[e->pc]; + return emu_execute(e, instr); +} + +EXPORT int emu_get_pc(emu_t *e) { + return e ? (int)e->pc : 0; +} + +EXPORT void emu_set_pc(emu_t *e, int pc) { + if (e) { + e->pc = (uint16_t)pc; } } + +EXPORT void emu_mem_write(emu_t *e, uint16_t addr, byte val) { + if (e) { + e->mem[addr] = val; + } +} + +EXPORT byte emu_mem_read(emu_t *e, uint16_t addr) { + return e ? e->mem[addr] : 0; +} + +EXPORT byte emu_get_reg(emu_t *e, byte c) { + return e ? emu_get(e, c) : 0; +} diff --git a/main.tscn b/main.tscn @@ -5,7 +5,6 @@ [ext_resource type="Texture2D" uid="uid://bb5mof51kodyv" path="res://lamp.png" id="3_h2yge"] [ext_resource type="Texture2D" uid="uid://blxdcjt4qu82c" path="res://paper.png" id="4_1bvp3"] [ext_resource type="Script" uid="uid://b6lty8spdabbf" path="res://paper_list.cs" id="4_lquwl"] -[ext_resource type="FontFile" uid="uid://bq48lr0d5eg8h" path="res://PxPlus_IBM_VGA8.ttf" id="6_7mycd"] [sub_resource type="LabelSettings" id="LabelSettings_7mycd"] font_size = 8 @@ -37,9 +36,30 @@ font_size = 8 line_spacing = 0.0 font_size = 8 +[sub_resource type="FontFile" id="FontFile_qbpvq"] +cache/0/variation_coordinates = {} +cache/0/face_index = 0 +cache/0/embolden = 0.0 +cache/0/transform = Transform2D(1, 0, 0, 1, 0, 0) +cache/0/spacing_top = 0 +cache/0/spacing_bottom = 0 +cache/0/spacing_space = 0 +cache/0/spacing_glyph = 0 +cache/0/baseline_offset = 0.0 +cache/0/16/0/ascent = 0.0 +cache/0/16/0/descent = 0.0 +cache/0/16/0/underline_position = 0.0 +cache/0/16/0/underline_thickness = 0.0 +cache/0/16/0/scale = 1.0 +cache/0/8/0/ascent = 0.0 +cache/0/8/0/descent = 0.0 +cache/0/8/0/underline_position = 0.0 +cache/0/8/0/underline_thickness = 0.0 +cache/0/8/0/scale = 1.0 + [sub_resource type="LabelSettings" id="LabelSettings_a5vro"] line_spacing = 0.0 -font = ExtResource("6_7mycd") +font = SubResource("FontFile_qbpvq") font_size = 8 font_color = Color(0, 0, 0, 1)