aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-05-01 21:44:35 +0100
committerJuan J. Martinez <jjm@usebox.net>2023-05-01 21:44:35 +0100
commitef84fb6fcb45a86fce97acda58606a76a937a1da (patch)
treea3e049b858724837cc9ce0106e30c9e1c028ddc6
parentc081dfe226c6e92865cbb97d8e9a2ef86d8c6acb (diff)
downloadtr8vm-ef84fb6fcb45a86fce97acda58606a76a937a1da.tar.gz
tr8vm-ef84fb6fcb45a86fce97acda58606a76a937a1da.zip
Added the VM player using SDL
- Wired basic functionality (fram-buffer, frame interrupt) - Bug fixes in the assembler
-rw-r--r--COPYING2
-rw-r--r--Makefile20
-rw-r--r--README.md51
-rw-r--r--example.asm137
-rw-r--r--tr8as.c6
-rw-r--r--tr8vm.c255
-rw-r--r--vm.c94
-rw-r--r--vm.h10
8 files changed, 422 insertions, 153 deletions
diff --git a/COPYING b/COPYING
index 1273d4b..2c45ca7 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-TR8 Assembler and VM
+TR8 Assembler, VM and Player
Copyright (C) 2023 by Juan J. Martinez <jjm@usebox.net>
Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/Makefile b/Makefile
index 746491b..de20dff 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,22 @@
-CC := gcc
-CFLAGS := -std=c89 -Wpedantic -s -O2 -Wall -I.
-LDFLAGS :=
+# common
+CC := gcc
+CFLAGS := -Wpedantic -s -O2 -Wall -I.
+LDFLAGS :=
+
+# only for the vm
+SDL2_CONFIG := sdl2-config
+LIBS := `$(SDL2_CONFIG) --libs` -lSDL2_mixer
all: tr8as tr8vm
-tr8vm: vm.c vm.h
- $(CC) $(CFLAGS) -DDO_MAIN $< -o $@
+tr8vm: tr8vm.c vm.o vm.h
+ $(CC) -std=c99 $(CFLAGS) `$(SDL2_CONFIG) --cflags` $< vm.o `$(SDL2_CONFIG) --libs` $(LIBS) -o $@
tr8as: tr8as.c
- $(CC) $(CFLAGS) -DDO_MAIN $< -o $@
+ $(CC) -std=c89 $(CFLAGS) -DDO_MAIN $< -o $@
+
+vm.o: vm.c vm.h
+ $(CC) -c -std=c89 $(CFLAGS) $< -o $@
example: example.tr8 tr8vm
./tr8vm example.tr8
diff --git a/README.md b/README.md
index 33e39b6..d847d49 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ TR8 is an 8-bit fantasy console inspired by MIPS, Z80 and 6502 real world CPUs.
## Specs
```
-Display: 128 x 128 pixels 16 colors (from palette of 32)
+Display: 128 x 128 pixels 16 colors
Memory: 64K
CPU: TR-8, 8M VM instr/sec
Sound: TBD
@@ -62,7 +62,6 @@ You can then compile and run the example with `make example`.
| Port | Type | Result |
| --- | --- | --- |
-| 0xe0 to 0xef | write | Color select |
| 0xf0 | read | Status of the controller 1 |
| 0xf1 | read | Status of the controller 2 |
@@ -87,10 +86,47 @@ controller 1, and `0xf1` for controller 2.
### Palette
-Ports from `0xe0` to `0xef` can be used to select the colors to use in the 16
-color palette from the 32 available.
+TODO: palette colors
-TODO: palette colours
+### Frame interrupt
+
+When interrupts are enabled (IF not set), 60 times per second there will be a
+frame interrupt:
+
+* the PC is saved on the stack
+* the F register (flags) is saved on the stack
+* all the flags are cleared and IF is set
+* the execution goes to the address in `0xff00` (the frame interrupt vector)
+* the interruption handler code must return with `IRET`, that will restore
+ the PC and the F register
+
+By default the vector points to `0x0000` so it has to be setup before enabling
+interrupts with `CIF`.
+
+Example:
+
+```asm
+ ; setup an int handler so we
+ ; can use the frame int o sync
+ ld a, 0xff
+ ld x, 0
+ ld b, <int_handler
+ ld [a : x], b
+ inc x
+ ld b, >int_handler
+ ld [a : x], b
+
+ ; enable interrupts
+ cif
+
+loop:
+ halt
+ jmp loop
+
+int_handler:
+ ; just return
+ iret
+```
### Instructions
@@ -363,7 +399,7 @@ Affected flags: IF
CIF
Clear IF, enabling the interrupt. If called in an interrupt handler, it won't
-have effect. Use IRET instead to return from the interrupt to unset IF.
+have effect. Use IRET instead to return from the interrupt.
Affected flags: IF
CCF
@@ -379,8 +415,7 @@ Clear overflow flag.
Affected flags: OF
IRET
-Return from an interrupt handler by setting PC to the top 16-bit value popped
-from the stack. It enables interrupts by clearing the interrupt flag.
+Return from an interrupt handler by restoring F and PC from the stack.
Affected flags: IF
### TR8 file format
diff --git a/example.asm b/example.asm
index 6d4521e..d96277b 100644
--- a/example.asm
+++ b/example.asm
@@ -3,54 +3,44 @@
;
.org 0
-; ; copy 16K from 0x0000 to 0xbf00
-; ;
-; start:
-; ld a, 0
-; ld b, 0xbf
-; ld x, 0
-; ld y, 0x40
-; loop:
-; push y
-; ld y, [a : x]
-; ld [b : x], y
-; pop y
-; inc x
-; bno
-; jmp loop
-; inc a
-; inc b
-; dec y
-; bnz
-; jmp loop
-;
- ld b, 15
+ ; setup an int handler so we
+ ; can use the frame int to sync
+ ld a, 0xff
+ ld x, 0
+ ld b, <int_handler
+ ld [a : x], b
+ inc x
+ ld b, >int_handler
+ ld [a : x], b
+
+ ; enable interrupts
+ cif
+
+ ; loop filling the screen with one
+ ; colour cycling the whole palette
+ ld b, 0
+loop:
call fill
+ inc b
+ and b, 15
+ ; wait some frames
+ halt
+ halt
+ halt
+ halt
+
+ halt
+ halt
+ halt
halt
-;
-; ; void copy(void *dst, void *src, uint16_t size)
-; ; size = 0x1000
-; ; src = 0
-; ; dst 0xbf00
-; ld a, 0x10
-; push a
-; ld a, 0
-; push a
-; push a
-; push a
-; ld a, 0xbf
-; push a
-; ld a, 0
-; push a
-; call copy
-; pop a
-; pop a
-; pop a
-; pop a
-; pop a
-; pop a
-; halt
+
+ halt
+ halt
+ halt
+ halt
+
+ jmp loop
; fill frame-buffer with a color in reg b
fill:
@@ -68,58 +58,5 @@ fill_loop:
jmp fill_loop
ret
- ; void copy(void *dst, void *src, uint16_t size)
- ;
- ; using C calling convention with the stack
- ; not used, but return value in a (8-bit), a: x (16-bit)
-; copy:
-; ld x, [sp + 6]
-; ld a, [sp + 7] ; size a:x
-;
-; ; local variable
-; push a
-; push x
-;
-; ld y, [sp + 4]
-; ld b, [sp + 5] ; dst b:y
-; ld x, [sp + 6]
-; ld a, [sp + 7] ; src a:x
-; copy_loop:
-; ; copy byte from a:x to b:y
-; push x
-; ld x, [a : x]
-; ld [b : y], x
-; pop x
-;
-; ; inc a:x
-; inc x
-; bo
-; inc a
-;
-; ; inc b:y
-; inc y
-; bo
-; inc b
-;
-; ; dec local var size
-; push a
-; push x
-; ld x, [sp + 2]
-; ld a, [sp + 3]
-; dec x
-; bo
-; dec a
-; ld [sp + 2], x
-; ld [sp + 3], a
-; or x, a
-; pop x
-; pop a
-;
-; bnz
-; jmp copy_loop
-;
-; pop x
-; pop x ; free local var
-; ret
-;
-;
+int_handler:
+ iret
diff --git a/tr8as.c b/tr8as.c
index fde3278..e450288 100644
--- a/tr8as.c
+++ b/tr8as.c
@@ -530,8 +530,8 @@ static uint8_t parse_r1_r2_or_imm(As *as, char *c, uint8_t *r1, uint8_t *r2, uin
if (*imm > 0xff)
return error_l("Overflow in immediate", &as->loc, word);
}
- /* AND r1, label */
- else if (!new_ref(as, word, 0xff, as->addr + 1))
+ /* ? r1, label */
+ else if (!new_ref(as, word, 0xff, as->addr))
return 0;
return 1;
@@ -1204,7 +1204,7 @@ static uint8_t parse_ld(As *as, char *c)
return error_l("Overflow in immediate", &as->loc, word);
}
/* LD r1, label */
- else if (!new_ref(as, word, 0xff, as->addr + 1))
+ else if (!new_ref(as, word, 0xff, as->addr))
return 0;
emit(as, 1, r1, 0, imm);
diff --git a/tr8vm.c b/tr8vm.c
new file mode 100644
index 0000000..941e207
--- /dev/null
+++ b/tr8vm.c
@@ -0,0 +1,255 @@
+/*
+ * TR8 VM Player
+ * Copyright (C) 2023 by Juan J. Martinez <jjm@usebox.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "SDL.h"
+
+#include "vm.h"
+
+#define ARGB(r, g, b) ((uint32_t)(((r)<<16)|((g)<<8)|(b)))
+
+#define APP_NAME "TR8 VM Player"
+#define APP_VERSION "0.1-alpha"
+
+#define TR8_W 128
+#define TR8_H 128
+
+#define WINDOW_SCALE 4
+#define WINDOW_W (TR8_W * WINDOW_SCALE)
+#define WINDOW_H (TR8_H * WINDOW_SCALE)
+
+static void resize_full_screen(SDL_Window *win, SDL_Renderer *renderer, int fullscreen, SDL_Rect *s)
+{
+ if (!fullscreen)
+ {
+ SDL_SetWindowFullscreen(win, 0);
+ s->x = 0;
+ s->y = 0;
+ s->w = WINDOW_W;
+ s->h = WINDOW_H;
+ }
+ else
+ {
+ SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);
+
+ int sw, sh, w, h, scale;
+
+ SDL_GetRendererOutputSize(renderer, &w, &h);
+
+ sw = w / TR8_W;
+ sh = h / TR8_H;
+ scale = sw > sh ? sh : sw;
+
+ s->x = (w - (TR8_W * scale)) / 2;
+ s->y = (h - (TR8_H * scale)) / 2;
+ s->w = TR8_W * scale;
+ s->h = TR8_H * scale;
+ }
+}
+
+static uint32_t palette[] =
+{
+ ARGB(0x00, 0x00, 0x00),
+ ARGB(0x00, 0x00, 0xaa),
+ ARGB(0x00, 0xaa, 0x00),
+ ARGB(0x00, 0xaa, 0xaa),
+ ARGB(0xaa, 0x00, 0x00),
+ ARGB(0xaa, 0x00, 0xaa),
+ ARGB(0xaa, 0x55, 0x00),
+ ARGB(0xaa, 0xaa, 0xaa),
+ ARGB(0x55, 0x55, 0x55),
+ ARGB(0x55, 0x55, 0xff),
+ ARGB(0x55, 0xff, 0x55),
+ ARGB(0x55, 0xff, 0xff),
+ ARGB(0xff, 0x55, 0x55),
+ ARGB(0xff, 0x55, 0xff),
+ ARGB(0xff, 0xff, 0x55),
+ ARGB(0xff, 0xff, 0xff),
+};
+
+uint8_t ram[UINT16_MAX + 1] = { 0 };
+uint32_t *fb_data = NULL;
+
+void write_m(uint16_t addr, uint8_t b)
+{
+ if (addr >= VIDEO_RAM && addr < (VIDEO_RAM + 16384))
+ fb_data[addr - VIDEO_RAM] = palette[b & 15];
+
+ ram[addr] = b;
+}
+
+uint8_t read_m(uint16_t addr)
+{
+ return ram[addr];
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *fd;
+ size_t size;
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "Usage: input.prg\n");
+ return 1;
+ }
+ fd = fopen(argv[1], "rb");
+ if (!fd)
+ {
+ fclose(fd);
+ fprintf(stderr, "Error opening input\n");
+ return 1;
+ }
+ fseek(fd, 0, SEEK_END);
+ size = ftell(fd);
+ if (size > UINT16_MAX + 1)
+ {
+ fclose(fd);
+ fprintf(stderr, "Input is too large\n");
+ return 1;
+ }
+ fseek(fd, 0, SEEK_SET);
+ if (fread(ram, 1, size, fd) != size)
+ {
+ fclose(fd);
+ fprintf(stderr, "Error reading input\n");
+ return 1;
+ }
+ fclose(fd);
+
+ SDL_Window *screen = SDL_CreateWindow(APP_NAME " " APP_VERSION,
+ SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
+ WINDOW_W, WINDOW_H,
+ SDL_WINDOW_OPENGL);
+ if (!screen)
+ {
+ fprintf(stderr, "Failed to create a window: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_Renderer *renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
+ if (!renderer)
+ {
+ fprintf(stderr, "Failed to create the renderer: %s\n", SDL_GetError());
+ return 1;
+ }
+ SDL_SetHint("SDL_HINT_RENDER_SCALE_QUALITY", "0");
+
+ SDL_Texture *canvas = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, TR8_W, TR8_H);
+ if (!canvas)
+ {
+ fprintf(stderr, "Failed to create the canvas: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_Texture *fb = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, TR8_W, TR8_H);
+ if (!fb)
+ {
+ fprintf(stderr, "Failed to create the frame-buffer: %s\n", SDL_GetError());
+ return 1;
+ }
+ SDL_SetTextureBlendMode(fb, SDL_BLENDMODE_NONE);
+
+ int fullscreen = 0;
+ SDL_Rect dst;
+ resize_full_screen(screen, renderer, fullscreen, &dst);
+
+ SDL_RenderClear(renderer);
+ SDL_RenderPresent(renderer);
+
+ Tr8 vm;
+ tr8_init(&vm, write_m, read_m);
+ int pitch = 0;
+ uint8_t rc;
+
+ SDL_Event ev;
+ while (1)
+ {
+ if (SDL_PollEvent(&ev))
+ {
+ if (ev.type == SDL_QUIT)
+ break;
+
+ if (ev.type == SDL_KEYDOWN)
+ {
+ if (ev.key.keysym.sym == SDLK_ESCAPE)
+ {
+ if (fullscreen)
+ resize_full_screen(screen, renderer, 0, &dst);
+ break;
+ }
+ if (ev.key.keysym.sym == SDLK_RETURN && (SDL_GetModState() & KMOD_LALT))
+ {
+ fullscreen ^= 1;
+ resize_full_screen(screen, renderer, fullscreen, &dst);
+ continue;
+ }
+ }
+ }
+
+ pitch = 0;
+ fb_data = NULL;
+ SDL_LockTexture(fb, NULL, (void **)&fb_data, &pitch);
+ rc = tr8_eval(&vm);
+ SDL_UnlockTexture(fb);
+
+ if (!rc)
+ break;
+
+ /* render to the canvas */
+ SDL_SetRenderTarget(renderer, canvas);
+ SDL_RenderClear(renderer);
+
+ SDL_RenderCopy(renderer, fb, NULL, NULL);
+
+ /* now target the screen */
+ SDL_SetRenderTarget(renderer, NULL);
+ SDL_RenderClear(renderer);
+ SDL_RenderCopy(renderer, canvas, NULL, &dst);
+
+ SDL_RenderPresent(renderer);
+
+ pitch = 0;
+ fb_data = NULL;
+ SDL_LockTexture(fb, NULL, (void **)&fb_data, &pitch);
+ rc = tr8_frame_int(&vm);
+ SDL_UnlockTexture(fb);
+
+ if (!rc)
+ break;
+ }
+
+ if (canvas)
+ SDL_DestroyTexture(canvas);
+ if (fb)
+ SDL_DestroyTexture(fb);
+
+ SDL_DestroyRenderer(renderer);
+ SDL_DestroyWindow(screen);
+
+ return 0;
+}
diff --git a/vm.c b/vm.c
index b9785ef..7d91eb8 100644
--- a/vm.c
+++ b/vm.c
@@ -81,7 +81,7 @@ static void dump(Tr8 *vm)
fprintf(stderr, " PC 0x%04x: ", vm->pc);
for (i = 0; i < 16 && i + vm->pc < UINT16_MAX + 1; i++)
- fprintf(stderr, "0x%02x ", vm->ram[vm->pc + i]);
+ fprintf(stderr, "0x%02x ", vm->read_m(vm->pc + i));
fprintf(stderr, "\n");
fprintf(stderr, " SP 0x%04x: ", vm->sp);
@@ -90,7 +90,7 @@ static void dump(Tr8 *vm)
else
{
for (i = 0; i < 16 && i + vm->sp < UINT16_MAX + 1; i++)
- fprintf(stderr, "0x%02x ", vm->ram[vm->sp + i]);
+ fprintf(stderr, "0x%02x ", vm->read_m(vm->sp + i));
}
fprintf(stderr, "\n");
@@ -113,11 +113,27 @@ static void dump(Tr8 *vm)
fprintf(stderr, "****\n");
}
-void tr8_init(Tr8 *vm, uint8_t *ram)
+void tr8_init(Tr8 *vm, void (*write_m)(uint16_t, uint8_t), uint8_t (*read_m)(uint16_t))
{
memset(vm, 0, sizeof(Tr8));
+ vm->write_m = write_m;
+ vm->read_m = read_m;
vm->f = IF;
- vm->ram = ram;
+}
+
+uint8_t tr8_frame_int(Tr8 *vm)
+{
+ if (vm->f & IF)
+ return 1;
+
+ vm->write_m(--vm->sp, vm->pc & 0xff);
+ vm->write_m(--vm->sp, vm->pc >> 8);
+ vm->write_m(--vm->sp, vm->f);
+ vm->pc = vm->read_m(FRAME_INT_VECT) | (vm->read_m(FRAME_INT_VECT + 1) << 8);
+ vm->f = IF;
+ vm->intr = 1;
+
+ return tr8_eval(vm);
}
uint8_t tr8_eval(Tr8 *vm)
@@ -129,7 +145,7 @@ uint8_t tr8_eval(Tr8 *vm)
for (;;)
{
/* each instruction is 16-bit */
- instr = vm->ram[vm->pc] | (vm->ram[vm->pc + 1] << 8);
+ instr = vm->read_m(vm->pc) | (vm->read_m(vm->pc + 1) << 8);
vm->pc += 2;
/* if the branch flag is set, we skip this instruction */
@@ -157,12 +173,12 @@ uint8_t tr8_eval(Tr8 *vm)
{
if (vm->f & IF)
{
- fprintf(stderr, "*HALT*\n");
+ fprintf(stderr, "*HALT with IF*\n");
vm->pc -= 2;
dump(vm);
- return 1;
+ return 0;
}
- return 0;
+ return 1;
}
/* PORT r1, r3 */
vm->regs[R1(instr)] = port(vm->regs[R1(instr)], vm->regs[R3(instr)]);
@@ -172,16 +188,21 @@ uint8_t tr8_eval(Tr8 *vm)
if (FHL(instr))
{
/* IRET */
- vm->pc = vm->ram[vm->sp + 1] | (vm->ram[vm->sp] << 8);
+ vm->f = vm->read_m(vm->sp++);
+ vm->pc = vm->read_m(vm->sp + 1) | (vm->read_m(vm->sp) << 8);
vm->sp += 2;
- vm->f |= (~IF);
+ if (vm->intr)
+ {
+ vm->intr = 0;
+ return 1;
+ }
}
else
{
if (FL(instr))
{
/* RET */
- vm->pc = vm->ram[vm->sp + 1] | (vm->ram[vm->sp] << 8);
+ vm->pc = vm->read_m(vm->sp + 1) | (vm->read_m(vm->sp) << 8);
vm->sp += 2;
}
}
@@ -202,10 +223,10 @@ uint8_t tr8_eval(Tr8 *vm)
case 2:
if (FL(instr))
/* LD [r1:r2], r3 */
- vm->ram[ADDR(vm->regs[R1(instr)], vm->regs[R2(instr)])] = vm->regs[R3(instr)];
+ vm->write_m(ADDR(vm->regs[R1(instr)], vm->regs[R2(instr)]), vm->regs[R3(instr)]);
else
/* LD r3, [r1:r2] */
- vm->regs[R3(instr)] = vm->ram[ADDR(vm->regs[R1(instr)], vm->regs[R2(instr)])];
+ vm->regs[R3(instr)] = vm->read_m(ADDR(vm->regs[R1(instr)], vm->regs[R2(instr)]));
break;
case 3:
@@ -213,10 +234,10 @@ uint8_t tr8_eval(Tr8 *vm)
{
if (FHL(instr))
/* PUSH F */
- vm->ram[--vm->sp] = vm->f;
+ vm->write_m(--vm->sp, vm->f);
else
/* POP F */
- vm->f = vm->ram[vm->sp++];
+ vm->f = vm->read_m(vm->sp++);
}
else
{
@@ -231,10 +252,10 @@ uint8_t tr8_eval(Tr8 *vm)
{
if (FHL(instr))
/* PUSH r1 */
- vm->ram[--vm->sp] = vm->regs[R1(instr)];
+ vm->write_m(--vm->sp, vm->regs[R1(instr)]);
else
/* POP r1 */
- vm->regs[R1(instr)] = vm->ram[vm->sp++];
+ vm->regs[R1(instr)] = vm->read_m(vm->sp++);
}
}
break;
@@ -338,12 +359,12 @@ uint8_t tr8_eval(Tr8 *vm)
{
if (FHH(instr))
/* JMP [vm->pc] */
- vm->pc = vm->ram[vm->pc] | (vm->ram[vm->pc + 1] << 8);
+ vm->pc = vm->read_m(vm->pc) | (vm->read_m(vm->pc + 1) << 8);
else
{
/* JMP [r1:r3] */
uint8_t addr = ADDR(vm->regs[R1(instr)], vm->regs[R3(instr)]);
- vm->pc = vm->ram[addr] | (vm->ram[addr + 1] << 8);
+ vm->pc = vm->read_m(addr) | (vm->read_m(addr + 1) << 8);
}
}
else
@@ -351,19 +372,19 @@ uint8_t tr8_eval(Tr8 *vm)
if (FHH(instr))
{
/* CALL [vm->pc] */
- vm->ram[--vm->sp] = (vm->pc + 2) & 0xff;
- vm->ram[--vm->sp] = (vm->pc + 2) >> 8;
- vm->pc = vm->ram[vm->pc] | (vm->ram[vm->pc + 1] << 8);
+ vm->write_m(--vm->sp, (vm->pc + 2) & 0xff);
+ vm->write_m(--vm->sp, (vm->pc + 2) >> 8);
+ vm->pc = vm->read_m(vm->pc) | (vm->read_m(vm->pc + 1) << 8);
}
else
{
/* CALL [r1:r3] */
uint16_t addr = ADDR(vm->regs[R1(instr)], vm->regs[R3(instr)]);
- vm->ram[--vm->sp] = vm->pc & 0xff;
- vm->ram[--vm->sp] = vm->pc >> 8;
+ vm->write_m(--vm->sp, vm->pc & 0xff);
+ vm->write_m(--vm->sp, vm->pc >> 8);
- vm->pc = vm->ram[addr] | (vm->ram[addr + 1] << 8);
+ vm->pc = vm->read_m(addr) | (vm->read_m(addr + 1) << 8);
}
}
break;
@@ -401,18 +422,18 @@ uint8_t tr8_eval(Tr8 *vm)
vm->f |= IF;
else
/* CIF */
- /* TODO: not in an interrupt */
- vm->f &= (~IF);
+ if (!vm->intr)
+ vm->f &= (~IF);
}
break;
case 12:
if (FHH(instr))
/* LD [SP + imm], r1 */
- vm->ram[vm->sp + IMM(instr)] = vm->regs[R1(instr)];
+ vm->write_m(vm->sp + IMM(instr), vm->regs[R1(instr)]);
else
/* LD r1, [SP + imm] */
- vm->regs[R1(instr)] = vm->ram[vm->sp + IMM(instr)];
+ vm->regs[R1(instr)] = vm->read_m(vm->sp + IMM(instr));
break;
case 13:
@@ -443,16 +464,23 @@ uint8_t tr8_eval(Tr8 *vm)
}
if (vm->icnt == INSTR_PER_FRAME)
- {
- dump(vm);
return 1;
- }
}
}
#ifdef DO_MAIN
uint8_t ram[UINT16_MAX + 1] = { 0 };
+void write_m(uint16_t addr, uint8_t b)
+{
+ ram[addr] = b;
+}
+
+uint8_t read_m(uint16_t addr)
+{
+ return ram[addr];
+}
+
int main(int argc, char *argv[])
{
FILE *fd;
@@ -489,7 +517,7 @@ int main(int argc, char *argv[])
}
fclose(fd);
- tr8_init(&vm, ram);
+ tr8_init(&vm, write_m, read_m);
return tr8_eval(&vm);
}
diff --git a/vm.h b/vm.h
index c35596d..4664168 100644
--- a/vm.h
+++ b/vm.h
@@ -25,18 +25,24 @@
#ifndef _TR8_H
#define _TR8_H
+#define VIDEO_RAM 0xbf00
+#define FRAME_INT_VECT 0xff00
+
typedef struct
{
uint16_t pc;
uint16_t sp;
uint16_t ssp;
uint8_t f;
+ uint8_t intr;
uint8_t regs[4];
- uint8_t *ram;
uint32_t icnt;
+ void (*write_m)(uint16_t, uint8_t);
+ uint8_t (*read_m)(uint16_t);
} Tr8;
-void tr8_init(Tr8 *vm, uint8_t *ram);
+void tr8_init(Tr8 *vm, void (*write_m)(uint16_t, uint8_t), uint8_t (*read_m)(uint16_t));
uint8_t tr8_eval(Tr8 *vm);
+uint8_t tr8_frame_int(Tr8 *vm);
#endif /* _TR8_H */