Created a debugger
This commit is contained in:
parent
1db61376a2
commit
82674a1484
22
README.md
22
README.md
|
@ -2,24 +2,14 @@
|
|||
|
||||
A [stack-based VM](https://wiki.xxiivv.com/site/uxn.html), written in ANSI C.
|
||||
|
||||
## Setup
|
||||
## Build
|
||||
|
||||
If you wish to build your own emulator, you can create a new instance of Uxn like:
|
||||
To build the Uxn emulator, you must have [SDL2](https://wiki.libsdl.org/).
|
||||
|
||||
```
|
||||
#include "uxn.h"
|
||||
|
||||
Uxn u;
|
||||
|
||||
if(!bootuxn(&u))
|
||||
return error("Boot", "Failed");
|
||||
if(!loaduxn(&u, argv[1]))
|
||||
return error("Load", "Failed");
|
||||
if(!init())
|
||||
return error("Init", "Failed");
|
||||
|
||||
evaluxn(u, u->vreset); /* Once on start */
|
||||
evaluxn(u, u->vframe); /* Each frame
|
||||
```sh
|
||||
./build.sh
|
||||
--debug # Add debug flags to compiler
|
||||
--cli # Run rom without graphics
|
||||
```
|
||||
|
||||
## Uxambly
|
||||
|
|
56
build.sh
56
build.sh
|
@ -1,28 +1,42 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Create bin folder
|
||||
mkdir -p bin
|
||||
echo "Formatting.."
|
||||
clang-format -i src/assembler.c
|
||||
clang-format -i src/uxn.h
|
||||
clang-format -i src/uxn.c
|
||||
clang-format -i src/emulator.c
|
||||
clang-format -i src/debugger.c
|
||||
|
||||
# Assembler
|
||||
clang-format -i assembler.c
|
||||
echo "Cleaning.."
|
||||
rm -f ./bin/assembler
|
||||
rm -f ./bin/boot.rom
|
||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined assembler.c -o bin/assembler
|
||||
|
||||
# Core
|
||||
clang-format -i uxn.h
|
||||
clang-format -i uxn.c
|
||||
|
||||
# Emulator
|
||||
clang-format -i emulator.c
|
||||
rm -f ./bin/emulator
|
||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined uxn.c emulator.c -L/usr/local/lib -lSDL2 -o bin/emulator
|
||||
# cc uxn.c emulator.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -L/usr/local/lib -lSDL2 -o bin/emulator
|
||||
rm -f ./bin/debugger
|
||||
rm -f ./bin/boot.rom
|
||||
|
||||
# Emulator(CLI)
|
||||
clang-format -i emulator-cli.c
|
||||
rm -f ./bin/emulator-cli
|
||||
echo "Building.."
|
||||
mkdir -p bin
|
||||
if [ "${1}" = '--debug' ];
|
||||
then
|
||||
echo "[debug]"
|
||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined src/assembler.c -o bin/assembler
|
||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined src/uxn.c src/emulator.c -L/usr/local/lib -lSDL2 -o bin/emulator
|
||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined src/uxn.c src/debugger.c -o bin/debugger
|
||||
else
|
||||
cc src/assembler.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o bin/assembler
|
||||
cc src/uxn.c src/debugger.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o bin/debugger
|
||||
cc src/uxn.c src/emulator.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -L/usr/local/lib -lSDL2 -o bin/emulator
|
||||
fi
|
||||
|
||||
# run
|
||||
./bin/assembler projects/software/nasu.usm bin/boot.rom
|
||||
./bin/emulator bin/boot.rom
|
||||
echo "Assembling.."
|
||||
./bin/assembler projects/examples/dev.console.usm bin/boot.rom
|
||||
|
||||
echo "Running.."
|
||||
if [ "${2}" = '--cli' ];
|
||||
then
|
||||
echo "[cli]"
|
||||
./bin/debugger bin/boot.rom
|
||||
else
|
||||
./bin/emulator bin/boot.rom
|
||||
fi
|
||||
|
||||
echo "Done."
|
|
@ -1,18 +0,0 @@
|
|||
( tests/cond )
|
||||
|
||||
|0100 @RESET
|
||||
|
||||
#1234 POP2
|
||||
#00 DUP2?
|
||||
|
||||
BRK
|
||||
|
||||
|
||||
|
||||
|c000 @FRAME
|
||||
|d000 @ERROR
|
||||
|
||||
|FF00 ;Console { pad 8 char 1 byte 1 short 2 }
|
||||
|
||||
|FFF0 .RESET .FRAME .ERROR ( vectors )
|
||||
|FFF8 [ 13fd 1ef3 1bf2 ] ( palette )
|
|
@ -1,71 +0,0 @@
|
|||
( tests/draw )
|
||||
|
||||
%RTN { JMP2r }
|
||||
%RTN? { JMP2r? }
|
||||
%ABS { DUP #07 SHR #ff SWP MUL? }
|
||||
%ABS2 { DUP2 #000f SFT2 #ffff SWP2 SWP POP MUL2? }
|
||||
|
||||
;cursor { x 2 y 2 }
|
||||
;a { x 2 y 2 }
|
||||
;b { x 2 y 2 }
|
||||
;s { x 2 y 2 }
|
||||
;d { x 2 y 2 }
|
||||
;err { short 2 }
|
||||
;err2 { short 2 }
|
||||
;i { byte 1 }
|
||||
;color { byte 1 }
|
||||
|
||||
|0100 @RESET
|
||||
|
||||
#0020 #0020 #0070 #0080 #01 ,draw-line JSR2
|
||||
#0020 #0080 #0070 #0030 #02 ,draw-line JSR2
|
||||
#00a0 #0020 #0050 #00b0 #03 ,draw-line JSR2
|
||||
#00b0 #0090 #0030 #0010 #01 ,draw-line JSR2
|
||||
|
||||
BRK
|
||||
|
||||
@draw-line ( x1 y1 x2 y2 )
|
||||
|
||||
=color
|
||||
=b.y =b.x =a.y =a.x
|
||||
~b.x ~a.x SUB2 ABS2 =d.x
|
||||
~b.y ~a.y SUB2 ABS2 #0000 SWP2 SUB2 =d.y
|
||||
#ffff #00 ~a.x ~b.x LTS2 #0002 MUL2 ADD2 =s.x
|
||||
#ffff #00 ~a.y ~b.y LTS2 #0002 MUL2 ADD2 =s.y
|
||||
~d.x ~d.y ADD2 =err
|
||||
|
||||
$loop
|
||||
|
||||
~a.x =Screen.x ~a.y =Screen.y ~color =Screen.color
|
||||
,$end ~a.x ~b.x EQU2 ~a.y ~b.y EQU2 #0101 EQU2 JMP2?
|
||||
~err #0002 MUL2 =err2
|
||||
|
||||
,$skipy ~err2 ~d.y LTS2 JMP2?
|
||||
~err ~d.y ADD2 =err
|
||||
~a.x ~s.x ADD2 =a.x
|
||||
$skipy
|
||||
|
||||
,$skipx ~err2 ~d.x GTS2 JMP2?
|
||||
~err ~d.x ADD2 =err
|
||||
~a.y ~s.y ADD2 =a.y
|
||||
$skipx
|
||||
|
||||
,$loop JMP2
|
||||
|
||||
$end
|
||||
|
||||
RTN
|
||||
|
||||
|c000 @FRAME
|
||||
|d000 @ERROR
|
||||
|
||||
|FF00 ;Console { pad 8 char 1 byte 1 short 2 }
|
||||
|FF10 ;Screen { width 2 height 2 pad 4 x 2 y 2 color 1 }
|
||||
|FF20 ;Sprite { pad 8 x 2 y 2 addr 2 color 1 }
|
||||
|FF30 ;Controller { buttons 1 }
|
||||
|FF40 ;Keys { key 1 }
|
||||
|FF50 ;Mouse { x 2 y 2 state 1 chord 1 change 1 }
|
||||
|FF60 ;File { pad 8 name 2 length 2 load 2 save 2 }
|
||||
|
||||
|FFF0 .RESET .FRAME .ERROR ( vectors )
|
||||
|FFF8 [ 13fd 1ef3 1bf2 ] ( palette )
|
|
@ -0,0 +1,9 @@
|
|||
|0100 ;Console { pad 8 char 1 byte 1 short 2 }
|
||||
|01F0 .RESET .FRAME .ERROR ( vectors )
|
||||
|
||||
@RESET
|
||||
|
||||
BRK
|
||||
|
||||
@FRAME BRK
|
||||
@ERROR BRK
|
|
@ -1,59 +0,0 @@
|
|||
( tests/jump )
|
||||
|
||||
|0100 @RESET
|
||||
|
||||
,test1 JSR2
|
||||
,test2 JSR2
|
||||
|
||||
BRK
|
||||
|
||||
@test1
|
||||
|
||||
( should print 11, 22, 33, 44 )
|
||||
|
||||
#11 =Console.byte
|
||||
#03 JMP BRK BRK BRK
|
||||
|
||||
( skip foward with id )
|
||||
|
||||
#22 =Console.byte
|
||||
^jump JMP BRK BRK BRK @jump
|
||||
|
||||
( skip patterns )
|
||||
|
||||
#33 =Console.byte
|
||||
|
||||
,skip1 #12 #34 LTH JMP2?
|
||||
#ff =Console.byte
|
||||
@skip1
|
||||
|
||||
#12 #34 LTH ^skip2 #04 SUB MUL JMP
|
||||
#ff =Console.byte
|
||||
@skip2
|
||||
|
||||
#44 =Console.byte
|
||||
|
||||
RTN
|
||||
|
||||
@test2
|
||||
|
||||
,end JMP2
|
||||
|
||||
( should print aa, bb, cc, dd )
|
||||
|
||||
@label1 #aa =Console.byte ^label3 JMP
|
||||
@label2 #cc =Console.byte ^label4 JMP
|
||||
@label3 #bb =Console.byte ^label2 JMP
|
||||
@label4 #dd =Console.byte BRK
|
||||
|
||||
@end
|
||||
|
||||
RTN
|
||||
|
||||
|c000 @FRAME
|
||||
|d000 @ERROR
|
||||
|
||||
|FF00 ;Console { pad 8 char 1 byte 1 short 2 }
|
||||
|
||||
|FFF0 .RESET .FRAME .ERROR ( vectors )
|
||||
|FFF8 [ 13fd 1ef3 1bf2 ] ( palette )
|
|
@ -1,21 +0,0 @@
|
|||
( tests/cond )
|
||||
|
||||
;a { byte 1 }
|
||||
;b { byte1 1 byte2 1 }
|
||||
;c { byte1 1 byte2 1 byte3 1 }
|
||||
|
||||
|0100 @RESET
|
||||
|
||||
#12 #00 POK
|
||||
|
||||
#00 PEK
|
||||
|
||||
BRK
|
||||
|
||||
|c000 @FRAME
|
||||
|d000 @ERROR
|
||||
|
||||
|FF00 ;Console { pad 8 char 1 byte 1 short 2 }
|
||||
|
||||
|FFF0 .RESET .FRAME .ERROR ( vectors )
|
||||
|FFF8 [ 13fd 1ef3 1bf2 ] ( palette )
|
13
run.sh
13
run.sh
|
@ -1,13 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
EMULATOR=./bin/emulator
|
||||
if [ "${1}" = '--no-sdl' ]; then
|
||||
EMULATOR=./bin/emulator-nosdl
|
||||
shift
|
||||
fi
|
||||
if [ -z "${1}" ]; then
|
||||
printf 'usage: %s [--no-sdl] USM_FILE\n' "${0}" >&2
|
||||
exit 2
|
||||
fi
|
||||
./bin/assembler "${1}" bin/boot.rom
|
||||
"${EMULATOR}" bin/boot.rom
|
|
@ -1,68 +1,3 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
Copyright (c) 2021 Devine Lu Linvega
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uxn.h"
|
||||
|
||||
#pragma mark - Core
|
||||
|
||||
int
|
||||
error(char *msg, const char *err)
|
||||
{
|
||||
printf("Error %s: %s\n", msg, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark - Devices
|
||||
|
||||
Uint8
|
||||
console_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
||||
{
|
||||
Uint8 *m = u->ram.dat;
|
||||
switch(b0) {
|
||||
case 0x08: printf("%c", b1); break;
|
||||
case 0x09: printf("0x%02x\n", b1); break;
|
||||
case 0x0b: printf("0x%04x\n", (m[ptr + 0x0a] << 8) + b1); break;
|
||||
}
|
||||
fflush(stdout);
|
||||
(void)m;
|
||||
(void)ptr;
|
||||
(void)b0;
|
||||
return b1;
|
||||
}
|
||||
|
||||
Uint8
|
||||
file_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
||||
{
|
||||
Uint8 *m = u->ram.dat;
|
||||
char *name = (char *)&m[(m[ptr + 8] << 8) + m[ptr + 8 + 1]];
|
||||
Uint16 length = (m[ptr + 8 + 2] << 8) + m[ptr + 8 + 3];
|
||||
if(b0 == 0x0d) {
|
||||
Uint16 addr = (m[ptr + 8 + 4] << 8) + b1;
|
||||
FILE *f = fopen(name, "r");
|
||||
if(f && fread(&m[addr], length, 1, f)) {
|
||||
fclose(f);
|
||||
printf("Loaded %d bytes, at %04x from %s\n", length, addr, name);
|
||||
}
|
||||
} else if(b0 == 0x0f) {
|
||||
Uint16 addr = (m[ptr + 8 + 6] << 8) + b1;
|
||||
FILE *f = fopen(name, "w");
|
||||
if(fwrite(&m[addr], length, 1, f)) {
|
||||
fclose(f);
|
||||
printf("Saved %d bytes, at %04x from %s\n", length, addr, name);
|
||||
}
|
||||
}
|
||||
return b1;
|
||||
}
|
||||
|
||||
static void
|
||||
stack_diff(Stack *old, Stack *new, char *title)
|
||||
|
@ -182,55 +117,3 @@ debug_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
|||
fflush(stdout);
|
||||
return b1;
|
||||
}
|
||||
|
||||
Uint8
|
||||
ppnil(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
||||
{
|
||||
(void)u;
|
||||
(void)ptr;
|
||||
(void)b0;
|
||||
return b1;
|
||||
}
|
||||
|
||||
#pragma mark - Generics
|
||||
|
||||
int
|
||||
start(Uxn *u)
|
||||
{
|
||||
evaluxn(u, u->vreset);
|
||||
evaluxn(u, u->vframe);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Uxn u;
|
||||
|
||||
if(argc < 2)
|
||||
return error("Input", "Missing");
|
||||
if(!bootuxn(&u))
|
||||
return error("Boot", "Failed");
|
||||
if(!loaduxn(&u, argv[1]))
|
||||
return error("Load", "Failed");
|
||||
if(!init())
|
||||
return error("Init", "Failed");
|
||||
|
||||
portuxn(&u, "console", console_poke);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "file", file_poke);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "debug", debug_poke);
|
||||
portuxn(&u, "system", system_poke);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
#include <stdio.h>
|
||||
|
||||
/*
|
||||
Copyright (c) 2021 Devine Lu Linvega
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "uxn.h"
|
||||
|
||||
#pragma mark - Core
|
||||
|
||||
int
|
||||
error(char *msg, const char *err)
|
||||
{
|
||||
printf("Error %s: %s\n", msg, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma mark - Devices
|
||||
|
||||
Uint8
|
||||
console_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
||||
{
|
||||
Uint8 *m = u->ram.dat;
|
||||
switch(b0) {
|
||||
case 0x08: printf("%c", b1); break;
|
||||
case 0x09: printf("0x%02x\n", b1); break;
|
||||
case 0x0b: printf("0x%04x\n", (m[ptr + 0x0a] << 8) + b1); break;
|
||||
}
|
||||
fflush(stdout);
|
||||
(void)m;
|
||||
(void)ptr;
|
||||
(void)b0;
|
||||
return b1;
|
||||
}
|
||||
|
||||
Uint8
|
||||
file_poke(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
||||
{
|
||||
Uint8 *m = u->ram.dat;
|
||||
char *name = (char *)&m[(m[ptr + 8] << 8) + m[ptr + 8 + 1]];
|
||||
Uint16 length = (m[ptr + 8 + 2] << 8) + m[ptr + 8 + 3];
|
||||
if(b0 == 0x0d) {
|
||||
Uint16 addr = (m[ptr + 8 + 4] << 8) + b1;
|
||||
FILE *f = fopen(name, "r");
|
||||
if(f && fread(&m[addr], length, 1, f)) {
|
||||
fclose(f);
|
||||
printf("Loaded %d bytes, at %04x from %s\n", length, addr, name);
|
||||
}
|
||||
} else if(b0 == 0x0f) {
|
||||
Uint16 addr = (m[ptr + 8 + 6] << 8) + b1;
|
||||
FILE *f = fopen(name, "w");
|
||||
if(fwrite(&m[addr], length, 1, f)) {
|
||||
fclose(f);
|
||||
printf("Saved %d bytes, at %04x from %s\n", length, addr, name);
|
||||
}
|
||||
}
|
||||
return b1;
|
||||
}
|
||||
|
||||
Uint8
|
||||
ppnil(Uxn *u, Uint16 ptr, Uint8 b0, Uint8 b1)
|
||||
{
|
||||
(void)u;
|
||||
(void)ptr;
|
||||
(void)b0;
|
||||
return b1;
|
||||
}
|
||||
|
||||
#pragma mark - Generics
|
||||
|
||||
int
|
||||
start(Uxn *u)
|
||||
{
|
||||
printf("RESET --------\n");
|
||||
if(!evaluxn(u, u->vreset))
|
||||
return error("Reset", "Failed");
|
||||
printf("FRAME --------\n");
|
||||
if(!evaluxn(u, u->vframe))
|
||||
return error("Frame", "Failed");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Uxn u;
|
||||
|
||||
if(argc < 2)
|
||||
return error("Input", "Missing");
|
||||
if(!bootuxn(&u))
|
||||
return error("Boot", "Failed");
|
||||
if(!loaduxn(&u, argv[1]))
|
||||
return error("Load", "Failed");
|
||||
|
||||
portuxn(&u, "console", console_poke);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "empty", ppnil);
|
||||
portuxn(&u, "file", file_poke);
|
||||
start(&u);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -201,7 +201,6 @@ bootuxn(Uxn *u)
|
|||
char *cptr = (char *)u;
|
||||
for(i = 0; i < sizeof(*u); i++)
|
||||
cptr[i] = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue