Improved uxncli and moved all demos into examples

This commit is contained in:
neauoire 2021-05-26 10:02:13 -07:00
parent 46658b7595
commit d163c43201
25 changed files with 222 additions and 63 deletions

View File

@ -1,6 +1,6 @@
# Uxn
An assembler and emulator for a [tiny stack-based computer](https://wiki.xxiivv.com/site/uxn.html), written in ANSI C.
An assembler and emulator for the [Uxn stack-machine](https://wiki.xxiivv.com/site/uxn.html), written in ANSI C.
## Build
@ -11,7 +11,6 @@ To build the Uxn emulator, you must have [SDL2](https://wiki.libsdl.org/).
```sh
./build.sh
--debug # Add debug flags to compiler
--cli # Run rom without graphics
```
### Plan 9
@ -22,8 +21,7 @@ To build the Uxn emulator on [9front](http://9front.org/), via [npe](https://git
mk
```
If the build fails on 9front because of missing headers or functions,
try again after `rm -r /sys/include/npe`.
If the build fails on 9front because of missing headers or functions, try again after `rm -r /sys/include/npe`.
## Getting Started
@ -36,7 +34,7 @@ Begin by building the assembler and emulator by running the build script. The as
The following command will create an Uxn-compatible rom from an [uxambly file](https://wiki.xxiivv.com/site/uxambly.html), point to a different usm file in `/projects` to assemble a different rom.
```
bin/uxnasm projects/demos/life.usm bin/life.rom
bin/uxnasm projects/examples/demos/life.usm bin/life.rom
```
To start the rom, point the emulator to the newly created rom:
@ -45,11 +43,11 @@ To start the rom, point the emulator to the newly created rom:
bin/uxnemu bin/life.rom
```
You can find additional roms [here](https://sr.ht/~rabbits/uxn/sources).
You can also use the emulator without graphics by using `uxncli`. You can find additional roms [here](https://sr.ht/~rabbits/uxn/sources).
## Emulator Controls
- `ctrl+h` toggle debugger
- `ctrl+h` toggle inspector
- `alt+h` toggle zoom
## Need a hand?

View File

@ -9,14 +9,14 @@ clang-format -i src/devices/apu.h
clang-format -i src/devices/apu.c
clang-format -i src/devices/mpu.h
clang-format -i src/devices/mpu.c
clang-format -i src/assembler.c
clang-format -i src/emulator.c
clang-format -i src/debugger.c
clang-format -i src/uxnasm.c
clang-format -i src/uxnemu.c
clang-format -i src/uxncli.c
echo "Cleaning.."
rm -f ./bin/uxnasm
rm -f ./bin/uxnemu
rm -f ./bin/debugger
rm -f ./bin/uxncli
rm -f ./bin/boot.rom
echo "Building.."
@ -24,13 +24,13 @@ 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/uxnasm
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/devices/ppu.c src/devices/apu.c src/devices/mpu.c src/emulator.c -L/usr/local/lib -lSDL2 -o bin/uxnemu
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
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/uxnasm.c -o bin/uxnasm
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/devices/ppu.c src/devices/apu.c src/devices/mpu.c src/uxnemu.c -L/usr/local/lib -lSDL2 -o bin/uxnemu
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/uxncli.c -o bin/uxncli
else
cc src/assembler.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o bin/uxnasm
cc src/uxn-fast.c src/debugger.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o bin/debugger
cc src/uxn-fast.c src/devices/ppu.c src/devices/apu.c src/devices/mpu.c src/emulator.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -L/usr/local/lib -lSDL2 -o bin/uxnemu
cc src/uxnasm.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o bin/uxnasm
cc src/uxn-fast.c src/uxncli.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -o bin/uxncli
cc src/uxn-fast.c src/devices/ppu.c src/devices/apu.c src/devices/mpu.c src/uxnemu.c -std=c89 -Os -DNDEBUG -g0 -s -Wall -Wno-unknown-pragmas -L/usr/local/lib -lSDL2 -o bin/uxnemu
fi
echo "Installing.."
@ -38,19 +38,14 @@ if [ -d "$HOME/bin" ] && [ -e ./bin/uxnemu ] && [ -e ./bin/uxnasm ]
then
cp ./bin/uxnemu $HOME/bin
cp ./bin/uxnasm $HOME/bin
cp ./bin/uxncli $HOME/bin
echo "Installed in $HOME/bin"
fi
echo "Assembling.."
./bin/uxnasm projects/demos/piano.usm bin/boot.rom
./bin/uxnasm projects/examples/demos/piano.usm bin/piano.rom
echo "Running.."
if [ "${2}" = '--cli' ];
then
echo "[cli]"
./bin/debugger bin/boot.rom
else
./bin/uxnemu bin/boot.rom
fi
./bin/uxnemu bin/piano.rom
echo "Done."

View File

@ -22,7 +22,7 @@ EOD
expect_failure() {
cat > 'in.usm'
if ../bin/debugger asma.rom > asma.log 2>/dev/null || ! grep -qF "${1}" asma.log; then
if ../bin/uxncli asma.rom > asma.log 2>/dev/null || ! grep -qF "${1}" asma.log; then
echo "error: asma didn't report error ${1} in faulty code"
tail asma.log
exit 1
@ -44,7 +44,7 @@ find ../projects -type f -name '*.usm' -not -name 'blank.usm' | sort | while rea
xxd "uxnasm-${BN}.rom" > "uxnasm-${BN}.hex"
cp "${F}" 'in.usm'
if ! ../bin/debugger asma.rom > asma.log; then
if ! ../bin/uxncli asma.rom > asma.log; then
echo "error: asma failed to assemble ${F}, while uxnasm succeeded"
tail asma.log
exit 1

View File

@ -23,7 +23,7 @@ local trees = {
local opcodes_in_order = { }
do
local wanted = false
for l in assert(io.lines('src/assembler.c')) do
for l in assert(io.lines('src/uxnasm.c')) do
if l == 'char ops[][4] = {' then
wanted = true
elseif wanted then

View File

@ -34,7 +34,7 @@ opcodes_in_order = {}
do -- opcodes
wanted = false
for l in assert io.lines 'src/assembler.c'
for l in assert io.lines 'src/uxnasm.c'
if l == 'char ops[][4] = {'
wanted = true
elseif wanted

View File

@ -219,7 +219,7 @@ for l in assert(io.lines('src/uxn.c')) do
end
i = 0
wanted = false
for l in assert(io.lines('src/assembler.c')) do
for l in assert(io.lines('src/uxnasm.c')) do
if l == 'char ops[][4] = {' then
wanted = true
elseif l == '};' then

View File

@ -156,7 +156,7 @@ for l in assert io.lines 'src/uxn.c'
i = 0
wanted = false
for l in assert io.lines 'src/assembler.c'
for l in assert io.lines 'src/uxnasm.c'
if l == 'char ops[][4] = {'
wanted = true
elseif l == '};'

10
mkfile
View File

@ -1,6 +1,6 @@
</$objtype/mkfile
TARG=bin/debugger bin/uxnasm bin/uxnemu
TARG=bin/uxncli bin/uxnasm bin/uxnemu
USM=`{walk -f projects/ | grep '\.usm$' | grep -v blank.usm}
ROM=${USM:%.usm=%.rom}
CFLAGS=$CFLAGS -I/sys/include/npe
@ -29,16 +29,16 @@ bin:
%.rom:Q: %.usm bin/uxnasm
bin/uxnasm $stem.usm $target >/dev/null
bin/debugger: debugger.$O uxn.$O
bin/uxncli: uxncli.$O uxn.$O
$LD $LDFLAGS -o $target $prereq
bin/uxnasm: assembler.$O
bin/uxnasm: uxnasm.$O
$LD $LDFLAGS -o $target $prereq
bin/uxnemu: emulator.$O apu.$O mpu.$O ppu.$O uxn.$O
bin/uxnemu: uxnemu.$O apu.$O mpu.$O ppu.$O uxn.$O
$LD $LDFLAGS -o $target $prereq
(assembler|debugger|emulator|uxn)\.$O:R: src/\1.c
(uxnasm|uxncli|uxnemu|uxn)\.$O:R: src/\1.c
$CC $CFLAGS -Isrc -o $target src/$stem1.c
(apu|mpu|ppu)\.$O:R: src/devices/\1.c

View File

@ -0,0 +1,143 @@
( dev/audio )
%4** { #20 SFT2 }
%8** { #30 SFT2 }
%MOD { DUP2 DIV MUL SUB }
( devices )
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &color $1 ]
|30 @Audio0 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ]
|40 @Audio1 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ]
|50 @Audio2 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ]
|60 @Audio3 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ]
( variables )
|0000
@timer $1
@counter $1
|0100 ( -> )
( theme )
#00ff .System/r DEO2
#0f0f .System/g DEO2
#0ff0 .System/b DEO2
( vectors )
;on-frame .Screen/vector DEO2
( setup synth )
#1202 .Audio0/adsr DEO2
;saw .Audio0/addr DEO2
#0100 .Audio0/length DEO2
#88 .Audio0/volume DEO
#0101 .Audio1/adsr DEO2
;tri .Audio1/addr DEO2
#0100 .Audio1/length DEO2
#88 .Audio1/volume DEO
#0112 .Audio2/adsr DEO2
;sin .Audio2/addr DEO2
#0100 .Audio2/length DEO2
#88 .Audio2/volume DEO
#0022 .Audio3/adsr DEO2
;piano .Audio3/addr DEO2
#0100 .Audio3/length DEO2
#88 .Audio3/volume DEO
BRK
@on-frame ( -> )
( incr ) .timer LDZ #01 ADD .timer STZ
( skip ) .timer LDZ #10 EQU #01 JCN [ BRK ]
( get note )
.counter LDZ #18 MOD #30 ADD
.Audio0/pitch .counter LDZ #04 MOD #10 MUL ADD DEO
.counter LDZ #01 ADD .counter STZ
#00 .timer STZ
BRK
@saw
0003 0609 0c0f 1215 181b 1e21 2427 2a2d
3033 3639 3b3e 4143 4649 4b4e 5052 5557
595b 5e60 6264 6667 696b 6c6e 7071 7274
7576 7778 797a 7b7b 7c7d 7d7e 7e7e 7e7e
7f7e 7e7e 7e7e 7d7d 7c7b 7b7a 7978 7776
7574 7271 706e 6c6b 6967 6664 6260 5e5b
5957 5552 504e 4b49 4643 413e 3b39 3633
302d 2a27 2421 1e1b 1815 120f 0c09 0603
00fd faf7 f4f1 eeeb e8e5 e2df dcd9 d6d3
d0cd cac7 c5c2 bfbd bab7 b5b2 b0ae aba9
a7a5 a2a0 9e9c 9a99 9795 9492 908f 8e8c
8b8a 8988 8786 8585 8483 8382 8282 8282
8182 8282 8282 8383 8485 8586 8788 898a
8b8c 8e8f 9092 9495 9799 9a9c 9ea0 a2a5
a7a9 abae b0b2 b5b7 babd bfc2 c5c7 cacd
d0d3 d6d9 dcdf e2e5 e8eb eef1 f4f7 fafd
@tri
8082 8486 888a 8c8e 9092 9496 989a 9c9e
a0a2 a4a6 a8aa acae b0b2 b4b6 b8ba bcbe
c0c2 c4c6 c8ca ccce d0d2 d4d6 d8da dcde
e0e2 e4e6 e8ea ecee f0f2 f4f6 f8fa fcfe
fffd fbf9 f7f5 f3f1 efed ebe9 e7e5 e3e1
dfdd dbd9 d7d5 d3d1 cfcd cbc9 c7c5 c3c1
bfbd bbb9 b7b5 b3b1 afad aba9 a7a5 a3a1
9f9d 9b99 9795 9391 8f8d 8b89 8785 8381
7f7d 7b79 7775 7371 6f6d 6b69 6765 6361
5f5d 5b59 5755 5351 4f4d 4b49 4745 4341
3f3d 3b39 3735 3331 2f2d 2b29 2725 2321
1f1d 1b19 1715 1311 0f0d 0b09 0705 0301
0103 0507 090b 0d0f 1113 1517 191b 1d1f
2123 2527 292b 2d2f 3133 3537 393b 3d3f
4143 4547 494b 4d4f 5153 5557 595b 5d5f
6163 6567 696b 6d6f 7173 7577 797b 7d7f
@sin
8083 8689 8c8f 9295 989b 9ea1 a4a7 aaad
b0b3 b6b9 bbbe c1c3 c6c9 cbce d0d2 d5d7
d9db dee0 e2e4 e6e7 e9eb ecee f0f1 f2f4
f5f6 f7f8 f9fa fbfb fcfd fdfe fefe fefe
fffe fefe fefe fdfd fcfb fbfa f9f8 f7f6
f5f4 f2f1 f0ee eceb e9e7 e6e4 e2e0 dedb
d9d7 d5d2 d0ce cbc9 c6c3 c1be bbb9 b6b3
b0ad aaa7 a4a1 9e9b 9895 928f 8c89 8683
807d 7a77 7471 6e6b 6865 625f 5c59 5653
504d 4a47 4542 3f3d 3a37 3532 302e 2b29
2725 2220 1e1c 1a19 1715 1412 100f 0e0c
0b0a 0908 0706 0505 0403 0302 0202 0202
0102 0202 0202 0303 0405 0506 0708 090a
0b0c 0e0f 1012 1415 1719 1a1c 1e20 2225
2729 2b2e 3032 3537 3a3d 3f42 4547 4a4d
5053 5659 5c5f 6265 686b 6e71 7477 7a7d
@piano
8182 8588 8d91 959b a1a6 aaad b2b5 b8bd
c1c7 cbd0 d5d9 dde1 e5e5 e4e4 e1dc d7d1
cbc5 bfb8 b2ac a6a2 9c97 928d 8884 807c
7977 7574 7372 7272 7273 7372 706d 6964
605b 5650 4d49 4643 4342 4244 4548 4a4d
5052 5556 5758 5554 5150 4c4a 4744 423f
3d3c 3a38 3835 3431 3030 2f31 3336 393e
4449 4e54 5a60 666b 7175 7b82 8990 989e
a6ab b1b6 babd bebf bfbe bbb9 b6b3 b0ae
aaa8 a6a3 a19e 9c9a 9997 9696 9798 9b9e
a1a4 a6a9 a9ac adad adae aeaf b0b0 b1b1
b3b3 b4b4 b4b3 b3b1 b0ad abab a9a9 a8a8
a7a5 a19d 9891 8b84 7e77 726e 6b6b 6b6c
6f71 7477 7776 7370 6c65 5e56 4e48 423f
3d3c 3b3a 3a39 3838 3839 393a 3c3e 4146
4a50 575b 6064 686a 6e70 7274 7677 7a7d
@melody [
54 52 54 4f 4b 4f 48 ff
54 52 54 4f 4b 4f 48 ff
54 56 57 56 57 54 56 54
56 52 54 52 54 50 54 ff ]

View File

@ -9,7 +9,7 @@
Asma - an in-Uxn assembler
This assembler aims to be binary compatible with the output from
src/assembler.c, but unlike that assembler this one can be run inside Uxn
src/uxnasm.c, but unlike that assembler this one can be run inside Uxn
itself!
Asma is designed to be able to be copy-pasted inside another project, so

View File

@ -107,7 +107,7 @@ putchr(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uin
/* output */
void
drawdebugger(Ppu *p, Uint8 *stack, Uint8 ptr)
inspect(Ppu *p, Uint8 *stack, Uint8 ptr)
{
Uint8 i, x, y, b;
for(i = 0; i < 0x20; ++i) { /* memory */

View File

@ -31,4 +31,4 @@ void putcolors(Ppu *p, Uint8 *addr);
void putpixel(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 color);
void puticn(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy);
void putchr(Ppu *p, Layer *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy);
void drawdebugger(Ppu *p, Uint8 *stack, Uint8 ptr);
void inspect(Ppu *p, Uint8 *stack, Uint8 ptr);

View File

@ -296,9 +296,9 @@ pass1(FILE *f)
printf("Pass 1\n");
while(fscanf(f, "%s", w) == 1) {
if(skipblock(w, &ccmnt, '(', ')')) continue;
if(w[0] == '|') {
if(w[0] == '|')
addr = shex(w + 1);
} else if(w[0] == '%') {
else if(w[0] == '%') {
if(!makemacro(w + 1, f))
return error("Pass1 failed", w);
} else if(w[0] == '@') {

View File

@ -1,4 +1,5 @@
#include <stdio.h>
#include <time.h>
#include "uxn.h"
/*
@ -25,6 +26,7 @@ void
printstack(Stack *s)
{
Uint8 x, y;
printf("\n\n");
for(y = 0; y < 0x08; ++y) {
for(x = 0; x < 0x08; ++x) {
Uint8 p = y * 0x08 + x;
@ -60,14 +62,35 @@ file_talk(Device *d, Uint8 b0, Uint8 w)
Uint16 addr = mempeek16(d->dat, b0 - 1);
FILE *f = fopen(name, read ? "r" : (offset ? "a" : "w"));
if(f) {
if(fseek(f, offset, SEEK_SET) != -1 && (result = read ? fread(&d->mem[addr], 1, length, f) : fwrite(&d->mem[addr], 1, length, f)))
printf("%s %d bytes, at %04x from %s\n", read ? "Loaded" : "Saved", result, addr, name);
printf("%s %04x %s %s: ", read ? "Loading" : "Saving", addr, read ? "from" : "to", name);
if(fseek(f, offset, SEEK_SET) != -1)
result = read ? fread(&d->mem[addr], 1, length, f) : fwrite(&d->mem[addr], 1, length, f);
printf("%04x bytes\n", result);
fclose(f);
}
mempoke16(d->dat, 0x2, result);
}
}
void
datetime_talk(Device *d, Uint8 b0, Uint8 w)
{
time_t seconds = time(NULL);
struct tm *t = localtime(&seconds);
t->tm_year += 1900;
mempoke16(d->dat, 0x0, t->tm_year);
d->dat[0x2] = t->tm_mon;
d->dat[0x3] = t->tm_mday;
d->dat[0x4] = t->tm_hour;
d->dat[0x5] = t->tm_min;
d->dat[0x6] = t->tm_sec;
d->dat[0x7] = t->tm_wday;
mempoke16(d->dat, 0x08, t->tm_yday);
d->dat[0xa] = t->tm_isdst;
(void)b0;
(void)w;
}
void
nil_talk(Device *d, Uint8 b0, Uint8 w)
{
@ -81,10 +104,8 @@ nil_talk(Device *d, Uint8 b0, Uint8 w)
int
start(Uxn *u)
{
printf("RESET --------\n");
if(!evaluxn(u, PAGE_PROGRAM))
return error("Reset", "Failed");
printstack(&u->wst);
return 1;
}
@ -100,23 +121,26 @@ main(int argc, char **argv)
if(!loaduxn(&u, argv[1]))
return error("Load", "Failed");
portuxn(&u, 0x00, "empty", nil_talk);
portuxn(&u, 0x01, "console", console_talk);
portuxn(&u, 0x02, "empty", nil_talk);
portuxn(&u, 0x03, "empty", nil_talk);
portuxn(&u, 0x04, "empty", nil_talk);
portuxn(&u, 0x05, "empty", nil_talk);
portuxn(&u, 0x06, "empty", nil_talk);
portuxn(&u, 0x07, "empty", nil_talk);
portuxn(&u, 0x08, "empty", nil_talk);
portuxn(&u, 0x09, "empty", nil_talk);
portuxn(&u, 0x0a, "file", file_talk);
portuxn(&u, 0x0b, "empty", nil_talk);
portuxn(&u, 0x0c, "empty", nil_talk);
portuxn(&u, 0x0d, "empty", nil_talk);
portuxn(&u, 0x0e, "empty", nil_talk);
portuxn(&u, 0x0f, "empty", nil_talk);
portuxn(&u, 0x0, "empty", nil_talk);
portuxn(&u, 0x1, "console", console_talk);
portuxn(&u, 0x2, "empty", nil_talk);
portuxn(&u, 0x3, "empty", nil_talk);
portuxn(&u, 0x4, "empty", nil_talk);
portuxn(&u, 0x5, "empty", nil_talk);
portuxn(&u, 0x6, "empty", nil_talk);
portuxn(&u, 0x7, "empty", nil_talk);
portuxn(&u, 0x8, "empty", nil_talk);
portuxn(&u, 0x9, "empty", nil_talk);
portuxn(&u, 0xa, "file", file_talk);
portuxn(&u, 0xb, "datetime", datetime_talk);
portuxn(&u, 0xc, "empty", nil_talk);
portuxn(&u, 0xd, "empty", nil_talk);
portuxn(&u, 0xe, "empty", nil_talk);
portuxn(&u, 0xf, "empty", nil_talk);
start(&u);
if(argc > 2)
printstack(&u.wst);
return 0;
}

View File

@ -59,7 +59,7 @@ void
redraw(Uxn *u)
{
if(debug)
drawdebugger(&ppu, u->wst.dat, u->wst.ptr);
inspect(&ppu, u->wst.dat, u->wst.ptr);
SDL_UpdateTexture(bgTexture, &gRect, ppu.bg.pixels, ppu.width * sizeof(Uint32));
SDL_UpdateTexture(fgTexture, &gRect, ppu.fg.pixels, ppu.width * sizeof(Uint32));
SDL_RenderClear(gRenderer);
@ -245,7 +245,6 @@ screen_talk(Device *d, Uint8 b0, Uint8 w)
puticn(&ppu, layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4);
else
putchr(&ppu, layer, x, y, addr, d->dat[0xe] & 0xf, mode & 0x2, mode & 0x4);
reqdraw = 1;
}
}