Created a debugger

This commit is contained in:
neauoire 2021-03-22 19:04:31 -07:00
parent 1db61376a2
commit 82674a1484
14 changed files with 164 additions and 339 deletions

View File

@ -1,25 +1,15 @@
# Uxn
A [stack-based VM](https://wiki.xxiivv.com/site/uxn.html), written in ANSI C.
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

View File

@ -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."

View File

@ -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 )

View File

@ -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 )

View File

@ -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

View File

@ -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 )

View File

@ -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
View File

@ -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

View File

@ -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)
@ -181,56 +116,4 @@ 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;
}
}

112
src/debugger.c Normal file
View File

@ -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;
}

View File

@ -201,7 +201,6 @@ bootuxn(Uxn *u)
char *cptr = (char *)u;
for(i = 0; i < sizeof(*u); i++)
cptr[i] = 0;
return 1;
}

View File