commit ef873235e84af879f075d75c54c1c89c2c39f00b
parent d8117dc8d37b7c00da929384ece4693be57d12a8
Author: evenfri <evenfri@4plt.ch>
Date: Tue, 27 Oct 2026 21:22:39 +0800
PATCH
Diffstat:
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)