Merge branch 'master' into improved-readme
|
@ -0,0 +1,4 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: 8bitworkshop
|
|
@ -5,3 +5,4 @@ local
|
|||
release
|
||||
gen
|
||||
test/output
|
||||
.DS_Store
|
||||
|
|
|
@ -16,15 +16,12 @@
|
|||
[submodule "localForage"]
|
||||
path = localForage
|
||||
url = https://github.com/localForage/localForage
|
||||
[submodule "bitmap-fonts"]
|
||||
path = bitmap-fonts
|
||||
url = https://github.com/Tecate/bitmap-fonts
|
||||
[submodule "ibmfonts"]
|
||||
path = ibmfonts
|
||||
url = https://github.com/farsil/ibmfonts
|
||||
[submodule "jsnes"]
|
||||
path = jsnes
|
||||
url = https://github.com/sehugg/jsnes
|
||||
[submodule "bootstrap-tourist"]
|
||||
path = bootstrap-tourist
|
||||
url = https://github.com/IGreatlyDislikeJavascript/bootstrap-tourist
|
||||
[submodule "nanoasm"]
|
||||
path = nanoasm
|
||||
url = https://github.com/sehugg/nanoasm
|
||||
|
|
4
Makefile
|
@ -2,6 +2,7 @@
|
|||
TSC=./node_modules/typescript/bin/tsc
|
||||
|
||||
all:
|
||||
cp nanoasm/src/assembler.ts src/worker/
|
||||
$(TSC)
|
||||
cd jsnes && npm i
|
||||
|
||||
|
@ -28,3 +29,6 @@ tsweb:
|
|||
ifconfig | grep inet
|
||||
$(TSC) -w &
|
||||
python3 scripts/serveit.py 2>> http.out
|
||||
|
||||
astrolibre.b64.txt: astrolibre.rom
|
||||
lzg -9 $< | base64 -w 0 > $@
|
||||
|
|
|
@ -44,7 +44,7 @@ make tsweb
|
|||
## Run tests
|
||||
|
||||
```sh
|
||||
make test
|
||||
npm test
|
||||
```
|
||||
|
||||
## Author
|
||||
|
@ -66,5 +66,11 @@ Give a ⭐️ if this project helped you!
|
|||
Copyright © 2019 [Steven Hugg](https://github.com/sehugg).<br />
|
||||
This project is [GPL-3.0](https://github.com/sehugg/8bitworkshop/blob/master/LICENSE) licensed.
|
||||
|
||||
Dependencies retain their original licenses.
|
||||
|
||||
All included code samples (all files under the presets/ directory) are licensed under
|
||||
[CC0](https://creativecommons.org/publicdomain/zero/1.0/)
|
||||
unless otherwise licensed.
|
||||
|
||||
***
|
||||
_This README was generated with ❤️ by [readme-md-generator](https://github.com/kefranabg/readme-md-generator)_
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 6f52a7ca0838967cc57e9a44d76c6e1f60e62842
|
|
@ -1,4 +0,0 @@
|
|||
*.nes
|
||||
*.o
|
||||
*.s
|
||||
*.lzg
|
|
@ -1,25 +0,0 @@
|
|||
|
||||
CC65FLAGS=-I/home/hugg/compilers/cc65/include -I/home/hugg/compilers/cc65/include/nes -L/home/hugg/compilers/cc65/lib --cfg-path /home/hugg/compilers/cc65/cfg/ -v
|
||||
|
||||
all: \
|
||||
default_neslib.neslib.nes default_conio.conio.nes \
|
||||
default_neslib.neslib.lzg default_conio.conio.lzg
|
||||
|
||||
clean:
|
||||
rm -f *.s *.o *.nes *.lzg
|
||||
|
||||
#%.s: %.c
|
||||
# cc65 $*.c
|
||||
# ca65 $*.s
|
||||
|
||||
%.neslib.nes: %.c
|
||||
cl65 $(CC65FLAGS) -o $@ -t nes -C neslib.cfg $*.c neslib.lib nes.lib
|
||||
|
||||
%.conio.nes: %.c
|
||||
cl65 $(CC65FLAGS) -o $@ -t nes $*.c nes.lib
|
||||
|
||||
%.rom: %.s
|
||||
time ld65 -o $@ -C atarivec.cfg $*.o atari2600.lib
|
||||
|
||||
%.lzg: %.nes
|
||||
lzg $< | hexdump -v -e '"\n" 32/1 "%u,"' > $@
|
|
@ -1,43 +0,0 @@
|
|||
|
||||
#include "nes.h"
|
||||
|
||||
unsigned char index;
|
||||
|
||||
const unsigned char TEXT[]={"No cart loaded"};
|
||||
|
||||
const unsigned char PALETTE[]={0x1, 0x00, 0x10, 0x20}; //blue, gray, lt gray, white
|
||||
|
||||
void main (void) {
|
||||
|
||||
// turn off the screen
|
||||
PPU.control = 0;
|
||||
PPU.mask = 0;
|
||||
|
||||
// load the palette
|
||||
PPU.vram.address = 0x3f;
|
||||
PPU.vram.address = 0x0;
|
||||
for(index = 0; index < sizeof(PALETTE); ++index){
|
||||
PPU.vram.data = PALETTE[index];
|
||||
}
|
||||
|
||||
// load the text
|
||||
PPU.vram.address = 0x21; // set an address in the PPU of 0x21ca
|
||||
PPU.vram.address = 0xc9; // about the middle of the screen
|
||||
for( index = 0; index < sizeof(TEXT); ++index ){
|
||||
PPU.vram.data = TEXT[index];
|
||||
}
|
||||
|
||||
// reset the scroll position
|
||||
PPU.vram.address = 0x20;
|
||||
PPU.vram.address = 0x0;
|
||||
PPU.scroll = 0;
|
||||
PPU.scroll = 0;
|
||||
|
||||
// turn on screen
|
||||
PPU.control = 0x80; // NMI on
|
||||
PPU.mask = 0x1e; // screen on
|
||||
|
||||
// infinite loop
|
||||
while (1) {
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
|
||||
//this example code shows how to put some text in nametable
|
||||
|
||||
#include "neslib.h"
|
||||
|
||||
// tileset data
|
||||
|
||||
const unsigned char TILESET[8*128] = {/*{w:8,h:8,bpp:1,count:128,brev:1}*/
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x7c,0x7c,0x7c,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x6c,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0xfe,0x6c,0xfe,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xfe,0xd0,0xfe,0x16,0xfe,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xce,0xdc,0x38,0x76,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x6c,0x7c,0xec,0xee,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x70,0x70,0x70,0x70,0x70,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x38,0x38,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x38,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0xfe,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x1e,0x3c,0x78,0xf0,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x7c,0xee,0xee,0xee,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x78,0x38,0x38,0x38,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x0e,0x7c,0xe0,0xee,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0x0e,0x3c,0x0e,0x0e,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x7e,0xee,0xee,0xfe,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xe0,0xfc,0x0e,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xe0,0xfc,0xee,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xee,0x1c,0x1c,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0x7c,0xee,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0xee,0x7e,0x0e,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x38,0x70,0x70,0x38,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x1c,0x1c,0x38,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0x1c,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x7c,0xee,0xee,0xee,0xe0,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0xee,0xee,0xfe,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xee,0xfc,0xee,0xee,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0xe0,0xe0,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf8,0xec,0xee,0xee,0xee,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xe0,0xf0,0xe0,0xe0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xe0,0xf8,0xe0,0xe0,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xe0,0xee,0xee,0xee,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xfe,0xee,0xee,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x38,0x38,0x38,0x38,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x0e,0x0e,0x0e,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xfc,0xf8,0xec,0xee,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0xe0,0xe0,0xe0,0xee,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc6,0xee,0xfe,0xfe,0xee,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xce,0xee,0xfe,0xfe,0xee,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0xee,0xee,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0xfc,0xee,0xee,0xee,0xfc,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0xee,0xee,0xec,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xee,0xee,0xee,0xfc,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xe0,0x7c,0x0e,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x38,0x38,0x38,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xee,0xee,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xee,0x6c,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xfe,0xfe,0xee,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0x7c,0x38,0x7c,0xee,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xee,0x7c,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x1c,0x38,0x70,0xe0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
//this macro is used remove need of calculation of the nametable address in runtime
|
||||
|
||||
#define NTADR(x,y) ((0x2000|((y)<<5)|x))
|
||||
|
||||
//put a string into the nametable
|
||||
|
||||
void put_str(unsigned int adr,const char *str)
|
||||
{
|
||||
vram_adr(adr);
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(!*str) break;
|
||||
vram_put((*str++)-0x20);//-0x20 because ASCII code 0x20 is placed in tile 0 of the CHR
|
||||
}
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
//copy tileset to RAM
|
||||
vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET));
|
||||
|
||||
//rendering is disabled at the startup, and palette is all black
|
||||
pal_col(0,0x1);
|
||||
pal_col(1,0x30);//set while color
|
||||
|
||||
//you can't put data into vram through vram_put while rendering is enabled
|
||||
//so you have to disable rendering to put things like text or a level map
|
||||
//into the nametable
|
||||
|
||||
//there is a way to update small number of nametable tiles while rendering
|
||||
//is enabled, using set_vram_update and an update list
|
||||
|
||||
put_str(NTADR(9,15),"NO CART LOADED");
|
||||
|
||||
ppu_on_all();//enable rendering
|
||||
|
||||
while(1);//do nothing, infinite loop
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
.macro jeq Target
|
||||
.if .match(Target, 0)
|
||||
bne *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
beq Target
|
||||
.else
|
||||
bne *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
||||
.macro jne Target
|
||||
.if .match(Target, 0)
|
||||
beq *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
bne Target
|
||||
.else
|
||||
beq *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
||||
.macro jmi Target
|
||||
.if .match(Target, 0)
|
||||
bpl *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
bmi Target
|
||||
.else
|
||||
bpl *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
||||
.macro jpl Target
|
||||
.if .match(Target, 0)
|
||||
bmi *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
bpl Target
|
||||
.else
|
||||
bmi *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
||||
.macro jcs Target
|
||||
.if .match(Target, 0)
|
||||
bcc *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
bcs Target
|
||||
.else
|
||||
bcc *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
||||
.macro jcc Target
|
||||
.if .match(Target, 0)
|
||||
bcs *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
bcc Target
|
||||
.else
|
||||
bcs *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
||||
.macro jvs Target
|
||||
.if .match(Target, 0)
|
||||
bvc *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
bvs Target
|
||||
.else
|
||||
bvc *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
||||
.macro jvc Target
|
||||
.if .match(Target, 0)
|
||||
bvs *+5
|
||||
jmp Target
|
||||
.elseif .def(Target) .and .const((*-2)-(Target)) .and ((*+2)-(Target) <= 127)
|
||||
bvc Target
|
||||
.else
|
||||
bvs *+5
|
||||
jmp Target
|
||||
.endif
|
||||
.endmacro
|
226
cc65/neslib.h
|
@ -1,226 +0,0 @@
|
|||
//NES hardware-dependent functions by Shiru (shiru@mail.ru)
|
||||
//Feel free to do anything you want with this code, consider it Public Domain
|
||||
|
||||
|
||||
//set bg and spr palettes, data is 32 bytes array
|
||||
|
||||
void __fastcall__ pal_all(const char *data);
|
||||
|
||||
//set bg palette only, data is 16 bytes array
|
||||
|
||||
void __fastcall__ pal_bg(const char *data);
|
||||
|
||||
//set spr palette only, data is 16 bytes array
|
||||
|
||||
void __fastcall__ pal_spr(const char *data);
|
||||
|
||||
//set a palette entry, index is 0..31
|
||||
|
||||
void __fastcall__ pal_col(unsigned char index,unsigned char color);
|
||||
|
||||
//reset palette to $0f
|
||||
|
||||
void __fastcall__ pal_clear(void);
|
||||
|
||||
//set virtual bright, 0 is black, 4 is normal, 8 is white
|
||||
|
||||
void __fastcall__ pal_bright(unsigned char bright);
|
||||
|
||||
|
||||
//turn off rendering and nmi
|
||||
|
||||
void __fastcall__ ppu_off(void);
|
||||
|
||||
//turn on bg, spr, and nmi
|
||||
|
||||
void __fastcall__ ppu_on_all(void);
|
||||
|
||||
//turn on bg only and nmi
|
||||
|
||||
void __fastcall__ ppu_on_bg(void);
|
||||
|
||||
//turn on spr only and nmi
|
||||
|
||||
void __fastcall__ ppu_on_spr(void);
|
||||
|
||||
//set PPU_MASK directly
|
||||
|
||||
;void __fastcall__ ppu_mask(unsigned char mask);
|
||||
|
||||
|
||||
|
||||
//clear OAM buffer, all the sprites are hidden
|
||||
|
||||
void __fastcall__ oam_clear(void);
|
||||
|
||||
//set sprites size, 0 for 8x8, 1 for 8x16
|
||||
|
||||
void __fastcall__ oam_size(unsigned char size);
|
||||
|
||||
//set sprite in OAM buffer, chrnum is tile, attr is attribute, sprid is offset in OAM in bytes
|
||||
//returns sprid+4, which is offset for a next sprite
|
||||
|
||||
unsigned char __fastcall__ oam_spr(unsigned char x,unsigned char y,unsigned char chrnum,unsigned char attr,unsigned char sprid);
|
||||
|
||||
//set metasprite in OAM buffer
|
||||
//meta sprite is a const unsigned char array, it contains four bytes per sprite
|
||||
//in order x offset, y offset, tile, attribute
|
||||
//x=128 is end of a meta sprite
|
||||
//returns sprid+4, which is offset for a next sprite
|
||||
|
||||
unsigned char __fastcall__ oam_meta_spr(unsigned char x,unsigned char y,unsigned char sprid,const unsigned char *data);
|
||||
|
||||
//hide all the sprites starting from given offset
|
||||
|
||||
void __fastcall__ oam_hide_rest(unsigned char sprid);
|
||||
|
||||
|
||||
|
||||
//wait NMI and sync to 50hz (with frameskip for NTSC)
|
||||
|
||||
void __fastcall__ ppu_waitnmi(void);
|
||||
|
||||
|
||||
|
||||
//play a music in FamiTone format
|
||||
|
||||
void __fastcall__ music_play(const unsigned char *data);
|
||||
|
||||
//stop music
|
||||
|
||||
void __fastcall__ music_stop(void);
|
||||
|
||||
//pause and unpause music
|
||||
|
||||
void __fastcall__ music_pause(unsigned char pause);
|
||||
|
||||
//play FamiTone sound effect on channel 0..3
|
||||
|
||||
void __fastcall__ sfx_play(unsigned char sound,unsigned char channel);
|
||||
|
||||
|
||||
|
||||
//poll controller and return flags like PAD_LEFT etc, input is pad number (0 or 1)
|
||||
|
||||
unsigned char __fastcall__ pad_poll(unsigned char pad);
|
||||
|
||||
//poll controller in trigger mode, a flag is set only on button down, not hold
|
||||
//if you need to poll the pad in both normal and trigger mode, poll it in the
|
||||
//trigger mode for first, then use pad_state
|
||||
|
||||
unsigned char __fastcall__ pad_trigger(unsigned char pad);
|
||||
|
||||
//get previous pad state without polling ports
|
||||
|
||||
unsigned char __fastcall__ pad_state(unsigned char pad);
|
||||
|
||||
|
||||
//set scroll, including top bits
|
||||
|
||||
void __fastcall__ scroll(unsigned int x,unsigned int y);
|
||||
|
||||
|
||||
|
||||
//select current chr bank for sprites, 0..1
|
||||
|
||||
void __fastcall__ bank_spr(unsigned char n);
|
||||
|
||||
//select current chr bank for background, 0..1
|
||||
|
||||
void __fastcall__ bank_bg(unsigned char n);
|
||||
|
||||
|
||||
|
||||
//returns random number 0..255 or 0..65535
|
||||
|
||||
unsigned char __fastcall__ rand8(void);
|
||||
unsigned int __fastcall__ rand16(void);
|
||||
|
||||
//set random seed
|
||||
|
||||
void __fastcall__ set_rand(unsigned int seed);
|
||||
|
||||
|
||||
|
||||
//set a pointer to update buffer, contents of the buffer is transferred to vram every frame
|
||||
//buffer structure is MSB, LSB, byte to write, len is number of entries (not bytes)
|
||||
//could be set during rendering, but only takes effect on a new frame
|
||||
//number of transferred bytes is limited by vblank time
|
||||
|
||||
void __fastcall__ set_vram_update(unsigned char len,unsigned char *buf);
|
||||
|
||||
//set vram pointer to write operations if you need to write some data to vram
|
||||
//works only when rendering is turned off
|
||||
|
||||
void __fastcall__ vram_adr(unsigned int adr);
|
||||
|
||||
//put a byte at current vram address, works only when rendering is turned off
|
||||
|
||||
void __fastcall__ vram_put(unsigned char n);
|
||||
|
||||
//fill a block with a byte at current vram address, works only when rendering is turned off
|
||||
|
||||
void __fastcall__ vram_fill(unsigned char n,unsigned int len);
|
||||
|
||||
//set vram autoincrement, 0 for +1 and not 0 for +32
|
||||
|
||||
void __fastcall__ vram_inc(unsigned char n);
|
||||
|
||||
//read a block from vram, works only when rendering is turned off
|
||||
|
||||
void __fastcall__ vram_read(unsigned char *dst,unsigned int adr,unsigned int size);
|
||||
|
||||
//write a block to vram, works only when rendering is turned off
|
||||
|
||||
void __fastcall__ vram_write(unsigned char *src,unsigned int adr,unsigned int size);
|
||||
|
||||
|
||||
//unpack a nametable into vram
|
||||
|
||||
void __fastcall__ unrle_vram(const unsigned char *data,unsigned int vram);
|
||||
|
||||
|
||||
|
||||
//like a normal memcpy, but does not return anything
|
||||
|
||||
void __fastcall__ memcpy(void *dst,void *src,unsigned int len);
|
||||
|
||||
//like memset, but does not return anything
|
||||
|
||||
void __fastcall__ memfill(void *dst,unsigned char value,unsigned int len);
|
||||
|
||||
//delay for N frames
|
||||
|
||||
void __fastcall__ delay(unsigned char frames);
|
||||
|
||||
//initialize sound effects
|
||||
|
||||
void __fastcall__ FamiToneSfxInit(void* src);
|
||||
|
||||
void __fastcall__ FamiToneSfxInit(void* src);
|
||||
|
||||
|
||||
#define PAD_A 0x01
|
||||
#define PAD_B 0x02
|
||||
#define PAD_SELECT 0x04
|
||||
#define PAD_START 0x08
|
||||
#define PAD_UP 0x10
|
||||
#define PAD_DOWN 0x20
|
||||
#define PAD_LEFT 0x40
|
||||
#define PAD_RIGHT 0x80
|
||||
|
||||
#define OAM_FLIP_V 0x80
|
||||
#define OAM_FLIP_H 0x40
|
||||
#define OAM_BEHIND 0x20
|
||||
|
||||
#define MAX(x1,x2) (x1<x2?x2:x1)
|
||||
#define MIN(x1,x2) (x1<x2?x1:x2)
|
||||
|
||||
#define MASK_SPR 0x10
|
||||
#define MASK_BG 0x08
|
||||
#define MASK_EDGE_SPR 0x04
|
||||
#define MASK_EDGE_BG 0x02
|
||||
|
||||
#define NULL 0
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
BIN
cc65/neslib.lib
248
cc65/threed.c
|
@ -1,248 +0,0 @@
|
|||
#include <string.h>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
|
||||
#define inline
|
||||
|
||||
#define dvgram ((word*)0x1000)
|
||||
#define _dvgstart (*((byte*)0x8840))
|
||||
|
||||
#define mathbox_sum (*((int*)0x8100))
|
||||
#define mathbox_arg1 (*((sbyte*)0x8102))
|
||||
#define mathbox_arg2 (*((sbyte*)0x8103))
|
||||
#define mathbox_go_mul (*((byte*)0x810f))
|
||||
|
||||
void start() {
|
||||
/*
|
||||
__asm
|
||||
LD SP,#0x0
|
||||
DI
|
||||
__endasm;
|
||||
*/
|
||||
}
|
||||
|
||||
int dvgwrofs; // write offset for DVG buffer
|
||||
|
||||
inline word ___swapw(word j) {
|
||||
return ((j << 8) | (j >> 8));
|
||||
}
|
||||
|
||||
inline void dvgreset() {
|
||||
dvgwrofs = 0;
|
||||
}
|
||||
|
||||
inline void dvgstart() {
|
||||
_dvgstart = 0;
|
||||
}
|
||||
|
||||
void dvgwrite(word w) {
|
||||
dvgram[dvgwrofs++] = w;
|
||||
}
|
||||
|
||||
inline void VCTR(int dx, int dy, byte bright) {
|
||||
dvgwrite((dy & 0x1fff));
|
||||
dvgwrite(((bright & 7) << 13) | (dx & 0x1fff));
|
||||
}
|
||||
|
||||
inline void SVEC(sbyte dx, sbyte dy, byte bright) {
|
||||
dvgwrite(0x4000 | (dx & 0x1f) | ((bright&7)<<5) | ((dy & 0x1f)<<8));
|
||||
}
|
||||
|
||||
inline void JSRL(word offset) {
|
||||
dvgwrite(0xa000 | offset);
|
||||
}
|
||||
|
||||
inline void JMPL(word offset) {
|
||||
dvgwrite(0xe000 | offset);
|
||||
}
|
||||
|
||||
inline void RTSL() {
|
||||
dvgwrite(0xc000);
|
||||
}
|
||||
|
||||
inline void CNTR() {
|
||||
dvgwrite(0x8000);
|
||||
}
|
||||
|
||||
inline void HALT() {
|
||||
dvgwrite(0x2000);
|
||||
}
|
||||
|
||||
inline void STAT(byte rgb, byte intens) {
|
||||
dvgwrite(0x6000 | ((intens & 0xf)<<4) | (rgb & 7));
|
||||
}
|
||||
|
||||
inline void STAT_sparkle(byte intens) {
|
||||
dvgwrite(0x6800 | ((intens & 0xf)<<4));
|
||||
}
|
||||
|
||||
inline void SCAL(word scale) {
|
||||
dvgwrite(0x7000 | scale);
|
||||
}
|
||||
|
||||
enum {
|
||||
BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE
|
||||
} Color;
|
||||
|
||||
///
|
||||
|
||||
typedef struct {
|
||||
sbyte m[3][3];
|
||||
} Matrix;
|
||||
|
||||
typedef struct {
|
||||
sbyte x,y,z;
|
||||
} Vector8;
|
||||
|
||||
typedef struct {
|
||||
int x,y,z;
|
||||
} Vector16;
|
||||
|
||||
typedef struct {
|
||||
byte numverts;
|
||||
const Vector8* verts; // array of vertices
|
||||
const sbyte* edges; // array of vertex indices (edges)
|
||||
} Wireframe;
|
||||
|
||||
void mat_identity(Matrix* m) {
|
||||
memset(m, 0, sizeof(*m));
|
||||
m->m[0][0] = 127;
|
||||
m->m[1][1] = 127;
|
||||
m->m[2][2] = 127;
|
||||
}
|
||||
|
||||
inline void mul16(sbyte a, sbyte b) {
|
||||
mathbox_arg1 = a;
|
||||
mathbox_arg2 = b;
|
||||
mathbox_go_mul=0;
|
||||
}
|
||||
|
||||
void vec_mat_transform(Vector16* dest, const Vector8* v, const Matrix* m) {
|
||||
byte i;
|
||||
int* result = &dest->x;
|
||||
const sbyte* mval = &m->m[0][0];
|
||||
for (i=0; i<3; i++) {
|
||||
mathbox_sum = 0;
|
||||
mul16(*mval++, v->x);
|
||||
mul16(*mval++, v->y);
|
||||
mul16(*mval++, v->z);
|
||||
*result++ = mathbox_sum;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void vec_mat_transform2(Vector16* dest, const Vector8* v, const Matrix* m) {
|
||||
dest->x = v->x*m->m[0][0] + v->y*m->m[0][1] + v->z*m->m[0][2];
|
||||
dest->y = v->x*m->m[1][0] + v->y*m->m[1][1] + v->z*m->m[1][2];
|
||||
dest->z = v->x*m->m[2][0] + v->y*m->m[2][1] + v->z*m->m[2][2];
|
||||
}
|
||||
*/
|
||||
|
||||
const sbyte sintbl[64] = {
|
||||
0, 3, 6, 9, 12, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43, 46,
|
||||
49, 51, 54, 57, 60, 63, 65, 68, 71, 73, 76, 78, 81, 83, 85, 88,
|
||||
90, 92, 94, 96, 98, 100, 102, 104, 106, 107, 109, 111, 112, 113, 115, 116,
|
||||
117, 118, 120, 121, 122, 122, 123, 124, 125, 125, 126, 126, 126, 127, 127, 127,
|
||||
};
|
||||
|
||||
sbyte isin(byte x0) {
|
||||
byte x = x0;
|
||||
if (x0 & 0x40) x = 127-x;
|
||||
if (x0 & 0x80) {
|
||||
return -sintbl[x+128];
|
||||
} else {
|
||||
return sintbl[x];
|
||||
}
|
||||
}
|
||||
|
||||
sbyte icos(byte x) {
|
||||
return isin(x+64);
|
||||
}
|
||||
|
||||
void mat_rotate(Matrix* m, byte axis, byte angle) {
|
||||
sbyte sin = isin(angle);
|
||||
sbyte cos = icos(angle);
|
||||
mat_identity(m);
|
||||
switch (axis) {
|
||||
case 0:
|
||||
m->m[1][1] = cos;
|
||||
m->m[2][1] = sin;
|
||||
m->m[1][2] = -sin;
|
||||
m->m[2][2] = cos;
|
||||
break;
|
||||
case 1:
|
||||
m->m[2][2] = cos;
|
||||
m->m[0][2] = sin;
|
||||
m->m[2][0] = -sin;
|
||||
m->m[0][0] = cos;
|
||||
break;
|
||||
case 2:
|
||||
m->m[0][0] = cos;
|
||||
m->m[1][0] = sin;
|
||||
m->m[0][1] = -sin;
|
||||
m->m[1][1] = cos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const Vector8 tetra_v[] = { {0,-86,86},{86,86,86},{-86,86,86},{0,0,-86} };
|
||||
const signed char tetra_e[] = { 0, 1, 2, 0, 3, 1, -1, 3, 2, -2 };
|
||||
const Wireframe tetra = { 4, tetra_v, tetra_e };
|
||||
|
||||
void xform_vertices(Vector16* dest, const Vector8* src, const Matrix* m, byte nv) {
|
||||
byte i;
|
||||
for (i=0; i<nv; i++) {
|
||||
vec_mat_transform(dest++, src++, m);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_wireframe_ortho(const Wireframe* wf, const Matrix* m) {
|
||||
const signed char* e = wf->edges;
|
||||
byte bright = 0;
|
||||
int x1 = 0;
|
||||
int y1 = 0;
|
||||
Vector16 scrnverts[16];
|
||||
xform_vertices(scrnverts, wf->verts, m, wf->numverts);
|
||||
do {
|
||||
sbyte i = *e++;
|
||||
if (i == -1)
|
||||
bright = 0;
|
||||
else if (i == -2)
|
||||
break;
|
||||
else {
|
||||
int x2 = scrnverts[i].x>>8;
|
||||
int y2 = scrnverts[i].y>>8;
|
||||
VCTR(x2-x1, y2-y1, bright);
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
bright = 2;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
word frame;
|
||||
|
||||
void main() {
|
||||
int x,y;
|
||||
Matrix m;
|
||||
mat_identity(&m);
|
||||
while (1) {
|
||||
dvgreset();
|
||||
CNTR();
|
||||
SCAL(0x1f);
|
||||
STAT(RED, 5);
|
||||
x = isin(frame/8);
|
||||
y = icos(frame/8);
|
||||
VCTR(x, y, 2);
|
||||
STAT(GREEN, 15);
|
||||
mat_rotate(&m, (frame>>8)&3, frame);
|
||||
draw_wireframe_ortho(&tetra, &m);
|
||||
HALT();
|
||||
dvgstart();
|
||||
frame++;
|
||||
}
|
||||
}
|
|
@ -2,10 +2,9 @@
|
|||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
border: 1px solid #eee;
|
||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||
font-size: 0.8em;
|
||||
height: 96vh;
|
||||
height: 94vh;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
|
45
css/ui.css
|
@ -49,8 +49,8 @@
|
|||
background-color:#000066;
|
||||
}
|
||||
#controls_top {
|
||||
position: absolute;
|
||||
padding: 0.5em;
|
||||
position:absolute;
|
||||
padding:0.5em;
|
||||
height:3em;
|
||||
width:100%;
|
||||
background-color:#999;
|
||||
|
@ -111,7 +111,7 @@ div.mem_info a.selected {
|
|||
text-align:right;
|
||||
}
|
||||
.btn_group {
|
||||
border-radius:6px;
|
||||
border-radius:8px;
|
||||
padding:8px;
|
||||
margin-left:8px;
|
||||
background-color: #666;
|
||||
|
@ -223,6 +223,8 @@ a.dropdown-toggle {
|
|||
div.emulator {
|
||||
background-color: #666;
|
||||
margin-top: 20px auto 0;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
}
|
||||
div.emuoverlay {
|
||||
display:flex;
|
||||
|
@ -249,6 +251,10 @@ div.emuspacer {
|
|||
width:90%;
|
||||
pointer-events:auto;
|
||||
}
|
||||
.emuvideo:focus {
|
||||
outline:none;
|
||||
border-color:#888;
|
||||
}
|
||||
canvas.pixelated {
|
||||
image-rendering: optimizeSpeed; /* Older versions of FF */
|
||||
image-rendering: -moz-crisp-edges; /* FF 6.0+ */
|
||||
|
@ -277,14 +283,15 @@ canvas.pixelated {
|
|||
font-family: TinyFont;
|
||||
src: url(04B_03__.TTF);
|
||||
}
|
||||
#booksMenuButton {
|
||||
border-width:3px;
|
||||
border-color:#99ff99;
|
||||
background-color:#006600;
|
||||
.toolbarMenuButton {
|
||||
background-color:#666;
|
||||
border-style:solid;
|
||||
font-family: "Andale Mono", "Menlo", "Lucida Console", monospace;
|
||||
position:relative;
|
||||
top:-0.25em;
|
||||
margin-left:0.5em;
|
||||
margin-right:0.5em;
|
||||
}
|
||||
a.toolbarMenuButton {
|
||||
padding:0.3em;
|
||||
}
|
||||
a.dropdown-toggle {
|
||||
}
|
||||
|
@ -516,3 +523,23 @@ div.asset_toolbar {
|
|||
padding:8px;
|
||||
margin:8px;
|
||||
}
|
||||
.control-insns {
|
||||
margin-top: auto;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
.control-key {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
border-radius: 0.6em;
|
||||
padding: 0.2em;
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
background-color: #eee;
|
||||
margin-left: 1em;
|
||||
color: #666;
|
||||
}
|
||||
.control-def {
|
||||
color: #ccc;
|
||||
}
|
||||
.book-title {
|
||||
font-size:12pt;
|
||||
}
|
||||
|
|
176
doc/notes.txt
|
@ -6,14 +6,8 @@ TODO:
|
|||
- confuse code/data in listing
|
||||
- show memory locations hovering over lines
|
||||
- don't check against ROM signatures
|
||||
- support 6502 test cases
|
||||
- DASM: macro forward refs
|
||||
- asm: support macro expansion
|
||||
- support narrow screens
|
||||
- case sensisitvity looking for mismatch variables
|
||||
- remove pulldown when no preset?
|
||||
- can't step after reset (or when funky frame; TIA frame is out of sync)
|
||||
- break on BRK/illegal opcode?
|
||||
- multiple breakpoints, expression breakpoints
|
||||
- watchpoints
|
||||
- debug inspector for variables
|
||||
|
@ -21,95 +15,96 @@ TODO:
|
|||
- step over (line, instruction)
|
||||
- slowdown beam for all platforms?
|
||||
- PC x86 support
|
||||
- https://bellard.org/tcc/
|
||||
- show errors in list (maybe window list?)
|
||||
- can't see 1st line in editor sometimes (when scrolling cursor past bottom of screen)
|
||||
- click to go to error
|
||||
- what if error in include file you can't edit b/c it never appears?
|
||||
- online help
|
||||
- show self-modifying code insns left of editor
|
||||
- facade/kbd shortcuts for emulators, focus
|
||||
- update Javatari version? (and others?)
|
||||
- unify versioning
|
||||
- disassembler for uploaded ROMs
|
||||
- compile stuck when errors unchanged
|
||||
- sound mute?
|
||||
- $error updates source editor
|
||||
- go to error in include files
|
||||
- online tools for music etc
|
||||
- text log debugging script
|
||||
- NES crt should mark raster pos when debugging
|
||||
- intro/help text for each platform
|
||||
- vscode/atom extension?
|
||||
- VCS asm library
|
||||
- better VCS single stepping, maybe also listings
|
||||
- VCS skips step on lsr/lsr after run to line
|
||||
- error msg when #link doesn't work
|
||||
- figure out folders for projects for real
|
||||
- click to break on raster position
|
||||
- restructure src/ folders
|
||||
- debug bankswitching for funky formats
|
||||
- spaces in filename don't parse code listing (DASM, maybe more)
|
||||
- 'undefined' for bitmap replacer
|
||||
- astrocade: run to cursor in hello world messes up emulation
|
||||
- requestInterrupt needs to be disabled after breakpoint?
|
||||
- C/asm formatter
|
||||
- C/asm source formatter
|
||||
- fix WebAudio (https://news.ycombinator.com/item?id=18066474)
|
||||
- allow download of JSASM output
|
||||
- update bootstrap to 4.0
|
||||
- batariBasic: proper line numbers, debugging
|
||||
- granular control over time scrubbing, show CPU state
|
||||
- error showing replay div before rom starts
|
||||
- compiler flags for final ROM build
|
||||
- workermain: split build functions, better msg types
|
||||
- vcs: INPTx needs to be added to control state
|
||||
- sdcc: can't link asm files before c files (e.g. acheader.s must be last)
|
||||
- what if >1 file with same name? (local/nonlocal/directory)
|
||||
- what if .c and .s names collide?
|
||||
- builds:
|
||||
- compiler flags for final ROM build
|
||||
- workermain: split build functions, better msg types
|
||||
- what if >1 file with same name? (local/nonlocal/directory)
|
||||
- what if .c and .s names collide?
|
||||
- maybe put stuff in examples/ dir?
|
||||
- error msg when #link doesn't work
|
||||
- warning when ROM too big
|
||||
- detect "libcv.h" and include library automagically?
|
||||
- sdcc:
|
||||
- can't link asm files before c files (e.g. acheader.s must be last)
|
||||
- figure out area names ordering
|
||||
- debug inline asm
|
||||
- live coding URL
|
||||
- resize memory browser when vertical div resize
|
||||
- preroll the emulator so optimizer does its thing before loading rom
|
||||
- resize memory browser, other windows when vertical div resize
|
||||
- preroll the Z80 emulator so optimizer does its thing before loading rom
|
||||
- wasm dynamic linking of emulators (https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md)
|
||||
- use alternate confirm/prompt dialogs
|
||||
- https://github.com/jvilk/BrowserFS
|
||||
- what if error in include file you can't edit b/c it never appears?
|
||||
- markdown, verilog: can't share
|
||||
- https://www.crowdsupply.com/tinyfpga/tinyfpga-bx
|
||||
- HTTPS warning
|
||||
- stego shareable images (http://pico-8.wikia.com/wiki/P8PNGFileFormat)
|
||||
- https://makecode.com/language?
|
||||
- open ROM from URL?
|
||||
- game starts even if switched away before first load
|
||||
- vcs: break on # of lines changed (maybe using getRasterPosition?)
|
||||
- profiler restarts when paused
|
||||
- it's pretty easy to add a new file named like a library file (bcd.c)
|
||||
- or have neslib.h in a subdirectory...
|
||||
- put globals into view/controller objects
|
||||
- upload binary files doesn't do what's expected, changing pulldown and whatnot
|
||||
- chrome autostart audio: https://github.com/processing/p5.js-sound/issues/249
|
||||
- firefox autostart audio: https://support.mozilla.org/en-US/kb/block-autoplay
|
||||
- show player controls for each platform, allow touch support, navigator.getGamepads
|
||||
- autostart audio
|
||||
- chrome: https://github.com/processing/p5.js-sound/issues/249
|
||||
- firefox: https://support.mozilla.org/en-US/kb/block-autoplay
|
||||
- touch support
|
||||
- better undo/diff for mistakes?
|
||||
- ide bug/feature visualizer for sponsors
|
||||
- optimization flags for sdcc (oldralloc)
|
||||
- global undo/redo at checkpoints (when rom changes)
|
||||
- pulldown shows wrong file if preset not present
|
||||
- landscape mode for arcade ports
|
||||
- symmetric load/save state types
|
||||
- pixel editor
|
||||
- persist palette/tilemap selections
|
||||
- more tools for editing
|
||||
- map editor
|
||||
- arbitrary nametable editing
|
||||
- metasprites
|
||||
- throw errors when bad/no refs
|
||||
- per-View keyboard shortcuts
|
||||
- parse labels
|
||||
- parse .incbin directives?
|
||||
- can't replace in hex directives
|
||||
- should maybe use same single-canvas editor for map + char editor
|
||||
- undo doesn't refresh editor
|
||||
- editing sometimes messes up cursor movement (CURBS)
|
||||
- crt0.s compiled each time?
|
||||
- debug highlight doesn't go away when debugging -> running
|
||||
- show breakpoint of PC or highest address on stack
|
||||
- can we highlight line instead of select?
|
||||
- replay doesn't work for nes (force background tile redraw)
|
||||
- running profiler while replaying? grand unified replay?
|
||||
- click on profiler to step to position
|
||||
- breakpoints stop profiler from running
|
||||
- profiler
|
||||
- profiler restarts emulator when paused
|
||||
- running profiler while replaying? grand unified replay?
|
||||
- click on profiler to step to position
|
||||
- breakpoints stop profiler from running
|
||||
- single-screen profiler
|
||||
- hide labels that aren't available, like BIOS addrs
|
||||
- show interrupts, other events
|
||||
- sometimes interleaves two different PCs? like two profilers running simultaneously?
|
||||
- ah, symbols persist across builds
|
||||
- https://remotestoragejs.readthedocs.io/en/latest/getting-started/how-to-add.html ?
|
||||
- Verilog
|
||||
- larger scope range, better scrolling
|
||||
|
@ -123,29 +118,66 @@ TODO:
|
|||
- toolbar overlaps scope
|
||||
- CPU debugging
|
||||
- use $readmem for inline asm programs?
|
||||
- can't add control instructions b/c of split
|
||||
- single-stepping vector games makes screen fade
|
||||
- break on stack overflow, bad op, bad access, etc
|
||||
- PPU/TIA register write visualization
|
||||
- nes debug view toolbar
|
||||
- vcs sound continues when paused
|
||||
- break on stack overflow, illegal op, bad access, BRK, etc
|
||||
- nes
|
||||
- replay doesn't work for nes (force background tile redraw)
|
||||
- nes debug view toolbar
|
||||
- support NES_HEADER_16K?
|
||||
- PPU/TIA register write visualization
|
||||
- show cur/tmp vram addresses
|
||||
- NES crt should mark raster pos when debugging
|
||||
- OAMDMA in profiler? (haltCycles)
|
||||
- ca65 skeleton
|
||||
- neslib.cfg nesbanked.cfg ZP segment is C64-ish, should use $00-$FF
|
||||
- JSNES
|
||||
- doesn't support hiding >8 sprites
|
||||
- doesn't do sprite zero test right
|
||||
- doesn't do clip right
|
||||
- doesn't do b/w tint
|
||||
- vcs
|
||||
- vcs sound continues when paused
|
||||
- vcs: INPTx needs to be added to control state
|
||||
- vcs: break on # of lines changed (maybe using getRasterPosition?)
|
||||
- chrome looks blurry on vcs
|
||||
- VCS asm game library
|
||||
- VCS skips step on lsr/lsr after run to line
|
||||
- better VCS single stepping, maybe also listings
|
||||
- upload multiple files/zip file to subdirectory
|
||||
- allow "include graphics.asm" instead of "include project/graphics.asm"
|
||||
- chrome looks blurry on vcs
|
||||
- convert more stuff to Promises
|
||||
- target ES6
|
||||
- don't have to include bootstrap-tourist each time?
|
||||
- don't have to include firebase always?
|
||||
- squelch error msgs?
|
||||
- test offline? (if window.firebase)
|
||||
- Github
|
||||
- platform_id/repo.platform mismatch (can't leave repository)
|
||||
- gh-pages branch with embedded
|
||||
- handle overwrite logic
|
||||
- test edge/failure cases
|
||||
- what to do about included files?
|
||||
- what if files already open in editor
|
||||
- un-bind from repo?
|
||||
- can published files retain path?
|
||||
- what if import interrupted and partial files?
|
||||
- CORS for some blobs?
|
||||
- confusing when examples load if file not found
|
||||
- don't import useless files
|
||||
- support projects with subdirectories, file list?
|
||||
- emulator needs reset shortcut for nes
|
||||
- switching platform of a repo?
|
||||
- make sure to flatten subdirs
|
||||
- astrocade
|
||||
- keyboard shortcuts
|
||||
- ctrl+alt+l on ubuntu locks screen
|
||||
- alt-D doesn't work anymore
|
||||
- facade/kbd shortcuts for emulators, focus
|
||||
- cookie
|
||||
- list of stuff for policy
|
||||
- popup
|
||||
- convert binary to hex stmts
|
||||
- "suggestions" (vblank overrun, variable # scanlines, etc)
|
||||
- SMS
|
||||
- can't step back twice?
|
||||
- compiler bug in chase
|
||||
|
||||
|
||||
WEB WORKER FORMAT
|
||||
|
@ -281,3 +313,43 @@ Pull
|
|||
Push
|
||||
|
||||
Git metadata kept in local storage
|
||||
|
||||
Converting from NESASM to DASM
|
||||
- asl a -> asl
|
||||
- subroutine keyword on labels
|
||||
- [zp],y to (zp),y
|
||||
- LOW(x) and HIGH(x) to <() and >()
|
||||
- .db to .byte, .dw to .word
|
||||
- use NES_HEADER macros
|
||||
- no .bank
|
||||
|
||||
Cross platform NES/SMS/GG library
|
||||
- use CHR RAM
|
||||
- create flipped tiles/sprites
|
||||
- create alternate palette tiles
|
||||
- metatiles
|
||||
- cross platform music/sound
|
||||
- scrolling
|
||||
- row/column mask
|
||||
- no nametable mirroring in SMS
|
||||
- 256x240 vs 256x192
|
||||
|
||||
Emulator Lib
|
||||
- move getPresets() (into presets/ dir?)
|
||||
- CPU interface
|
||||
- execCycle(), execInsn()
|
||||
- fix/unfix PC
|
||||
- interrupt
|
||||
- generic raster scanline platform
|
||||
- PlatformRunner
|
||||
- handles rewind, intra-frame breakpoint, debugging
|
||||
- profiling log, exec/read/write/intr (for each bus?)
|
||||
- expose video, audio, controller interfaces
|
||||
- new debugging info
|
||||
- memory map interface
|
||||
- "About" metadata
|
||||
- auto load/save state?
|
||||
- handle legacy
|
||||
- VCS
|
||||
- NES
|
||||
- MAME
|
||||
|
|
|
@ -0,0 +1,265 @@
|
|||
|
||||
class Platform
|
||||
--------------
|
||||
|
||||
Mandatory functions:
|
||||
~~~
|
||||
start() : void;
|
||||
reset() : void;
|
||||
isRunning() : boolean;
|
||||
pause() : void;
|
||||
resume() : void;
|
||||
loadROM(title:string, rom:any);
|
||||
~~~
|
||||
|
||||
These are for the compiler/editor:
|
||||
~~~
|
||||
getToolForFilename(s:string) : string;
|
||||
getDefaultExtension() : string;
|
||||
getPresets() : Preset[];
|
||||
~~~
|
||||
|
||||
Most platforms have these:
|
||||
~~~
|
||||
loadState?(state : EmuState) : void;
|
||||
saveState?() : EmuState;
|
||||
~~~
|
||||
|
||||
... etc
|
||||
|
||||
|
||||
6502
|
||||
----
|
||||
|
||||
`advance()` advances one frame.
|
||||
The basic idea: iterate through all the scanlines, run a bunch of CPU cycles per scanline.
|
||||
If we hit a breakpoint, exit the loop.
|
||||
|
||||
~~~
|
||||
var debugCond = this.getDebugCallback();
|
||||
for (var sl=0; sl<262; sl++) {
|
||||
for (var i=0; i<cpuCyclesPerLine; i++) {
|
||||
if (debugCond && debugCond()) {
|
||||
debugCond = null;
|
||||
sl = 999;
|
||||
break;
|
||||
}
|
||||
clock++;
|
||||
cpu.clockPulse();
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Hitting a breakpoint does a `saveState()` but debug info is better when the platform is stopped at the breakpoint instead of being allowed to continue.
|
||||
|
||||
Some platforms like `vector` aren't scanline-based, they just have a target number of scanlines per frame (per 1/60 sec)
|
||||
|
||||
The 6502 CPU core is usually a byte behind the current instruction at breakpoints.
|
||||
So when saving state we +1 the PC by calling `fixPC`.
|
||||
When loading state we have to -1 the PC, load state, then +1 the PC.
|
||||
|
||||
~~~
|
||||
this.unfixPC(state.c);
|
||||
cpu.loadState(state.c);
|
||||
this.fixPC(state.c);
|
||||
~~~
|
||||
|
||||
|
||||
|
||||
Z80
|
||||
---
|
||||
|
||||
There's a `runCPU()` wrapper:
|
||||
|
||||
~~~
|
||||
advance(novideo : boolean) {
|
||||
for (var sl=0; sl<scanlinesPerFrame; sl++) {
|
||||
drawScanline(pixels, sl);
|
||||
this.runCPU(cpu, cpuCyclesPerLine);
|
||||
}
|
||||
// NMI each frame
|
||||
if (interruptEnabled) { cpu.nonMaskableInterrupt(); }
|
||||
}
|
||||
~~~
|
||||
|
||||
|
||||
Atari 2600
|
||||
-----------
|
||||
8bitworkshop was originally VCS-only, Javatari.js was the first emulator it supported.
|
||||
|
||||
It's a wonderful emulator, but it didn't have hooks for debugging.
|
||||
I had to hack it up quite a bit, and wasn't sure what I was doing.
|
||||
A lot of the debugging functions just pass-through to my hacked-up functions:
|
||||
|
||||
~~~
|
||||
step() { Javatari.room.console.debugSingleStepCPUClock(); }
|
||||
stepBack() { Javatari.room.console.debugStepBackInstruction(); }
|
||||
runEval(evalfunc) { Javatari.room.console.debugEval(evalfunc); }
|
||||
~~~
|
||||
|
||||
Even so, I decided to monkey-patch the `clockPulse()` function so that I could record frames:
|
||||
|
||||
~~~
|
||||
Javatari.room.console.oldClockPulse = Javatari.room.console.clockPulse;
|
||||
Javatari.room.console.clockPulse = function() {
|
||||
self.updateRecorder();
|
||||
this.oldClockPulse();
|
||||
}
|
||||
~~~
|
||||
|
||||
Eventually I'd like to make it more like the other platforms.
|
||||
8bitworkshop uses its CPU core for other 6502 platforms.
|
||||
|
||||
|
||||
BasicZ80ScanlinePlatform
|
||||
------------------------
|
||||
|
||||
Can be used to easily build a Z80-based raster platform.
|
||||
Just have to fill out the following:
|
||||
|
||||
~~~
|
||||
cpuFrequency : number;
|
||||
canvasWidth : number;
|
||||
numTotalScanlines : number;
|
||||
numVisibleScanlines : number;
|
||||
defaultROMSize : number;
|
||||
|
||||
abstract newRAM() : Uint8Array;
|
||||
abstract newMembus() : MemoryBus;
|
||||
abstract newIOBus() : MemoryBus;
|
||||
abstract getVideoOptions() : {};
|
||||
abstract getKeyboardMap();
|
||||
abstract startScanline(sl : number) : void;
|
||||
abstract drawScanline(sl : number) : void;
|
||||
getRasterScanline() : number { return this.currentScanline; }
|
||||
getKeyboardFunction() { return null; }
|
||||
~~~
|
||||
|
||||
|
||||
NES
|
||||
---
|
||||
|
||||
NES uses the JSNES emulator, which has a callback function after each frame.
|
||||
|
||||
~~~
|
||||
this.nes = new jsnes.NES({
|
||||
onFrame: (frameBuffer : number[]) => {
|
||||
},
|
||||
onAudioSample: (left:number, right:number) => {
|
||||
},
|
||||
onStatusUpdate: function(s) {
|
||||
},
|
||||
});
|
||||
~~~
|
||||
|
||||
We monkey-patch the code to add a debugging hook:
|
||||
|
||||
~~~
|
||||
// insert debug hook
|
||||
this.nes.cpu._emulate = this.nes.cpu.emulate;
|
||||
this.nes.cpu.emulate = () => {
|
||||
var cycles = this.nes.cpu._emulate();
|
||||
this.evalDebugCondition();
|
||||
return cycles;
|
||||
}
|
||||
~~~
|
||||
|
||||
NES was the first platform with an "illegal opcode" hard stop, so we added a special `EmuHalt` exception which causes a breakpoint:
|
||||
|
||||
~~~
|
||||
this.nes.stop = () => {
|
||||
console.log(this.nes.cpu.toJSON());
|
||||
throw new EmuHalt("CPU STOPPED @ PC $" + hex(this.nes.cpu.REG_PC));
|
||||
};
|
||||
~~~
|
||||
|
||||
|
||||
MAME
|
||||
----
|
||||
|
||||
The `BaseMAMEPlatform` class implements a MAME platform.
|
||||
You just have to pass it various parameters when starting, and tell it how to load the ROM file:
|
||||
|
||||
~~~
|
||||
class ColecoVisionMAMEPlatform extends BaseMAMEPlatform implements Platform {
|
||||
|
||||
start() {
|
||||
this.startModule(this.mainElement, {
|
||||
jsfile: 'mamecoleco.js',
|
||||
cfgfile: 'coleco.cfg',
|
||||
biosfile: 'coleco/313 10031-4005 73108a.u2',
|
||||
driver: 'coleco',
|
||||
width: 280 * 2,
|
||||
height: 216 * 2,
|
||||
romfn: '/emulator/cart.rom',
|
||||
romsize: 0x8000,
|
||||
preInit: function(_self) {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
loadROM(title, data) {
|
||||
this.loadROMFile(data);
|
||||
this.loadRegion(":coleco_cart:rom", data);
|
||||
}
|
||||
|
||||
getPresets() { return ColecoVision_PRESETS; }
|
||||
getToolForFilename = getToolForFilename_z80;
|
||||
getDefaultExtension() { return ".c"; };
|
||||
}
|
||||
~~~
|
||||
|
||||
A lot of things are done via Lua scripting -- for example, loading a ROM requires we loop over the memory region and issue `rgn:write_u32` calls.
|
||||
It kinda-sorta works, except debugging isn't reliable because MAME [doesn't return from the event loop](https://github.com/mamedev/mame/issues/3649) at breakpoints.
|
||||
|
||||
MAME platforms don't have state load/save either.
|
||||
|
||||
|
||||
Verilog
|
||||
--------
|
||||
|
||||
The Verilog platform is the odd one out, since it has no fixed CPU as such.
|
||||
The `loadROM` function instead loads a JavaScript function.
|
||||
Some platforms do have a ROM if using assembly, so we load that into a Verilog array.
|
||||
It's quite the hack, and it could be better.
|
||||
|
||||
Verilog has its own debugger, logging signals in a fixed-size buffer.
|
||||
|
||||
|
||||
|
||||
Profiling
|
||||
----------
|
||||
|
||||
`EmuProfilerImpl` runs the profiler.
|
||||
When started, it calls `setBreakpoint` to add a profiler-specific breakpoint that never hits, just records the CPU state at each clock.
|
||||
It uses `getRasterScanline` to associate IPs with scanlines.
|
||||
Platforms can also log their own reads, writes, interrupts, etc.
|
||||
|
||||
|
||||
Future Ideas
|
||||
------------
|
||||
|
||||
There should be a standard CPU interface, buses, memory map.
|
||||
More like MAME configuration.
|
||||
|
||||
Platforms might have different ideas of "clock" (CPU clock, pixel clock, 1 clock per instruction, etc)
|
||||
|
||||
The goal is to rewind and advance to any clock cycle within a frame, and get complete introspection of events, without hurting performance.
|
||||
|
||||
Unify raster platforms, they should all allow the same debugging and CPU interfaces.
|
||||
|
||||
Separate UI/sim parts of platform?
|
||||
A lot of platforms write into a uint32 buffer.
|
||||
We might want to buffer audio the same way.
|
||||
Also some way to log events, and handle input.
|
||||
|
||||
Figure out how to make platform-specific type for load/save state.
|
||||
(generics?)
|
||||
|
||||
Separate emulators from 8bitworkshop IDE.
|
||||
|
||||
Can we use WASM emulators without JS interop penalty?
|
||||
Maybe using [AssemblyScript](https://docs.assemblyscript.org/)?
|
||||
Startup would be faster, probably runtime too.
|
||||
Drawback is that dynamic stuff (custom breakpoint functions, profiling) might be slow, slower dev too maybe.
|
||||
Need proof-of-concept.
|
10
embed.html
|
@ -13,8 +13,11 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
#emuscreen {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.emuvideo {
|
||||
height:80%;
|
||||
width:90%;
|
||||
border-radius:20px;
|
||||
border: 4px solid #222;
|
||||
outline-color: #666;
|
||||
|
@ -35,6 +38,9 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<body>
|
||||
|
||||
<div id="emulator">
|
||||
<!-- emulator video -->
|
||||
<div id="emuscreen">
|
||||
</div>
|
||||
<div id="javatari-div" style="margin:10px; display:none">
|
||||
<div id="javatari-screen" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
||||
<div id="javatari-console-panel" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
||||
|
@ -44,7 +50,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<script src="jquery/jquery-3.4.1.min.js"></script>
|
||||
|
||||
<script src="javatari.js/release/javatari/javatari.js"></script>
|
||||
<script src="src/cpu/z80fast.js"></script>
|
||||
<script src="src/cpu/z80.js"></script>
|
||||
<script src="jsnes/dist/jsnes.min.js"></script>
|
||||
<script src="src/cpu/6809.js"></script>
|
||||
<script src="FileSaver.js/FileSaver.min.js"></script>
|
||||
|
|
1
ibmfonts
|
@ -1 +0,0 @@
|
|||
Subproject commit 7a9227d43057b6ab6271a2577ecce47fa3360134
|
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 49 KiB |
222
index.html
|
@ -4,6 +4,7 @@
|
|||
<head>
|
||||
<title>8bitworkshop IDE</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<meta name="googlebot" content="nosnippet" />
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="application-name" content="8bitworkshop">
|
||||
|
@ -27,7 +28,6 @@ window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
|
|||
if (window.location.host.endsWith('8bitworkshop.com')) {
|
||||
ga('create', 'UA-54497476-9', 'auto');
|
||||
ga('set', 'anonymizeIp', true);
|
||||
ga('send', 'pageview');
|
||||
}
|
||||
</script>
|
||||
<script async src='https://www.google-analytics.com/analytics.js'></script>
|
||||
|
@ -44,12 +44,14 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<input type="file" id="uploadFileElem" multiple accept="*" style="display:none" onchange="handleFileUpload(this.files)">
|
||||
|
||||
<div id="controls_top" class="disable-select">
|
||||
<span class="dropdown">
|
||||
<a class="btn btn-secondary dropdown-toggle" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Menu">
|
||||
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<div id="controls_dynamic" style="visibility:hidden">
|
||||
<!-- main menu -->
|
||||
<span class="dropdown">
|
||||
<a class="btn dropdown-toggle toolbarMenuButton" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" title="Menu">
|
||||
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-left" aria-labelledby="dropdownMenuButton" style="left:auto">
|
||||
<li><a class="dropdown-item" href="#" id="item_new_file">New Project...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_upload_file">Upload...</a></li>
|
||||
<hr>
|
||||
|
@ -62,17 +64,22 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<hr>
|
||||
<li><a class="dropdown-item" href="#" id="item_addfile_include">Add Include File...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_addfile_link">Add Linked File...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_switch_https" style="display:none">Switch to HTTPS...</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Sync</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#" id="item_github_import">Import Project from GitHub...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_publish">Publish Project on GitHub...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_login">Sign in to Github...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_logout">Log out</a></li>
|
||||
<hr>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_import">Import Project from GitHub...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_pull">Pull Latest from Repository</a></li>
|
||||
<hr>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_publish">Publish Project on GitHub...</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_push">Push Changes to Repository...</a></li>
|
||||
<hr>
|
||||
<li><a class="dropdown-item" href="#" id="item_github_pull">Pull Latest from Repository</a></li>
|
||||
<li><a class="dropdown-item" href="#" id="item_repo_delete">Delete Local Repository...</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
|
@ -101,7 +108,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Tools</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" target="_8bws_tools" href="./tools/fontgen/">Bitmap Font Generator</a></li>
|
||||
<li><a class="dropdown-item" target="_8bws_tools" href="//8bitworkshop.com/bitmapfontgenerator/">Bitmap Font Generator</a></li>
|
||||
<li><a class="dropdown-item" target="_8bws_tools" href="http://tomeko.net/online_tools/file_to_hex.php?lang=en">Binary File to Hex Converter</a></li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Atari 2600/VCS</a>
|
||||
|
@ -114,57 +121,76 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
</li>
|
||||
<hr>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Platform</a>
|
||||
<a tabindex="-1" href="#">About</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" target="_8bws_about" href="https://8bitworkshop.com/">8bitworkshop.com</a></li>
|
||||
<li><a class="dropdown-item" target="_8bws_about" href="https://8bitworkshop.com/blog">Latest News</a></li>
|
||||
<li><a class="dropdown-item" target="_8bws_about" href="https://8bitworkshop.com/projects">Projects</a></li>
|
||||
<li><a class="dropdown-item" target="_8bws_about" href="https://twitter.com/8bitworkshop">Twitter</a></li>
|
||||
<li><a class="dropdown-item" target="_8bws_about" href="https://github.com/sehugg/8bitworkshop">GitHub</a></li>
|
||||
<li><a class="dropdown-item" target="_8bws_about" href="https://github.com/sehugg/8bitworkshop/issues/new">Report an Issue</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<!--
|
||||
<hr><li><a class="dropdown-item" href="/redir.html">Use Latest Version</a></li>
|
||||
-->
|
||||
</ul>
|
||||
</span>
|
||||
|
||||
<!-- PLATFORMS menu -->
|
||||
<span class="dropdown">
|
||||
<a class="btn dropdown-toggle hidden-xs toolbarMenuButton" id="platformsMenuButton" style="min-width:90px" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="platform_name">PLATFORMS</span> <span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="platformsMenuButton">
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Game Consoles</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="?platform=vcs" id="item_platform_vcs">Atari 2600/VCS</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=nes" id="item_platform_nes">NES</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=vcs">Atari 2600/VCS</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=nes">NES</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Computers</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="?platform=apple2" id="item_platform_apple2">Apple ][+</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=apple2">Apple ][+</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Arcade Systems</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="?platform=vicdual" id="item_platform_vicdual">VIC Dual</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=mw8080bw" id="item_platform_mw8080bw">Midway 8080</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=galaxian-scramble" id="item_platform_galaxian_scramble">Galaxian/Scramble Hardware</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=vector-z80color" id="item_platform_vector_z80color">Atari Color Vector (Z80)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=williams-z80" id="item_platform_williams_z80">Williams (Z80)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=sound_williams-z80" id="item_platform_sound_williams_z80">Williams Sound (Z80)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=vicdual">VIC Dual</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=mw8080bw">Midway 8080</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=galaxian-scramble">Galaxian/Scramble</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=vector-z80color">Atari Color Vector (Z80)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=williams-z80">Williams (Z80)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=sound_williams-z80">Williams Sound (Z80)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Hardware</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="?platform=verilog" id="item_platform_verilog">Verilog</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=verilog-vga" id="item_platform_verilog">Verilog (VGA @ 25 Mhz)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=verilog">Verilog</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=verilog-vga">Verilog (VGA @ 25 Mhz)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown dropdown-submenu">
|
||||
<a tabindex="-1" href="#">Other</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="?platform=vcs.mame" id="item_platform_vcs_mame">Atari 2600/VCS (MAME)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=nes.mame" id="item_platform_nes_mame">NES (MAME)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=vector-ataricolor" id="item_platform_nes_mame">Atari Color Vector (6502)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=markdown" id="item_platform_markdown">Markdown</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=vcs.mame">Atari 2600/VCS (MAME)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=nes.mame">NES (MAME)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=vector-ataricolor">Atari Color Vector (6502)</a></li>
|
||||
<li><a class="dropdown-item" href="?platform=markdown">Markdown</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
|
||||
<select id="preset_select" name="" title="Project Select" style="width:18em;visibility:hidden">
|
||||
<!-- project selector -->
|
||||
<select id="preset_select" name="" title="Project Select" style="width:18em;visibility:hidden;height:2.3em">
|
||||
</select>
|
||||
|
||||
<img id="compile_spinner" src="images/spinner.gif" height="20em" style="visibility:hidden;margin-left:8px;margin-right:8px">
|
||||
<img id="compile_spinner" src="images/spinner.gif" style="visibility:hidden;margin-left:8px;margin-right:8px;height:2em">
|
||||
<span id="toolbar" class="hidden-xs"></span>
|
||||
<span class="btn_group view_group hidden-sm hidden-xs" id="speed_bar" style="display:none">
|
||||
<button id="dbg_slowest" class="btn" title="Slowest"><span class="glyphicon glyphicon-fast-backward" aria-hidden="true"></span></button>
|
||||
|
@ -177,35 +203,45 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<span class="label"><span id="settle_label"></span> evals/clk</span>
|
||||
</span>
|
||||
|
||||
<span class="dropdown" style="float:right">
|
||||
<span class="logo-gradient hidden-xs hidden-sm hidden-md">8bitworkshop</span>
|
||||
|
||||
<a class="btn btn-secondary dropdown-toggle hidden-xs" id="booksMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
GET BOOKS <span class="caret"></span>
|
||||
<!-- BOOKS menu -->
|
||||
<span class="dropdown pull-right">
|
||||
<a class="btn dropdown-toggle hidden-xs toolbarMenuButton" id="booksMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="glyphicon glyphicon-book" aria-hidden="true"></span>
|
||||
Books <span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu pull-right" aria-labelledby="dropdownMenuButton">
|
||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="booksMenuButton">
|
||||
<li>
|
||||
<a class="dropdown-item dropdown-link" target="_book_a2600" href="https://www.amazon.com/gp/product/1541021304/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&tag=pzp-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B01N4DSRIZ&linkId=04d39e274c06e6c93b93d20a9a977111">
|
||||
<img src="images/book_a2600.png"/>
|
||||
<b>Making Games For The Atari 2600</b>
|
||||
<span class="book-title">Making Games For The Atari 2600</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item dropdown-link" target="_book_arcade" href="https://www.amazon.com/gp/product/1545484759/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1545484759&linkCode=as2&tag=pzp-20&linkId=b27709c022d2ebe639e90316d9f4fd5b">
|
||||
<img src="images/book_arcade.png"/>
|
||||
<b>Making 8-bit Arcade Games in C</b>
|
||||
<span class="book-title">Making 8-bit Arcade Games in C</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item dropdown-link" target="_book_verilog" href="https://www.amazon.com/gp/product/1728619440/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1728619440&linkCode=as2&tag=pzp-20">
|
||||
<a class="dropdown-item dropdown-link" target="_book_verilog" href="https://www.amazon.com/gp/product/1728619440/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1728619440&linkCode=as2&tag=pzp-20&linkId=7237a25861cb6b49a4128ba53d84c3e2">
|
||||
<img src="images/book_verilog.png"/>
|
||||
<b>Designing Video Game Hardware in Verilog</b>
|
||||
<span class="book-title">Designing Video Game Hardware in Verilog</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item dropdown-link" target="_book_nes" href="https://www.amazon.com/gp/product/1075952727/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1075952727&linkCode=as2&tag=pzp-20&linkId=633176e8b36fea7f927020e2c322d80a">
|
||||
<img src="images/book_nes.png"/>
|
||||
<span class="book-title">Making Games For The NES</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<!--<span id="best_in_firefox" style="display:none;font-size:12px;font-style:italic;float:right;color:#666">Note: Works best in Firefox</span>-->
|
||||
</div>
|
||||
<!-- 8bitworkshop logo -->
|
||||
<span class="logo-gradient hidden-xs hidden-sm hidden-md pull-right" style="margin-left:auto" onclick="window.open('/','_8bitws');">8bitworkshop</span>
|
||||
|
||||
</div><!-- controls_dynamic -->
|
||||
</div><!-- controls_top -->
|
||||
|
||||
<div id="notebook">
|
||||
<div id="sidebar">
|
||||
<ul id="windowMenuList">
|
||||
|
@ -213,7 +249,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
</div>
|
||||
<div id="workspace">
|
||||
</div>
|
||||
<div class="emulator" id="emulator">
|
||||
<div class="emulator disable-select" id="emulator">
|
||||
<div id="replaydiv" class="replaydiv" style="display:none">
|
||||
<div style="display:flex">
|
||||
<button id="replay_min" class="btn" title="Start of replay"><span class="glyphicon glyphicon-fast-backward" aria-hidden="true"></span></button>
|
||||
|
@ -224,10 +260,61 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<button id="replay_max" class="btn" title="End of replay"><span class="glyphicon glyphicon-fast-forward" aria-hidden="true"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- emulator video -->
|
||||
<div id="emuscreen">
|
||||
</div>
|
||||
<div id="javatari-div" style="float:center;margin:10px;display:none">
|
||||
<div id="javatari-screen" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
||||
<div id="javatari-console-panel" style="margin: 0 auto; box-shadow: 2px 2px 10px rgb(60, 60, 60);"></div>
|
||||
</div>
|
||||
<!-- control instructions -->
|
||||
<div class="emucontrols-vcs text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">←↑↓→</span> Joystick</span>
|
||||
<span class="control-def"><span class="control-key small">Space</span> Button</span>
|
||||
</div>
|
||||
<div class="emucontrols-nes text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">←↑↓→</span> Joypad</span>
|
||||
<span class="control-def"><span class="control-key small">Space</span> Button A</span>
|
||||
<span class="control-def"><span class="control-key small">Shift</span> Button B</span>
|
||||
<span class="control-def"><span class="control-key small">\</span> Select</span>
|
||||
<span class="control-def"><span class="control-key small">Enter</span> Start</span>
|
||||
</div>
|
||||
<div class="emucontrols-msx emucontrols-coleco emucontrols-sms text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">←↑↓→</span> Joypad</span>
|
||||
<span class="control-def"><span class="control-key small">Space</span> Button A</span>
|
||||
<span class="control-def"><span class="control-key small">Shift</span> Button B</span>
|
||||
</div>
|
||||
<div class="emucontrols-vicdual emucontrols-galaxian emucontrols-vector text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">←↑↓→</span> Joystick</span>
|
||||
<span class="control-def"><span class="control-key small">Space</span> Button 1</span>
|
||||
<span class="control-def"><span class="control-key small">Shift</span> Button 2</span>
|
||||
<span class="control-def"><span class="control-key">\</span> Coin</span>
|
||||
<span class="control-def"><span class="control-key small">Enter</span> Start</span>
|
||||
</div>
|
||||
<div class="emucontrols-mw8080bw text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">← →</span> Joystick</span>
|
||||
<span class="control-def"><span class="control-key small">Space</span> Fire</span>
|
||||
</div>
|
||||
<div class="emucontrols-williams text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">A W S D</span> Move</span>
|
||||
<span class="control-def"><span class="control-key">←↑↓→</span> Fire</span>
|
||||
<span class="control-def"><span class="control-key">\</span> Coin</span>
|
||||
<span class="control-def"><span class="control-key small">Enter</span> Start</span>
|
||||
<span class="control-def"><span class="control-key small">6 7 8 9</span> Extra</span>
|
||||
</div>
|
||||
<div class="emucontrols-astrocade text-center small control-insns" style="display:none">
|
||||
<span class="control-def"><span class="control-key">←↑↓→</span> Joystick</span>
|
||||
<span class="control-def"><span class="control-key small">Space</span> Trigger</span>
|
||||
<span class="control-def"><span class="control-key small">Mouse X</span> Knob</span>
|
||||
<span class="control-def"><span class="control-key small" style="display:inline-block;font-family:monospace">
|
||||
U I O P<br>
|
||||
J K L /<br>
|
||||
7 8 9 X<br>
|
||||
4 5 6 -<br>
|
||||
1 2 3 ,<br>
|
||||
\ 0 . =</span> Keypad</span>
|
||||
</div>
|
||||
<!-- -->
|
||||
<div id="emuoverlay" class="emuoverlay" style="display:none">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -244,7 +331,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<!--<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>-->
|
||||
<!--</div>-->
|
||||
<div id="pleaseWaitModal" class="modal fade">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-md" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
Please wait...
|
||||
|
@ -294,8 +381,27 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="debugExprModal" class="modal fade">
|
||||
<div class="modal-dialog modal-md" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Break Expression</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Enter a break expression:</p>
|
||||
<p><input id="debugExprInput" size="60"></input></p>
|
||||
<p>Examples:</p>
|
||||
<pre id="debugExprExamples"></pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-primary" id="debugExprSubmit">Debug</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="importGithubModal" class="modal fade">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-md" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Import Project from GitHub</h3>
|
||||
|
@ -303,6 +409,9 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<div class="modal-body">
|
||||
<p>Enter the GitHub repository URL:</p>
|
||||
<p><input id="importGithubURL" size="60" placeholder="https://github.com/user/repo"></input></p>
|
||||
<p>If the project is compatible with 8bitworkshop, it should build automatically.</p>
|
||||
<p>Otherwise, some work may be required -- make sure you've selected the correct platform.</p>
|
||||
<p>Source files must be in the root folder of the repository.</p>
|
||||
<p><button type="button" class="btn btn-primary" id="importGithubButton">Import Project</button></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
@ -312,23 +421,23 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
</div>
|
||||
</div>
|
||||
<div id="publishGithubModal" class="modal fade">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-md" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Publish Project on GitHub</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>This will migrate your existing files to a new GitHub repository.</p>
|
||||
<p><input id="githubRepoName" size="50" placeholder="Enter a project name"></input></p>
|
||||
<p><input id="githubRepoDesc" size="50" placeholder="Enter a project description"></input></p>
|
||||
<p>This will migrate your existing project to a new GitHub repository.</p>
|
||||
<p>https://github.com/username/ <input id="githubRepoName" size="35" placeholder="Enter a project name"></input></p>
|
||||
<p><input id="githubRepoDesc" size="60" placeholder="Enter a project description"></input></p>
|
||||
<p>Your repository will be <select id="githubRepoPrivate">
|
||||
<option value="public">Public</option>
|
||||
<option value="private">Private</option>
|
||||
</select></p>
|
||||
<p>License: <select id="githubRepoLicense">
|
||||
<option value="">Will decide later</option>
|
||||
<option value="cc0-1.0">CC Zero (public domain)</option>
|
||||
<option value="mit">MIT (public domain, must preserve notices)</option>
|
||||
<option value="">Will decide later / all rights reserved</option>
|
||||
<option value="cc0-1.0">CC Zero (public domain, remix-friendly)</option>
|
||||
<option value="mit">MIT (must preserve notices)</option>
|
||||
<option value="cc-by-4.0">CC BY (must attribute)</option>
|
||||
<option value="cc-by-sa-4.0">CC BY-SA (must attribute, use same license)</option>
|
||||
<option value="gpl-3.0">GPL v3 (must publish source)</option>
|
||||
|
@ -343,7 +452,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
</div>
|
||||
</div>
|
||||
<div id="pushGithubModal" class="modal fade">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-md" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3 class="modal-title">Push Project Changes to GitHub</h3>
|
||||
|
@ -363,7 +472,8 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
|
||||
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
|
||||
<script src="bootstrap/js/bootstrap.min.js"></script>
|
||||
<link rel="stylesheet" href="bootstrap-tourist/bootstrap-tourist.min.css">
|
||||
<script src="bootstrap/js/bootbox.all.min.js"></script>
|
||||
<link rel="stylesheet" href="bootstrap-tourist/bootstrap-tourist.css">
|
||||
<script src="bootstrap-tourist/bootstrap-tourist.js"></script>
|
||||
|
||||
<script src="src/codemirror/codemirror.js"></script>
|
||||
|
@ -386,7 +496,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<script src="javatari.js/src/main/Javatari.js"></script>
|
||||
<script src="javatari.js/temp/javatari.part.concat.js"></script>
|
||||
-->
|
||||
<script src="src/cpu/z80fast.js"></script>
|
||||
<script src="src/cpu/z80.js"></script>
|
||||
<script src="jsnes/dist/jsnes.min.js"></script>
|
||||
<script src="src/cpu/6809.js"></script>
|
||||
<!--<script src="jsnes/lib/dynamicaudio-min.js" type="text/javascript" charset="utf-8"></script>-->
|
||||
|
|
3247
lib/w2ui-1.5.rc1.css
18953
lib/w2ui-1.5.rc1.js
|
@ -0,0 +1 @@
|
|||
Subproject commit 53470410c34d2738a9f52e65bf8ffe1eabbef19b
|
|
@ -1,9 +1,18 @@
|
|||
{
|
||||
"name": "8bitworkshop",
|
||||
"version": "3.3.1",
|
||||
"version": "3.4.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/bootbox": {
|
||||
"version": "4.4.36",
|
||||
"resolved": "https://registry.npmjs.org/@types/bootbox/-/bootbox-4.4.36.tgz",
|
||||
"integrity": "sha512-RNNb0guOAm9RXPMOHlRILqLfuNaSjL/VEXej6izAwpWrN7pTtHLLhmh/eCkCLaItcrXuivXNdJLQT2okBT0Dog==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/jquery": "*"
|
||||
}
|
||||
},
|
||||
"@types/bootstrap": {
|
||||
"version": "3.3.42",
|
||||
"resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-3.3.42.tgz",
|
||||
|
@ -231,6 +240,12 @@
|
|||
"graceful-readlink": ">= 1.0.0"
|
||||
}
|
||||
},
|
||||
"commandpost": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/commandpost/-/commandpost-1.4.0.tgz",
|
||||
"integrity": "sha512-aE2Y4MTFJ870NuB/+2z1cXBhSBBzRydVVjzhFC4gtenEhpnj15yu0qptWGJsO9YGrcPZ3ezX8AWb1VA391MKpQ==",
|
||||
"dev": true
|
||||
},
|
||||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||
|
@ -315,6 +330,35 @@
|
|||
"safer-buffer": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"editorconfig": {
|
||||
"version": "0.15.3",
|
||||
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz",
|
||||
"integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^2.19.0",
|
||||
"lru-cache": "^4.1.5",
|
||||
"semver": "^5.6.0",
|
||||
"sigmund": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": {
|
||||
"version": "2.20.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
|
||||
"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"encoding": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
|
||||
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"iconv-lite": "~0.4.13"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
|
@ -382,6 +426,28 @@
|
|||
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
|
||||
"dev": true
|
||||
},
|
||||
"fetch-vcr": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fetch-vcr/-/fetch-vcr-1.1.2.tgz",
|
||||
"integrity": "sha512-bFOx3+5YtViximcqhG05tqMlsyPRXNOmiToDCf6TyVUCKHYP/vGPmn0HUhGVNd1jI0KpElwz+RH3X/ZQo0Asfg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"node-fetch": "^1.6.3",
|
||||
"whatwg-fetch": "^2.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-fetch": {
|
||||
"version": "1.7.3",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
|
||||
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"encoding": "^0.1.11",
|
||||
"is-stream": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"filepath": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filepath/-/filepath-1.1.0.tgz",
|
||||
|
@ -514,6 +580,12 @@
|
|||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
|
||||
"dev": true
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
|
||||
"dev": true
|
||||
},
|
||||
"is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
|
@ -527,9 +599,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"jquery": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
|
||||
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==",
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
|
||||
"integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==",
|
||||
"dev": true
|
||||
},
|
||||
"jsbn": {
|
||||
|
@ -612,9 +684,9 @@
|
|||
}
|
||||
},
|
||||
"lodash": {
|
||||
"version": "4.17.11",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
|
||||
"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
|
||||
"version": "4.17.15",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.sortby": {
|
||||
|
@ -623,6 +695,16 @@
|
|||
"integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
|
||||
"dev": true
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
|
||||
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pseudomap": "^1.0.2",
|
||||
"yallist": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"lzg": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lzg/-/lzg-1.0.0.tgz",
|
||||
|
@ -763,6 +845,12 @@
|
|||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
|
||||
"dev": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz",
|
||||
"integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw==",
|
||||
"dev": true
|
||||
},
|
||||
"nwsapi": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.0.tgz",
|
||||
|
@ -775,6 +863,17 @@
|
|||
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"octokat": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/octokat/-/octokat-0.10.0.tgz",
|
||||
"integrity": "sha512-VJ21L1gMlByYMurduLYiOcI8AwlZkUV8OXRN8pMXsbkIqIVqn0tgdTfxzWM9spX4VJTTG02OgqwDTqQsOmDing==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fetch-vcr": "^1.1.0",
|
||||
"lodash": "^4.16.4",
|
||||
"node-fetch": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
|
@ -840,6 +939,12 @@
|
|||
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
|
||||
"dev": true
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
|
||||
"dev": true
|
||||
},
|
||||
"psl": {
|
||||
"version": "1.1.31",
|
||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
|
||||
|
@ -951,6 +1056,18 @@
|
|||
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
},
|
||||
"sigmund": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
|
||||
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
|
@ -1052,11 +1169,21 @@
|
|||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz",
|
||||
"integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==",
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
|
||||
"integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript-formatter": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript-formatter/-/typescript-formatter-7.2.2.tgz",
|
||||
"integrity": "sha512-V7vfI9XArVhriOTYHPzMU2WUnm5IMdu9X/CPxs8mIMGxmTBFpDABlbkBka64PZJ9/xgQeRpK8KzzAG4MPzxBDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commandpost": "^1.0.0",
|
||||
"editorconfig": "^0.15.0"
|
||||
}
|
||||
},
|
||||
"uri-js": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||
|
@ -1113,6 +1240,12 @@
|
|||
"iconv-lite": "0.4.24"
|
||||
}
|
||||
},
|
||||
"whatwg-fetch": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz",
|
||||
"integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==",
|
||||
"dev": true
|
||||
},
|
||||
"whatwg-mimetype": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
|
||||
|
@ -1162,6 +1295,12 @@
|
|||
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-1.3.1.tgz",
|
||||
"integrity": "sha512-tGkGJkN8XqCod7OT+EvGYK5Z4SfDQGD30zAa58OcnAa0RRWgzUEK72tkXhsX1FZd+rgnhRxFtmO+ihkp8LHSkw==",
|
||||
"dev": true
|
||||
},
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
18
package.json
|
@ -1,9 +1,16 @@
|
|||
{
|
||||
"name": "8bitworkshop",
|
||||
"version": "3.4.0",
|
||||
"version": "3.4.1",
|
||||
"author": "Steven Hugg",
|
||||
"description": "8bitworkshop.com",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/sehugg/8bitworkshop.git"
|
||||
},
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/bootbox": "^4.4.36",
|
||||
"@types/bootstrap": "^3.3.42",
|
||||
"@types/jquery": "^3.3.29",
|
||||
"@types/w2ui": "^1.4.x",
|
||||
|
@ -16,10 +23,10 @@
|
|||
"mocha": "^5.2.x",
|
||||
"octokat": "^0.10.0",
|
||||
"pngjs": "^3.3.3",
|
||||
"typescript": "^3.3.3",
|
||||
"typescript": "^3.5.3",
|
||||
"typescript-formatter": "^7.2.2",
|
||||
"wavedrom-cli": "^0.5.x"
|
||||
},
|
||||
"description": "8bitworkshop.com",
|
||||
"main": "main.js",
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
|
@ -34,14 +41,9 @@
|
|||
"test-platforms": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 test/cli/testplatforms.js",
|
||||
"test-profile": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 --prof test/cli"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/sehugg/8bitworkshop.git"
|
||||
},
|
||||
"keywords": [
|
||||
"8bit"
|
||||
],
|
||||
"license": "GPL-3.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/sehugg/8bitworkshop/issues"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
/*
|
||||
NOTE: The alternate Apple ][ ROM used by 8bitworkshop
|
||||
is not compatible with the hi-res TGI driver.
|
||||
So we use the lo-res driver here.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <cc65.h>
|
||||
|
|
|
@ -0,0 +1,392 @@
|
|||
|
||||
; ****** HVGLIB.H (formally called ballyequ.h) (C)1977,78
|
||||
; *** Bally Astrocade Equates and Macros Header File ***
|
||||
; From the nutting_manual and reformatted using Mixed Case
|
||||
; Version 3.01 - thru December 29, 2010
|
||||
; by Richard C Degler, from scratch
|
||||
;
|
||||
; > Retyped and proofread by Adam Trionfo and Lance F. Squire
|
||||
; > Version 1.0 (as ballyequ.h) - January 17, 2002
|
||||
; > Version 2.52 (Version 1.0 of HVGLIB.H) - March 28, 2003
|
||||
; > Version 2.6 - March 2, 2004 - as seen on BallyAlley.com
|
||||
; > Version 3.0 - 2009
|
||||
; > Version 3.01 - Changed "FonT BASE character" comment
|
||||
;
|
||||
; ***************************
|
||||
; * Home Video Game =ates *
|
||||
; ***************************
|
||||
;
|
||||
; ASSEMBLY CONTROL
|
||||
;
|
||||
XPNDON = 1 ; ** SET TO 1 WHEN HARDWARE EXP
|
||||
NWHDWR = 1 ; ** SET TO 1 WHEN NEW HARDWARE
|
||||
;
|
||||
; General goodies (HEX and Decimal values):
|
||||
NORMEM = 0x4000 ; 8192 ; NORmal MEMory start
|
||||
FIRSTC = 0x2000 ; 4096 ; FIRST address in Cartridge
|
||||
SCREEN = 0x0000 ; 0 ; magic SCREEN start
|
||||
BYTEPL = 0x28 ; 40 ; BYTEs Per Line
|
||||
BITSPL = 0xA0 ; 160 ; BITS Per Line
|
||||
;
|
||||
; Stuff in SYSTEM DOPE VECTOR (valid for ALL system ROMs):
|
||||
STIMER = 0x0200 ; Seconds and game TIMER, music
|
||||
CTIMER = 0x0203 ; Custom TIMERs
|
||||
FNTSYS = 0x0206 ; FoNT descriptor for SYStem font
|
||||
FNTSML = 0x020D ; FoNT descriptor for SMaLl font
|
||||
ALKEYS = 0x0214 ; ALl KEYS keypad mask
|
||||
MENUST = 0x0218 ; head of onboard MENU STart
|
||||
MXSCR = 0x021E ; address of 'MaX SCoRe' text string
|
||||
NOPLAY = 0x0228 ; address of 'Number Of PLAYers' string
|
||||
NOGAME = 0x0235 ; address of 'Number Of GAMEs' string
|
||||
;
|
||||
; BITS in PROCESSOR FLAG byte:
|
||||
PSWCY = 0 ; Processor Status Word, CarrY bit
|
||||
PSWPV = 2 ; Processor Status Word, Parity or oVerflow bit
|
||||
PSWZRO = 6 ; Processor Status Word, ZeRO bit
|
||||
PSWSGN = 7 ; Processor Status Word, SiGN bit
|
||||
;
|
||||
; BITS in GAME STATUS Byte:
|
||||
GSBTIM = 0 ; Game Status Byte, if TIMe is up set end bit
|
||||
GSBSCR = 1 ; Game Status Byte, if SCoRe reached set end bit
|
||||
GSBEND = 7 ; Game Status Byte, END flag bit
|
||||
;
|
||||
; Standard VECTOR DISPLACEMENTS and bits:
|
||||
VBMR = 0x00 ; +0 ; Vector Block, Magic Register
|
||||
VBSTAT = 0x01 ; +1 ; Vector Block, STATus byte
|
||||
VBTIMB = 0x02 ; +2 ; Vector Block, TIMe Base
|
||||
VBDXL = 0x03 ; +3 ; Vector Block, Delta for X Low
|
||||
VBDXH = 0x04 ; +4 ; Vector Block, Delta for X Hi
|
||||
VBXL = 0x05 ; +5 ; Vector Block, X coord Low
|
||||
VBXH = 0x06 ; +6 ; Vector Block, X coord Hi
|
||||
VBXCHK = 0x07 ; +7 ; Vector Block, X CHecK flags
|
||||
VBDYL = 0x08 ; +8 ; Vector Block, Delta for Y Low
|
||||
VBDYH = 0x09 ; +9 ; Vector Block, Delta for Y Hi
|
||||
VBYL = 0x0A ; +10 ; Vector Block, Y coord Low
|
||||
VBYH = 0x0B ; +11 ; Vector Block, Y coord Hi
|
||||
VBYCHK = 0x0C ; +12 ; Vector Block, Y CHecK flags
|
||||
VBOAL = 0x0D ; +13 ; Vector Block, Old Address Low
|
||||
VBOAH = 0x0E ; +14 ; Vector Block, Old Address Hi
|
||||
;
|
||||
; DISPLACEMENTS from start of COORDINATE AREA (X or Y):
|
||||
VBDCL = 0x00 ; +0 ; Vector Block, Delta for Coord Low
|
||||
VBDCH = 0x01 ; +1 ; Vector Block, Delta for Coord Hi
|
||||
VBCL = 0x02 ; +2 ; Vector Block, Coord Low
|
||||
VBCH = 0x03 ; +3 ; Vector Block, Coord Hi
|
||||
VBCCHK = 0x04 ; +4 ; Vector Block, Coord CHecK flags
|
||||
;
|
||||
; BITS in STATUS byte:
|
||||
VBBLNK = 6 ; Vector Block status, BLaNK bit
|
||||
VBSACT = 7 ; Vector Block Status, ACTive bit
|
||||
;
|
||||
; BITS in (X or Y) VB CHECK FLAG bit mask:
|
||||
VBCLMT = 0 ; Vector Block Check, LiMiT bit
|
||||
VBCREV = 1 ; Vector Block Check, REVerse delta on limit attain
|
||||
VBCLAT = 3 ; Vector Block Check, coordinate Limit ATtained
|
||||
;
|
||||
; FONT TABLE DISPLACEMENTS for CHARACTER DESCRIPTOR BLOCK:
|
||||
FTBASE = 0x00 ; +0 ; FonT BASE character (normally 0xA0)
|
||||
FTFSX = 0x01 ; +1 ; FonT Frame X Size width
|
||||
FTFSY = 0x02 ; +2 ; FonT Frame Y Size height
|
||||
FTBYTE = 0x03 ; +3 ; FonT X size for char in BYTEs
|
||||
FTYSIZ = 0x04 ; +4 ; FonT Y SIZe height in rows
|
||||
FTPTL = 0x05 ; +5 ; FonT Pattern Table address Low
|
||||
FTPTH = 0x06 ; +6 ; FonT Pattern Table address Hi
|
||||
;
|
||||
; BITS for MAGIC REGISTER (write option) byte:
|
||||
MRSHFT = 0x03 ; Magic Register, mask of SHiFT amount 0-3
|
||||
MRROT = 2 ; Magic Register, write with ROTata bit
|
||||
MRXPND = 3 ; Magic Register, write with eXPaND bit
|
||||
MROR = 4 ; Magic Register, write with OR bit
|
||||
MRXOR = 5 ; Magic Register, write with eXclusive-OR bit
|
||||
MRFLOP = 6 ; Magic Register, write with FLOP bit
|
||||
;
|
||||
; BITS of CONTROL HANDLE Input port:
|
||||
CHUP = 0 ; Control Handle, UP bit
|
||||
CHDOWN = 1 ; Control Handle, DOWN bit
|
||||
CHLEFT = 2 ; Control Handle, joystick LEFT bit
|
||||
CHRIGH = 3 ; Control Handle, joystick RIGHT bit
|
||||
CHTRIG = 4 ; Control Handle, TRIGger bit
|
||||
;
|
||||
; CONTEXT BLOCK Register DISPLACEMENTS:
|
||||
CBIYL = 0x00 ; +0 ; Context Block, IY register Low
|
||||
CBIYH = 0x01 ; +1 ; Context Block, IY register Hi
|
||||
CBIXL = 0x02 ; +2 ; Context Block, IX register Low
|
||||
CBIXH = 0x03 ; +3 ; Context Block, IX register Hi
|
||||
CBE = 0x04 ; +4 ; Context Block, E register
|
||||
CBD = 0x05 ; +5 ; Context Block, D register
|
||||
CBC = 0x06 ; +6 ; Context Block, C register
|
||||
CBB = 0x07 ; +7 ; Context Block, B register
|
||||
CBFLAG = 0x08 ; +8 ; Context Block, FLAGs register
|
||||
CBA = 0x09 ; +9 ; Context Block, A register
|
||||
CBL = 0x0A ; +10 ; Context Block, L register
|
||||
CBH = 0x0B ; +11 ; Context Block, H register
|
||||
;
|
||||
; SENTRY RETURN Codes =ates:
|
||||
SNUL = 0x00 ; Sentry return NULl, nothing happened
|
||||
SCT0 = 0x01 ; Sentry, Counter-Timer 0 has counted down
|
||||
SCT1 = 0x02 ; Sentry, Counter-Timer 1 has counted down
|
||||
SCT2 = 0x03 ; Sentry, Counter-Timer 2 has counted down
|
||||
SCT3 = 0x04 ; Sentry, Counter-Timer 3 has counted down
|
||||
SCT4 = 0x05 ; Sentry, Counter-Timer 4 has counted down
|
||||
SCT5 = 0x06 ; Sentry, Counter-Timer 5 has counted down
|
||||
SCT6 = 0x07 ; Sentry, Counter-Timer 6 has counted down
|
||||
SCT7 = 0x08 ; Sentry, Counter-Timer 7 has counted down
|
||||
SF0 = 0x09 ; Sentry, Flag bit 0 has changed
|
||||
SF1 = 0x0A ; Sentry, Flag bit 1 has changed
|
||||
SF2 = 0x0B ; Sentry, Flag bit 2 has changed
|
||||
SF3 = 0x0C ; Sentry, Flag bit 3 has changed
|
||||
SF4 = 0x0D ; Sentry, Flag bit 4 has changed
|
||||
SF5 = 0x0E ; Sentry, Flag bit 5 has changed
|
||||
SF6 = 0x0F ; Sentry, Flag bit 6 has changed
|
||||
SF7 = 0x10 ; Sentry, Flag bit 7 has changed
|
||||
SSEC = 0x11 ; Sentry, SEConds timer has counted down
|
||||
SKYU = 0x12 ; Sentry, KeY is now Up
|
||||
SKYD = 0x13 ; Sentry, KeY is now Down
|
||||
ST0 = 0x14 ; Sentry, Trigger 0 for player 1 has changed
|
||||
SJ0 = 0x15 ; Sentry, Joystick 0 for player 1 has changed
|
||||
ST1 = 0x16 ; Sentry, Trigger 1 for player 2 has changed
|
||||
SJ1 = 0x17 ; Sentry, Joystick 1 for player 2 has changed
|
||||
ST2 = 0x18 ; Sentry, Trigger 2 for player 3 has changed
|
||||
SJ2 = 0x19 ; Sentry, Joystick 2 for player 3 has changed
|
||||
ST3 = 0x1A ; Sentry, Trigger 3 for player 4 has changed
|
||||
SJ3 = 0x1B ; Sentry, Joystick 3 for player 4 has changed
|
||||
SP0 = 0x1C ; Sentry, POTentiometer 0 has changed
|
||||
SP1 = 0x1D ; Sentry, POTentiometer 1 has changed
|
||||
SP2 = 0x1E ; Sentry, POTentiometer 2 has changed
|
||||
SP3 = 0x1F ; Sentry, POTentiometer 3 has changed
|
||||
;
|
||||
;
|
||||
; ********************************
|
||||
; * Home Video Game PORT =ates *
|
||||
; ********************************
|
||||
;
|
||||
; OUTPUT Ports for VIRTUAL COLOR:
|
||||
COL0R = 0x00 ; &(0)= ; write COLor 0 Right
|
||||
COL1R = 0x01 ; &(1)= ; write COLor 1 Right
|
||||
COL2R = 0x02 ; &(2)= ; write COLor 2 Right
|
||||
COL3R = 0x03 ; &(3)= ; write COLor 3 Right
|
||||
COL0L = 0x04 ; &(4)= ; write COLor 0 Left
|
||||
COL1L = 0x05 ; &(5)= ; write COLor 1 Left
|
||||
COL2L = 0x06 ; &(6)= ; write COLor 2 Left
|
||||
COL3L = 0x07 ; &(7)= ; write COLor 3 Left
|
||||
HORCB = 0x09 ; &(9)= ; write HORizontal Color Boundary
|
||||
VERBL = 0x0A ;&(10)= ; write VERtical Blanking Line
|
||||
COLBX = 0x0B ;&(11)= ; write COLor BloCK multi-port
|
||||
;
|
||||
; OUTPUT Ports for MUSIC and SOUNDS:
|
||||
TONMO = 0x10 ;&(16)= ; write TONe Master Oscillator
|
||||
TONEA = 0x11 ;&(17)= ; write TONe A oscillator
|
||||
TONEB = 0x12 ;&(18)= ; write TONe B oscillator
|
||||
TONEC = 0x13 ;&(19)= ; write TONe C oscillator
|
||||
VIBRA = 0x14 ;&(20)= ; write VIBRAto frequency & range
|
||||
VOLC = 0x15 ;&(21)= ; write VOLume of tone C
|
||||
VOLAB = 0x16 ;&(22)= ; write VOLumes of tones A & B
|
||||
VOLN = 0x17 ;&(23)= ; write VOLume of Noise
|
||||
SNDBX = 0x18 ;&(24)= ; write SouND BloCK multi-port
|
||||
;
|
||||
; INTERRUPT and CONTROL OUTPUT Ports:
|
||||
CONCM = 0x08 ; &(8)= ; write 0 for CONsumer, 1 for CoMmercial mode
|
||||
MAGIC = 0x0C ;&(12)= ; write MAGIC register
|
||||
INFBK = 0x0D ;&(13)= ; write INterrupt FeedBacK
|
||||
INMOD = 0x0E ;&(14)= ; write INterrupt MODe
|
||||
INLIN = 0x0F ;&(15)= ; write INterrupt LINe
|
||||
XPAND = 0x19 ;&(25)= ; eXPANDer pixel definition port
|
||||
;
|
||||
; INTERRUPT and INTERCEPT INPUT Ports:
|
||||
INTST = 0x08 ; =&(8) ; read INTercept STatus
|
||||
VERAF = 0x0E ;=&(14) ; read VERtical Address Feedback
|
||||
HORAF = 0x0F ;=&(15) ; read HORizontal Address Feedback
|
||||
;
|
||||
; HAND CONTROL INPUT Ports:
|
||||
SW0 = 0x10 ;=&(16) ; read SWitch bank 0 for player 1 hand control
|
||||
SW1 = 0x11 ;=&(17) ; read SWitch bank 1 for player 2 hand control
|
||||
SW2 = 0x12 ;=&(18) ; read SWitch bank 2 for player 3 hand control
|
||||
SW3 = 0x13 ;=&(19) ; read SWitch bank 3 for player 4 hand control
|
||||
POT0 = 0x1C ;=&(28) ; read POTentiometer 0 for player 1 knob
|
||||
POT1 = 0x1D ;=&(29) ; read POTentiometer 1 for player 2 knob
|
||||
POT2 = 0x1E ;=&(30) ; read POTentiometer 2 for player 3 knob
|
||||
POT3 = 0x1F ;=&(31) ; read POTentiometer 3 for player 4 knob
|
||||
;
|
||||
; KEYBOARD INPUT Ports:
|
||||
KEY0 = 0x14 ;=&(20) ; KEYboard column 0 (right side)
|
||||
KEY1 = 0x15 ;=&(21) ; KEYboard column 1 (center right)
|
||||
KEY2 = 0x16 ;=&(22) ; KEYboard column 2 (center left)
|
||||
KEY3 = 0x17 ;=&(23) ; KEYboard column 3 (left side)
|
||||
;
|
||||
;
|
||||
; ***************************************
|
||||
; * Home Video Game SYSTEM CALL Indexes *
|
||||
; ***************************************
|
||||
;
|
||||
; USER PROGRAM Interface:
|
||||
INTPC = 0x00 ; # 0 ; INTerPret with Context create
|
||||
XINTC = 0x02 ; # 2 ; eXit INTerpreter with Context
|
||||
RCALL = 0x04 ; # 4 ; Real CALL asm language subroutine
|
||||
MCALL = 0x06 ; # 6 ; Macro CALL interpreter subroutine
|
||||
MRET = 0x08 ; # 8 ; Macro RETurn from interpreter subroutine
|
||||
MJUMP = 0x0A ; # 10 ; Macro JUMP to interpreter subroutine
|
||||
SUCK = 0x0C ; # 12 ; SUCK inline args into context block
|
||||
;
|
||||
; SCHEDULER Routines:
|
||||
ACTINT = 0x0E ; # 14 ; ACTivate sub timer INTerrupts
|
||||
DECCTS = 0x10 ; # 16 ; DECrement CTS under mask
|
||||
;
|
||||
; MUSIC and SOUNDS:
|
||||
BMUSIC = 0x12 ; # 18 ; Begin playing MUSIC
|
||||
EMUSIC = 0x14 ; # 20 ; End playing MUSIC
|
||||
;
|
||||
; SCREEN HANDLER Routines:
|
||||
SETOUT = 0x16 ; # 22 ; SET some OUTput ports
|
||||
COLSET = 0x18 ; # 24 ; COLors SET
|
||||
FILL = 0x1A ; # 26 ; FILL memory with data
|
||||
RECTAN = 0x1C ; # 28 ; paint a RECTANgle
|
||||
VWRITR = 0x1E ; # 30 ; Vector WRITe Relative
|
||||
WRITR = 0x20 ; # 32 ; WRITe Relative
|
||||
WRITP = 0x22 ; # 34 ; WRITe with Pattern size lookup
|
||||
WRIT = 0x24 ; # 36 ; WRITe with sizes provided
|
||||
WRITA = 0x26 ; # 38 ; WRITe Absolute
|
||||
VBLANK = 0x28 ; # 40 ; Vector BLANK area
|
||||
BLANK = 0x2A ; # 42 ; BLANK area
|
||||
SAVE = 0x2C ; # 44 ; SAVE area
|
||||
RESTOR = 0x2E ; # 46 ; RESTORe area
|
||||
SCROLL = 0x30 ; # 48 ; SCROLL area of screen
|
||||
;
|
||||
CHRDIS = 0x32 ; # 50 ; CHaRacter DISplay
|
||||
STRDIS = 0x34 ; # 52 ; STRing DISplay
|
||||
DISNUM = 0x36 ; # 54 ; DISplay NUMber
|
||||
;
|
||||
RELABS = 0x38 ; # 56 ; RELative to ABSolute conversion
|
||||
RELAB1 = 0x3A ; # 58 ; RELative to non-magic ABSolute
|
||||
VECTC = 0x3C ; # 60 ; VECTor move single Coordinate
|
||||
VECT = 0x3E ; # 62 ; VECTor move coordinate pair
|
||||
;
|
||||
; HUMAN INTERFACE Routines:
|
||||
KCTASC = 0x40 ; # 64 ; Key Code in B To ASCii
|
||||
SENTRY = 0x42 ; # 66 ; SENse TRansition Y
|
||||
DOIT = 0x44 ; # 68 ; DOIT table, branch to translation handler
|
||||
DOITB = 0x46 ; # 70 ; DOIT table, use B instead of A
|
||||
PIZBRK = 0x48 ; # 72 ; take a PIZza BReaK
|
||||
MENU = 0x4A ; # 74 ; display a MENU
|
||||
GETPAR = 0x4C ; # 76 ; GET game PARameter from user
|
||||
GETNUM = 0x4E ; # 78 ; GET NUMber from user
|
||||
PAWS = 0x50 ; # 80 ; PAUSE
|
||||
DISTIM = 0x52 ; # 82 ; DISplay TIMe
|
||||
INCSCR = 0x54 ; # 84 ; INCrement SCoRe
|
||||
;
|
||||
; MATH Routines:
|
||||
INDEXN = 0x56 ; # 86 ; INDEX Nibble by C
|
||||
STOREN = 0x58 ; # 88 ; STORE Nibble in A by C
|
||||
INDEXW = 0x5A ; # 90 ; INDEX Word by A
|
||||
INDEXB = 0x5C ; # 92 ; INDEX Byte by A
|
||||
MOVE = 0x5E ; # 94 ; MOVE block transfer
|
||||
SHIFTU = 0x60 ; # 96 ; SHIFT Up digit in A
|
||||
BCDADD = 0x62 ; # 98 ; BCD ADDition
|
||||
BCDSUB = 0x64 ;# 100 ; BCD SUBtraction
|
||||
BCDMUL = 0x66 ;# 102 ; BCD MULtiplication
|
||||
BCDDIV = 0x68 ;# 104 ; BCD DIVision
|
||||
BCDCHS = 0x6A ;# 106 ; BCD CHange Sign
|
||||
BCDNEG = 0x6C ;# 108 ; BCD NEGate to decimal
|
||||
DADD = 0x6E ;# 110 ; Decimal ADDition
|
||||
DSMG = 0x70 ;# 112 ; Decimal convert to Sign MaGnitude
|
||||
DABS = 0x72 ;# 114 ; Decimal ABSolute value
|
||||
NEGT = 0x74 ;# 116 ; decimal NEGaTe
|
||||
RANGED = 0x76 ;# 118 ; RANGED random number
|
||||
QUIT = 0x78 ;# 120 ; QUIT cassette execution
|
||||
SETB = 0x7A ;# 122 ; SET Byte
|
||||
SETW = 0x7C ;# 124 ; SET Word
|
||||
MSKTD = 0x7E ;# 127 ; MaSK joystick in B To Deltas
|
||||
;
|
||||
;
|
||||
; ***************************
|
||||
; * SYSTEM RAM MEMORY Cells *
|
||||
; ***************************
|
||||
WASTE = 0x0FFF
|
||||
WASTER = WASTE
|
||||
;
|
||||
SYSRAM = 0x4FCE ; Resides at the highest possible address
|
||||
BEGRAM = SYSRAM ; typically used for initial Stack Pointer
|
||||
; Used by MUSIC PROCESSOR:
|
||||
MUZPC = 0x4FCE ; MUSic Program Counter
|
||||
MUZSP = 0x4FD0 ; MUSic Stack Pointer
|
||||
PVOLAB = 0x4FD2 ; Preset VOLume for tones A and B
|
||||
PVOLMC = 0x4FD3 ; Preset VOLuMe for tone C and Noise Mode
|
||||
VOICES = 0x4FD4 ; music VOICES mask
|
||||
; COUNTER TIMERS (used by DECCTS,ACTINT,CTIMER):
|
||||
CT0 = 0x4FD5 ; Counter Timer 0
|
||||
CT1 = 0x4FD6 ; Counter Timer 1
|
||||
CT2 = 0x4FD7 ; Counter Timer 2
|
||||
CT3 = 0x4FD8 ; Counter Timer 3
|
||||
CT4 = 0x4FD9 ; Counter Timer 4
|
||||
CT5 = 0x4FDA ; Counter Timer 5
|
||||
CT6 = 0x4FDB ; Counter Timer 6
|
||||
CT7 = 0x4FDC ; Counter Timer 7
|
||||
;Used by SENTRY to track controls:
|
||||
CNT = 0x4FDD ; Counter update & Number Tracking
|
||||
SEMI4S = 0x4FDE ; SEMAPHORE flag bitS
|
||||
OPOT0 = 0x4FDF ; Old POT 0 tracking byte
|
||||
OPOT1 = 0x4FE0 ; Old POT 1 tracking byte
|
||||
OPOT2 = 0x4FE1 ; Old POT 2 tracking byte
|
||||
OPOT3 = 0x4FE2 ; Old POT 3 tracking byte
|
||||
KEYSEX = 0x4FE3 ; KEYS-EX tracking byte
|
||||
OSW0 = 0x4FE4 ; Old SWitch 0 tracking byte
|
||||
OSW1 = 0x4FE5 ; Old SWitch 1 tracking byte
|
||||
OSW2 = 0x4FE6 ; Old SWitch 2 tracking byte
|
||||
OSW3 = 0x4FE7 ; Old SWitch 3 tracking byte
|
||||
COLLST = 0x4FE8 ; COLset LaST address for P.B. A
|
||||
; Used by STIMER:
|
||||
DURAT = 0x4FEA ; note DURATion
|
||||
TMR60 = 0x4FEB ; TiMeR for SIXTYths of sec
|
||||
TIMOUT = 0x4FEC ; TIMer for blackOUT
|
||||
GTSECS = 0x4FED ; Game Time SECondS
|
||||
GTMINS = 0x4FEE ; Game Time MINuteS
|
||||
; Used by MENU:
|
||||
RANSHT = 0x4FEF ; RANdom number SHifT register
|
||||
NUMPLY = 0x4FF3 ; NUMber of PLaYers
|
||||
ENDSCR = 0x4FF4 ; END SCoRe to 'play to'
|
||||
MRLOCK = 0x4FF7 ; Magic Register LOCK out flag
|
||||
GAMSTB = 0x4FF8 ; GAMe STatus Byte
|
||||
PRIOR = 0x4FF9 ; PRIOR music protect flag
|
||||
SENFLG = 0x4FFA ; SENtry control seizure FLaG
|
||||
; User UPI Routines, even numbers from 0x80 to 0xFE ( + 1 for SUCK):
|
||||
UMARGT = 0x4FFB ; User Mask ARGument Table + (routine / 2)
|
||||
USERTB = 0x4FFD ; USER Table Base + routine = JumP address
|
||||
;
|
||||
URINAL = 0x4FFF ; WASTER flushes here!
|
||||
;
|
||||
;
|
||||
|
||||
;
|
||||
; MACROs to generate SYSTEM CALLs:
|
||||
.macro SYSTEM NUMBA
|
||||
rst 0x38
|
||||
.db NUMBA
|
||||
; .if NUMBA = INTPC
|
||||
;INTPCC = 1
|
||||
; .endif
|
||||
.endm
|
||||
; MACRO to generate SYSTEM CALL with SUCK option ON:
|
||||
.macro SYSSUK UMBA
|
||||
rst 0x38
|
||||
.db UMBA + 1
|
||||
; .if UMBA = INTPC
|
||||
;INTPCC = 1
|
||||
; .endif
|
||||
.endm
|
||||
; MACROs to generate MACRO INTERPRETER CALLs:
|
||||
; INTERPRET without INLINE SUCK:
|
||||
.macro DONT CID
|
||||
.db CID
|
||||
.endm
|
||||
; INTERPRET with INLINE SUCK option ON:
|
||||
.macro DO CID
|
||||
.db CID + 1
|
||||
.endm
|
||||
;
|
||||
; EXIT interpreter with context restore:
|
||||
.macro EXIT
|
||||
.db XINTC
|
||||
;INTPCC = 0
|
||||
.endm
|
||||
;
|
||||
ENDx = 0xC0 ; END of DOIT Table
|
||||
;
|
|
@ -1,61 +1,38 @@
|
|||
|
||||
|
||||
#define TEST
|
||||
/**
|
||||
AstroLibre
|
||||
An open source Bally Astrocade BIOS implementation in C
|
||||
by Steven Hugg (@sehugg) for 8bitworkshop.com
|
||||
|
||||
To the extent possible under law, the author(s) have
|
||||
dedicated all copyright and related and neighboring
|
||||
rights to this software to the public domain worldwide.
|
||||
This software is distributed without any warranty.
|
||||
|
||||
See: http://creativecommons.org/publicdomain/zero/1.0/
|
||||
**/
|
||||
|
||||
//#resource "astrocade.inc"
|
||||
//#link "biosasm.s"
|
||||
|
||||
// demo code
|
||||
//#link "test1.s"
|
||||
|
||||
// music processor
|
||||
//#link "bmusic.c"
|
||||
|
||||
// input
|
||||
//#link "input.c"
|
||||
|
||||
// graphics
|
||||
//#link "gfx.c"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
typedef signed short sword;
|
||||
#include "bios.h"
|
||||
|
||||
/// HARDWARE
|
||||
|
||||
__sfr __at(0x00) hw_col0r; // palette 0
|
||||
__sfr __at(0x01) hw_col1r;
|
||||
__sfr __at(0x02) hw_col2r;
|
||||
__sfr __at(0x03) hw_col3r;
|
||||
__sfr __at(0x04) hw_col0l;
|
||||
__sfr __at(0x05) hw_col1l;
|
||||
__sfr __at(0x06) hw_col2l;
|
||||
__sfr __at(0x07) hw_col3l; // palette 7
|
||||
|
||||
__sfr __at(0x08) hw_intst; // intercept test feedback
|
||||
__sfr __at(0x09) hw_horcb; // horiz color boundary
|
||||
__sfr __at(0x0a) hw_verbl; // vertical blanking line * 2
|
||||
__sfr __at(0x0c) hw_magic; // magic register
|
||||
__sfr __at(0x0d) hw_infbk; // interrupt feedback
|
||||
__sfr __at(0x0e) hw_inmod; // interrupt enable
|
||||
__sfr __at(0x0f) hw_inlin; // interrupt line
|
||||
__sfr __at(0x19) hw_xpand; // expander register
|
||||
|
||||
__sfr __at(0x10) hw_p1ctrl; // player controls
|
||||
__sfr __at(0x11) hw_p2ctrl; // player controls
|
||||
__sfr __at(0x12) hw_p3ctrl; // player controls
|
||||
__sfr __at(0x13) hw_p4ctrl; // player controls
|
||||
|
||||
#define M_SHIFT0 0x00
|
||||
#define M_SHIFT1 0x01
|
||||
#define M_SHIFT2 0x02
|
||||
#define M_SHIFT3 0x03
|
||||
#define M_XPAND 0x08
|
||||
#define M_MOVE 0x00
|
||||
#define M_OR 0x10
|
||||
#define M_XOR 0x20
|
||||
#define M_FLOP 0x40
|
||||
#define M_SHIFT(x) ((x)&3)
|
||||
#define XPAND_COLORS(off,on) (((off)&3) | (((on)&3)<<2))
|
||||
|
||||
/// GRAPHICS FUNCTIONS
|
||||
|
||||
#define VHEIGHT 89 // number of scanlines
|
||||
#define VBWIDTH 40 // number of bytes per scanline
|
||||
#define PIXWIDTH 160 // 4 pixels per byte
|
||||
|
||||
#define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return
|
||||
|
||||
byte __at (0x0000) vmagic[VHEIGHT][VBWIDTH];
|
||||
byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH];
|
||||
// uncomment to make code better, but slower compile
|
||||
#pragma opt_code_speed
|
||||
|
||||
// start @ $4FCE
|
||||
volatile word MUZPC; // music PC
|
||||
|
@ -66,6 +43,7 @@ volatile byte VOICES; // voice smask
|
|||
|
||||
volatile byte CT[8]; // counter timers
|
||||
|
||||
// for SENTRY
|
||||
volatile byte CNT;
|
||||
volatile byte SEMI4S;
|
||||
volatile byte OPOT[4];
|
||||
|
@ -90,105 +68,62 @@ byte SENFLG; // sentry control
|
|||
byte* UMARGT; // user mask table (-64 bytes)
|
||||
word* USERTB; // user routine table (-128 bytes)
|
||||
|
||||
// start routine @ 0x0
|
||||
void bios_start() __naked {
|
||||
__asm
|
||||
DI ; disable interrupts
|
||||
LD HL,#0x2000
|
||||
LD A,(HL) ; A <- mem[0x2000]
|
||||
CP #0x55 ; found sentinel byte? ($55)
|
||||
JP Z,FoundSentinel ; yes, load program
|
||||
#ifndef TEST
|
||||
JP 0x2000 ; jump to $2000
|
||||
// from bmusic.c
|
||||
extern void music_update(void);
|
||||
|
||||
// INTERRUPT HANDLER
|
||||
//#define USE_ALT_REGS
|
||||
void hw_interrupt()
|
||||
#ifdef USE_ALT_REGS
|
||||
__naked {
|
||||
__asm__("ex af,af'");
|
||||
__asm__("exx");
|
||||
#else
|
||||
JP _main ; jump to test program
|
||||
__interrupt {
|
||||
#endif
|
||||
FoundSentinel:
|
||||
LD SP,#0x4fce ; position stack below BIOS vars
|
||||
CALL _bios_init ; misc. bios init routines
|
||||
LD HL,#0x2005 ; cartridge start vector
|
||||
LD A,(HL)
|
||||
INC HL
|
||||
LD H,(HL)
|
||||
LD L,A
|
||||
JP (HL) ; jump to cart start vector
|
||||
.ds 0x38 - 0x1b ; eat up space until 0x38
|
||||
__endasm;
|
||||
}
|
||||
|
||||
void interrupt_0x38() __naked {
|
||||
__asm
|
||||
push hl
|
||||
push af
|
||||
push bc
|
||||
push de
|
||||
push ix
|
||||
push iy
|
||||
ld hl,#0
|
||||
add hl,sp
|
||||
push hl ; HL points to context block
|
||||
call _SYSCALL ; syscall handler
|
||||
pop hl
|
||||
pop iy
|
||||
pop ix
|
||||
pop de
|
||||
pop bc
|
||||
pop af
|
||||
pop hl
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
|
||||
void _predope() __naked {
|
||||
__asm
|
||||
.ds 0x200-0x52 ; skip to 0x200
|
||||
__endasm;
|
||||
}
|
||||
|
||||
// DOPE vector @ 0x200
|
||||
void DOPE() __naked {
|
||||
__asm
|
||||
JP _STIMER
|
||||
JP _CTIMER
|
||||
.db 0x20, 8, 8, 1, 7 ; Font descriptor (big font)
|
||||
.dw _BIGFONT
|
||||
.db 0xa0, 4, 6, 1, 5 ; Font descriptor (small font)
|
||||
.dw _SMLFONT
|
||||
__endasm;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
byte base_ch;
|
||||
byte frame_x;
|
||||
byte frame_y;
|
||||
byte pattern_x;
|
||||
byte pattern_y;
|
||||
const byte* chartab;
|
||||
} FontDescriptor;
|
||||
|
||||
#define LOCHAR 0x20
|
||||
#define HICHAR 0x63
|
||||
|
||||
extern const char BIGFONT[HICHAR-LOCHAR+1][7];
|
||||
extern const char SMLFONT[HICHAR-LOCHAR+1][5];
|
||||
|
||||
const FontDescriptor __at(0x206) FNTSYS; // = { 0x20, 8, 8, 1, 7, (byte*)BIGFONT };
|
||||
const FontDescriptor __at(0x20d) FNTSML; // = { 0xa0, 4, 6, 1, 5, (byte*)SMLFONT };
|
||||
|
||||
void hw_interrupt() __interrupt {
|
||||
CT[0]++;
|
||||
CT[1]++;
|
||||
CT[2]++;
|
||||
CT[3]++;
|
||||
if (++TMR60 == 60) {
|
||||
TMR60 = 0;
|
||||
++TIMOUT;
|
||||
KEYSEX |= 0x80; // notify SENTRY
|
||||
if (++GTSECS == 60) {
|
||||
GTMINS++;
|
||||
}
|
||||
}
|
||||
// TODO?
|
||||
if (VOICES) {
|
||||
if (DURAT) {
|
||||
DURAT--;
|
||||
} else {
|
||||
music_update();
|
||||
}
|
||||
}
|
||||
#ifdef USE_ALT_REGS
|
||||
__asm__("exx");
|
||||
__asm__("ex af,af'");
|
||||
__asm__("ei");
|
||||
__asm__("reti");
|
||||
#endif
|
||||
}
|
||||
|
||||
const void* const actint_vec = &hw_interrupt;
|
||||
void add_counters(byte mask, byte delta) {
|
||||
byte i = 0;
|
||||
while (mask) {
|
||||
if (mask & 1) {
|
||||
if (CT[i]) {
|
||||
// notify SENTRY if counters go to 0
|
||||
if (!(CT[i] += delta)) {
|
||||
SENFLG |= 1<<i;
|
||||
}
|
||||
}
|
||||
}
|
||||
mask >>= 1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void STIMER() {
|
||||
}
|
||||
|
@ -196,49 +131,28 @@ void STIMER() {
|
|||
void CTIMER() {
|
||||
}
|
||||
|
||||
void bios_init() {
|
||||
memset((void*)0x4fce, 0, 0x5000-0x4fce);
|
||||
void TIMEZ() {
|
||||
// updates game timer, blackout timer, and music processor
|
||||
}
|
||||
|
||||
///// INTERPRETER
|
||||
void TIMEY() {
|
||||
add_counters(0x0f, -1);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
word iy,ix,de,bc,af,hl;
|
||||
} w;
|
||||
struct {
|
||||
byte iyl,iyh,ixl,ixh,e,d,c,b,f,a,l,h;
|
||||
} b;
|
||||
} regs;
|
||||
byte* params;
|
||||
} ContextBlock;
|
||||
void TIMEX() {
|
||||
}
|
||||
|
||||
void DECCTS(ContextBlock *ctx) {
|
||||
add_counters(_C, -1);
|
||||
}
|
||||
|
||||
#define REG_IY 0x1
|
||||
#define REG_E 0x2
|
||||
#define REG_D 0x4
|
||||
#define REG_C 0x8
|
||||
#define REG_B 0x10
|
||||
#define REG_IX 0x20
|
||||
#define REG_A 0x40
|
||||
#define REG_HL 0x80
|
||||
#define REG_DE (REG_D|REG_E)
|
||||
#define REG_BC (REG_B|REG_C)
|
||||
|
||||
typedef void (Routine)();
|
||||
typedef void (SysRoutine)(ContextBlock *ctx);
|
||||
|
||||
typedef struct {
|
||||
SysRoutine* routine;
|
||||
byte argmask;
|
||||
} SysCallEntry;
|
||||
|
||||
void SYSCALL(ContextBlock *ctx);
|
||||
// INTERPRETER
|
||||
|
||||
void INTPC(ContextBlock *ctx) {
|
||||
while (ctx->params[0] != 2) { // 2 = exit
|
||||
while (ctx->params[0] > 2) { // 0,2 = exit
|
||||
SYSCALL(ctx);
|
||||
}
|
||||
ctx->params++; // skip EXIT opcode
|
||||
}
|
||||
|
||||
// never called, hopefully
|
||||
|
@ -248,12 +162,15 @@ void EXIT(ContextBlock *ctx) {
|
|||
|
||||
// jumps to HL
|
||||
void RCALL(ContextBlock *ctx) {
|
||||
((Routine*)ctx->regs.w.hl)();
|
||||
((Routine*)_HL)();
|
||||
}
|
||||
|
||||
// start interpreting at HL
|
||||
void MCALL(ContextBlock *ctx) {
|
||||
ctx; // TODO
|
||||
ctx->params = (byte*)_HL;
|
||||
while (ctx->params[0] != 8) { // 8 = MRET
|
||||
SYSCALL(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
// exit MCALL loop
|
||||
|
@ -261,208 +178,188 @@ void MRET(ContextBlock *ctx) {
|
|||
ctx; // TODO
|
||||
}
|
||||
|
||||
void NOOP(ContextBlock *ctx) {
|
||||
ctx;
|
||||
}
|
||||
|
||||
// jump within MCALL
|
||||
void MJUMP(ContextBlock *ctx) {
|
||||
ctx->params = (byte*) ctx->regs.w.hl; // TODO?
|
||||
ctx->params = (byte*) _HL; // TODO?
|
||||
}
|
||||
|
||||
void suckParams(ContextBlock *ctx, byte argmask) {
|
||||
byte* dest = (byte*) ctx;
|
||||
byte* src = ctx->params;
|
||||
if (argmask & REG_IX) {
|
||||
ctx->regs.b.ixl = *src++;
|
||||
ctx->regs.b.ixh = *src++;
|
||||
_IXL = *src++;
|
||||
_IXH = *src++;
|
||||
}
|
||||
if (argmask & REG_E)
|
||||
ctx->regs.b.e = *src++;
|
||||
_E = *src++;
|
||||
if (argmask & REG_D)
|
||||
ctx->regs.b.d = *src++;
|
||||
_D = *src++;
|
||||
if (argmask & REG_C)
|
||||
ctx->regs.b.c = *src++;
|
||||
_C = *src++;
|
||||
if (argmask & REG_B)
|
||||
ctx->regs.b.b = *src++;
|
||||
_B = *src++;
|
||||
if (argmask & REG_A)
|
||||
ctx->regs.b.a = *src++;
|
||||
_A = *src++;
|
||||
if (argmask & REG_HL) {
|
||||
ctx->regs.b.l = *src++;
|
||||
ctx->regs.b.h = *src++;
|
||||
_L = *src++;
|
||||
_H = *src++;
|
||||
}
|
||||
ctx->params = src;
|
||||
}
|
||||
|
||||
void SUCK(ContextBlock* ctx) {
|
||||
suckParams(ctx, ctx->regs.b.b);
|
||||
suckParams(ctx, _B);
|
||||
}
|
||||
|
||||
|
||||
const void* const actint_vec = &hw_interrupt;
|
||||
|
||||
void ACTINT(ContextBlock *ctx) {
|
||||
ctx;
|
||||
hw_inlin = 200;
|
||||
hw_infbk = (byte) &actint_vec;
|
||||
hw_inmod = 8;
|
||||
__asm
|
||||
LD A,#0x2 ; I = 0x200
|
||||
LD BC,#(_actint_vec) ; upper 8 bits of address
|
||||
LD A,B
|
||||
LD I,A
|
||||
IM 2 ; mode 2
|
||||
EI ; enable interrupts
|
||||
__endasm;
|
||||
hw_inlin = 200;
|
||||
hw_infbk = (byte) &actint_vec;
|
||||
hw_inmod = 0x8;
|
||||
TIMEZ();
|
||||
TIMEY();
|
||||
}
|
||||
|
||||
// Outputs D to port 0A, B to port 09, A to port 0E.
|
||||
void SETOUT(ContextBlock *ctx) {
|
||||
hw_verbl = ctx->regs.b.d;
|
||||
hw_horcb = ctx->regs.b.b;
|
||||
hw_inmod = ctx->regs.b.a;
|
||||
hw_verbl = _D;
|
||||
hw_horcb = _B;
|
||||
hw_inmod = _A;
|
||||
}
|
||||
|
||||
// set entire palette at once (8 bytes to port 0xb)
|
||||
// bytes in array should be in reverse
|
||||
void set_palette(byte palette[8]) __z88dk_fastcall;
|
||||
|
||||
// sets color palettes from (HL)
|
||||
void COLSET(ContextBlock *ctx) {
|
||||
byte* palette = (byte*) ctx->regs.w.hl;
|
||||
hw_col0r = *palette++;
|
||||
hw_col1r = *palette++;
|
||||
hw_col2r = *palette++;
|
||||
hw_col3r = *palette++;
|
||||
hw_col0l = *palette++;
|
||||
hw_col1l = *palette++;
|
||||
hw_col2l = *palette++;
|
||||
hw_col3l = *palette++;
|
||||
set_palette((byte*)_HL);
|
||||
}
|
||||
|
||||
// Stores A in BC bytes starting at location DE.
|
||||
void FILL(ContextBlock *ctx) {
|
||||
byte* dest = (byte*) ctx->regs.w.de;
|
||||
word count = ctx->regs.w.bc;
|
||||
byte val = ctx->regs.b.a;
|
||||
byte* dest = (byte*) _DE;
|
||||
word count = _BC;
|
||||
byte val = _A;
|
||||
memset(dest, val, count);
|
||||
}
|
||||
|
||||
const char BIGFONT[HICHAR-LOCHAR+1][7] = {/*{count:68,w:8,h:7,brev:1}*/
|
||||
{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00 },{ 0x00,0x20,0x20,0x20,0x00,0x20,0x00 },{ 0x50,0x50,0x50,0x00,0x00,0x00,0x00 },{ 0x00,0x50,0xF8,0x50,0xF8,0x50,0x00 },{ 0x00,0xF8,0xA0,0xF8,0x28,0xF8,0x00 },{ 0x00,0xC8,0xD0,0x20,0x58,0x98,0x00 },{ 0x00,0xE0,0xA8,0xF8,0x90,0xF8,0x00 },{ 0x40,0x40,0x40,0x00,0x00,0x00,0x00 },{ 0x30,0x20,0x20,0x20,0x20,0x20,0x30 },{ 0x60,0x20,0x20,0x20,0x20,0x20,0x60 },{ 0x00,0x20,0xA8,0x70,0xA8,0x20,0x00 },{ 0x00,0x20,0x20,0xF8,0x20,0x20,0x00 },{ 0x00,0x00,0x00,0x00,0x60,0x60,0x40 },{ 0x00,0x00,0x00,0xF8,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0x60,0x60,0x00 },{ 0x00,0x08,0x10,0x20,0x40,0x80,0x00 },{ 0x00,0xF8,0x88,0xE8,0x88,0xF8,0x00 },{ 0x00,0x10,0x30,0x50,0x10,0x10,0x00 },{ 0x00,0xF8,0x08,0xF8,0x80,0xF8,0x00 },{ 0x00,0xF8,0x08,0xF8,0x08,0xF8,0x00 },{ 0x00,0x38,0x48,0x88,0xF8,0x08,0x00 },{ 0x00,0xF8,0x80,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x88,0xF8,0x00 },{ 0x00,0xF8,0x08,0x10,0x20,0x40,0x00 },{ 0x00,0xF8,0x88,0xF8,0x88,0xF8,0x00 },{ 0x00,0xF8,0x88,0xF8,0x08,0xF8,0x00 },{ 0x00,0x30,0x30,0x00,0x30,0x30,0x00 },{ 0x00,0x30,0x30,0x00,0x30,0x30,0x20 },{ 0x08,0x10,0x20,0x40,0x20,0x10,0x08 },{ 0x00,0x00,0xF8,0x00,0xF8,0x00,0x00 },{ 0x40,0x20,0x10,0x08,0x10,0x20,0x40 },{ 0x00,0xF8,0x08,0x78,0x00,0x60,0x00 },{ 0x00,0xF8,0xA8,0xB8,0x80,0xF8,0x00 },{ 0x00,0xF8,0x88,0xF8,0x88,0x88,0x00 },{ 0x00,0xF0,0x90,0xF8,0x88,0xF8,0x00 },{ 0x00,0xF8,0x80,0x80,0x80,0xF8,0x00 },{ 0x00,0xE0,0x90,0x88,0x88,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x80,0xF8,0x00 },{ 0x00,0xF8,0x80,0xF8,0x80,0x80,0x00 },{ 0x00,0xF8,0x80,0xB8,0x88,0xF8,0x00 },{ 0x00,0x88,0x88,0xF8,0x88,0x88,0x00 },{ 0x00,0x40,0x40,0x40,0x40,0x40,0x00 },{ 0x00,0x08,0x08,0x88,0x88,0xF8,0x00 },{ 0x00,0x88,0x90,0xA0,0x90,0x88,0x00 },{ 0x00,0x80,0x80,0x80,0x80,0xF8,0x00 },{ 0x00,0xFE,0x92,0x92,0x92,0x92,0x00 },{ 0x00,0x88,0xC8,0xA8,0x98,0x88,0x00 },{ 0x00,0xF8,0x88,0x88,0x88,0xF8,0x00 },{ 0x00,0xF8,0x88,0x88,0xF8,0x80,0x00 },{ 0x00,0xF8,0x88,0xA8,0xA8,0xF8,0x10 },{ 0x00,0xF8,0x88,0xF8,0x90,0x88,0x00 },{ 0x00,0xF8,0x80,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x20,0x20,0x20,0x20,0x00 },{ 0x00,0x88,0x88,0x88,0x88,0xF8,0x00 },{ 0x00,0x88,0x88,0x90,0xA0,0xC0,0x00 },{ 0x00,0x92,0x92,0x92,0x92,0xFE,0x00 },{ 0x00,0x88,0x50,0x20,0x50,0x88,0x00 },{ 0x00,0x88,0x88,0xF8,0x08,0xF8,0x00 },{ 0x00,0xF8,0x10,0x20,0x40,0xF8,0x00 },{ 0x38,0x20,0x20,0x20,0x20,0x20,0x38 },{ 0x00,0x80,0x40,0x20,0x10,0x08,0x00 },{ 0x70,0x10,0x10,0x10,0x10,0x10,0x70 },{ 0x00,0x20,0x70,0xA8,0x20,0x20,0x00 },{ 0x00,0x20,0x40,0xF8,0x40,0x20,0x00 },{ 0x00,0x20,0x20,0xA8,0x70,0x20,0x00 },{ 0x00,0x20,0x10,0xF8,0x10,0x20,0x00 },{ 0x00,0x88,0x50,0x20,0x50,0x88,0x00 },{ 0x00,0x20,0x00,0xF8,0x00,0x20,0x00 }};
|
||||
|
||||
const char SMLFONT[HICHAR-LOCHAR+1][5] = {/*{count:68,w:5,h:5,brev:1}*/
|
||||
{ 0x00,0x00,0x00,0x00,0x00 },{ 0x40,0x40,0x00,0x40,0x00 },{ 0xA0,0xA0,0x00,0x00,0x00 },{ 0x60,0xF0,0xF0,0x60,0x00 },{ 0x40,0xE0,0xE0,0x40,0x00 },{ 0x90,0x20,0x40,0x90,0x00 },{ 0xC0,0xB0,0xE0,0xD0,0x00 },{ 0x20,0x40,0x00,0x00,0x00 },{ 0x20,0x40,0x40,0x20,0x00 },{ 0x40,0x20,0x20,0x40,0x00 },{ 0x40,0xE0,0x40,0xA0,0x00 },{ 0x00,0x40,0xE0,0x40,0x00 },{ 0x00,0x00,0x00,0x60,0x20 },{ 0x00,0x00,0xE0,0x00,0x00 },{ 0x00,0x00,0x00,0x40,0x00 },{ 0x20,0x20,0x40,0x40,0x00 },{ 0xE0,0xA0,0xA0,0xE0,0x00 },{ 0xC0,0x40,0x40,0xE0,0x00 },{ 0xE0,0x20,0xC0,0xE0,0x00 },{ 0xE0,0x60,0x20,0xE0,0x00 },{ 0xA0,0xA0,0xE0,0x20,0x00 },{ 0xE0,0xC0,0x20,0xE0,0x00 },{ 0xC0,0x80,0xE0,0xE0,0x00 },{ 0xE0,0x20,0x40,0x40,0x00 },{ 0x60,0xE0,0xA0,0xE0,0x00 },{ 0xE0,0xE0,0x20,0x60,0x00 },{ 0x00,0x40,0x00,0x40,0x00 },{ 0x00,0x40,0x00,0x60,0x20 },{ 0x00,0x20,0x40,0x20,0x00 },{ 0x00,0xE0,0x00,0xE0,0x00 },{ 0x00,0x40,0x20,0x40,0x00 },{ 0xE0,0x20,0x60,0x00,0x40 },{ 0xF0,0x90,0x10,0xD0,0xF0 },{ 0x60,0xA0,0xE0,0xA0,0x00 },{ 0xC0,0xE0,0xA0,0xE0,0x00 },{ 0x60,0x80,0x80,0xE0,0x00 },{ 0xC0,0xA0,0xA0,0xC0,0x00 },{ 0xE0,0xC0,0x80,0xE0,0x00 },{ 0xE0,0xC0,0x80,0x80,0x00 },{ 0x60,0x80,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xE0,0xA0,0x00 },{ 0xE0,0x40,0x40,0xE0,0x00 },{ 0x60,0x20,0xA0,0xE0,0x00 },{ 0xA0,0xC0,0xC0,0xA0,0x00 },{ 0x80,0x80,0x80,0xE0,0x00 },{ 0xE0,0xE0,0xE0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xE0,0x00 },{ 0xE0,0xA0,0xE0,0x80,0x00 },{ 0xE0,0xA0,0xE0,0xF0,0x00 },{ 0xE0,0xA0,0xC0,0xA0,0x00 },{ 0xE0,0x80,0x60,0xE0,0x00 },{ 0xE0,0x40,0x40,0x40,0x00 },{ 0xA0,0xA0,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xC0,0x80,0x00 },{ 0xA0,0xE0,0xE0,0xE0,0x00 },{ 0xA0,0x40,0xA0,0xA0,0x00 },{ 0xA0,0xE0,0x40,0x40,0x00 },{ 0xE0,0x20,0x40,0xE0,0x00 },{ 0x60,0x40,0x40,0x60,0x00 },{ 0x40,0x40,0x20,0x20,0x00 },{ 0x60,0x20,0x20,0x60,0x00 },{ 0x40,0xA0,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0xF0 },{ 0x80,0x40,0x00,0x00,0x00 },{ 0x00,0x60,0xA0,0xE0,0x00 },{ 0x80,0xE0,0xA0,0xE0,0x00 },{ 0x00,0x60,0x80,0xE0,0x00 }};
|
||||
|
||||
// draw a letter
|
||||
void draw_char(const FontDescriptor* font, byte ch, byte x, byte y, byte op) {
|
||||
const byte* src = font->chartab + (ch-font->base_ch)*font->pattern_y;
|
||||
byte xb = x>>2; // divide x by 4
|
||||
byte* dest = &vmagic[y][xb]; // destination address
|
||||
hw_magic = M_SHIFT(x) | M_XPAND | op;
|
||||
for (byte i=0; i<font->pattern_y; i++) {
|
||||
char b = *src++;
|
||||
EXIT_CLIPDEST(dest);
|
||||
*dest++ = b; // expand lower nibble -> 1st byte
|
||||
*dest++ = b; // expand upper nibble -> 2nd byte
|
||||
*dest++ = 0; // leftover -> 3rd byte
|
||||
*dest = 0; // reset upper/lower flag
|
||||
dest += VBWIDTH-3; // we incremented 3 bytes for this line
|
||||
}
|
||||
}
|
||||
|
||||
#define FONT_IX ((const FontDescriptor*)ctx->regs.w.ix)
|
||||
|
||||
void draw_string(ContextBlock *ctx, const char* str, byte x, byte y, byte op) {
|
||||
do {
|
||||
byte ch = *str++;
|
||||
if (!ch) {
|
||||
ctx->regs.b.e = x;
|
||||
break;
|
||||
}
|
||||
if (ch < 0x20) {
|
||||
x += 8 * ch;
|
||||
} else if (ch < 0x64) {
|
||||
draw_char(&FNTSYS, ch, x, y, op);
|
||||
x += 8;
|
||||
} else if (ch >= 0x80) {
|
||||
draw_char(FONT_IX, ch, x, y, op);
|
||||
x += FONT_IX->frame_x;
|
||||
} else {
|
||||
/*
|
||||
if (ch & 0x10) {
|
||||
ctx->regs.b.ixl = *str++;
|
||||
ctx->regs.b.ixh = *str++;
|
||||
}
|
||||
if (ch & 0x1)
|
||||
ctx->regs.b.e = *str++;
|
||||
if (ch & 0x2)
|
||||
ctx->regs.b.d = *str++;
|
||||
if (ch & 0x4)
|
||||
ctx->regs.b.c = *str++;
|
||||
*/
|
||||
// TODO: only can change font
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
// String display routine (pass pointer to string)
|
||||
void STRDIS2(ContextBlock *ctx, char *str) {
|
||||
byte opts = ctx->regs.b.c;
|
||||
byte x = ctx->regs.b.e;
|
||||
byte y = ctx->regs.b.d;
|
||||
void* fontdesc = (void*) ctx->regs.w.ix;
|
||||
hw_xpand = opts & 0xf;
|
||||
draw_string(ctx, str, x, y, 3&(opts>>4)); // TODO: opts
|
||||
}
|
||||
|
||||
// String display routine
|
||||
void STRDIS(ContextBlock *ctx) {
|
||||
char* str = (char*) ctx->regs.w.hl;
|
||||
STRDIS2(ctx, str);
|
||||
}
|
||||
|
||||
// Character display routine
|
||||
void CHRDIS(ContextBlock *ctx) {
|
||||
char chstr[2];
|
||||
chstr[0] = ctx->regs.b.a;
|
||||
chstr[1] = 0;
|
||||
STRDIS2(ctx, chstr);
|
||||
}
|
||||
|
||||
// BCD routine
|
||||
const char BCDTAB[17] = "0123456789*+,-./";
|
||||
|
||||
void DISNUM(ContextBlock *ctx) {
|
||||
// TODO: options, B
|
||||
word oldhl = ctx->regs.w.hl;
|
||||
byte val = *(byte*) oldhl;
|
||||
char bcdstr[3];
|
||||
bcdstr[0] = BCDTAB[val >> 4];
|
||||
bcdstr[1] = BCDTAB[val & 15];
|
||||
bcdstr[2] = 0;
|
||||
STRDIS2(ctx, bcdstr);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
sbyte xofs, yofs;
|
||||
byte xsize, ysize;
|
||||
byte pattern[0];
|
||||
} PatternBlock;
|
||||
// TODO
|
||||
|
||||
void wait_vsync() {
|
||||
byte x = TMR60;
|
||||
while (x == TMR60) ; // wait until timer/60 changes
|
||||
}
|
||||
|
||||
void PAWS(ContextBlock *ctx) {
|
||||
while (ctx->regs.b.b--) {
|
||||
while (_B--) {
|
||||
wait_vsync();
|
||||
}
|
||||
}
|
||||
|
||||
// MATH
|
||||
|
||||
void MOVE(ContextBlock *ctx) {
|
||||
memcpy((byte*)_DE, (const byte*)_HL, _BC);
|
||||
}
|
||||
|
||||
word bcdadd8(byte a, byte b, byte c);
|
||||
|
||||
void BCDADD(ContextBlock *ctx) {
|
||||
byte* dest = (byte*) _DE;
|
||||
const byte* src = (const byte*) _HL;
|
||||
byte n = _B;
|
||||
byte carry = 0;
|
||||
while (n--) {
|
||||
byte a = *src++;
|
||||
byte b = *dest;
|
||||
word r = bcdadd8(a,b,carry);
|
||||
carry = (r>>8);
|
||||
*dest++ = r;
|
||||
}
|
||||
}
|
||||
|
||||
void RANGED(ContextBlock *ctx) {
|
||||
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
|
||||
RANSHT ^= RANSHT << 13;
|
||||
RANSHT ^= RANSHT >> 17;
|
||||
RANSHT ^= RANSHT << 5;
|
||||
if (ctx->regs.b.a == 0) {
|
||||
ctx->regs.b.a = (byte)RANSHT;
|
||||
if (_A == 0) {
|
||||
_A = (byte)RANSHT;
|
||||
} else {
|
||||
ctx->regs.b.a = (byte)(RANSHT % ctx->regs.b.a);
|
||||
_A = (byte)(RANSHT % _A);
|
||||
}
|
||||
}
|
||||
|
||||
void INDEXB(ContextBlock *ctx) {
|
||||
word addr = _HL + _A;
|
||||
_HL = addr;
|
||||
_A = *((byte*)addr);
|
||||
}
|
||||
|
||||
void INDEXW(ContextBlock *ctx) {
|
||||
word addr = _HL + _A*2;
|
||||
_HL = addr;
|
||||
_DE = *((word*)addr);
|
||||
}
|
||||
|
||||
void INDEXN(ContextBlock *ctx) {
|
||||
byte ofs = _C;
|
||||
word addr = _HL + ofs/2;
|
||||
byte val = *((byte*)addr);
|
||||
_A = (ofs & 1) ? (val>>4) : (val&0xf);
|
||||
}
|
||||
|
||||
// input
|
||||
|
||||
extern const byte KCTASC_TABLE[25];
|
||||
|
||||
void KCTASC(ContextBlock *ctx) {
|
||||
_A = KCTASC_TABLE[_B];
|
||||
}
|
||||
|
||||
// music
|
||||
|
||||
void BMUSIC(ContextBlock *ctx) {
|
||||
VOICES = _A;
|
||||
MUZPC = _HL;
|
||||
MUZSP = _IX;
|
||||
DURAT = 0;
|
||||
}
|
||||
|
||||
void EMUSIC(ContextBlock *ctx) {
|
||||
ctx;
|
||||
VOICES = 0;
|
||||
}
|
||||
|
||||
// externals
|
||||
|
||||
extern void SENTRY(ContextBlock *ctx);
|
||||
extern void DOIT(ContextBlock *ctx);
|
||||
extern void DOITB(ContextBlock *ctx);
|
||||
|
||||
extern void RECTAN(const ContextBlock *ctx);
|
||||
extern void WRITR(const ContextBlock *ctx);
|
||||
extern void WRITP(const ContextBlock *ctx);
|
||||
extern void WRIT(const ContextBlock *ctx);
|
||||
extern void CHRDIS(const ContextBlock *ctx);
|
||||
extern void STRDIS(const ContextBlock *ctx);
|
||||
extern void DISNUM(const ContextBlock *ctx);
|
||||
|
||||
// table
|
||||
|
||||
const SysCallEntry SYSCALL_TABLE[64] = {
|
||||
/* 0 */
|
||||
{ &INTPC, 0 },
|
||||
|
@ -474,73 +371,73 @@ const SysCallEntry SYSCALL_TABLE[64] = {
|
|||
{ &MJUMP, REG_HL },
|
||||
{ &SUCK, REG_B },
|
||||
{ &ACTINT, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &DECCTS, REG_C },
|
||||
{ &BMUSIC, REG_HL|REG_IX|REG_A },
|
||||
/* 20 */
|
||||
{ 0, 0 },
|
||||
{ &EMUSIC, },
|
||||
{ &SETOUT, REG_D|REG_B|REG_A },
|
||||
{ &COLSET, REG_HL },
|
||||
{ &FILL, REG_A|REG_BC|REG_DE },
|
||||
{ 0, 0 },
|
||||
{ &RECTAN, REG_A|REG_B|REG_C|REG_D|REG_E },
|
||||
/* 30 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &NOOP, REG_HL|REG_IX }, // VWRITR
|
||||
{ &WRITR, REG_E|REG_D|REG_A|REG_HL },
|
||||
{ &WRITP, REG_E|REG_D|REG_A|REG_HL },
|
||||
{ &WRIT, REG_E|REG_D|REG_C|REG_B|REG_A|REG_HL },
|
||||
{ &NOOP, REG_E|REG_D|REG_C|REG_B|REG_A|REG_HL }, // WRITA
|
||||
/* 40 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &NOOP, REG_E|REG_D|REG_IX }, // VBLANK
|
||||
{ &NOOP, REG_E|REG_D|REG_B|REG_HL }, // BLANK
|
||||
{ &NOOP, REG_B|REG_C|REG_DE|REG_HL }, // SAVE
|
||||
{ &NOOP, REG_DE|REG_HL }, // RESTORE
|
||||
{ &NOOP, REG_B|REG_C|REG_DE|REG_HL }, // SCROLL
|
||||
/* 50 */
|
||||
{ &CHRDIS, REG_E|REG_D|REG_C|REG_A },
|
||||
{ &STRDIS, REG_E|REG_D|REG_C|REG_HL },
|
||||
{ &DISNUM, REG_E|REG_D|REG_C|REG_HL },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &DISNUM, REG_E|REG_D|REG_C|REG_B|REG_HL },
|
||||
{ &NOOP, REG_DE|REG_A }, // RELABS
|
||||
{ &NOOP, REG_E|REG_D|REG_A }, // RELAB1
|
||||
/* 60 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &NOOP, REG_IX|REG_HL|REG_C }, // VECTC
|
||||
{ &NOOP, REG_IX|REG_HL }, // VECT
|
||||
{ &KCTASC, 0 },
|
||||
{ &SENTRY, REG_DE },
|
||||
{ &DOIT, REG_HL },
|
||||
/* 70 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &DOITB, REG_HL },
|
||||
{ &NOOP, 0 }, // PIZBRK
|
||||
{ &NOOP, REG_DE|REG_HL }, // MENU
|
||||
{ &NOOP, REG_BC|REG_HL }, // GETPAR
|
||||
{ &NOOP, REG_B|REG_C|REG_D|REG_E|REG_HL }, // GETNUM
|
||||
/* 80 */
|
||||
{ &PAWS, REG_B },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &NOOP, REG_E|REG_D|REG_C }, // DISTIM
|
||||
{ &NOOP, REG_HL }, // INCSCR
|
||||
{ &INDEXN, REG_C|REG_HL }, // INDEXN
|
||||
{ &NOOP, REG_HL }, // STOREN
|
||||
/* 90 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &INDEXW, REG_A|REG_HL }, // INDEXW
|
||||
{ &INDEXB, REG_A|REG_HL }, // INDEXB
|
||||
{ &MOVE, REG_DE|REG_BC|REG_HL },
|
||||
{ &NOOP, 0 }, // SHIFTU
|
||||
{ &BCDADD, REG_DE|REG_B|REG_HL },
|
||||
/* 100 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &NOOP, 0 }, // BCDSUB
|
||||
{ &NOOP, 0 }, // BCDMUL
|
||||
{ &NOOP, 0 }, // BCDDIV
|
||||
{ &NOOP, 0 }, // BCDCHS
|
||||
{ &NOOP, 0 }, // BCDNEG
|
||||
/* 110 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &NOOP, 0 }, // DADD
|
||||
{ &NOOP, 0 }, // DSMG
|
||||
{ &NOOP, 0 }, // DABS
|
||||
{ &NOOP, 0 }, // NEGT
|
||||
{ &RANGED, REG_A },
|
||||
/* 120 */
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ 0, 0 },
|
||||
{ &NOOP, 0 }, // QUIT
|
||||
{ &NOOP, REG_A|REG_HL }, // SETB
|
||||
{ &NOOP, REG_DE|REG_HL }, // SETW
|
||||
{ &NOOP, REG_C|REG_DE|REG_HL }, // MSKTD
|
||||
};
|
||||
|
||||
void SYSCALL(ContextBlock *ctx) {
|
||||
|
@ -561,71 +458,17 @@ void SYSCALL(ContextBlock *ctx) {
|
|||
suckParams(ctx, argmask);
|
||||
}
|
||||
// call the routine
|
||||
if (routine) {
|
||||
routine(ctx);
|
||||
}
|
||||
routine(ctx);
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
void main() {
|
||||
__asm
|
||||
LD SP,#0x4fce ; position stack below BIOS vars
|
||||
ld hl,#0x20d
|
||||
push hl
|
||||
pop ix
|
||||
RST 0x38
|
||||
.db 0 ; INTPC
|
||||
.db 22+1 ; SETOUT
|
||||
.db 102*2, 0x1c, 0x08
|
||||
.db 14 ; ACTINT
|
||||
.db 24+1 ; COLSET
|
||||
.dw _main ; palette???
|
||||
.db 26+1 ; FILL
|
||||
.dw 0x4000
|
||||
.dw 90*40
|
||||
.db 0xaa
|
||||
.db 52+1 ; draw string
|
||||
.db 0
|
||||
.db 32
|
||||
.db 0x0c
|
||||
.dw HelloString
|
||||
.db 52+1 ; draw string
|
||||
.db 0
|
||||
.db 48
|
||||
.db 0x0c
|
||||
.dw HelloString
|
||||
.db 50+1 ; draw char
|
||||
.db 0
|
||||
.db 64
|
||||
.db 0x0c
|
||||
.db 0x40
|
||||
.db 2 ; EXIT
|
||||
.loop:
|
||||
ld hl,#0x4FED
|
||||
ld a,(hl)
|
||||
add a,#0x30
|
||||
RST 0x38
|
||||
.db 50 ; draw char
|
||||
jp .loop
|
||||
HelloString:
|
||||
.ascii "HELLO WORLD! "
|
||||
.db 0xc1, 0xc2, 0xc3, 0xc4, 0xc5
|
||||
.db 0
|
||||
; Critter Pattern
|
||||
; Color 0 = White and Color 2 = Black
|
||||
;
|
||||
PATERN: .DB 0,0 ; (0,0) Position
|
||||
.DB 0x02,0x08 ; 2 byte, 8 line pattern size
|
||||
|
||||
.DB 0x0A,0xA0 ; 0000101010100000 - . . 2 2 2 2 . .
|
||||
.DB 0x22,0x88 ; 0010001010001000 - . 2 . 2 2 . 2 .
|
||||
.DB 0xAA,0xAA ; 1010101010101010 - 2 2 2 2 2 2 2 2
|
||||
.DB 0x2A,0xA8 ; 0010101010101000 - . 2 2 2 2 2 2 .
|
||||
.DB 0x08,0x20 ; 0000100000100000 - . . 2 . . 2 . .
|
||||
.DB 0x20,0x08 ; 0010000000001000 - . 2 . . . . 2 .
|
||||
.DB 0x08,0x20 ; 0000100000100000 - . . 2 . . 2 . .
|
||||
.DB 0x00,0x00 ; 0000000000000000 - . . . . . . . .
|
||||
__endasm;
|
||||
while (1) ;
|
||||
void bios_init() {
|
||||
ContextBlock ctx;
|
||||
memset((void*)0x4fce, 0, 0x5000-0x4fce);
|
||||
ACTINT(0);
|
||||
hw_verbl = 96*2;
|
||||
hw_horcb = 41;
|
||||
hw_inmod = 0x8;
|
||||
// call SENTRY once to set current values
|
||||
// (context block doesn't matter)
|
||||
SENTRY(&ctx);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
typedef signed short sword;
|
||||
|
||||
/// HARDWARE
|
||||
|
||||
__sfr __at(0x00) hw_col0r; // palette 0
|
||||
__sfr __at(0x01) hw_col1r;
|
||||
__sfr __at(0x02) hw_col2r;
|
||||
__sfr __at(0x03) hw_col3r;
|
||||
__sfr __at(0x04) hw_col0l;
|
||||
__sfr __at(0x05) hw_col1l;
|
||||
__sfr __at(0x06) hw_col2l;
|
||||
__sfr __at(0x07) hw_col3l; // palette 7
|
||||
|
||||
__sfr __at(0x08) hw_intst; // intercept test feedback
|
||||
__sfr __at(0x09) hw_horcb; // horiz color boundary
|
||||
__sfr __at(0x0a) hw_verbl; // vertical blanking line * 2
|
||||
__sfr __at(0x0c) hw_magic; // magic register
|
||||
__sfr __at(0x0d) hw_infbk; // interrupt feedback
|
||||
__sfr __at(0x0e) hw_inmod; // interrupt enable
|
||||
__sfr __at(0x0f) hw_inlin; // interrupt line
|
||||
__sfr __at(0x19) hw_xpand; // expander register
|
||||
|
||||
__sfr __at(0x10) hw_p1ctrl; // player controls
|
||||
__sfr __at(0x11) hw_p2ctrl; // player controls
|
||||
__sfr __at(0x12) hw_p3ctrl; // player controls
|
||||
__sfr __at(0x13) hw_p4ctrl; // player controls
|
||||
__sfr __at(0x14) hw_keypad0;
|
||||
__sfr __at(0x15) hw_keypad1;
|
||||
__sfr __at(0x16) hw_keypad2;
|
||||
__sfr __at(0x17) hw_keypad3;
|
||||
__sfr __at(0x1c) hw_p1pot; // player pot
|
||||
__sfr __at(0x1d) hw_p2pot; // player pot
|
||||
__sfr __at(0x1e) hw_p3pot; // player pot
|
||||
__sfr __at(0x1f) hw_p4pot; // player pot
|
||||
|
||||
#define M_SHIFT0 0x00
|
||||
#define M_SHIFT1 0x01
|
||||
#define M_SHIFT2 0x02
|
||||
#define M_SHIFT3 0x03
|
||||
#define M_XPAND 0x08
|
||||
#define M_MOVE 0x00
|
||||
#define M_OR 0x10
|
||||
#define M_XOR 0x20
|
||||
#define M_FLOP 0x40
|
||||
#define M_SHIFT(x) ((x)&3)
|
||||
#define XPAND_COLORS(off,on) (((off)&3) | (((on)&3)<<2))
|
||||
|
||||
// font options
|
||||
#define OPT_1x1 0x00
|
||||
#define OPT_2x2 0x40
|
||||
#define OPT_4x4 0x80
|
||||
#define OPT_8x8 0xc0
|
||||
#define OPT_XOR 0x20
|
||||
#define OPT_OR 0x10
|
||||
#define OPT_ON(n) ((n)<<2)
|
||||
#define OPT_OFF(n) ((n))
|
||||
|
||||
// bcd options
|
||||
#define DISBCD_SML 0x40
|
||||
#define DISBCD_NOZERO 0x80
|
||||
|
||||
/// GRAPHICS FUNCTIONS
|
||||
|
||||
#define VHEIGHT 102 // number of scanlines
|
||||
#define VBWIDTH 40 // number of bytes per scanline
|
||||
#define PIXWIDTH 160 // 4 pixels per byte
|
||||
|
||||
//#define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return
|
||||
#define EXIT_CLIPDEST(addr)
|
||||
|
||||
byte __at (0x0000) vmagic[VHEIGHT][VBWIDTH];
|
||||
byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH];
|
||||
|
||||
typedef enum {
|
||||
SNUL,
|
||||
SCT0,SCT1,SCT2,SCT3,SCT4,SCT5,SCT6,SCT7,
|
||||
SF0,SF1,SF2,SF3,SF4,SF5,SF6,SF7,
|
||||
SSEC,
|
||||
SKYU,SKYD,
|
||||
ST0,SJ0,ST1,SJ1,ST2,SJ2,ST3,SJ3,
|
||||
SP0,SP1,SP2,SP3
|
||||
} SENTRYCode;
|
||||
|
||||
typedef struct {
|
||||
byte base_ch; // first char
|
||||
byte frame_x; // frame width
|
||||
byte frame_y; // frame height
|
||||
byte pattern_x; // pattern width
|
||||
byte pattern_y; // pattern height
|
||||
const byte* chartab; // pointer to char data
|
||||
} FontDescriptor;
|
||||
|
||||
typedef struct {
|
||||
sbyte xofs, yofs;
|
||||
byte xsize, ysize;
|
||||
byte pattern[0];
|
||||
} PatternBlock;
|
||||
|
||||
const FontDescriptor __at(0x206) FNTSYS; // = { 0x20, 8, 8, 1, 7, (byte*)BIGFONT };
|
||||
const FontDescriptor __at(0x20d) FNTSML; // = { 0xa0, 4, 6, 1, 5, (byte*)SMLFONT };
|
||||
|
||||
///// INTERPRETER
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
word iy,ix,de,bc,af,hl;
|
||||
} w;
|
||||
struct {
|
||||
byte iyl,iyh,ixl,ixh,e,d,c,b,f,a,l,h;
|
||||
} b;
|
||||
} regs;
|
||||
byte* params;
|
||||
} ContextBlock;
|
||||
|
||||
#define REG_IY 0x1
|
||||
#define REG_E 0x2
|
||||
#define REG_D 0x4
|
||||
#define REG_C 0x8
|
||||
#define REG_B 0x10
|
||||
#define REG_IX 0x20
|
||||
#define REG_A 0x40
|
||||
#define REG_HL 0x80
|
||||
#define REG_DE (REG_D|REG_E)
|
||||
#define REG_BC (REG_B|REG_C)
|
||||
|
||||
#define _IY (ctx->regs.w.iy)
|
||||
#define _IX (ctx->regs.w.ix)
|
||||
#define _DE (ctx->regs.w.de)
|
||||
#define _BC (ctx->regs.w.bc)
|
||||
#define _AF (ctx->regs.w.af)
|
||||
#define _HL (ctx->regs.w.hl)
|
||||
#define _IXL (ctx->regs.b.ixl)
|
||||
#define _IXH (ctx->regs.b.ixh)
|
||||
#define _IYL (ctx->regs.b.iyl)
|
||||
#define _IYH (ctx->regs.b.iyh)
|
||||
#define _E (ctx->regs.b.e)
|
||||
#define _D (ctx->regs.b.d)
|
||||
#define _C (ctx->regs.b.c)
|
||||
#define _B (ctx->regs.b.b)
|
||||
#define _A (ctx->regs.b.a)
|
||||
#define _L (ctx->regs.b.l)
|
||||
#define _H (ctx->regs.b.h)
|
||||
|
||||
typedef void (Routine)();
|
||||
typedef void (SysRoutine)(ContextBlock *ctx);
|
||||
|
||||
typedef struct {
|
||||
SysRoutine* routine;
|
||||
byte argmask;
|
||||
} SysCallEntry;
|
||||
|
||||
void SYSCALL(ContextBlock *ctx);
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
TEST = 1
|
||||
|
||||
.module biosasm
|
||||
.globl _STIMER,_CTIMER,_BIGFONT,_SMLFONT
|
||||
|
||||
BIOSStart:
|
||||
di ; disable interrupts
|
||||
ld HL,#0x2000
|
||||
.if TEST
|
||||
ld HL,#(_main)
|
||||
.endif
|
||||
ld A,(HL) ; A <- mem[0x2000]
|
||||
cp #0x55 ; found sentinel byte? ($55)
|
||||
jp Z,FoundSentinel ; yes, load program
|
||||
.if TEST
|
||||
jp _main ; jump to test program
|
||||
.else
|
||||
jp 0x2000 ; jump to $2000
|
||||
.endif
|
||||
FoundSentinel:
|
||||
ld SP,#0x4fce ; position stack below BIOS vars
|
||||
call _bios_init ; misc. bios init routines
|
||||
.if TEST
|
||||
ld HL,#(_main+5)
|
||||
.else
|
||||
ld HL,#0x2005 ; cartridge start vector
|
||||
.endif
|
||||
ld A,(HL)
|
||||
inc HL
|
||||
ld H,(HL)
|
||||
ld L,A
|
||||
jp (HL) ; jump to cart start vector
|
||||
|
||||
.ds 0x38 - (. - BIOSStart) ; eat up space until 0x38
|
||||
.globl SYSCALL38
|
||||
SYSCALL38:
|
||||
push hl
|
||||
push af
|
||||
push bc
|
||||
push de
|
||||
push ix
|
||||
push iy
|
||||
ld hl,#0
|
||||
add hl,sp
|
||||
push hl ; HL points to context block
|
||||
call _SYSCALL ; syscall handler
|
||||
pop hl
|
||||
pop iy
|
||||
pop ix
|
||||
pop de
|
||||
pop bc
|
||||
pop af
|
||||
pop hl
|
||||
ret
|
||||
|
||||
; out to port
|
||||
.globl _portOut
|
||||
_portOut:
|
||||
ld c,h
|
||||
out (c),l
|
||||
ret
|
||||
|
||||
.globl _bcdadd8
|
||||
_bcdadd8:
|
||||
push ix
|
||||
ld ix,#0
|
||||
add ix,sp
|
||||
ld a,6(ix) ; carry
|
||||
rrc a ; set carry bit
|
||||
ld h,#0 ; carry goes here
|
||||
ld a,4(ix) ; a -> A
|
||||
adc a,5(ix) ; a + b -> A
|
||||
daa ; BCD conversion
|
||||
ld l,a ; result -> L
|
||||
rl h ; carry -> H
|
||||
pop ix
|
||||
ret
|
||||
|
||||
;void set_palette(byte palette[8]) __z88dk_fastcall;
|
||||
.globl _set_palette
|
||||
_set_palette:
|
||||
ld bc,#0x80b ; B -> 8, C -> 0xb
|
||||
otir ; write C bytes from HL to port[B]
|
||||
ret
|
||||
|
||||
.globl _KCTASC_TABLE
|
||||
_KCTASC_TABLE:
|
||||
.db 0x00
|
||||
.db 0x43, 0x5e, 0x5c, 0x25, 0x52, 0x53, 0x3b, 0x2f
|
||||
.db 0x37, 0x38, 0x39, 0x2a, 0x34, 0x35, 0x36, 0x2d
|
||||
.db 0x31, 0x32, 0x33, 0x2b, 0x26, 0x30, 0x2e, 0x3d
|
||||
|
||||
|
||||
.ds 0x200 - (. - BIOSStart) ; eat up space until 0x200
|
||||
DOPEVector:
|
||||
JP _STIMER
|
||||
JP _CTIMER
|
||||
.db 0x20, 8, 8, 1, 7 ; Font descriptor (big font)
|
||||
.dw _BIGFONT
|
||||
.db 0xa0, 4, 6, 1, 5 ; Font descriptor (small font)
|
||||
.dw _SMLFONT
|
||||
.db 0x3f ; all keys mask
|
||||
.db 0x3f
|
||||
.db 0x3f
|
||||
.db 0x3f
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
#pragma opt_code_speed
|
||||
|
||||
#include "bios.h"
|
||||
|
||||
extern byte* MUZPC; // music PC
|
||||
extern byte* MUZSP; // music SP
|
||||
extern byte PVOLAB; // channels A and B volume
|
||||
extern byte PVOLMC; // channel C volume and noise mask
|
||||
extern byte VOICES; // voices mmask
|
||||
extern byte DURAT; // note duration
|
||||
|
||||
__sfr __at(0x10) hw_tonmo;
|
||||
__sfr __at(0x11) hw_tonea;
|
||||
__sfr __at(0x12) hw_toneb;
|
||||
__sfr __at(0x13) hw_tonec;
|
||||
__sfr __at(0x14) hw_vibra;
|
||||
__sfr __at(0x15) hw_volc;
|
||||
__sfr __at(0x16) hw_volab;
|
||||
__sfr __at(0x17) hw_voln;
|
||||
__sfr __at(0x18) hw_sndbx;
|
||||
|
||||
extern void portOut(word portVal) __z88dk_fastcall;
|
||||
|
||||
static byte NEXT(void) {
|
||||
return *MUZPC++;
|
||||
}
|
||||
|
||||
static void PUSH(byte b) {
|
||||
*++MUZSP = b;
|
||||
}
|
||||
|
||||
static byte POP() {
|
||||
return *MUZSP--;
|
||||
}
|
||||
|
||||
static byte DECTOP() {
|
||||
return --(*MUZSP);
|
||||
}
|
||||
|
||||
void music_update(void) {
|
||||
byte op = NEXT();
|
||||
if (op < 0x80) {
|
||||
DURAT = op;
|
||||
op = VOICES;
|
||||
if (op & 0x01) hw_voln = NEXT();
|
||||
if (op & 0x02) hw_vibra = NEXT();
|
||||
if (op & 0x04 && (hw_tonec = *MUZPC)) {
|
||||
hw_volc = PVOLMC;
|
||||
}
|
||||
if (op & 0x08) MUZPC++;
|
||||
if (op & 0x10) {
|
||||
if (!(hw_toneb = *MUZPC))
|
||||
op ^= 0x10;
|
||||
}
|
||||
if (op & 0x20) MUZPC++;
|
||||
if (op & 0x40) {
|
||||
if (!(hw_tonea = *MUZPC))
|
||||
op ^= 0x40;
|
||||
}
|
||||
if (op & 0x80) MUZPC++;
|
||||
hw_volab =
|
||||
((op & 0x40) ? (PVOLAB & 0x0f) : 0) |
|
||||
((op & 0x10) ? (PVOLAB & 0xf0) : 0);
|
||||
} else if (op < 0x88) {
|
||||
portOut( NEXT() | ((op-0x70)<<8) );
|
||||
} else if (op == 0x88) {
|
||||
for (byte i=0; i<8; i++) {
|
||||
portOut( NEXT() | (0x17-i) );
|
||||
}
|
||||
} else switch (op & 0xf0) {
|
||||
case 0x90:
|
||||
VOICES = NEXT();
|
||||
break;
|
||||
case 0xa0:
|
||||
PUSH(op - 0x9f);
|
||||
break;
|
||||
case 0xb0:
|
||||
PVOLAB = NEXT();
|
||||
PVOLMC = NEXT();
|
||||
break;
|
||||
case 0xc0:
|
||||
if (DECTOP()) {
|
||||
MUZPC = (byte*)*(word*)MUZPC;
|
||||
} else {
|
||||
MUZPC += 2;
|
||||
POP();
|
||||
}
|
||||
break;
|
||||
case 0xd0:
|
||||
MUZPC += op & 0xf;
|
||||
break;
|
||||
case 0xe0:
|
||||
// REST
|
||||
if (op == 0xe1) {
|
||||
hw_volab = hw_volc = 0;
|
||||
DURAT = *MUZPC++;
|
||||
} else {
|
||||
// TODO: legatto/stacatto
|
||||
}
|
||||
break;
|
||||
case 0xf0:
|
||||
hw_volab = hw_volc = 0;
|
||||
VOICES = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,256 @@
|
|||
|
||||
#include "bios.h"
|
||||
|
||||
#pragma opt_code_speed
|
||||
|
||||
#define LOCHAR 0x20
|
||||
#define HICHAR 0x63
|
||||
|
||||
const byte LMASK[4] = {0xff, 0x3f, 0x0f, 0x03};
|
||||
|
||||
static void hline(byte x1, byte x2, byte y, byte pattern) {
|
||||
byte xb1 = x1/4;
|
||||
byte xb2 = x2/4;
|
||||
byte* dest = &vidmem[y][xb1];
|
||||
byte mask = LMASK[x1&3];
|
||||
if (xb1 == xb2) {
|
||||
mask &= ~LMASK[x2&3];
|
||||
}
|
||||
*dest = *dest & ~mask | (mask & pattern);
|
||||
if (xb1 != xb2) {
|
||||
dest++;
|
||||
while (++xb1 < xb2) {
|
||||
*dest++ = pattern;
|
||||
}
|
||||
*dest = *dest & LMASK[x2&3] | (~LMASK[x2&3] & pattern);
|
||||
}
|
||||
}
|
||||
|
||||
// Fill rect (E,D,C,B) color A
|
||||
void RECTAN(const ContextBlock *ctx) {
|
||||
for (byte y=_D; y<_D+_B; y++) {
|
||||
hline(_E, _E+_C, y, _A);
|
||||
}
|
||||
}
|
||||
|
||||
const char BIGFONT[HICHAR-LOCHAR+1][7] = {/*{count:68,w:8,h:7,brev:1}*/
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00},{0x20,0x20,0x20,0x20,0x00,0x00,0x20},{0x50,0x50,0x00,0x00,0x00,0x00,0x00},{0x48,0xFC,0x48,0x48,0x48,0xFC,0x48},{0x20,0x78,0x80,0x70,0x08,0xF0,0x20},{0x00,0x48,0x10,0x20,0x40,0x90,0x00},{0x60,0x90,0x60,0xA0,0xA8,0x90,0x68},{0x60,0x60,0x20,0x00,0x00,0x00,0x00},{0x20,0x40,0x40,0x40,0x40,0x40,0x20},{0x40,0x20,0x20,0x20,0x20,0x20,0x40},{0x00,0xA8,0x70,0xF8,0x70,0xA8,0x00},{0x00,0x20,0x20,0xF8,0x20,0x20,0x00},{0x00,0x00,0x00,0x00,0x60,0x20,0x40},{0x00,0x00,0x00,0xF0,0x00,0x00,0x00},{0x00,0x00,0x00,0x00,0x00,0x60,0x60},{0x00,0x08,0x10,0x20,0x40,0x80,0x00},{0x70,0x88,0x88,0xA8,0x88,0x88,0x70},{0x20,0x60,0x20,0x20,0x20,0x20,0x70},{0x70,0x88,0x08,0x30,0x40,0x80,0xF8},{0x70,0x88,0x08,0x70,0x08,0x88,0x70},{0x10,0x30,0x50,0x90,0xF8,0x10,0x10},{0xF8,0x80,0x80,0x70,0x08,0x88,0x70},{0x70,0x88,0x80,0xF0,0x88,0x88,0x70},{0xF8,0x88,0x10,0x20,0x20,0x20,0x20},{0x70,0x88,0x88,0x70,0x88,0x88,0x70},{0x70,0x88,0x88,0x78,0x08,0x88,0x70},{0x00,0x00,0x60,0x00,0x60,0x00,0x00},{0x00,0x00,0x60,0x00,0x60,0x20,0x40},{0x10,0x20,0x40,0x80,0x40,0x20,0x10},{0x00,0x00,0xF8,0x00,0xF8,0x00,0x00},{0x40,0x20,0x10,0x08,0x10,0x20,0x40},{0x70,0x08,0x08,0x30,0x20,0x00,0x20},{0x70,0x88,0xB8,0xA8,0x90,0x80,0x70},{0x70,0x88,0x88,0xF8,0x88,0x88,0x88},{0xF0,0x88,0x88,0xF0,0x88,0x88,0xF0},{0x70,0x88,0x80,0x80,0x80,0x88,0x70},{0xF0,0x88,0x88,0x88,0x88,0x88,0xF0},{0xF8,0x80,0x80,0xF0,0x80,0x80,0xF8},{0xF8,0x80,0x80,0xF0,0x80,0x80,0x80},{0x70,0x88,0x80,0xB0,0x88,0x88,0x70},{0x88,0x88,0x88,0xF8,0x88,0x88,0x88},{0x70,0x20,0x20,0x20,0x20,0x20,0x70},{0x08,0x08,0x08,0x08,0x88,0x88,0x70},{0x88,0x90,0xA0,0xC0,0xA0,0x90,0x88},{0x80,0x80,0x80,0x80,0x80,0x80,0xF8},{0x88,0xD8,0xA8,0x88,0x88,0x88,0x88},{0x88,0xC8,0xA8,0xA8,0x98,0x88,0x88},{0xF8,0x88,0x88,0x88,0x88,0x88,0xF8},{0xF0,0x88,0x88,0xF0,0x80,0x80,0x80},{0x70,0x88,0x88,0xA8,0xA8,0x90,0x68},{0xF0,0x88,0x88,0xF0,0x90,0x90,0x88},{0x70,0x88,0x80,0x70,0x08,0x88,0x70},{0xF8,0x20,0x20,0x20,0x20,0x20,0x20},{0x88,0x88,0x88,0x88,0x88,0x88,0x70},{0x88,0x88,0x88,0x88,0x88,0x50,0x20},{0x88,0x88,0x88,0x88,0xA8,0xD8,0x88},{0x88,0x88,0x50,0x20,0x50,0x88,0x88},{0x88,0x88,0x50,0x20,0x20,0x20,0x20},{0xF8,0x08,0x10,0x20,0x40,0x80,0xF8},{0x70,0x40,0x40,0x40,0x40,0x40,0x70},{0x00,0x80,0x40,0x20,0x10,0x08,0x00},{0x70,0x10,0x10,0x10,0x10,0x10,0x70},{0x20,0x70,0xA8,0x20,0x20,0x20,0x00},{0x00,0x20,0x40,0xF8,0x40,0x20,0x00},{0x00,0x20,0x20,0x20,0xA8,0x70,0x20},{0x00,0x20,0x10,0xF8,0x10,0x20,0x00},{0x00,0x88,0x50,0x20,0x50,0x88,0x00},{0x00,0x20,0x00,0xF8,0x00,0x20,0x00}};
|
||||
|
||||
const char SMLFONT[HICHAR-LOCHAR+1][5] = {/*{count:68,w:5,h:5,brev:1}*/
|
||||
{ 0x00,0x00,0x00,0x00,0x00 },{ 0x40,0x40,0x00,0x40,0x00 },{ 0xA0,0xA0,0x00,0x00,0x00 },{ 0x60,0xF0,0xF0,0x60,0x00 },{ 0x40,0xE0,0xE0,0x40,0x00 },{ 0x90,0x20,0x40,0x90,0x00 },{ 0xC0,0xB0,0xE0,0xD0,0x00 },{ 0x20,0x40,0x00,0x00,0x00 },{ 0x20,0x40,0x40,0x20,0x00 },{ 0x40,0x20,0x20,0x40,0x00 },{ 0x40,0xE0,0x40,0xA0,0x00 },{ 0x00,0x40,0xE0,0x40,0x00 },{ 0x00,0x00,0x00,0x60,0x20 },{ 0x00,0x00,0xE0,0x00,0x00 },{ 0x00,0x00,0x00,0x40,0x00 },{ 0x20,0x20,0x40,0x40,0x00 },{ 0xE0,0xA0,0xA0,0xA0,0xE0 },{ 0xC0,0x40,0x40,0x40,0xE0 },{ 0xE0,0x20,0xE0,0x80,0xE0 },{ 0xE0,0x20,0x60,0x20,0xE0 },{ 0xA0,0xA0,0xE0,0x20,0x20 },{ 0xE0,0x80,0xE0,0x20,0xE0 },{ 0xE0,0x80,0xE0,0xA0,0xE0 },{ 0xE0,0x20,0x40,0x40,0x40 },{ 0xE0,0xA0,0xE0,0xA0,0xE0 },{ 0xE0,0xA0,0xE0,0x20,0xE0 },{ 0x00,0x40,0x00,0x40,0x00 },{ 0x00,0x40,0x00,0x60,0x20 },{ 0x00,0x20,0x40,0x20,0x00 },{ 0x00,0xE0,0x00,0xE0,0x00 },{ 0x00,0x40,0x20,0x40,0x00 },{ 0xE0,0x20,0x60,0x00,0x40 },{ 0xF0,0x90,0x10,0xD0,0xF0 },{ 0x60,0xA0,0xE0,0xA0,0x00 },{ 0xC0,0xE0,0xA0,0xE0,0x00 },{ 0x60,0x80,0x80,0xE0,0x00 },{ 0xC0,0xA0,0xA0,0xC0,0x00 },{ 0xE0,0xC0,0x80,0xE0,0x00 },{ 0xE0,0xC0,0x80,0x80,0x00 },{ 0x60,0x80,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xE0,0xA0,0x00 },{ 0xE0,0x40,0x40,0xE0,0x00 },{ 0x60,0x20,0xA0,0xE0,0x00 },{ 0xA0,0xC0,0xC0,0xA0,0x00 },{ 0x80,0x80,0x80,0xE0,0x00 },{ 0xE0,0xE0,0xE0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xA0,0x00 },{ 0xE0,0xA0,0xA0,0xE0,0x00 },{ 0xE0,0xA0,0xE0,0x80,0x00 },{ 0xE0,0xA0,0xE0,0xF0,0x00 },{ 0xE0,0xA0,0xC0,0xA0,0x00 },{ 0xE0,0x80,0x60,0xE0,0x00 },{ 0xE0,0x40,0x40,0x40,0x00 },{ 0xA0,0xA0,0xA0,0xE0,0x00 },{ 0xA0,0xA0,0xC0,0x80,0x00 },{ 0xA0,0xE0,0xE0,0xE0,0x00 },{ 0xA0,0x40,0xA0,0xA0,0x00 },{ 0xA0,0xE0,0x40,0x40,0x00 },{ 0xE0,0x20,0x40,0xE0,0x00 },{ 0x60,0x40,0x40,0x60,0x00 },{ 0x40,0x40,0x20,0x20,0x00 },{ 0x60,0x20,0x20,0x60,0x00 },{ 0x40,0xA0,0x00,0x00,0x00 },{ 0x00,0x00,0x00,0x00,0xF0 },{ 0x80,0x40,0x00,0x00,0x00 },{ 0x00,0x60,0xA0,0xE0,0x00 },{ 0x80,0xE0,0xA0,0xE0,0x00 },{ 0x00,0x60,0x80,0xE0,0x00 }};
|
||||
|
||||
// draw a letter
|
||||
static byte draw_char(const FontDescriptor* font, byte ch, byte x, byte y, byte op) {
|
||||
const byte* src = font->chartab + (ch-font->base_ch)*font->pattern_y;
|
||||
byte* dest = &vmagic[y][x>>2];// destination address
|
||||
byte magic = M_SHIFT(x) | M_XPAND | (op & 0x30);
|
||||
// big sizes?
|
||||
if (op & 0xc0) {
|
||||
char buf[8]; // expansion buffer
|
||||
char* mbuf = (buf - 0x4000);// make it magic
|
||||
byte sc = 1 << (op >> 6); // 2x2 = 2, 4x4 = 4, 8x8 = 8
|
||||
for (byte i=0; i<font->pattern_y; i++) {
|
||||
// expand into magic buffer onto stack
|
||||
hw_magic = M_XPAND;
|
||||
hw_xpand = 0b1100; // on = 11, off = 00
|
||||
// 2x2 size
|
||||
mbuf[1] = mbuf[0] = *src++;
|
||||
// 4x4 size
|
||||
if (op & 0x80) {
|
||||
byte b = buf[0];
|
||||
mbuf[3] = mbuf[2] = buf[1];
|
||||
mbuf[1] = mbuf[0] = b;
|
||||
}
|
||||
// 8x8 size
|
||||
if ((op & 0xc0) == 0xc0) {
|
||||
byte b = buf[0];
|
||||
mbuf[7] = mbuf[6] = buf[3];
|
||||
mbuf[5] = mbuf[4] = buf[2];
|
||||
mbuf[3] = mbuf[2] = buf[1];
|
||||
mbuf[1] = mbuf[0] = b;
|
||||
}
|
||||
// draw to screen (magic, again)
|
||||
hw_xpand = op & 0xf;
|
||||
for (byte j=0; j<sc; j++) {
|
||||
hw_magic = magic; // reset flip flop
|
||||
EXIT_CLIPDEST(dest);
|
||||
for (byte k=0; k<sc; k++) {
|
||||
byte b = buf[k];
|
||||
*dest++ = b;
|
||||
*dest++ = b;
|
||||
}
|
||||
dest += VBWIDTH-sc*2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hw_xpand = op & 0xf;
|
||||
for (byte i=0; i<font->pattern_y; i++) {
|
||||
char b = *src++;
|
||||
EXIT_CLIPDEST(dest);
|
||||
hw_magic = magic; // reset flip flop
|
||||
*dest++ = b; // expand lower nibble -> 1st byte
|
||||
*dest++ = b; // expand upper nibble -> 2nd byte
|
||||
*dest++ = 0; // leftover -> 3rd byte
|
||||
dest += VBWIDTH-3; // we incremented 3 bytes for this line
|
||||
}
|
||||
}
|
||||
return font->frame_x << (op >> 6);
|
||||
}
|
||||
|
||||
#define FONT_IX ((const FontDescriptor*)ctx->regs.w.ix)
|
||||
|
||||
static void draw_string(ContextBlock *ctx, const char* str, byte x, byte y, byte op) {
|
||||
do {
|
||||
byte ch = *str++;
|
||||
if (!ch) {
|
||||
_E = x;
|
||||
break;
|
||||
}
|
||||
if (ch < 0x20) {
|
||||
x += draw_char(&FNTSYS, ' ', x, y, op); // TODO
|
||||
} else if (ch < 0x64) {
|
||||
x += draw_char(&FNTSYS, ch, x, y, op);
|
||||
} else if (ch >= 0x80) {
|
||||
x += draw_char(FONT_IX, ch, x, y, op);
|
||||
} else {
|
||||
/*
|
||||
if (ch & 0x10) {
|
||||
ctx->regs.b.ixl = *str++;
|
||||
ctx->regs.b.ixh = *str++;
|
||||
}
|
||||
if (ch & 0x1)
|
||||
_E = *str++;
|
||||
if (ch & 0x2)
|
||||
_D = *str++;
|
||||
if (ch & 0x4)
|
||||
_C = *str++;
|
||||
*/
|
||||
// TODO: only can change font
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
|
||||
// String display routine (pass pointer to string)
|
||||
void STRDIS2(ContextBlock *ctx, char *str) {
|
||||
byte opts = _C;
|
||||
byte x = _E;
|
||||
byte y = _D;
|
||||
void* fontdesc = (void*) ctx->regs.w.ix;
|
||||
draw_string(ctx, str, x, y, opts); // TODO: opts
|
||||
}
|
||||
|
||||
// String display routine
|
||||
void STRDIS(ContextBlock *ctx) {
|
||||
char* str = (char*) _HL;
|
||||
STRDIS2(ctx, str);
|
||||
}
|
||||
|
||||
// Character display routine
|
||||
void CHRDIS(ContextBlock *ctx) {
|
||||
char chstr[2];
|
||||
chstr[0] = _A;
|
||||
chstr[1] = 0;
|
||||
STRDIS2(ctx, chstr);
|
||||
}
|
||||
|
||||
// BCD routine
|
||||
const char BCDTAB[18] = "0123456789*+,-./ ";
|
||||
|
||||
// DISNUM - (E.D) x/y (C) options (B) ext (HL) BCD-addr
|
||||
void DISNUM(ContextBlock *ctx) {
|
||||
// TODO: options, B
|
||||
byte x = _E;
|
||||
byte y = _D;
|
||||
byte opt = _C;
|
||||
byte ext = _B;
|
||||
byte ndigits = ext & 63;
|
||||
const FontDescriptor* font = (ext&64) ? &FNTSML : &FNTSYS;
|
||||
byte add = (ext&64) ? 128 : 0;
|
||||
byte noleadingzero = ext & 128;
|
||||
byte* pbcd = (byte*) _HL;
|
||||
pbcd += (ndigits-1)/2;
|
||||
while (ndigits--) {
|
||||
byte val = *pbcd;
|
||||
if (ndigits & 1) {
|
||||
val >>= 4;
|
||||
} else {
|
||||
val &= 15;
|
||||
pbcd--;
|
||||
}
|
||||
if (val == 0 && noleadingzero) {
|
||||
val = 16;
|
||||
} else {
|
||||
noleadingzero = 0;
|
||||
}
|
||||
x += draw_char(font, BCDTAB[val]+add, x, y, opt);
|
||||
}
|
||||
}
|
||||
|
||||
// write pattern (E,D,C,B) magic A @ HL
|
||||
void WRIT(ContextBlock *ctx) {
|
||||
byte w = _C;
|
||||
byte h = _B;
|
||||
byte x = _E;
|
||||
byte y = _D;
|
||||
byte magic = _A | (x & 3); // add X shift
|
||||
byte* src = (byte*) _HL;
|
||||
byte* dest = &vmagic[y][0]; // destination address
|
||||
byte xb = (magic & M_FLOP) ? (39-(x>>2)) : (x>>2);
|
||||
byte i,j,b;
|
||||
// iterate through all lines
|
||||
for (j=0; j<h; j++) {
|
||||
EXIT_CLIPDEST(dest);
|
||||
hw_magic = magic;
|
||||
if (magic & M_XPAND) {
|
||||
// when XPAND set, write twice as many bytes
|
||||
for (i=0; i<w*2; i+=2) {
|
||||
b = *src++;
|
||||
// when FLOP set, sprite position is also mirrored
|
||||
if (magic & M_FLOP) {
|
||||
dest[xb-i] = b;
|
||||
dest[xb-i-1] = b;
|
||||
} else {
|
||||
dest[xb+i] = b;
|
||||
dest[xb+i+1] = b;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i=0; i<w; i++) {
|
||||
// when FLOP set, sprite position is also mirrored
|
||||
if (magic & M_FLOP) {
|
||||
dest[xb-i] = *src++;
|
||||
} else {
|
||||
dest[xb+i] = *src++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (magic & M_FLOP)
|
||||
dest[xb-i] = 0;
|
||||
else
|
||||
dest[xb+i] = 0;
|
||||
dest += VBWIDTH;
|
||||
}
|
||||
}
|
||||
|
||||
// write sized pattern (E,D) magic A @ HL
|
||||
void WRITP(ContextBlock *ctx) {
|
||||
byte* src = (byte*) _HL;
|
||||
// get size
|
||||
_C = *src++;
|
||||
_B = *src++;
|
||||
// update src
|
||||
_HL = (word) src;
|
||||
WRIT(ctx);
|
||||
}
|
||||
|
||||
// write relative pattern (E,D) magic A @ HL
|
||||
void WRITR(ContextBlock *ctx) {
|
||||
byte* src = (byte*) _HL;
|
||||
// sub offset
|
||||
_E -= *src++;
|
||||
_D -= *src++;
|
||||
// update src
|
||||
_HL = (word) src;
|
||||
WRITP(ctx);
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
|
||||
#include "bios.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#pragma opt_code_speed
|
||||
|
||||
// for SENTRY
|
||||
extern volatile byte CNT;
|
||||
extern volatile byte SEMI4S;
|
||||
extern volatile byte OPOT[4];
|
||||
extern volatile byte KEYSEX;
|
||||
extern volatile byte OSW[4];
|
||||
extern volatile word COLLST;
|
||||
extern volatile byte SENFLG;
|
||||
extern volatile byte TIMOUT;
|
||||
|
||||
void RCALL(ContextBlock *ctx);
|
||||
void MCALL(ContextBlock *ctx);
|
||||
|
||||
void SENTRY(ContextBlock *ctx) {
|
||||
byte i;
|
||||
byte A = SNUL;
|
||||
byte B = 0;
|
||||
byte key = 0;
|
||||
byte val[4];
|
||||
// joysticks and switches
|
||||
val[0] = hw_p1ctrl;
|
||||
val[1] = hw_p2ctrl;
|
||||
val[2] = hw_p3ctrl;
|
||||
val[3] = hw_p4ctrl;
|
||||
for (i=0; i<4; i++) {
|
||||
if (val[i] != OSW[i]) {
|
||||
A = SJ0+i*2;
|
||||
if ((val[i] ^ OSW[i]) & 0x10) {
|
||||
A++;
|
||||
}
|
||||
B = val[i];
|
||||
}
|
||||
}
|
||||
memcpy(OSW, val, 4); // update previous state
|
||||
// keypad
|
||||
val[0] = hw_keypad0;
|
||||
val[1] = hw_keypad1;
|
||||
val[2] = hw_keypad2;
|
||||
val[3] = hw_keypad3;
|
||||
for (i=0; i<4; i++) {
|
||||
// key down? and with mask
|
||||
if (val[i] && (val[i] &= ((byte*)_DE)[i])) {
|
||||
key = i+1;
|
||||
while (val[i]) {
|
||||
key += 4;
|
||||
val[i] >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// key up?
|
||||
// TODO: race condition with KEYSEX and interrupt
|
||||
if (key && key != KEYSEX) {
|
||||
B = KEYSEX = key;
|
||||
A = SKYD;
|
||||
}
|
||||
else if (!key && KEYSEX) {
|
||||
if (KEYSEX & 0x80) {
|
||||
A = SSEC; // second timer
|
||||
} else {
|
||||
A = SKYU;
|
||||
}
|
||||
B = 0;
|
||||
KEYSEX = 0;
|
||||
}
|
||||
// pots
|
||||
val[0] = hw_p1pot;
|
||||
val[1] = hw_p2pot;
|
||||
val[2] = hw_p3pot;
|
||||
val[3] = hw_p4pot;
|
||||
for (i=0; i<4; i++) {
|
||||
if (val[i] != OPOT[i]) {
|
||||
A = SP0+i;
|
||||
B = val[i];
|
||||
}
|
||||
}
|
||||
memcpy(OPOT, val, 4); // update previous state
|
||||
// semiphores
|
||||
if (SEMI4S) {
|
||||
B = SEMI4S;
|
||||
for (i=7; i>=0; i--) {
|
||||
if (B & 0x80) {
|
||||
A = SF0+i;
|
||||
SEMI4S ^= 1 << i;
|
||||
break;
|
||||
}
|
||||
B <<= 1;
|
||||
}
|
||||
}
|
||||
// counters
|
||||
if (SENFLG) {
|
||||
B = SENFLG;
|
||||
for (i=7; i>=0; i--) {
|
||||
if (B & 0x80) {
|
||||
A = SF0+i;
|
||||
SENFLG ^= 1 << i;
|
||||
break;
|
||||
}
|
||||
B <<= 1;
|
||||
}
|
||||
}
|
||||
// clear timeout counter (TODO)
|
||||
if (A >= SKYU) {
|
||||
TIMOUT = 0xff;
|
||||
}
|
||||
_A = A;
|
||||
_B = B;
|
||||
}
|
||||
|
||||
void DOIT(ContextBlock *ctx) {
|
||||
byte* list = (byte*) _HL;
|
||||
byte code = _A;
|
||||
byte op;
|
||||
while ((op = *list) < 0xc0) {
|
||||
if ((op & 0x3f) == code) {
|
||||
_HL = *(word*)(list+1);
|
||||
switch (op & 0xc0) {
|
||||
// TODO: JMP
|
||||
case 0x00:
|
||||
// RCALL
|
||||
case 0x40:
|
||||
RCALL(ctx);
|
||||
break;
|
||||
// MCALL
|
||||
case 0x80:
|
||||
MCALL(ctx);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
list += 3;
|
||||
}
|
||||
}
|
||||
|
||||
void DOITB(ContextBlock *ctx) {
|
||||
_A = _B;
|
||||
DOIT(ctx);
|
||||
}
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
|
||||
|
||||
; need these in 1st file sdcc linker sees
|
||||
.area _HOME
|
||||
.area _INITIALIZER
|
||||
.area _DATA
|
||||
.area _INITIALIZED
|
||||
.area _BSEG
|
||||
.area _BSS
|
||||
.area _HEAP
|
||||
.area _CODE
|
||||
|
||||
.include "astrocade.inc"
|
||||
.globl _main
|
||||
_main:
|
||||
LD SP,#0x4fce ; position stack below BIOS vars
|
||||
ld hl,#0x20d ; small font -> IX
|
||||
push hl
|
||||
pop ix
|
||||
SYSTEM INTPC
|
||||
DO SETOUT
|
||||
.db 102*2, 23, 0x00
|
||||
DONT EMUSIC
|
||||
DONT ACTINT
|
||||
DO COLSET
|
||||
.dw palette
|
||||
DO FILL
|
||||
.dw 0x4000
|
||||
.dw 95*40
|
||||
.db 0x00
|
||||
DO STRDIS
|
||||
.db 2
|
||||
.db 2
|
||||
.db (1<<2)
|
||||
.dw HelloString
|
||||
DO STRDIS
|
||||
.db 4
|
||||
.db 16
|
||||
.db (2<<2)|0x40
|
||||
.dw BigString
|
||||
DO STRDIS ; draw string
|
||||
.db 4 ; x
|
||||
.db 36 ; y
|
||||
.db (2<<2)|0x80 ; options
|
||||
.dw FourString
|
||||
DO CHRDIS ; draw char
|
||||
.db 109
|
||||
.db 24
|
||||
.db (3<<2)|0x20|0xc0 ; xor 8x8
|
||||
.db 0x3f
|
||||
DO STRDIS
|
||||
.db 4
|
||||
.db 80
|
||||
.db (1<<2)
|
||||
.dw NumString
|
||||
DO RECTAN
|
||||
.db 4
|
||||
.db 72
|
||||
.db 100
|
||||
.db 4
|
||||
.db 0xaa
|
||||
DO RECTAN
|
||||
.db 6
|
||||
.db 74
|
||||
.db 100
|
||||
.db 4
|
||||
.db 0x55
|
||||
DO WRITR
|
||||
.db 50
|
||||
.db 80
|
||||
.db 0x00
|
||||
.dw PATERN
|
||||
DO WRITR
|
||||
.db 0
|
||||
.db 80
|
||||
.db 0x40 ;+expand
|
||||
.dw PATERN
|
||||
DO WRITR
|
||||
.db 140
|
||||
.db 70
|
||||
.db 0x00|0x08 ;+expand
|
||||
.dw BALL
|
||||
DO WRITR
|
||||
.db 0
|
||||
.db 70
|
||||
.db 0x40|0x08 ;flop+expand
|
||||
.dw BALL
|
||||
DO WRITR
|
||||
.db 67
|
||||
.db 80
|
||||
.db 0x08|1 ;expand
|
||||
.dw BALL
|
||||
DO MOVE
|
||||
.dw BCDNUM
|
||||
.dw 3
|
||||
.dw _BCDNUM
|
||||
DO BMUSIC
|
||||
.dw 0x4e80
|
||||
.db 0b11111100
|
||||
.dw ANTHEM
|
||||
; exit interpreter
|
||||
EXIT
|
||||
nop
|
||||
.loop:
|
||||
SYSSUK DISNUM
|
||||
.db 80
|
||||
.db 80
|
||||
.db (2<<2) ;opts
|
||||
.db 6|0x40|0x80 ;ext
|
||||
.dw BCDNUM
|
||||
.waitinput:
|
||||
SYSSUK SENTRY
|
||||
.dw keymask
|
||||
or a
|
||||
jp z,.waitinput
|
||||
; draw result of SENTRY
|
||||
push bc
|
||||
ld e,#114
|
||||
ld d,#80
|
||||
ld c,#0x0c
|
||||
add a,#0x20
|
||||
SYSTEM CHRDIS
|
||||
pop bc
|
||||
ld a,b
|
||||
ld e,#114
|
||||
ld d,#70
|
||||
ld c,#0x0c
|
||||
add a,#0x20
|
||||
SYSTEM CHRDIS
|
||||
SYSSUK BCDADD
|
||||
.dw BCDNUM
|
||||
.db 3
|
||||
.dw BCDINC
|
||||
jp .loop
|
||||
HelloString:
|
||||
.ascii "HELLO WORLD! "
|
||||
.db 0xb1, 0xb2, 0xb3, 0xb4, 0xb5
|
||||
.db 0
|
||||
BigString:
|
||||
.ascii "BIG TEXT!"
|
||||
.db 0
|
||||
FourString:
|
||||
.ascii "4X4"
|
||||
.db 0
|
||||
NumString:
|
||||
.db 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9
|
||||
.db 0
|
||||
palette:
|
||||
.db 0x77, 0xD4, 0x35, 0x01
|
||||
.db 0x07, 0xD4, 0x35, 0x01
|
||||
keymask:
|
||||
.db 0b111111
|
||||
.db 0b111111
|
||||
.db 0b111111
|
||||
.db 0b111111
|
||||
|
||||
BCDNUM = 0x4ea0 ; RAM
|
||||
_BCDNUM:
|
||||
.db 0x97,0x99,0x09
|
||||
BCDINC:
|
||||
.db 0x01,0x00,0x00
|
||||
; Critter Pattern
|
||||
; Color 0 = White and Color 2 = Black
|
||||
;
|
||||
PATERN: .DB 0,0 ; (0,0) Position
|
||||
.DB 0x02,0x08 ; 2 byte, 8 line pattern size
|
||||
|
||||
.DB 0x0A,0xA0 ; 0000101010100000 - . . 2 2 2 2 . .
|
||||
.DB 0x22,0x88 ; 0010001010001000 - . 2 . 2 2 . 2 .
|
||||
.DB 0xAA,0xAA ; 1010101010101010 - 2 2 2 2 2 2 2 2
|
||||
.DB 0x2A,0xA8 ; 0010101010101000 - . 2 2 2 2 2 2 .
|
||||
.DB 0x08,0x20 ; 0000100000100000 - . . 2 . . 2 . .
|
||||
.DB 0x20,0x08 ; 0010000000001000 - . 2 . . . . 2 .
|
||||
.DB 0x08,0x20 ; 0000100000100000 - . . 2 . . 2 . .
|
||||
.DB 0x00,0x00 ; 0000000000000000 - . . . . . . . .
|
||||
|
||||
BALL: .db 0,0
|
||||
.db 1,6
|
||||
.db 0b01111010
|
||||
.db 0b11011101
|
||||
.db 0b10111101
|
||||
.db 0b10111101
|
||||
.db 0b11111101
|
||||
.db 0b01111010
|
||||
|
||||
RINGING:
|
||||
.db 0x80,0x23,0xB0,0x80,0x00,0x3C,0x17,0x3C,0x11,0xE1,0x50,0x3C,0x17,0x3C,0x11,0xE1,0xA0,0xC3,0x5B,0x23,0x00
|
||||
|
||||
ANTHEM:
|
||||
.db 0x80
|
||||
.db 0x20,0xB0,0xCC,0x0F,0x0C,0x7E,0x00,0x00
|
||||
.db 0x0C,0x7E,0x00,0x00,0x24,0x5E,0x7E,0x96
|
||||
.db 0x0C,0x54,0x64,0x7E,0x0E,0x4A,0x5E,0x7E
|
||||
.db 0x10,0x46,0x54,0x7E,0x48,0x3E,0x4A,0x5E
|
||||
.db 0x0E,0x5E,0x8D,0x70,0x10,0x54,0x8D,0x70
|
||||
.db 0x36,0x4A,0x5E,0x70,0x12,0x46,0x54,0x7E
|
||||
.db 0x24,0x54,0x64,0x7E,0x48,0x5E,0x96,0x7E
|
||||
CHEERS:
|
||||
.db 0xE0,0x80,0x18,0x90,0xFD,0xB0,0xFF,0x1F
|
||||
.db 0xA4
|
||||
CHEERLOOP:
|
||||
.db 0x1E,0x19,0x03,0x3C,0x50,0xC0
|
||||
.dw CHEERLOOP
|
||||
.db 0xE0,0xF0
|
|
@ -0,0 +1,49 @@
|
|||
; Demo 1: HELLO, WORLDS! / 2018 hxlnt
|
||||
; Inspired by Adam Trionfo Hello World
|
||||
; http://www.ballyalley.com/ml/ml_homebrew/helloworld/hello.asm
|
||||
; From: https://github.com/hxlnt/astrocade
|
||||
|
||||
; need these in 1st file sdcc linker sees
|
||||
.area _HOME
|
||||
.area _INITIALIZER
|
||||
.area _DATA
|
||||
.area _INITIALIZED
|
||||
.area _BSEG
|
||||
.area _BSS
|
||||
.area _HEAP
|
||||
.area _CODE
|
||||
|
||||
.include "astrocade.inc"
|
||||
.globl _main
|
||||
_main:
|
||||
.db 0x55 ; ... with the code for a normal menued cartridge
|
||||
.dw MENUST ; Initialize menu
|
||||
.dw PrgName ; ... with string at PrgName
|
||||
.dw PrgStart ; ... such that selecting the program enters PrgStart
|
||||
PrgName: .ascii "HELLO, WORLDS!"; String
|
||||
.db 0 ; ... which must be followed by 0
|
||||
PrgStart: DI ; Disable interrupts
|
||||
LD SP,#0x4fce ; position stack below BIOS vars
|
||||
ld hl,#0x20d ; small font -> IX
|
||||
push hl
|
||||
pop ix
|
||||
SYSTEM INTPC ; Begin interpreter mode
|
||||
DO SETOUT ; Set output ports
|
||||
.db 100*2 ; ... with VBLANK line set to line 100
|
||||
.db 112/4 ; ... with color boundary 112 pixels from the left of the screen
|
||||
.db 0b00001000 ; ... with screen interrupts reenabled
|
||||
DO COLSET ; Set color palettes
|
||||
.dw Palettes ; ... with the values at Palettes
|
||||
DO FILL ; Set background fill
|
||||
.dw NORMEM ; ... starting at the beginning of screen RAM
|
||||
.dw 99*BYTEPL ; ... and going for 100 lines
|
||||
.db 0b00010010 ; ... with a fill pattern of three different colored pixels
|
||||
DO STRDIS ; Set string display
|
||||
.db 0 ; ... starting 0 pixels from the left of the screen
|
||||
.db 32 ; ... and 32 pixels from the top of the screen
|
||||
.db 0b00001100 ; ... with no enlargement, foreground color = 11, background color = 00
|
||||
.dw PrgName ; ... to show string at PrgName
|
||||
DONT XINTC
|
||||
Loop: JP Loop ; Play infinite loop
|
||||
Palettes: .db 0xBF,0x00,0x00,0x00 ; Left color palette (11b, 10b, 01b, 00b)
|
||||
.db 0xE7,0x9A,0x39,0x19 ; Right color palette (11b, 10b, 01b, 00b)
|
|
@ -0,0 +1,103 @@
|
|||
; "HORCB Pal" demo 2018 hxlnt
|
||||
; Inspired by Michael Garber Color Picker
|
||||
; http://ballyalley.com/ml/ml_homebrew/colorpicker.asm
|
||||
; From: https://github.com/hxlnt/astrocade
|
||||
|
||||
; need these in 1st file sdcc linker sees
|
||||
.area _HOME
|
||||
.area _INITIALIZER
|
||||
.area _DATA
|
||||
.area _INITIALIZED
|
||||
.area _BSEG
|
||||
.area _BSS
|
||||
.area _HEAP
|
||||
.area _CODE
|
||||
|
||||
.include "astrocade.inc"
|
||||
.globl _main
|
||||
_main:
|
||||
FrameCount = 0x4F00 ; Reserve a space for a frame counter
|
||||
.db 0x55 ; ... with the code for a normal menued cartridge
|
||||
.dw MENUST ; Initialize menu
|
||||
.dw PrgName ; ... with string at PrgName
|
||||
.dw PrgStart ; ... such that selecting the program enters PrgStart
|
||||
PrgName: .ascii "HORCB PAL" ; String
|
||||
.db 0 ; ... which must be followed by 0
|
||||
PrgStart: DI ; Disable interrupts
|
||||
LD SP,#0x4fce ; position stack below BIOS vars
|
||||
ld hl,#0x20d ; small font -> IX
|
||||
push hl
|
||||
pop ix
|
||||
SYSTEM INTPC ; Begin interpreter mode
|
||||
DO SETOUT ; Set output ports
|
||||
.db 96*2 ; ... with VBLANK line set to line 96
|
||||
.db 0/4 ; ... with color boundary 0 pixels from the left of the screen
|
||||
.db 0b00001000 ; ... with screen interrupts enabled
|
||||
DO COLSET ; Set color palettes
|
||||
.dw Palettes ; ... with the values at Palettes
|
||||
DO FILL ; Set background fill
|
||||
.dw NORMEM ; ... starting at the beginning of screen RAM
|
||||
.dw 24*BYTEPL ; ... and going for 24 lines
|
||||
.db 0b00011011 ; ... with a fill pattern of four different colored pixels
|
||||
DO FILL ; Set background fill
|
||||
.dw NORMEM+(24*BYTEPL)
|
||||
.dw 24*BYTEPL ; ... and going for 24 lines
|
||||
.db 0b00000000 ; ... with a solid fill of color 00
|
||||
DO FILL ; Set background fill
|
||||
.dw NORMEM+(48*BYTEPL)
|
||||
.dw 24*BYTEPL ; ... and going for 24 lines
|
||||
.db 0b11111111 ; ... with a solid fill of color 11
|
||||
DO STRDIS ; Set string display
|
||||
.db 28 ; ... starting 28 pixels from the left of the screen
|
||||
.db 40 ; ... and 40 pixels from the top of the screen
|
||||
.db 0b00001100 ; ... with no enlargement, foreground color = 11, background color = 00
|
||||
.dw PrgName ; ... with string at PrgName
|
||||
DONT XINTC ; Exit interpreter mode
|
||||
Loop: IN A,(POT0) ; Let A = controller 1 knob value
|
||||
OUT (HORCB),A ; Let horizontal color boundary = A
|
||||
CALL UpdateDisp ; Call UpdateDisp subroutine
|
||||
JP Loop ; Go back to beginning of infinite loop
|
||||
Palettes: .db 0xF4,0x1C,0x1F,0x5F ; Left color palette (11b, 10b, 01b, 00b)
|
||||
.db 0xED,0xCD,0xD5,0x8E ; Right color palette (11b, 10b, 01b, 00b)
|
||||
UpdateDisp:
|
||||
DI ; Disable interrupts
|
||||
PUSH AF ; Push AF to SP
|
||||
LD C,A ; Get first hex digit from knob value
|
||||
SRL C ; ...
|
||||
SRL C ; ...
|
||||
SRL C ; ...
|
||||
SRL C ; ...
|
||||
LD B,#0 ; Display first hex digit from knob value
|
||||
LD HL,#Hex ; ... Load HL with address Hex
|
||||
ADD HL,BC ; ... Offset Hex by BC to get first hex digit
|
||||
LD A,(HL) ; ... Load A with first hex digit
|
||||
LD C,#0b00000100 ; ... Load C with string options
|
||||
LD D,#40 ; ... Load D with string Y-coordinate
|
||||
LD E,#120 ; ... Load E with X-coordinate
|
||||
SYSTEM (CHRDIS) ; ... Display first digit
|
||||
POP AF ; Pop AF off SP
|
||||
AND A,#0x0F ; Get second hex digit from knob value
|
||||
LD C,A ; ...
|
||||
LD B,#0 ; Display second hex digit from knob value
|
||||
LD HL,#Hex ; ... Load HL with address Hex
|
||||
ADD HL,BC ; ... Offset Hex by BC to get second hex digit
|
||||
LD A,(HL) ; ... Load A with second hex digit
|
||||
LD C,#0b00000100 ; ... Load C with string options
|
||||
LD D,#40 ; ... Load D with Y-coordinate
|
||||
LD E,#128 ; ... Load E with X-coordinate
|
||||
SYSTEM (CHRDIS) ; ... Display second digit
|
||||
LD A,(FrameCount) ; Increment frame counter
|
||||
INC A ; ...
|
||||
LD (FrameCount),A ; ...
|
||||
AND #0b00000111 ; Every fourth frame, run AnimBars
|
||||
CP #0b00000100 ; ...
|
||||
JR Z, AnimBars ; ...
|
||||
JP AnimDone ; Otherwise, skip AnimBars
|
||||
AnimBars: SYSSUK RANGED ; Load a random 8-bit number in A
|
||||
.db 0 ; ...
|
||||
LD BC,#24*BYTEPL ; Load BC with one scanline length
|
||||
LD DE,#NORMEM+(72*BYTEPL)
|
||||
SYSTEM FILL ; Fill remainder of screen with repeating random tile
|
||||
AnimDone: EI ; Enable interrupts
|
||||
RET ; Return from subroutine
|
||||
Hex: .ascii "0123456789ABCDEF"
|
|
@ -13,6 +13,7 @@
|
|||
PrgName: DB "HELLO, WORLDS!"; String
|
||||
DB 0 ; ... which must be followed by 0
|
||||
PrgStart: DI ; Disable interrupts
|
||||
; db $ed,$ff
|
||||
SYSTEM INTPC ; Begin interpreter mode
|
||||
DO SETOUT ; Set output ports
|
||||
DB 100*2 ; ... with VBLANK line set to line 100
|
||||
|
@ -22,14 +23,53 @@ PrgStart: DI ; Disable interrupts
|
|||
DW Palettes ; ... with the values at Palettes
|
||||
DO FILL ; Set background fill
|
||||
DW NORMEM ; ... starting at the beginning of screen RAM
|
||||
DW 100*BYTEPL ; ... and going for 100 lines
|
||||
DW 98*BYTEPL ; ... and going for 100 lines
|
||||
DB 00010010b ; ... with a fill pattern of three different colored pixels
|
||||
DO STRDIS ; Set string display
|
||||
DB 0 ; ... starting 0 pixels from the left of the screen
|
||||
DB 32 ; ... and 32 pixels from the top of the screen
|
||||
DB 00001100b ; ... with no enlargement, foreground color = 11, background color = 00
|
||||
DW PrgName ; ... to show string at PrgName
|
||||
; call Begin Music system routine
|
||||
DO ACTINT
|
||||
DO BMUSIC ; START THE NATIONAL ANTHEM
|
||||
DW MUSICWRK ; MUSIC STACK
|
||||
DB 11111100B ; 3-VOICE (A,B,C)
|
||||
DW ANTHEM ; SCORE
|
||||
EXIT ; Exit interpreter mode
|
||||
Loop: JP Loop ; Play infinite loop
|
||||
Palettes: DB $BF,$00,$00,$00 ; Left color palette (11b, 10b, 01b, 00b)
|
||||
DB $E7,$9A,$39,$19 ; Right color palette (11b, 10b, 01b, 00b)
|
||||
|
||||
; Music stack in RAM
|
||||
MUSICWRK EQU $4E7F ; BLOCK 2
|
||||
; [...]
|
||||
|
||||
ANTHEM: MASTER 32
|
||||
VOLUME $CC,$0F ; A,B=12, C=15
|
||||
NOTE3 12,G1,0,0 ; G1, 0, 0
|
||||
NOTE3 12,G1,0,0 ; G1, 0, 0
|
||||
NOTE3 36,C2,G1,E1 ; C2, G1, E1
|
||||
NOTE3 12,D2,B1,G1 ; D2, B1, G1
|
||||
NOTE3 14,E2,C2,G1 ; E2, C2, G1
|
||||
NOTE3 16,F2,D2,G1 ; F2, D2, G1
|
||||
NOTE3 72,G2,E2,C2 ; G2, E2, C2
|
||||
;
|
||||
NOTE3 14,C2,F1,A1 ; C2, F1, A1
|
||||
NOTE3 16,D2,F1,A1 ; D2, F1, A1
|
||||
NOTE3 54,E2,C2,A1 ; E2, C2, A1
|
||||
NOTE3 18,F2,D2,G1
|
||||
NOTE3 36,D2,B1,G1 ; D2, B1, G1
|
||||
NOTE3 72,C2,E1,G1 ; C2, E1, G1
|
||||
;
|
||||
CHEERS: LEGSTA ; Cheers
|
||||
MASTER 24
|
||||
VOICEM 11111101B ; A,B,C & Noise
|
||||
VOLUME $FF,$1F ; Max. Volume
|
||||
;
|
||||
PUSHN 5
|
||||
L2FE8: DB 30 ; Noise
|
||||
NOTE3 25,G6,60,80
|
||||
DSJNZ L2FE8
|
||||
LEGSTA
|
||||
QUIET
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
#ifndef _ACBIOS_H
|
||||
#define _ACBIOS_H
|
||||
|
||||
#include "aclib.h"
|
||||
|
||||
// FONT DESCRIPTORS
|
||||
|
||||
typedef struct {
|
||||
byte base_ch;
|
||||
byte frame_x;
|
||||
byte frame_y;
|
||||
byte pattern_x;
|
||||
byte pattern_y;
|
||||
const byte* chartab;
|
||||
} FontDescriptor;
|
||||
|
||||
const FontDescriptor __at(0x206) FNTSYS; // system font
|
||||
const FontDescriptor __at(0x20d) FNTSML; // small font
|
||||
const byte __at(0x214) ALKEYS[4]; // "all keys" keyboard mask
|
||||
|
||||
// SENTRY
|
||||
|
||||
typedef enum {
|
||||
SNUL,
|
||||
SCT0,SCT1,SCT2,SCT3,SCT4,SCT5,SCT6,SCT7,
|
||||
SF0,SF1,SF2,SF3,SF4,SF5,SF6,SF7,
|
||||
SSEC,
|
||||
SKYU,SKYD,
|
||||
ST0,SJ0,ST1,SJ1,ST2,SJ2,ST3,SJ3,
|
||||
SP0,SP1,SP2,SP3
|
||||
} SENTRYCode;
|
||||
|
||||
typedef struct {
|
||||
byte code;
|
||||
word address;
|
||||
} DOITEntry;
|
||||
|
||||
#define DOIT_END 0xff
|
||||
|
||||
// PATTERNS
|
||||
|
||||
typedef struct {
|
||||
sbyte xofs, yofs;
|
||||
byte xsize, ysize;
|
||||
byte pattern[0];
|
||||
} RelativeBlock;
|
||||
|
||||
typedef struct {
|
||||
byte xsize, ysize;
|
||||
byte pattern[0];
|
||||
} PatternBlock;
|
||||
|
||||
// FUNCTIONS
|
||||
|
||||
#define OPT_1x1 0x00
|
||||
#define OPT_2x2 0x40
|
||||
#define OPT_4x4 0x80
|
||||
#define OPT_8x8 0xc0
|
||||
#define OPT_XOR 0x20
|
||||
#define OPT_OR 0x10
|
||||
#define OPT_ON(n) ((n)<<2)
|
||||
#define OPT_OFF(n) ((n))
|
||||
|
||||
#define DISBCD_SML 0x40
|
||||
#define DISBCD_NOZERO 0x80
|
||||
|
||||
void activate_interrupts(void);
|
||||
void sleep(byte frames) __z88dk_fastcall;
|
||||
void fast_vsync(void);
|
||||
|
||||
void display_string(byte x, byte y, byte options, const char* str);
|
||||
void paint_rectangle(byte x, byte y, byte w, byte h, byte colormask);
|
||||
void blank_area(byte wb, byte h, byte data, byte* video);
|
||||
|
||||
void write_relative(byte x, byte y, byte magic, const byte* pattern);
|
||||
void write_pattern(byte x, byte y, byte magic, const byte* pattern);
|
||||
|
||||
void display_bcd_number(byte x, byte y, byte options, const byte* number, byte extopt);
|
||||
void bcdn_add(byte* dest, byte size, const byte* n);
|
||||
void bcdn_sub(byte* dest, byte size, const byte* n);
|
||||
byte ranged_random(byte n) __z88dk_fastcall;
|
||||
byte keycode_to_ascii(byte n) __z88dk_fastcall;
|
||||
|
||||
word sense_transition(const byte keypad_mask[4]) __z88dk_fastcall;
|
||||
void respond_to_input(const DOITEntry* doit_table, byte a);
|
||||
void respond_to_input_b(const DOITEntry* doit_table, byte b);
|
||||
|
||||
void begin_music(const byte* stack, byte voices, const byte* musicdata);
|
||||
void end_music(void);
|
||||
|
||||
// QUICK MACROS
|
||||
|
||||
#define SYS_ACTINT()\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x0f");\
|
||||
|
||||
#define SYS_PAWS(frames)\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x51");\
|
||||
__asm__(".db "#frames);\
|
||||
|
||||
#define SYS_SETOUT(verbl,horcb,inmod)\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x17");\
|
||||
__asm__(".db "#verbl);\
|
||||
__asm__(".db "#horcb);\
|
||||
__asm__(".db "#inmod);\
|
||||
|
||||
#define SYS_FILL(dest,count,val)\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x1b");\
|
||||
__asm__(".dw "#dest);\
|
||||
__asm__(".dw "#count);\
|
||||
__asm__(".db "#val);\
|
||||
|
||||
#define SYS_MOVE(dest,src,count)\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x5f");\
|
||||
__asm__(".dw "#dest);\
|
||||
__asm__(".dw "#count);\
|
||||
__asm__(".dw "#src);\
|
||||
|
||||
#define SYS_RECTAN(x,y,width,height,color)\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x1d");\
|
||||
__asm__(".db "#x);\
|
||||
__asm__(".db "#y);\
|
||||
__asm__(".db "#width);\
|
||||
__asm__(".db "#height);\
|
||||
__asm__(".db "#color);\
|
||||
|
||||
#define SYS_BMUSIC(stack,voices,musicdata)\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x13");\
|
||||
__asm__(".dw "#stack);\
|
||||
__asm__(".db "#voices);\
|
||||
__asm__(".dw "#musicdata);\
|
||||
|
||||
#define SYS_EMUSIC()\
|
||||
__asm__("rst 0x38");\
|
||||
__asm__(".db 0x15");\
|
||||
|
||||
#define RESET_TIMEOUT() \
|
||||
__asm__("ld a,#0xff");\
|
||||
__asm__("ld (0x4FEC),a");
|
||||
|
||||
#endif
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
.include "astrocade.inc"
|
||||
|
||||
;;; C functions
|
||||
|
||||
.area _CODE_ACBIOS
|
||||
|
||||
; activate interrupts
|
||||
.globl _activate_interrupts
|
||||
_activate_interrupts:
|
||||
SYSTEM ACTINT
|
||||
; set INMOD
|
||||
ld a,#0x8
|
||||
out (INMOD),a
|
||||
ret
|
||||
|
||||
; wait for next interrupt
|
||||
.globl _sleep
|
||||
_sleep:
|
||||
ld b,l
|
||||
SYSTEM PAWS
|
||||
ret
|
||||
|
||||
.globl _fast_vsync
|
||||
_fast_vsync:
|
||||
ld hl,#TMR60
|
||||
ld c,(hl)
|
||||
.lvsync:
|
||||
ld a,(hl)
|
||||
sub c
|
||||
jp z,.lvsync
|
||||
ret
|
||||
|
||||
; load 5 bytes from stack into registers
|
||||
load5_edca_hl:
|
||||
ld ix,#4
|
||||
add ix,sp
|
||||
ld e,0(ix) ; x
|
||||
ld d,1(ix) ; y
|
||||
ld c,2(ix) ; options
|
||||
ld b,c
|
||||
ld a,c
|
||||
ld l,3(ix) ; addr lo
|
||||
ld h,4(ix) ; addr hi
|
||||
ret
|
||||
|
||||
; STRDIR x y options string-addr
|
||||
.globl _display_string
|
||||
_display_string:
|
||||
call load5_edca_hl
|
||||
ld ix,#0x20d ; alternate font desc.
|
||||
SYSTEM STRDIS
|
||||
ret
|
||||
|
||||
; RECTAN x y w h colormask
|
||||
.globl _paint_rectangle
|
||||
_paint_rectangle:
|
||||
call load5_edca_hl
|
||||
ld b,l
|
||||
ld a,h
|
||||
SYSTEM RECTAN
|
||||
ret
|
||||
|
||||
; WRITR x y magic pattern-addr
|
||||
.globl _write_relative
|
||||
_write_relative:
|
||||
call load5_edca_hl
|
||||
SYSTEM WRITR
|
||||
ret
|
||||
|
||||
; WRITP x y magic pattern-addr
|
||||
.globl _write_pattern
|
||||
_write_pattern:
|
||||
call load5_edca_hl
|
||||
SYSTEM WRITP
|
||||
ret
|
||||
|
||||
; DISNUM x y options number-addr
|
||||
.globl _display_bcd_number
|
||||
_display_bcd_number:
|
||||
call load5_edca_hl
|
||||
ld b,5(ix) ; addr hi
|
||||
ld ix,#0x20d ; alternate font desc.
|
||||
SYSTEM DISNUM
|
||||
ret
|
||||
|
||||
; BCDADD arg1 size arg2
|
||||
.globl _bcdn_add
|
||||
_bcdn_add:
|
||||
call load5_edca_hl
|
||||
ld b,c
|
||||
SYSTEM BCDADD
|
||||
ret
|
||||
|
||||
; RANGED n
|
||||
.globl _ranged_random
|
||||
_ranged_random:
|
||||
ld a,l
|
||||
SYSTEM RANGED
|
||||
ret
|
||||
|
||||
; KCTASC n
|
||||
.globl _keycode_to_ascii
|
||||
_keycode_to_ascii:
|
||||
ld a,l
|
||||
SYSTEM KCTASC
|
||||
ret
|
||||
|
||||
; BLANK w h data video-addr
|
||||
.globl _blank_area
|
||||
_blank_area:
|
||||
call load5_edca_hl
|
||||
SYSTEM BLANK
|
||||
ret
|
||||
|
||||
; SENTRY mask-addr
|
||||
.globl _sense_transition
|
||||
_sense_transition:
|
||||
ld l,e
|
||||
ld h,d
|
||||
SYSTEM SENTRY
|
||||
ld l,a
|
||||
ld h,b
|
||||
ret
|
||||
|
||||
; DOIT table-addr
|
||||
.globl _respond_to_input
|
||||
_respond_to_input:
|
||||
call load5_edca_hl
|
||||
SYSTEM DOIT
|
||||
ret
|
||||
|
||||
; DOITB table-addr
|
||||
.globl _respond_to_input_b
|
||||
_respond_to_input_b:
|
||||
call load5_edca_hl
|
||||
SYSTEM DOIT
|
||||
ret
|
||||
|
||||
; BMUSIC stack-addr voices score-addr
|
||||
.globl _begin_music
|
||||
_begin_music:
|
||||
call load5_edca_hl
|
||||
push de
|
||||
pop ix
|
||||
SYSTEM BMUSIC
|
||||
ret
|
||||
|
|
@ -1,65 +1,59 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#include "aclib.h"
|
||||
#include "acextra.h"
|
||||
|
||||
#pragma opt_code_speed
|
||||
|
||||
#define EXIT_CLIPDEST(addr) if ((((word)addr)&0xfff) >= 0xe10) return
|
||||
|
||||
// clear screen and set graphics mode
|
||||
void clrscr() {
|
||||
void clrscr(void) {
|
||||
memset(vidmem, 0, VHEIGHT*VBWIDTH); // clear page 1
|
||||
}
|
||||
|
||||
// draw vertical line
|
||||
void vline(byte x, byte y1, byte y2, byte col, byte op) {
|
||||
byte xb = x>>2; // divide x by 4
|
||||
byte* dest = &vmagic[y1][xb]; // destination address
|
||||
byte y;
|
||||
byte* dest = &vmagic[y1][x>>2];// destination address
|
||||
col <<= 6; // color goes in top 2 bits
|
||||
hw_magic = M_SHIFT(x) | op; // set magic register
|
||||
col <<= 6; // put color in high pixel
|
||||
for (y=y1; y<=y2; y++) {
|
||||
EXIT_CLIPDEST(dest);
|
||||
*dest = col; // shift + xor color
|
||||
dest += VBWIDTH; // dest address to next scanline
|
||||
if (y2 >= VHEIGHT) y2 = VHEIGHT-1; // clipping
|
||||
if (y1 > y2) return;
|
||||
*dest = col;
|
||||
while (++y1 <= y2) {
|
||||
dest += VBWIDTH; // dest address to next scanline
|
||||
*dest = col;
|
||||
}
|
||||
}
|
||||
|
||||
// draw a pixel
|
||||
void pixel(byte x, byte y, byte col, byte op) {
|
||||
vline(x, y, y, col, op); // draw line with 1-pixel height
|
||||
}
|
||||
|
||||
// render a sprite with the given graphics operation
|
||||
void render_sprite(const byte* src, byte x, byte y, byte op) {
|
||||
byte i,j;
|
||||
byte i;
|
||||
byte w = *src++; // get width from 1st byte of sprite
|
||||
byte h = *src++; // get height from 2nd byte of sprite
|
||||
byte xb = x>>2; // divide x by 4
|
||||
byte* dest = &vmagic[y][xb]; // destination address
|
||||
byte* dest = &vmagic[y][x>>2];// destination address
|
||||
hw_magic = M_SHIFT(x) | op; // set magic register
|
||||
for (j=0; j<h; j++) {
|
||||
EXIT_CLIPDEST(dest);
|
||||
for (i=0; i<w; i++) {
|
||||
*dest++ = *src++;
|
||||
}
|
||||
*dest = 0; // rest of shifted byte
|
||||
dest += VBWIDTH-w; // dest address to next scanline
|
||||
// y clipping off bottom
|
||||
if (y+h >= VHEIGHT) {
|
||||
if (y >= VHEIGHT) return;
|
||||
h = VHEIGHT-y;
|
||||
}
|
||||
}
|
||||
|
||||
// erase a sprite
|
||||
void erase_sprite(const byte* src, byte x, byte y) {
|
||||
byte i,j;
|
||||
byte w = *src++; // get width from 1st byte of sprite
|
||||
byte h = *src++; // get height from 2nd byte of sprite
|
||||
byte xb = x>>2; // divide x by 4
|
||||
byte* dest = &vidmem[y][xb]; // destination address
|
||||
for (j=0; j<h; j++) {
|
||||
EXIT_CLIPDEST(dest);
|
||||
for (i=0; i<w; i++) {
|
||||
*dest++ = 0;
|
||||
// memory copy loop
|
||||
if (op != M_ERASE) {
|
||||
while (h--) {
|
||||
for (i=0; i<w; i++) {
|
||||
*dest++ = *src++; // copy bytes
|
||||
}
|
||||
*dest = 0; // rest of shifted byte
|
||||
dest += VBWIDTH-w; // dest address to next scanline
|
||||
}
|
||||
// erase sprite loop
|
||||
} else {
|
||||
while (h--) {
|
||||
memset(dest, 0, w+1); // erase bytes
|
||||
dest += VBWIDTH; // dest address to next scanline
|
||||
}
|
||||
*dest = 0; // rest of shifted byte
|
||||
dest += VBWIDTH-w; // dest address to next scanline
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,25 +65,29 @@ const char FONT[HICHAR-LOCHAR+1][FONT_HEIGHT*FONT_BWIDTH] = {
|
|||
// draw a letter
|
||||
void draw_char(byte ch, byte x, byte y, byte op) {
|
||||
const byte* src = &FONT[(ch-LOCHAR)][0];
|
||||
byte xb = x>>2; // divide x by 4
|
||||
byte* dest = &vmagic[y][xb]; // destination address
|
||||
byte* dest = &vmagic[y][x>>2]; // destination address
|
||||
hw_magic = M_SHIFT(x) | M_XPAND | op;
|
||||
for (byte i=0; i<8; i++) {
|
||||
char b = *src++;
|
||||
EXIT_CLIPDEST(dest);
|
||||
*dest++ = b; // expand lower nibble -> 1st byte
|
||||
*dest++ = b; // expand upper nibble -> 2nd byte
|
||||
*dest++ = 0; // leftover -> 3rd byte
|
||||
*dest = 0; // reset upper/lower flag
|
||||
if (x & 3) {
|
||||
*dest++ = 0; // leftover -> 3rd byte
|
||||
*dest = 0; // reset upper/lower flag
|
||||
} else {
|
||||
dest++;
|
||||
}
|
||||
dest += VBWIDTH-3; // we incremented 3 bytes for this line
|
||||
}
|
||||
}
|
||||
|
||||
void draw_string(const char* str, byte x, byte y) {
|
||||
void draw_string(byte x, byte y, byte options, const char* str) {
|
||||
hw_xpand = XPAND_COLORS(0, options);
|
||||
do {
|
||||
byte ch = *str++;
|
||||
if (!ch) break;
|
||||
draw_char(ch, x, y, M_MOVE);
|
||||
draw_char(ch, x, y, M_XOR);
|
||||
x += 8;
|
||||
} while (1);
|
||||
}
|
||||
|
@ -105,24 +103,24 @@ void draw_bcd_word(word bcd, byte x, byte y, byte op) {
|
|||
}
|
||||
|
||||
// add two 16-bit BCD values
|
||||
word bcd_add(word a, word b) {
|
||||
word bcd_add(word a, word b) __naked {
|
||||
a; b; // to avoid warning
|
||||
__asm
|
||||
ld hl,#4
|
||||
add hl,sp
|
||||
ld iy,#2
|
||||
add iy,sp
|
||||
ld a,0 (iy)
|
||||
add a, (hl)
|
||||
daa
|
||||
ld c,a
|
||||
ld a,1 (iy)
|
||||
inc hl
|
||||
adc a, (hl)
|
||||
daa
|
||||
ld b,a
|
||||
ld l, c
|
||||
ld h, b
|
||||
push ix
|
||||
ld ix,#0
|
||||
add ix,sp
|
||||
ld a,4 (ix)
|
||||
add a, 6 (ix)
|
||||
daa
|
||||
ld c,a
|
||||
ld a,5 (ix)
|
||||
adc a, 7 (ix)
|
||||
daa
|
||||
ld b,a
|
||||
ld l, c
|
||||
ld h, b
|
||||
pop ix
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
#ifndef _ACEXTRA_H
|
||||
#define _ACEXTRA_H
|
||||
|
||||
#include "aclib.h"
|
||||
|
||||
// special case for draw_sprite()
|
||||
#define M_ERASE 0x04
|
||||
|
||||
// font constants
|
||||
#define LOCHAR 32
|
||||
#define HICHAR 127
|
||||
#define FONT_BWIDTH 1
|
||||
#define FONT_HEIGHT 8
|
||||
|
||||
void clrscr();
|
||||
void vline(byte x, byte y1, byte y2, byte col, byte op);
|
||||
void pixel(byte x, byte y, byte col, byte op);
|
||||
void render_sprite(const byte* src, byte x, byte y, byte op);
|
||||
void draw_char(byte ch, byte x, byte y, byte op);
|
||||
void draw_string(byte x, byte y, byte options, const char* str);
|
||||
void draw_bcd_word(word bcd, byte x, byte y, byte op);
|
||||
word bcd_add(word a, word b);
|
||||
|
||||
#define pixel(x,y,color,op) vline(x, y, y, color, op);
|
||||
#define erase_sprite(src,x,y) render_sprite(src,x,y,M_ERASE);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
#include "aclib.h"
|
||||
|
||||
extern void fast_sprite_8(const byte* pattern, byte* dst);
|
||||
extern void fast_sprite_16(const byte* pattern, byte* dst);
|
||||
// clips off bottom
|
||||
extern void fast_sprite_16_yclip(const byte* pattern, byte* dst, byte height);
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
|
||||
; FAST SPRITE ROUTINES FOR ASTROCADE
|
||||
; fast_sprite_8: 8 (2 bytes) by H pixels, unexpanded
|
||||
; fast_sprite_16: 16 (4 bytes) by H pixels, unexpanded
|
||||
; Pattern format: bytewidth height data...
|
||||
.area _CODE_ACFAST
|
||||
|
||||
;void fast_sprite_8(const byte* src, byte* dst) {
|
||||
.globl _fast_sprite_8
|
||||
_fast_sprite_8:
|
||||
push ix
|
||||
ld ix,#0
|
||||
add ix,sp ; IX = arg pointer
|
||||
ld l,4(ix) ; src (HL)
|
||||
ld h,5(ix)
|
||||
ld e,6(ix) ; dst (DE)
|
||||
ld d,7(ix)
|
||||
inc hl ; skip width
|
||||
ld c,(hl) ; load height -> C
|
||||
sla c ; C *= 2
|
||||
ld b,#0 ; B always 0 (BC < 256)
|
||||
inc hl ; move HL to pattern start
|
||||
001$:
|
||||
ldi
|
||||
ldi ; copy 2 bytes src to dst
|
||||
ld a,b ; 0 -> A, doesnt affect flags
|
||||
ld (de),a ; copy 3rd 0 (for shifts)
|
||||
jp po,002$ ; exit if BC == 0
|
||||
ld a,e ; E -> A
|
||||
add a,#38 ; next scanline (dest += 38)
|
||||
ld e,a ; A -> E
|
||||
jr nc,001$ ; loop unless lo byte overflow
|
||||
inc d ; inc hi byte of dest. addr
|
||||
jr 001$ ; loop to next line
|
||||
002$:
|
||||
pop ix
|
||||
ret
|
||||
|
||||
;void fast_sprite_16(const byte* src, byte* dst) {
|
||||
.globl _fast_sprite_16
|
||||
_fast_sprite_16:
|
||||
push ix
|
||||
ld ix,#0
|
||||
add ix,sp ; IX = arg pointer
|
||||
ld l,4(ix) ; src (HL)
|
||||
ld h,5(ix)
|
||||
inc hl ; skip width
|
||||
ld c,(hl) ; load height -> C
|
||||
fast_sprite_16_clip_entry:
|
||||
sla c
|
||||
sla c ; C *= 4
|
||||
ld b,#0 ; B always 0 (BC < 256)
|
||||
inc hl ; move HL to pattern start
|
||||
ld e,6(ix) ; dst (DE)
|
||||
ld d,7(ix)
|
||||
001$:
|
||||
ldi
|
||||
ldi
|
||||
ldi
|
||||
ldi ; copy 4 bytes src to dst
|
||||
ld a,b ; 0 -> A, doesnt affect flags
|
||||
ld (de),a ; copy 3rd 0 (for shifts)
|
||||
jp po,002$ ; exit if BC == 0
|
||||
ld a,e ; E -> A
|
||||
add a,#36 ; next scanline (dest += 38)
|
||||
ld e,a ; A -> E
|
||||
jr nc,001$ ; loop unless lo byte overflow
|
||||
inc d ; inc hi byte of dest. addr
|
||||
jr 001$ ; loop to next line
|
||||
002$:
|
||||
pop ix
|
||||
ret
|
||||
|
||||
;void fast_sprite_16_yclip(const byte* src, byte* dst, byte height) {
|
||||
.globl _fast_sprite_16_yclip
|
||||
_fast_sprite_16_yclip:
|
||||
push ix
|
||||
ld ix,#0
|
||||
add ix,sp ; IX = arg pointer
|
||||
ld l,4(ix) ; src (HL)
|
||||
ld h,5(ix)
|
||||
ld c,8(ix) ; height (C)
|
||||
inc hl ; skip width
|
||||
jp fast_sprite_16_clip_entry
|
|
@ -1,9 +0,0 @@
|
|||
|
||||
; Minimal header file for use with Astrocade C programs
|
||||
|
||||
.area _CODE
|
||||
|
||||
jp start ; jump to main()
|
||||
start:
|
||||
ld sp,#0x4fce
|
||||
jp _main
|
|
@ -2,11 +2,14 @@
|
|||
#ifndef _ACLIB_H
|
||||
#define _ACLIB_H
|
||||
|
||||
// convenient type definitions
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
typedef enum { false, true } bool;
|
||||
|
||||
/// HARDWARE
|
||||
/// registers
|
||||
|
||||
__sfr __at(0x00) hw_col0r; // palette 0
|
||||
__sfr __at(0x01) hw_col1r;
|
||||
|
@ -16,53 +19,117 @@ __sfr __at(0x04) hw_col0l;
|
|||
__sfr __at(0x05) hw_col1l;
|
||||
__sfr __at(0x06) hw_col2l;
|
||||
__sfr __at(0x07) hw_col3l; // palette 7
|
||||
|
||||
__sfr __at(0x08) hw_concm; // consumer/commercial mode
|
||||
__sfr __at(0x09) hw_horcb; // horiz color boundary
|
||||
__sfr __at(0x0a) hw_verbl; // vertical blanking line * 2
|
||||
__sfr __at(0x0b) hw_colbx; // palette transfer
|
||||
__sfr __at(0x0c) hw_magic; // magic register
|
||||
__sfr __at(0x0d) hw_infbk; // interrupt feedback
|
||||
__sfr __at(0x0e) hw_inmod; // interrupt enable, mode
|
||||
__sfr __at(0x0f) hw_inlin; // interrupt line
|
||||
__sfr __at(0x19) hw_xpand; // expander register
|
||||
|
||||
__sfr __at(0x08) hw_intst; // intercept test feedback
|
||||
|
||||
__sfr __at(0x10) hw_p1ctrl; // player controls
|
||||
__sfr __at(0x11) hw_p2ctrl; // player controls
|
||||
__sfr __at(0x12) hw_p3ctrl; // player controls
|
||||
__sfr __at(0x13) hw_p4ctrl; // player controls
|
||||
__sfr __at(0x10) hw_p1ctrl; // player 1 controls
|
||||
__sfr __at(0x11) hw_p2ctrl; // player 2 controls
|
||||
__sfr __at(0x12) hw_p3ctrl; // player 3 controls
|
||||
__sfr __at(0x13) hw_p4ctrl; // player 4 controls
|
||||
__sfr __at(0x14) hw_keypad0; // keypad column
|
||||
__sfr __at(0x15) hw_keypad1; // keypad column
|
||||
__sfr __at(0x16) hw_keypad2; // keypad column
|
||||
__sfr __at(0x17) hw_keypad3; // keypad column
|
||||
__sfr __at(0x1c) hw_p1pot; // player 1 paddle
|
||||
__sfr __at(0x1d) hw_p2pot; // player 1 paddle
|
||||
__sfr __at(0x1e) hw_p3pot; // player 1 paddle
|
||||
__sfr __at(0x1f) hw_p4pot; // player 1 paddle
|
||||
|
||||
__sfr __at(0x10) hw_tonmo; // tone master oscillator
|
||||
__sfr __at(0x11) hw_tonea;
|
||||
__sfr __at(0x12) hw_toneb;
|
||||
__sfr __at(0x13) hw_tonec;
|
||||
__sfr __at(0x14) hw_vibra;
|
||||
__sfr __at(0x15) hw_volc;
|
||||
__sfr __at(0x16) hw_volab;
|
||||
__sfr __at(0x17) hw_voln;
|
||||
__sfr __at(0x18) hw_sndbx;
|
||||
|
||||
// magic register flags
|
||||
|
||||
#define M_SHIFT0 0x00
|
||||
#define M_SHIFT1 0x01
|
||||
#define M_SHIFT2 0x02
|
||||
#define M_SHIFT3 0x03
|
||||
#define M_ROTATE 0x04
|
||||
#define M_XPAND 0x08
|
||||
#define M_MOVE 0x00
|
||||
#define M_OR 0x10
|
||||
#define M_XOR 0x20
|
||||
#define M_FLOP 0x40
|
||||
|
||||
#define M_SHIFT(x) ((x)&3)
|
||||
|
||||
// xpand register
|
||||
|
||||
#define XPAND_COLORS(off,on) (((off)&3) | (((on)&3)<<2))
|
||||
|
||||
#define VHEIGHT 89 // number of scanlines
|
||||
// collision detection
|
||||
|
||||
#define RESET_COLLISION() (hw_intst)
|
||||
#define WAS_COLLISION() ((hw_intst & 0xf0)!=0)
|
||||
|
||||
// controller flags
|
||||
|
||||
#define JOY_UP 0x1
|
||||
#define JOY_DOWN 0x2
|
||||
#define JOY_LEFT 0x4
|
||||
#define JOY_RIGHT 0x8
|
||||
#define JOY_TRIGGER 0x10
|
||||
|
||||
// constants
|
||||
|
||||
#define VTOTAL 102 // number of total scanlines
|
||||
#define VHEIGHT 89 // number of scanlines in use
|
||||
#define VBWIDTH 40 // number of bytes per scanline
|
||||
#define PIXWIDTH 160 // 4 pixels per byte
|
||||
|
||||
byte __at (0x0000) vmagic[VHEIGHT][VBWIDTH];
|
||||
byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH];
|
||||
// magic register active area
|
||||
byte __at (0x0000) vmagic[VTOTAL][VBWIDTH];
|
||||
// regular frame buffer RAM
|
||||
byte __at (0x4000) vidmem[VTOTAL][VBWIDTH];
|
||||
|
||||
byte __at(0xfff) WASTER; // to soak up shifter residue
|
||||
|
||||
#define LOCHAR 32
|
||||
#define HICHAR 127
|
||||
#define FONT_BWIDTH 1
|
||||
#define FONT_HEIGHT 8
|
||||
|
||||
/// GRAPHICS FUNCTIONS
|
||||
|
||||
void clrscr();
|
||||
void vline(byte x, byte y1, byte y2, byte col, byte op);
|
||||
void pixel(byte x, byte y, byte col, byte op);
|
||||
void render_sprite(const byte* src, byte x, byte y, byte op);
|
||||
void erase_sprite(const byte* src, byte x, byte y);
|
||||
void draw_char(byte ch, byte x, byte y, byte op);
|
||||
void draw_string(const char* str, byte x, byte y);
|
||||
void draw_bcd_word(word bcd, byte x, byte y, byte op);
|
||||
word bcd_add(word a, word b);
|
||||
void set_palette(byte palette[8]) __z88dk_fastcall; // palette in reverse order
|
||||
|
||||
#define SET_PALETTE(palette)\
|
||||
__asm__("ld hl,#"#palette);\
|
||||
__asm__("ld bc,#0x80b");\
|
||||
__asm__("otir");\
|
||||
|
||||
#define SET_RIGHT_PALETTE(palette)\
|
||||
__asm__("ld hl,#"#palette);\
|
||||
__asm__("ld bc,#0x40b");\
|
||||
__asm__("otir");\
|
||||
|
||||
/// SOUND FUNCTIONS
|
||||
|
||||
void set_sound_registers(byte regs[8]) __z88dk_fastcall; // in reverse too
|
||||
|
||||
/// INTERRUPTS
|
||||
|
||||
typedef void (*t_interrupt_handler)(void) __interrupt;
|
||||
|
||||
void set_interrupt_vector(t_interrupt_handler*ih) __z88dk_fastcall;
|
||||
|
||||
#define CHANGE_INTERRUPT_VECTOR(ihp)\
|
||||
__asm__("ld hl,#"#ihp);\
|
||||
__asm__("ld a,l");\
|
||||
__asm__("out (0x0D),a");\
|
||||
__asm__("ld a,h");\
|
||||
__asm__("ld i,a");\
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
.include "astrocade.inc"
|
||||
|
||||
;;; C functions
|
||||
|
||||
.area _CODE_ACLIB
|
||||
|
||||
; set entire palette at once (8 bytes to port 0xb)
|
||||
; bytes in array should be in reverse
|
||||
;void set_palette(byte palette[8]) __z88dk_fastcall {
|
||||
.globl _set_palette
|
||||
_set_palette:
|
||||
ld bc,#0x80b ; B -> 8, C -> 0xb
|
||||
otir ; write C bytes from HL to port[B]
|
||||
ret
|
||||
|
||||
; set entire sound registers at once (8 bytes to port 0x18)
|
||||
; bytes in array should be in reverse
|
||||
;void set_sound_registers(byte regs[8]) __z88dk_fastcall {
|
||||
.globl _set_sound_registers
|
||||
_set_sound_registers:
|
||||
ld bc,#0x818 ; B -> 8, C -> 0x18
|
||||
otir ; write C bytes from HL to port[B]
|
||||
ret
|
||||
|
||||
; set interrupt vector
|
||||
; pass address of 16-bit pointer to routine
|
||||
.globl _set_interrupt_vector
|
||||
_set_interrupt_vector:
|
||||
di
|
||||
ld a,l
|
||||
out (INFBK),a
|
||||
ld a,h ; upper 8 bits of address
|
||||
ld i,a ; -> I
|
||||
im 2 ; mode 2
|
||||
ei ; enable interrupts
|
||||
ret
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
; Minimal header file for use with Astrocade C programs
|
||||
|
||||
.area _CODE
|
||||
.area _CODE
|
||||
|
||||
.byte 0x55 ; ... with the code for a normal menued cartridge
|
||||
.word 0x0218 ; Initialize menu
|
||||
|
|
|
@ -0,0 +1,383 @@
|
|||
|
||||
; ****** HVGLIB.H (formally called ballyequ.h) (C)1977,78
|
||||
; *** Bally Astrocade Equates and Macros Header File ***
|
||||
; From the nutting_manual and reformatted using Mixed Case
|
||||
; Version 3.01 - thru December 29, 2010
|
||||
; by Richard C Degler, from scratch
|
||||
;
|
||||
; > Retyped and proofread by Adam Trionfo and Lance F. Squire
|
||||
; > Version 1.0 (as ballyequ.h) - January 17, 2002
|
||||
; > Version 2.52 (Version 1.0 of HVGLIB.H) - March 28, 2003
|
||||
; > Version 2.6 - March 2, 2004 - as seen on BallyAlley.com
|
||||
; > Version 3.0 - 2009
|
||||
; > Version 3.01 - Changed "FonT BASE character" comment
|
||||
;
|
||||
; ***************************
|
||||
; * Home Video Game =ates *
|
||||
; ***************************
|
||||
;
|
||||
; ASSEMBLY CONTROL
|
||||
;
|
||||
XPNDON = 1 ; ** SET TO 1 WHEN HARDWARE EXP
|
||||
NWHDWR = 1 ; ** SET TO 1 WHEN NEW HARDWARE
|
||||
;
|
||||
; General goodies (HEX and Decimal values):
|
||||
NORMEM = 0x4000 ; 8192 ; NORmal MEMory start
|
||||
FIRSTC = 0x2000 ; 4096 ; FIRST address in Cartridge
|
||||
SCREEN = 0x0000 ; 0 ; magic SCREEN start
|
||||
BYTEPL = 0x28 ; 40 ; BYTEs Per Line
|
||||
BITSPL = 0xA0 ; 160 ; BITS Per Line
|
||||
;
|
||||
; Stuff in SYSTEM DOPE VECTOR (valid for ALL system ROMs):
|
||||
STIMER = 0x0200 ; Seconds and game TIMER, music
|
||||
CTIMER = 0x0203 ; Custom TIMERs
|
||||
FNTSYS = 0x0206 ; FoNT descriptor for SYStem font
|
||||
FNTSML = 0x020D ; FoNT descriptor for SMaLl font
|
||||
ALKEYS = 0x0214 ; ALl KEYS keypad mask
|
||||
MENUST = 0x0218 ; head of onboard MENU STart
|
||||
MXSCR = 0x021E ; address of 'MaX SCoRe' text string
|
||||
NOPLAY = 0x0228 ; address of 'Number Of PLAYers' string
|
||||
NOGAME = 0x0235 ; address of 'Number Of GAMEs' string
|
||||
;
|
||||
; BITS in PROCESSOR FLAG byte:
|
||||
PSWCY = 0 ; Processor Status Word, CarrY bit
|
||||
PSWPV = 2 ; Processor Status Word, Parity or oVerflow bit
|
||||
PSWZRO = 6 ; Processor Status Word, ZeRO bit
|
||||
PSWSGN = 7 ; Processor Status Word, SiGN bit
|
||||
;
|
||||
; BITS in GAME STATUS Byte:
|
||||
GSBTIM = 0 ; Game Status Byte, if TIMe is up set end bit
|
||||
GSBSCR = 1 ; Game Status Byte, if SCoRe reached set end bit
|
||||
GSBEND = 7 ; Game Status Byte, END flag bit
|
||||
;
|
||||
; Standard VECTOR DISPLACEMENTS and bits:
|
||||
VBMR = 0x00 ; +0 ; Vector Block, Magic Register
|
||||
VBSTAT = 0x01 ; +1 ; Vector Block, STATus byte
|
||||
VBTIMB = 0x02 ; +2 ; Vector Block, TIMe Base
|
||||
VBDXL = 0x03 ; +3 ; Vector Block, Delta for X Low
|
||||
VBDXH = 0x04 ; +4 ; Vector Block, Delta for X Hi
|
||||
VBXL = 0x05 ; +5 ; Vector Block, X coord Low
|
||||
VBXH = 0x06 ; +6 ; Vector Block, X coord Hi
|
||||
VBXCHK = 0x07 ; +7 ; Vector Block, X CHecK flags
|
||||
VBDYL = 0x08 ; +8 ; Vector Block, Delta for Y Low
|
||||
VBDYH = 0x09 ; +9 ; Vector Block, Delta for Y Hi
|
||||
VBYL = 0x0A ; +10 ; Vector Block, Y coord Low
|
||||
VBYH = 0x0B ; +11 ; Vector Block, Y coord Hi
|
||||
VBYCHK = 0x0C ; +12 ; Vector Block, Y CHecK flags
|
||||
VBOAL = 0x0D ; +13 ; Vector Block, Old Address Low
|
||||
VBOAH = 0x0E ; +14 ; Vector Block, Old Address Hi
|
||||
;
|
||||
; DISPLACEMENTS from start of COORDINATE AREA (X or Y):
|
||||
VBDCL = 0x00 ; +0 ; Vector Block, Delta for Coord Low
|
||||
VBDCH = 0x01 ; +1 ; Vector Block, Delta for Coord Hi
|
||||
VBCL = 0x02 ; +2 ; Vector Block, Coord Low
|
||||
VBCH = 0x03 ; +3 ; Vector Block, Coord Hi
|
||||
VBCCHK = 0x04 ; +4 ; Vector Block, Coord CHecK flags
|
||||
;
|
||||
; BITS in STATUS byte:
|
||||
VBBLNK = 6 ; Vector Block status, BLaNK bit
|
||||
VBSACT = 7 ; Vector Block Status, ACTive bit
|
||||
;
|
||||
; BITS in (X or Y) VB CHECK FLAG bit mask:
|
||||
VBCLMT = 0 ; Vector Block Check, LiMiT bit
|
||||
VBCREV = 1 ; Vector Block Check, REVerse delta on limit attain
|
||||
VBCLAT = 3 ; Vector Block Check, coordinate Limit ATtained
|
||||
;
|
||||
; FONT TABLE DISPLACEMENTS for CHARACTER DESCRIPTOR BLOCK:
|
||||
FTBASE = 0x00 ; +0 ; FonT BASE character (normally 0xA0)
|
||||
FTFSX = 0x01 ; +1 ; FonT Frame X Size width
|
||||
FTFSY = 0x02 ; +2 ; FonT Frame Y Size height
|
||||
FTBYTE = 0x03 ; +3 ; FonT X size for char in BYTEs
|
||||
FTYSIZ = 0x04 ; +4 ; FonT Y SIZe height in rows
|
||||
FTPTL = 0x05 ; +5 ; FonT Pattern Table address Low
|
||||
FTPTH = 0x06 ; +6 ; FonT Pattern Table address Hi
|
||||
;
|
||||
; BITS for MAGIC REGISTER (write option) byte:
|
||||
MRSHFT = 0x03 ; Magic Register, mask of SHiFT amount 0-3
|
||||
MRROT = 2 ; Magic Register, write with ROTata bit
|
||||
MRXPND = 3 ; Magic Register, write with eXPaND bit
|
||||
MROR = 4 ; Magic Register, write with OR bit
|
||||
MRXOR = 5 ; Magic Register, write with eXclusive-OR bit
|
||||
MRFLOP = 6 ; Magic Register, write with FLOP bit
|
||||
;
|
||||
; BITS of CONTROL HANDLE Input port:
|
||||
CHUP = 0 ; Control Handle, UP bit
|
||||
CHDOWN = 1 ; Control Handle, DOWN bit
|
||||
CHLEFT = 2 ; Control Handle, joystick LEFT bit
|
||||
CHRIGH = 3 ; Control Handle, joystick RIGHT bit
|
||||
CHTRIG = 4 ; Control Handle, TRIGger bit
|
||||
;
|
||||
; CONTEXT BLOCK Register DISPLACEMENTS:
|
||||
CBIYL = 0x00 ; +0 ; Context Block, IY register Low
|
||||
CBIYH = 0x01 ; +1 ; Context Block, IY register Hi
|
||||
CBIXL = 0x02 ; +2 ; Context Block, IX register Low
|
||||
CBIXH = 0x03 ; +3 ; Context Block, IX register Hi
|
||||
CBE = 0x04 ; +4 ; Context Block, E register
|
||||
CBD = 0x05 ; +5 ; Context Block, D register
|
||||
CBC = 0x06 ; +6 ; Context Block, C register
|
||||
CBB = 0x07 ; +7 ; Context Block, B register
|
||||
CBFLAG = 0x08 ; +8 ; Context Block, FLAGs register
|
||||
CBA = 0x09 ; +9 ; Context Block, A register
|
||||
CBL = 0x0A ; +10 ; Context Block, L register
|
||||
CBH = 0x0B ; +11 ; Context Block, H register
|
||||
;
|
||||
; SENTRY RETURN Codes =ates:
|
||||
SNUL = 0x00 ; Sentry return NULl, nothing happened
|
||||
SCT0 = 0x01 ; Sentry, Counter-Timer 0 has counted down
|
||||
SCT1 = 0x02 ; Sentry, Counter-Timer 1 has counted down
|
||||
SCT2 = 0x03 ; Sentry, Counter-Timer 2 has counted down
|
||||
SCT3 = 0x04 ; Sentry, Counter-Timer 3 has counted down
|
||||
SCT4 = 0x05 ; Sentry, Counter-Timer 4 has counted down
|
||||
SCT5 = 0x06 ; Sentry, Counter-Timer 5 has counted down
|
||||
SCT6 = 0x07 ; Sentry, Counter-Timer 6 has counted down
|
||||
SCT7 = 0x08 ; Sentry, Counter-Timer 7 has counted down
|
||||
SF0 = 0x09 ; Sentry, Flag bit 0 has changed
|
||||
SF1 = 0x0A ; Sentry, Flag bit 1 has changed
|
||||
SF2 = 0x0B ; Sentry, Flag bit 2 has changed
|
||||
SF3 = 0x0C ; Sentry, Flag bit 3 has changed
|
||||
SF4 = 0x0D ; Sentry, Flag bit 4 has changed
|
||||
SF5 = 0x0E ; Sentry, Flag bit 5 has changed
|
||||
SF6 = 0x0F ; Sentry, Flag bit 6 has changed
|
||||
SF7 = 0x10 ; Sentry, Flag bit 7 has changed
|
||||
SSEC = 0x11 ; Sentry, SEConds timer has counted down
|
||||
SKYU = 0x12 ; Sentry, KeY is now Up
|
||||
SKYD = 0x13 ; Sentry, KeY is now Down
|
||||
ST0 = 0x14 ; Sentry, Trigger 0 for player 1 has changed
|
||||
SJ0 = 0x15 ; Sentry, Joystick 0 for player 1 has changed
|
||||
ST1 = 0x16 ; Sentry, Trigger 1 for player 2 has changed
|
||||
SJ1 = 0x17 ; Sentry, Joystick 1 for player 2 has changed
|
||||
ST2 = 0x18 ; Sentry, Trigger 2 for player 3 has changed
|
||||
SJ2 = 0x19 ; Sentry, Joystick 2 for player 3 has changed
|
||||
ST3 = 0x1A ; Sentry, Trigger 3 for player 4 has changed
|
||||
SJ3 = 0x1B ; Sentry, Joystick 3 for player 4 has changed
|
||||
SP0 = 0x1C ; Sentry, POTentiometer 0 has changed
|
||||
SP1 = 0x1D ; Sentry, POTentiometer 1 has changed
|
||||
SP2 = 0x1E ; Sentry, POTentiometer 2 has changed
|
||||
SP3 = 0x1F ; Sentry, POTentiometer 3 has changed
|
||||
;
|
||||
;
|
||||
; ********************************
|
||||
; * Home Video Game PORT =ates *
|
||||
; ********************************
|
||||
;
|
||||
; OUTPUT Ports for VIRTUAL COLOR:
|
||||
COL0R = 0x00 ; &(0)= ; write COLor 0 Right
|
||||
COL1R = 0x01 ; &(1)= ; write COLor 1 Right
|
||||
COL2R = 0x02 ; &(2)= ; write COLor 2 Right
|
||||
COL3R = 0x03 ; &(3)= ; write COLor 3 Right
|
||||
COL0L = 0x04 ; &(4)= ; write COLor 0 Left
|
||||
COL1L = 0x05 ; &(5)= ; write COLor 1 Left
|
||||
COL2L = 0x06 ; &(6)= ; write COLor 2 Left
|
||||
COL3L = 0x07 ; &(7)= ; write COLor 3 Left
|
||||
HORCB = 0x09 ; &(9)= ; write HORizontal Color Boundary
|
||||
VERBL = 0x0A ;&(10)= ; write VERtical Blanking Line
|
||||
COLBX = 0x0B ;&(11)= ; write COLor BloCK multi-port
|
||||
;
|
||||
; OUTPUT Ports for MUSIC and SOUNDS:
|
||||
TONMO = 0x10 ;&(16)= ; write TONe Master Oscillator
|
||||
TONEA = 0x11 ;&(17)= ; write TONe A oscillator
|
||||
TONEB = 0x12 ;&(18)= ; write TONe B oscillator
|
||||
TONEC = 0x13 ;&(19)= ; write TONe C oscillator
|
||||
VIBRA = 0x14 ;&(20)= ; write VIBRAto frequency & range
|
||||
VOLC = 0x15 ;&(21)= ; write VOLume of tone C
|
||||
VOLAB = 0x16 ;&(22)= ; write VOLumes of tones A & B
|
||||
VOLN = 0x17 ;&(23)= ; write VOLume of Noise
|
||||
SNDBX = 0x18 ;&(24)= ; write SouND BloCK multi-port
|
||||
;
|
||||
; INTERRUPT and CONTROL OUTPUT Ports:
|
||||
CONCM = 0x08 ; &(8)= ; write 0 for CONsumer, 1 for CoMmercial mode
|
||||
MAGIC = 0x0C ;&(12)= ; write MAGIC register
|
||||
INFBK = 0x0D ;&(13)= ; write INterrupt FeedBacK
|
||||
INMOD = 0x0E ;&(14)= ; write INterrupt MODe
|
||||
INLIN = 0x0F ;&(15)= ; write INterrupt LINe
|
||||
XPAND = 0x19 ;&(25)= ; eXPANDer pixel definition port
|
||||
;
|
||||
; INTERRUPT and INTERCEPT INPUT Ports:
|
||||
INTST = 0x08 ; =&(8) ; read INTercept STatus
|
||||
VERAF = 0x0E ;=&(14) ; read VERtical Address Feedback
|
||||
HORAF = 0x0F ;=&(15) ; read HORizontal Address Feedback
|
||||
;
|
||||
; HAND CONTROL INPUT Ports:
|
||||
SW0 = 0x10 ;=&(16) ; read SWitch bank 0 for player 1 hand control
|
||||
SW1 = 0x11 ;=&(17) ; read SWitch bank 1 for player 2 hand control
|
||||
SW2 = 0x12 ;=&(18) ; read SWitch bank 2 for player 3 hand control
|
||||
SW3 = 0x13 ;=&(19) ; read SWitch bank 3 for player 4 hand control
|
||||
POT0 = 0x1C ;=&(28) ; read POTentiometer 0 for player 1 knob
|
||||
POT1 = 0x1D ;=&(29) ; read POTentiometer 1 for player 2 knob
|
||||
POT2 = 0x1E ;=&(30) ; read POTentiometer 2 for player 3 knob
|
||||
POT3 = 0x1F ;=&(31) ; read POTentiometer 3 for player 4 knob
|
||||
;
|
||||
; KEYBOARD INPUT Ports:
|
||||
KEY0 = 0x14 ;=&(20) ; KEYboard column 0 (right side)
|
||||
KEY1 = 0x15 ;=&(21) ; KEYboard column 1 (center right)
|
||||
KEY2 = 0x16 ;=&(22) ; KEYboard column 2 (center left)
|
||||
KEY3 = 0x17 ;=&(23) ; KEYboard column 3 (left side)
|
||||
;
|
||||
;
|
||||
; ***************************************
|
||||
; * Home Video Game SYSTEM CALL Indexes *
|
||||
; ***************************************
|
||||
;
|
||||
; USER PROGRAM Interface:
|
||||
INTPC = 0x00 ; # 0 ; INTerPret with Context create
|
||||
XINTC = 0x02 ; # 2 ; eXit INTerpreter with Context
|
||||
RCALL = 0x04 ; # 4 ; Real CALL asm language subroutine
|
||||
MCALL = 0x06 ; # 6 ; Macro CALL interpreter subroutine
|
||||
MRET = 0x08 ; # 8 ; Macro RETurn from interpreter subroutine
|
||||
MJUMP = 0x0A ; # 10 ; Macro JUMP to interpreter subroutine
|
||||
SUCK = 0x0C ; # 12 ; SUCK inline args into context block
|
||||
;
|
||||
; SCHEDULER Routines:
|
||||
ACTINT = 0x0E ; # 14 ; ACTivate sub timer INTerrupts
|
||||
DECCTS = 0x10 ; # 16 ; DECrement CTS under mask
|
||||
;
|
||||
; MUSIC and SOUNDS:
|
||||
BMUSIC = 0x12 ; # 18 ; Begin playing MUSIC
|
||||
EMUSIC = 0x14 ; # 20 ; End playing MUSIC
|
||||
;
|
||||
; SCREEN HANDLER Routines:
|
||||
SETOUT = 0x16 ; # 22 ; SET some OUTput ports
|
||||
COLSET = 0x18 ; # 24 ; COLors SET
|
||||
FILL = 0x1A ; # 26 ; FILL memory with data
|
||||
RECTAN = 0x1C ; # 28 ; paint a RECTANgle
|
||||
VWRITR = 0x1E ; # 30 ; Vector WRITe Relative
|
||||
WRITR = 0x20 ; # 32 ; WRITe Relative
|
||||
WRITP = 0x22 ; # 34 ; WRITe with Pattern size lookup
|
||||
WRIT = 0x24 ; # 36 ; WRITe with sizes provided
|
||||
WRITA = 0x26 ; # 38 ; WRITe Absolute
|
||||
VBLANK = 0x28 ; # 40 ; Vector BLANK area
|
||||
BLANK = 0x2A ; # 42 ; BLANK area
|
||||
SAVE = 0x2C ; # 44 ; SAVE area
|
||||
RESTOR = 0x2E ; # 46 ; RESTORe area
|
||||
SCROLL = 0x30 ; # 48 ; SCROLL area of screen
|
||||
;
|
||||
CHRDIS = 0x32 ; # 50 ; CHaRacter DISplay
|
||||
STRDIS = 0x34 ; # 52 ; STRing DISplay
|
||||
DISNUM = 0x36 ; # 54 ; DISplay NUMber
|
||||
;
|
||||
RELABS = 0x38 ; # 56 ; RELative to ABSolute conversion
|
||||
RELAB1 = 0x3A ; # 58 ; RELative to non-magic ABSolute
|
||||
VECTC = 0x3C ; # 60 ; VECTor move single Coordinate
|
||||
VECT = 0x3E ; # 62 ; VECTor move coordinate pair
|
||||
;
|
||||
; HUMAN INTERFACE Routines:
|
||||
KCTASC = 0x40 ; # 64 ; Key Code in B To ASCii
|
||||
SENTRY = 0x42 ; # 66 ; SENse TRansition Y
|
||||
DOIT = 0x44 ; # 68 ; DOIT table, branch to translation handler
|
||||
DOITB = 0x46 ; # 70 ; DOIT table, use B instead of A
|
||||
PIZBRK = 0x48 ; # 72 ; take a PIZza BReaK
|
||||
MENU = 0x4A ; # 74 ; display a MENU
|
||||
GETPAR = 0x4C ; # 76 ; GET game PARameter from user
|
||||
GETNUM = 0x4E ; # 78 ; GET NUMber from user
|
||||
PAWS = 0x50 ; # 80 ; PAUSE
|
||||
DISTIM = 0x52 ; # 82 ; DISplay TIMe
|
||||
INCSCR = 0x54 ; # 84 ; INCrement SCoRe
|
||||
;
|
||||
; MATH Routines:
|
||||
INDEXN = 0x56 ; # 86 ; INDEX Nibble by C
|
||||
STOREN = 0x58 ; # 88 ; STORE Nibble in A by C
|
||||
INDEXW = 0x5A ; # 90 ; INDEX Word by A
|
||||
INDEXB = 0x5C ; # 92 ; INDEX Byte by A
|
||||
MOVE = 0x5E ; # 94 ; MOVE block transfer
|
||||
SHIFTU = 0x60 ; # 96 ; SHIFT Up digit in A
|
||||
BCDADD = 0x62 ; # 98 ; BCD ADDition
|
||||
BCDSUB = 0x64 ;# 100 ; BCD SUBtraction
|
||||
BCDMUL = 0x66 ;# 102 ; BCD MULtiplication
|
||||
BCDDIV = 0x68 ;# 104 ; BCD DIVision
|
||||
BCDCHS = 0x6A ;# 106 ; BCD CHange Sign
|
||||
BCDNEG = 0x6C ;# 108 ; BCD NEGate to decimal
|
||||
DADD = 0x6E ;# 110 ; Decimal ADDition
|
||||
DSMG = 0x70 ;# 112 ; Decimal convert to Sign MaGnitude
|
||||
DABS = 0x72 ;# 114 ; Decimal ABSolute value
|
||||
NEGT = 0x74 ;# 116 ; decimal NEGaTe
|
||||
RANGED = 0x76 ;# 118 ; RANGED random number
|
||||
QUIT = 0x78 ;# 120 ; QUIT cassette execution
|
||||
SETB = 0x7A ;# 122 ; SET Byte
|
||||
SETW = 0x7C ;# 124 ; SET Word
|
||||
MSKTD = 0x7E ;# 127 ; MaSK joystick in B To Deltas
|
||||
;
|
||||
;
|
||||
; ***************************
|
||||
; * SYSTEM RAM MEMORY Cells *
|
||||
; ***************************
|
||||
WASTE = 0x0FFF
|
||||
WASTER = WASTE
|
||||
;
|
||||
SYSRAM = 0x4FCE ; Resides at the highest possible address
|
||||
BEGRAM = SYSRAM ; typically used for initial Stack Pointer
|
||||
; Used by MUSIC PROCESSOR:
|
||||
MUZPC = 0x4FCE ; MUSic Program Counter
|
||||
MUZSP = 0x4FD0 ; MUSic Stack Pointer
|
||||
PVOLAB = 0x4FD2 ; Preset VOLume for tones A and B
|
||||
PVOLMC = 0x4FD3 ; Preset VOLuMe for tone C and Noise Mode
|
||||
VOICES = 0x4FD4 ; music VOICES mask
|
||||
; COUNTER TIMERS (used by DECCTS,ACTINT,CTIMER):
|
||||
CT0 = 0x4FD5 ; Counter Timer 0
|
||||
CT1 = 0x4FD6 ; Counter Timer 1
|
||||
CT2 = 0x4FD7 ; Counter Timer 2
|
||||
CT3 = 0x4FD8 ; Counter Timer 3
|
||||
CT4 = 0x4FD9 ; Counter Timer 4
|
||||
CT5 = 0x4FDA ; Counter Timer 5
|
||||
CT6 = 0x4FDB ; Counter Timer 6
|
||||
CT7 = 0x4FDC ; Counter Timer 7
|
||||
;Used by SENTRY to track controls:
|
||||
CNT = 0x4FDD ; Counter update & Number Tracking
|
||||
SEMI4S = 0x4FDE ; SEMAPHORE flag bitS
|
||||
OPOT0 = 0x4FDF ; Old POT 0 tracking byte
|
||||
OPOT1 = 0x4FE0 ; Old POT 1 tracking byte
|
||||
OPOT2 = 0x4FE1 ; Old POT 2 tracking byte
|
||||
OPOT3 = 0x4FE2 ; Old POT 3 tracking byte
|
||||
KEYSEX = 0x4FE3 ; KEYS-EX tracking byte
|
||||
OSW0 = 0x4FE4 ; Old SWitch 0 tracking byte
|
||||
OSW1 = 0x4FE5 ; Old SWitch 1 tracking byte
|
||||
OSW2 = 0x4FE6 ; Old SWitch 2 tracking byte
|
||||
OSW3 = 0x4FE7 ; Old SWitch 3 tracking byte
|
||||
COLLST = 0x4FE8 ; COLset LaST address for P.B. A
|
||||
; Used by STIMER:
|
||||
DURAT = 0x4FEA ; note DURATion
|
||||
TMR60 = 0x4FEB ; TiMeR for SIXTYths of sec
|
||||
TIMOUT = 0x4FEC ; TIMer for blackOUT
|
||||
GTSECS = 0x4FED ; Game Time SECondS
|
||||
GTMINS = 0x4FEE ; Game Time MINuteS
|
||||
; Used by MENU:
|
||||
RANSHT = 0x4FEF ; RANdom number SHifT register
|
||||
NUMPLY = 0x4FF3 ; NUMber of PLaYers
|
||||
ENDSCR = 0x4FF4 ; END SCoRe to 'play to'
|
||||
MRLOCK = 0x4FF7 ; Magic Register LOCK out flag
|
||||
GAMSTB = 0x4FF8 ; GAMe STatus Byte
|
||||
PRIOR = 0x4FF9 ; PRIOR music protect flag
|
||||
SENFLG = 0x4FFA ; SENtry control seizure FLaG
|
||||
; User UPI Routines, even numbers from 0x80 to 0xFE ( + 1 for SUCK):
|
||||
UMARGT = 0x4FFB ; User Mask ARGument Table + (routine / 2)
|
||||
USERTB = 0x4FFD ; USER Table Base + routine = JumP address
|
||||
;
|
||||
URINAL = 0x4FFF ; WASTER flushes here!
|
||||
;
|
||||
;
|
||||
|
||||
;
|
||||
; MACROs to generate SYSTEM CALLs:
|
||||
.macro SYSTEM NUMBA
|
||||
rst 0x38
|
||||
.db NUMBA
|
||||
; .if NUMBA = INTPC
|
||||
;INTPCC = 1
|
||||
; .endif
|
||||
.endm
|
||||
; MACRO to generate SYSTEM CALL with SUCK option ON:
|
||||
.macro SYSSUK UMBA
|
||||
rst 0x38
|
||||
.db UMBA + 1
|
||||
; .if UMBA = INTPC
|
||||
;INTPCC = 1
|
||||
; .endif
|
||||
.endm
|
||||
; MACROs to generate MACRO INTERPRETER CALLs:
|
||||
; INTERPRET without INLINE SUCK:
|
||||
.macro DONT CID
|
||||
.db CID
|
||||
.endm
|
||||
; INTERPRET with INLINE SUCK option ON:
|
||||
.macro DO CID
|
||||
.db CID + 1
|
||||
.endm
|
|
@ -6,32 +6,40 @@
|
|||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//#resource "astrocade.inc"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
#include "aclib.h"
|
||||
|
||||
//#link "aclib.c"
|
||||
|
||||
//#link "acheader.s"
|
||||
//#link "aclib.s"
|
||||
#include "acextra.h"
|
||||
//#link "acextra.c"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
|
||||
//
|
||||
// GAME GRAPHICS
|
||||
//
|
||||
|
||||
const byte player_bitmap[] =
|
||||
{3,14,/*{w:12,h:16,bpp:2,brev:1}*/0x00,0x3C,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x04,0x18,0x20,0x0C,0x3C,0x30,0x3C,0x3C,0x3C,0x1F,0xE7,0xF4,0x1F,0x66,0xF4,0x17,0xE7,0xE4,0x17,0xE7,0xE4,0x1C,0x7E,0x34,0x1C,0xFF,0x34,0x3C,0x18,0x3C,0x0C,0x18,0x30,0x04,0x18,0x20};
|
||||
const byte player_bitmap[2+9*3] =
|
||||
{3,9,/*{w:12,h:9,bpp:2,brev:1}*/0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x14,0x00,0x30,0x3C,0x0C,0x3A,0xBE,0xAC,0x3E,0xFF,0xBC,0x3F,0xFF,0xFC,0x37,0x7D,0xDC,0x3C,0x3C,0x3C};
|
||||
const byte bomb_bitmap[] =
|
||||
{1,5,/*{w:8,h:5,bpp:2,brev:1}*/0x88,0x55,0x77,0x55,0x88};
|
||||
{1,3,/*{w:4,h:3,bpp:2,brev:1}*/0xF8,0x3E,0xF8};
|
||||
const byte bullet_bitmap[] =
|
||||
{1,5,/*{w:8,h:5,bpp:2,brev:1}*/0x14,0x28,0x14,0x14,0x28};
|
||||
const byte enemy1_bitmap[] =
|
||||
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x70,0x38,0xF8,0x7C,0xFC,0xFC,0xFE,0xFC,0xFE,0xFF,0xFC,0xFF,0xF8,0x7F,0xF0,0x3F,0x88,0x47,0xF0,0x3F,0xF0,0x3F,0xD0,0x2F,0x8C,0xC7,0x48,0x48,0x80,0x04};
|
||||
{1,5,/*{w:4,h:5,bpp:2,brev:1}*/0x0C,0x24,0x18,0x10,0x04};
|
||||
const byte enemy1_bitmap[18] =
|
||||
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x22,0x88,0x2A,0xA8,0x3F,0xFC,0x37,0xDC,0x3F,0xFC,0x38,0x2C,0x30,0x0C,0x0C,0x30};
|
||||
const byte enemy2_bitmap[] =
|
||||
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x30,0x0C,0x14,0x28,0x2E,0x74,0x08,0x10,0x20,0x04,0xE0,0x07,0xD0,0x0B,0xB0,0x0D,0xB2,0x4D,0x19,0x98,0x8E,0x71,0x82,0x41,0xB1,0x8D,0x59,0x9A,0x4A,0x52};
|
||||
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x0C,0x30,0x30,0x0C,0x17,0xE8,0x23,0xC4,0x0B,0xD0,0x2C,0x34,0x2F,0xF4,0x10,0x08};
|
||||
const byte enemy3_bitmap[] =
|
||||
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x00,0x00,0x04,0x20,0x05,0xA0,0x05,0xA0,0x25,0xA4,0xA7,0xE5,0xF7,0xEF,0xF7,0xEF,0xFE,0x7F,0xFC,0x3F,0xBC,0x3D,0xE4,0x27,0x20,0x00,0x00,0x00,0x00,0x00};
|
||||
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x0F,0xC0,0x00,0xC0,0x10,0xC4,0x26,0xD8,0x27,0x98,0x26,0xD8,0x14,0x14,0x10,0x04};
|
||||
const byte enemy4_bitmap[] =
|
||||
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x00,0x00,0xF0,0x0F,0xF8,0x1F,0xD8,0x1B,0xF8,0x1F,0xF8,0x1F,0xF8,0x1F,0xF0,0x0F,0xA8,0x15,0xCC,0x33,0xE8,0x17,0x66,0x66,0x33,0xCC,0x61,0x86,0x40,0x02};
|
||||
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x30,0x0C,0x3C,0x3C,0x0F,0xF0,0x3A,0xE8,0x3B,0xEC,0x3F,0xFC,0x30,0x0C,0x00,0x00};
|
||||
const byte mothership_bitmap[2+3*6] =
|
||||
{3,6,/*{w:12,h:6,bpp:2,brev:1}*/0x00,0x28,0x00,0x02,0xBE,0x80,0x2A,0xFF,0xA8,0x25,0x55,0x58,0x0A,0xAA,0xA0,0x02,0xAA,0x80};
|
||||
const byte explode_bitmap[18] =
|
||||
{2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x40,0x44,0x10,0x40,0x06,0x81,0x0B,0xE4,0x5B,0xE0,0x02,0x81,0x04,0x10,0x10,0x44};
|
||||
|
||||
const byte* const enemy_bitmaps[4] = {
|
||||
enemy1_bitmap,
|
||||
|
@ -40,27 +48,37 @@ const byte* const enemy_bitmaps[4] = {
|
|||
enemy4_bitmap
|
||||
};
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x07, 0xD4, 0x35, 0x01,
|
||||
0x07, 0xD4, 0x35, 0x01,
|
||||
};
|
||||
|
||||
#define COLOR_BUNKER 1
|
||||
#define COLOR_GROUND 2
|
||||
#define COLOR_SCORE 3
|
||||
#define COLOR_SCORE 2
|
||||
|
||||
//
|
||||
// GAME CODE
|
||||
//
|
||||
|
||||
#define MAXLIVES 5
|
||||
#define PLYRHEIGHT 14
|
||||
#define ENEMY_SPACING_X 17
|
||||
#define PLYRHEIGHT 9
|
||||
#define ENEMY_WIDTH 8
|
||||
#define ENEMY_HEIGHT 8
|
||||
#define ENEMY_SPACING_X 14
|
||||
#define ENEMY_SPACING_Y 11
|
||||
#define ENEMY_WIDTH 8
|
||||
#define ENEMY_MARCH_X 1
|
||||
#define ENEMY_MARCH_Y 2
|
||||
#define EXPLODE_TIME 8
|
||||
|
||||
typedef struct {
|
||||
byte x,y;
|
||||
const byte* shape; // need const here
|
||||
} Enemy;
|
||||
|
||||
#define MAX_ENEMIES 28
|
||||
#define MAX_ENEMIES 40
|
||||
|
||||
Enemy enemies[MAX_ENEMIES];
|
||||
byte enemy_index;
|
||||
|
@ -73,7 +91,6 @@ typedef struct {
|
|||
|
||||
MarchMode this_mode, next_mode;
|
||||
|
||||
byte attract;
|
||||
word score;
|
||||
byte lives;
|
||||
|
||||
|
@ -83,12 +100,15 @@ byte bullet_x;
|
|||
byte bullet_y;
|
||||
byte bomb_x;
|
||||
byte bomb_y;
|
||||
byte explode_x;
|
||||
byte explode_y;
|
||||
byte explode_timer;
|
||||
|
||||
void draw_lives() {
|
||||
byte i;
|
||||
byte n = lives;
|
||||
byte y = 0;
|
||||
byte x = PIXWIDTH-4*5;
|
||||
byte x = PIXWIDTH-4*6;
|
||||
hw_xpand = XPAND_COLORS(0, COLOR_SCORE);
|
||||
for (i=0; i<MAXLIVES; i++) {
|
||||
draw_char(i<n?'|':' ', x, y, M_MOVE);
|
||||
|
@ -108,30 +128,28 @@ void draw_bunker(byte x, byte y, byte y2, byte h, byte w) {
|
|||
for (i=0; i<h; i++) {
|
||||
a = y-y2-i*2;
|
||||
b = y-i;
|
||||
vline(x+i, a, b, M_XOR, COLOR_BUNKER);
|
||||
vline(x+h*2+w-i-1, a, b, M_XOR, COLOR_BUNKER);
|
||||
vline(x+i, a, b, COLOR_BUNKER, M_XOR);
|
||||
vline(x+h*2+w-i-1, a, b, COLOR_BUNKER, M_XOR);
|
||||
}
|
||||
for (i=0; i<w; i++) {
|
||||
vline(x+h+i, a, b, M_XOR, COLOR_BUNKER);
|
||||
vline(x+h+i, a, b, COLOR_BUNKER, M_XOR);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_playfield() {
|
||||
byte i;
|
||||
clrscr();
|
||||
hw_xpand = XPAND_COLORS(0, COLOR_SCORE);
|
||||
draw_string("PLAYER 1", 0, 0);
|
||||
draw_string(0, 0, COLOR_SCORE, "PLAYER 1");
|
||||
draw_score();
|
||||
draw_lives();
|
||||
for (i=0; i<PIXWIDTH; i++)
|
||||
pixel(i, VHEIGHT-1, COLOR_GROUND, M_OR);
|
||||
// TODO: const
|
||||
draw_bunker(20, 65, 15, 15, 20);
|
||||
draw_bunker(100, 65, 15, 15, 20);
|
||||
draw_bunker(20, 75, 5, 5, 20);
|
||||
draw_bunker(100, 75, 5, 5, 20);
|
||||
}
|
||||
|
||||
void add_score(word pts) {
|
||||
if (attract) return;
|
||||
score = bcd_add(score, pts);
|
||||
draw_score();
|
||||
}
|
||||
|
@ -140,7 +158,7 @@ void xor_player_derez() {
|
|||
byte i,j;
|
||||
byte x = player_x+13;
|
||||
byte y = player_y+PLYRHEIGHT-1;
|
||||
byte* rand = (byte*) &clrscr; // use code as random #'s
|
||||
byte* rand = (byte*) &xor_player_derez; // use code as random #'s
|
||||
for (j=1; j<=0xf; j++) {
|
||||
for (i=0; i<100; i++) {
|
||||
signed char xx = x + (*rand++ & 0xf) - 15;
|
||||
|
@ -152,7 +170,7 @@ void xor_player_derez() {
|
|||
|
||||
void destroy_player() {
|
||||
xor_player_derez(); // xor derez pattern
|
||||
render_sprite(player_bitmap, player_x, VHEIGHT-PLYRHEIGHT, M_XOR); // erase ship via xor
|
||||
render_sprite(player_bitmap, player_x, player_y, M_XOR); // erase ship via xor
|
||||
xor_player_derez(); // xor 2x to erase derez pattern
|
||||
player_x = 0xff;
|
||||
lives--;
|
||||
|
@ -185,8 +203,14 @@ void init_enemies() {
|
|||
|
||||
void delete_enemy(Enemy* e) {
|
||||
erase_sprite(e->shape, e->x, e->y);
|
||||
if (explode_timer == 0) {
|
||||
explode_x = e->x;
|
||||
explode_y = e->y;
|
||||
explode_timer = EXPLODE_TIME;
|
||||
}
|
||||
memmove(e, e+1, sizeof(Enemy)*(enemies-e+MAX_ENEMIES-1));
|
||||
num_enemies--; // update_next_enemy() will check enemy_index
|
||||
// TODO: enemy_index might skip updating an enemy
|
||||
}
|
||||
|
||||
void update_next_enemy() {
|
||||
|
@ -196,11 +220,11 @@ void update_next_enemy() {
|
|||
memcpy(&this_mode, &next_mode, sizeof(this_mode));
|
||||
}
|
||||
e = &enemies[enemy_index];
|
||||
erase_sprite(e->shape, e->x, e->y);
|
||||
if (this_mode.down) {
|
||||
erase_sprite(e->shape, e->x, e->y);
|
||||
e->y += ENEMY_MARCH_Y;
|
||||
// if too close to ground, end game
|
||||
if (e->y > VHEIGHT-ENEMY_SPACING_Y) {
|
||||
if (e->y >= player_y) {
|
||||
destroy_player();
|
||||
lives = 0;
|
||||
}
|
||||
|
@ -220,21 +244,21 @@ void update_next_enemy() {
|
|||
}
|
||||
}
|
||||
}
|
||||
render_sprite(e->shape, e->x, e->y, M_XOR);
|
||||
render_sprite(e->shape, e->x, e->y, M_MOVE);
|
||||
enemy_index++;
|
||||
}
|
||||
|
||||
char in_rect(Enemy* e, byte x, byte y, byte w, byte h) {
|
||||
byte ew = e->shape[0]*8;
|
||||
byte ew = e->shape[0]*4;
|
||||
byte eh = e->shape[1];
|
||||
return (x >= e->x-w && x <= e->x+ew && y >= e->y-h && y <= e->y+eh);
|
||||
return (x >= e->x-w && x <= e->x+ew+w && y >= e->y-h && y <= e->y+eh+h);
|
||||
}
|
||||
|
||||
Enemy* find_enemy_at(byte x, byte y) {
|
||||
byte i;
|
||||
for (i=0; i<num_enemies; i++) {
|
||||
Enemy* e = &enemies[i];
|
||||
if (in_rect(e, x, y, 0, 2)) {
|
||||
if (in_rect(e, x, y, 4, 1)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
@ -249,49 +273,63 @@ void check_bullet_hit(byte x, byte y) {
|
|||
}
|
||||
}
|
||||
|
||||
void xor_bullet() {
|
||||
render_sprite(bullet_bitmap, bullet_x, bullet_y, M_XOR);
|
||||
}
|
||||
|
||||
void fire_bullet() {
|
||||
bullet_x = player_x + 4;
|
||||
bullet_y = VHEIGHT-PLYRHEIGHT-6;
|
||||
render_sprite(bullet_bitmap, bullet_x, bullet_y, M_XOR); // draw
|
||||
xor_bullet();
|
||||
}
|
||||
|
||||
void move_bullet() {
|
||||
byte leftover;
|
||||
xor_bullet();
|
||||
//erase_sprite(bullet_bitmap, bullet_x, bullet_y);
|
||||
hw_intst; // reset intercept counters
|
||||
render_sprite(bullet_bitmap, bullet_x, bullet_y, M_XOR); // erase
|
||||
leftover = (hw_intst & 0xf0); // any pixels leftover?
|
||||
bullet_y -= 2;
|
||||
xor_bullet();
|
||||
leftover = hw_intst; // any pixels leftover?
|
||||
if (leftover || bullet_y < 10) {
|
||||
erase_sprite(bullet_bitmap, bullet_x, bullet_y);
|
||||
check_bullet_hit(bullet_x, bullet_y+2);
|
||||
bullet_y = 0;
|
||||
} else {
|
||||
bullet_y -= 4;
|
||||
render_sprite(bullet_bitmap, bullet_x, bullet_y, M_XOR); // draw
|
||||
}
|
||||
}
|
||||
|
||||
void drop_bomb() {
|
||||
Enemy* e = &enemies[enemy_index];
|
||||
bomb_x = e->x + 7;
|
||||
bomb_y = e->y + 16;
|
||||
void xor_bomb() {
|
||||
render_sprite(bomb_bitmap, bomb_x, bomb_y, M_XOR);
|
||||
}
|
||||
|
||||
void drop_bomb() {
|
||||
byte i = rand() % num_enemies;
|
||||
Enemy* e = &enemies[i];
|
||||
// don't drop on someone else!
|
||||
if (find_enemy_at(e->x, e->y+ENEMY_HEIGHT+ENEMY_SPACING_Y+1)) {
|
||||
return;
|
||||
}
|
||||
bomb_x = e->x + ENEMY_WIDTH/4;
|
||||
bomb_y = e->y + ENEMY_HEIGHT;
|
||||
xor_bomb();
|
||||
}
|
||||
|
||||
void move_bomb() {
|
||||
hw_intst; // reset intercept counters
|
||||
render_sprite(bomb_bitmap, bomb_x, bomb_y, M_XOR); // erase
|
||||
if (bomb_y > VHEIGHT-12) {
|
||||
bomb_y = 0;
|
||||
} else if (hw_intst & 0xf0) { // any pixels leftover?
|
||||
erase_sprite(bomb_bitmap, bomb_x, bomb_y); // erase bunker
|
||||
if (bomb_y > VHEIGHT-23) {
|
||||
// player was hit (probably)
|
||||
destroy_player();
|
||||
}
|
||||
xor_bomb();
|
||||
if (bomb_y >= VHEIGHT-5) {
|
||||
bomb_y = 0;
|
||||
} else {
|
||||
bomb_y += 3;
|
||||
render_sprite(bomb_bitmap, bomb_x, bomb_y, M_XOR);
|
||||
bomb_y += 1;
|
||||
hw_intst; // reset intercept counters
|
||||
xor_bomb();
|
||||
if (hw_intst & 0xf0) { // any pixels leftover?
|
||||
erase_sprite(bomb_bitmap, bomb_x, bomb_y);
|
||||
if (bomb_y >= player_y-2) {
|
||||
// player was hit (probably)
|
||||
destroy_player();
|
||||
}
|
||||
bomb_y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,34 +337,38 @@ byte frame;
|
|||
signed char player_dir = 0;
|
||||
|
||||
void move_player() {
|
||||
if (attract) {
|
||||
if (bullet_y == 0) fire_bullet();
|
||||
player_dir = 0;
|
||||
} else {
|
||||
byte mask = hw_p1ctrl;
|
||||
if (mask & 0x4) {
|
||||
if (player_x > 0)
|
||||
player_x--;
|
||||
}
|
||||
if (mask & 0x8) {
|
||||
if (player_x < PIXWIDTH-16)
|
||||
player_x++;
|
||||
}
|
||||
if (mask & 0x10) {
|
||||
if (bullet_y == 0) {
|
||||
fire_bullet();
|
||||
}
|
||||
byte mask = hw_p1ctrl;
|
||||
if (mask & 0x4) {
|
||||
if (player_x > 0)
|
||||
player_x--;
|
||||
}
|
||||
if (mask & 0x8) {
|
||||
if (player_x < PIXWIDTH-16)
|
||||
player_x++;
|
||||
}
|
||||
if (mask & 0x10) {
|
||||
if (bullet_y == 0) {
|
||||
fire_bullet();
|
||||
}
|
||||
}
|
||||
// move player
|
||||
render_sprite(player_bitmap, player_x, player_y, M_MOVE);
|
||||
}
|
||||
|
||||
void animate_explosion() {
|
||||
if (--explode_timer == 0) {
|
||||
erase_sprite(explode_bitmap, explode_x, explode_y);
|
||||
} else {
|
||||
render_sprite(explode_bitmap, explode_x, explode_y, M_OR);
|
||||
}
|
||||
}
|
||||
|
||||
void play_round() {
|
||||
draw_playfield();
|
||||
player_x = PIXWIDTH/2-8;
|
||||
bullet_y = 0;
|
||||
bomb_y = 0;
|
||||
explode_timer = 0;
|
||||
frame = 0;
|
||||
while (player_x != 0xff && num_enemies) {
|
||||
move_player();
|
||||
|
@ -341,6 +383,9 @@ void play_round() {
|
|||
move_bomb();
|
||||
}
|
||||
}
|
||||
if (explode_timer) {
|
||||
animate_explosion();
|
||||
}
|
||||
frame++;
|
||||
}
|
||||
}
|
||||
|
@ -356,16 +401,15 @@ void game_over_msg() {
|
|||
byte y=10;
|
||||
hw_xpand = XPAND_COLORS(0, COLOR_SCORE);
|
||||
for (i=0; i<50; i++) {
|
||||
draw_string(" *************** ", x, y+0*8);
|
||||
draw_string("*** ***", x, y+1*8);
|
||||
draw_string("** GAME OVER **", x, y+2*8);
|
||||
draw_string("*** ***", x, y+3*8);
|
||||
draw_string(" *************** ", x, y+4*8);
|
||||
draw_string(x, y+0*8, COLOR_SCORE, " *************** ");
|
||||
draw_string(x, y+1*8, COLOR_SCORE, "*** ***");
|
||||
draw_string(x, y+2*8, COLOR_SCORE, "** GAME OVER **");
|
||||
draw_string(x, y+3*8, COLOR_SCORE, "*** ***");
|
||||
draw_string(x, y+4*8, COLOR_SCORE, " *************** ");
|
||||
}
|
||||
}
|
||||
|
||||
void play_game() {
|
||||
attract = 0;
|
||||
init_game();
|
||||
init_enemies();
|
||||
while (lives) {
|
||||
|
@ -377,26 +421,10 @@ void play_game() {
|
|||
game_over_msg();
|
||||
}
|
||||
|
||||
void attract_mode() {
|
||||
attract = 1;
|
||||
while (1) {
|
||||
init_enemies();
|
||||
play_round();
|
||||
}
|
||||
}
|
||||
|
||||
void setup_registers() {
|
||||
hw_col0r = 0x00;
|
||||
hw_col1r = 0x2f;
|
||||
hw_col2r = 0xef;
|
||||
hw_col3r = 0xaf;
|
||||
hw_horcb = 0;
|
||||
hw_verbl = VHEIGHT*2;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
setup_registers();
|
||||
hw_horcb = 40;
|
||||
hw_verbl = VHEIGHT*2;
|
||||
set_palette(palette);
|
||||
// NOTE: initializers don't get run, so we init here
|
||||
while (1) {
|
||||
//attract_mode();
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
#include "acfast.h"
|
||||
//#link "acfast.s"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma opt_code_speed
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x77, 0xBC, 0x35, 0x01,
|
||||
0x07, 0xF2, 0x64, 0x01,
|
||||
};
|
||||
|
||||
const byte SPRITE[] = {
|
||||
2,8,
|
||||
/*{w:8,h:8,bpp:2,brev:1}*/
|
||||
0x01,0x40, 0x06,0x90, 0x15,0x54, 0x47,0x51,
|
||||
0x45,0xD1, 0x05,0x50, 0x04,0x10, 0x3C,0x3C,
|
||||
};
|
||||
|
||||
#define MAX_SPRITES 8
|
||||
|
||||
typedef struct {
|
||||
byte x; // x coordinate
|
||||
byte y; // y coordinate
|
||||
byte lastmagic; // last magic byte used
|
||||
byte* lastdest; // last destination address
|
||||
const byte* pattern; // pattern definition
|
||||
byte _unused;
|
||||
} Actor;
|
||||
|
||||
Actor actors[MAX_SPRITES];
|
||||
|
||||
void erase_actor(Actor* actor) {
|
||||
hw_magic = actor->lastmagic;
|
||||
fast_sprite_8(actor->pattern, actor->lastdest);
|
||||
}
|
||||
|
||||
void draw_actor(Actor* actor) {
|
||||
byte op = M_XOR;
|
||||
byte x = actor->x;
|
||||
byte y = actor->y;
|
||||
actor->lastdest = &vmagic[y][x>>2];// destination address
|
||||
actor->lastmagic = M_SHIFT(x) | op; // set magic register
|
||||
erase_actor(actor);
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
byte i;
|
||||
// setup palette
|
||||
set_palette(palette);
|
||||
// set screen height
|
||||
// set horizontal color split (position / 4)
|
||||
// set interrupt status
|
||||
SYS_SETOUT(89*2, 0, 0);
|
||||
// clear screen
|
||||
SYS_FILL(0x4000, 89*40, 0);
|
||||
// infinite loop
|
||||
activate_interrupts();
|
||||
// fill array
|
||||
for (i=0; i<MAX_SPRITES; i++) {
|
||||
actors[i].x = rand() & 0x7f;
|
||||
actors[i].y = (i*8) & 0x3f;
|
||||
actors[i].pattern = SPRITE;
|
||||
draw_actor(&actors[i]);
|
||||
}
|
||||
while (1) {
|
||||
fast_vsync();
|
||||
hw_col0r = 0x2;
|
||||
for (i=0; i<MAX_SPRITES; i++) {
|
||||
Actor* a = &actors[i];
|
||||
erase_actor(a);
|
||||
draw_actor(a);
|
||||
a->x++;
|
||||
}
|
||||
hw_col0r = 0x1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
; Minimal header file for use with Astrocade C programs
|
||||
|
||||
.area _CODE
|
||||
|
||||
jp Start ; jump to main()
|
||||
Start:
|
||||
ld hl,#0x4fce ; stack start
|
||||
ld sp,hl ; setup stack pointer
|
||||
; clear BIOS RAM
|
||||
ld bc,#0x4fff-0x4fce
|
||||
xor a ; A = 0
|
||||
ld (hl),a ; set initial zero
|
||||
push hl
|
||||
pop de
|
||||
inc de ; DE = HL + 1
|
||||
ldir ; clear RAM
|
||||
; initialize INITIALIZED segment
|
||||
ld BC, #l__INITIALIZER
|
||||
ld a,c
|
||||
or b
|
||||
jp z,.nomeminit
|
||||
ld A, B
|
||||
ld DE, #s__INITIALIZED
|
||||
ld HL, #s__INITIALIZER
|
||||
ldir
|
||||
.nomeminit:
|
||||
; jump to main C function
|
||||
jp _main
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
.include "astrocade.inc"
|
||||
|
||||
; Minimal header file for use with Astrocade C programs
|
||||
|
||||
.area _CODE
|
||||
|
||||
.db 0x55 ; sentinel
|
||||
.dw MENUST
|
||||
.dw PrgName
|
||||
.dw PrgStart
|
||||
PrgName:
|
||||
.ascii "8BITWORKSHOP"
|
||||
.db 0
|
||||
PrgStart:
|
||||
jp _main
|
|
@ -0,0 +1,107 @@
|
|||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
//#link "hdr_autostart.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x77, 0xD4, 0x35, 0x01,
|
||||
0x07, 0xD4, 0x35, 0x01,
|
||||
};
|
||||
|
||||
const byte BALL[] = {
|
||||
0, 0, // x and y offset
|
||||
1, 6, // width (bytes) and height (lines)
|
||||
/*{w:8,h:6,brev:1}*/
|
||||
0b01111000,
|
||||
0b11011100,
|
||||
0b10111100,
|
||||
0b10111100,
|
||||
0b11111100,
|
||||
0b01111000,
|
||||
};
|
||||
|
||||
// BCD number
|
||||
byte bcdnum[3] = {0x96,0x99,0x09};
|
||||
const byte bcdinc[3] = {0x01,0x00,0x00};
|
||||
|
||||
byte music_stack[16];
|
||||
const byte MUSICDATA[] = {
|
||||
0x80,
|
||||
0x20,0xB0,0xCC,0x0F,0x0C,0x7E,0x00,0x00,
|
||||
0x0C,0x7E,0x00,0x00,0x24,0x5E,0x7E,0x96,
|
||||
0x0C,0x54,0x64,0x7E,0x0E,0x4A,0x5E,0x7E,
|
||||
0x10,0x46,0x54,0x7E,0x48,0x3E,0x4A,0x5E,
|
||||
0x0E,0x5E,0x8D,0x70,0x10,0x54,0x8D,0x70,
|
||||
0x36,0x4A,0x5E,0x70,0x12,0x46,0x54,0x7E,
|
||||
0x24,0x54,0x64,0x7E,0x48,0x5E,0x96,0x7E,
|
||||
0xE0,0x80,0x18,0x90,0xFD,0xB0,0xFF,0x1F,
|
||||
0xF0,
|
||||
};
|
||||
|
||||
void main(void) {
|
||||
// setup palette
|
||||
set_palette(palette);
|
||||
// set screen height
|
||||
// set horizontal color split (position / 4)
|
||||
// set interrupt status
|
||||
// use SYS_SETOUT macro
|
||||
SYS_SETOUT(89*2, 23, 0);
|
||||
// clear screen w/ SYS_FILL macro
|
||||
SYS_FILL(0x4000, 89*40, 0);
|
||||
// display standard characters
|
||||
display_string(2, 2, OPT_ON(1), "HELLO, WORLD!\xb1\xb2\xb3\xb4\xb5");
|
||||
// 2x2 must have X coordinate multiple of 2
|
||||
display_string(4, 16, OPT_2x2|OPT_ON(2), "BIG TEXT!");
|
||||
// 4x4 must have X coordinate multiple of 4
|
||||
display_string(4, 36, OPT_4x4|OPT_ON(2), "4X4");
|
||||
// we can use OR mode to make a shadow
|
||||
display_string(4, 38, OPT_4x4|OPT_ON(3)|OPT_OR, "4X4");
|
||||
// and XOR mode to invert existing pixels
|
||||
// (careful, there's no clipping)
|
||||
display_string(109, 24, OPT_8x8|OPT_ON(3)|OPT_XOR, "?");
|
||||
// small font must be aligned to multiple of 4
|
||||
display_string(4, 80, OPT_ON(1), "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9");
|
||||
// paint a rectangle with a pattern mask (0xa5)
|
||||
paint_rectangle(4, 72, 100, 5, 0x55);
|
||||
// more compact macro
|
||||
SYS_RECTAN(6, 74, 100, 4, 0xaa);
|
||||
// write from pattern block
|
||||
write_relative(50, 80, M_XPAND, BALL);
|
||||
write_relative(60, 80, M_XPAND, BALL);
|
||||
// write_pattern() doesn't use the x/y offset
|
||||
write_pattern(70, 80, M_XPAND, BALL+2);
|
||||
write_pattern(0, 80, M_XPAND|M_FLOP, BALL+2);
|
||||
write_pattern(1, 70, M_XPAND|M_FLOP, BALL+2);
|
||||
write_pattern(2, 60, M_XPAND|M_FLOP, BALL+2);
|
||||
// infinite loop
|
||||
activate_interrupts();
|
||||
// make sure screen doesn't black out
|
||||
RESET_TIMEOUT();
|
||||
// play music
|
||||
//SYS_BMUSIC(_music_stack, 0b11111100, _MUSICDATA);
|
||||
//begin_music(music_stack, 0b11111100, MUSICDATA);
|
||||
while (1) {
|
||||
// wait for SENTRY result
|
||||
word code;
|
||||
do {
|
||||
code = sense_transition(ALKEYS);
|
||||
} while (code == 0);
|
||||
// respond to SENTRY
|
||||
switch (code & 0xff) {
|
||||
case SSEC:
|
||||
display_bcd_number(80, 80, OPT_ON(2), bcdnum, 6|DISBCD_SML|DISBCD_NOZERO);
|
||||
bcdn_add(bcdnum, 3, bcdinc);
|
||||
break;
|
||||
case SP0:
|
||||
hw_horcb = (code>>8)>>2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@
|
|||
; > Version 2.6 - March 2, 2004 - as seen on BallyAlley.com
|
||||
; > Version 3.0 - 2009
|
||||
; > Version 3.01 - Changed "FonT BASE character" comment
|
||||
; > (also patched for latest zmac with default args)
|
||||
; >
|
||||
; > This file contains the equates and macros that Bally
|
||||
; > programs require for assembly. This file has been
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
#include "acbios.h"
|
||||
#include "acextra.h"
|
||||
//#link "acextra.c"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma opt_code_speed
|
||||
|
||||
void draw_line(int x0, int y0, int x1, int y1, byte color) {
|
||||
int dx = abs(x1-x0);
|
||||
int sx = x0<x1 ? 1 : -1;
|
||||
int dy = abs(y1-y0);
|
||||
int sy = y0<y1 ? 1 : -1;
|
||||
int err = (dx>dy ? dx : -dy)>>1;
|
||||
int e2;
|
||||
for(;;) {
|
||||
pixel(x0, y0, color, M_XOR);
|
||||
if (x0==x1 && y0==y1) break;
|
||||
e2 = err;
|
||||
if (e2 > -dx) { err -= dy; x0 += sx; }
|
||||
if (e2 < dy) { err += dx; y0 += sy; }
|
||||
}
|
||||
}
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x06, 0x62, 0xF1, 0x04,
|
||||
0x07, 0xD4, 0x35, 0x00,
|
||||
};
|
||||
|
||||
void main() {
|
||||
set_palette(palette);
|
||||
SYS_SETOUT(89*2, 20, 0);
|
||||
SYS_FILL(0x4000, 89*40, 0);
|
||||
hw_xpand = XPAND_COLORS(0, 2);
|
||||
draw_string(2, 80, 0, "Hello, Lines!");
|
||||
draw_line(0, 0, 159, 95, 1);
|
||||
// infinite loop
|
||||
srand(1);
|
||||
while(1) {
|
||||
draw_line(rand()%159, rand()%79, rand()%159, rand()%79, rand()&3);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,458 @@
|
|||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
#include "acfast.h"
|
||||
//#link "acfast.s"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma opt_code_speed
|
||||
|
||||
// reserve 240 bytes to expand screen RAM to 4eff
|
||||
byte UNUSED[0xf0];
|
||||
|
||||
#define SKYH 35
|
||||
#define GNDH 45
|
||||
#define BOTTOM (35+45)
|
||||
#define DASH_Y (BOTTOM+8)
|
||||
#define PLAYER_Y (BOTTOM-67)
|
||||
#define DASH_HEIGHT 16
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x07, 0xA5, 0x00, 0x03,
|
||||
0xE6, 0xE5, 0xE4, 0xE3,
|
||||
};
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte dash_palette[4] = {
|
||||
0x05, 0x53, 0x86, 0x00,
|
||||
};
|
||||
|
||||
/*{pal:"astrocade"}*/
|
||||
const byte ground_colors[8] = {
|
||||
0xA5, 0xA4, 0xA3, 0xA2, 0x91, 0x81, 0x80, 0x01,
|
||||
};
|
||||
|
||||
/*{pal:"astrocade"}*/
|
||||
const byte sky_colors[4*8] = {
|
||||
0xE6, 0xE5, 0xE4, 0xE3,
|
||||
0xE5, 0xE4, 0xF3, 0x12,
|
||||
0xE4, 0xE3, 0x12, 0x22,
|
||||
0xE3, 0x12, 0x22, 0x44,
|
||||
0x12, 0x22, 0x44, 0x64,
|
||||
0x12, 0x22, 0x20, 0xE0,
|
||||
0x12, 0x22, 0xE0, 0x00,
|
||||
0x11, 0xE0, 0x00, 0x00,
|
||||
};
|
||||
|
||||
const byte CURBS[4*16] = {
|
||||
/*{w:16,h:16,bpp:2,brev:1}*/
|
||||
0xBF, 0xFF, 0xFF, 0xFA,
|
||||
0xBF, 0xFF, 0xFF, 0xFA,
|
||||
0xAF, 0xFF, 0xFF, 0xEA,
|
||||
0xAF, 0xFF, 0xFF, 0xEA,
|
||||
0xAB, 0xFF, 0xFF, 0xAA,
|
||||
0xAB, 0xFF, 0xFF, 0xAA,
|
||||
0xAA, 0xFF, 0xFE, 0xAA,
|
||||
0xAA, 0xFF, 0xFE, 0xAA,
|
||||
0xAA, 0xBF, 0xFA, 0xAA,
|
||||
0xAA, 0xBF, 0xFA, 0xAA,
|
||||
0xAA, 0xAF, 0xEA, 0xAA,
|
||||
0xAA, 0xAB, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA,
|
||||
0xAA, 0xAA, 0xAA, 0xAA,
|
||||
};
|
||||
|
||||
const byte CAR_10_MASK[2+4*10] = {
|
||||
4,10,
|
||||
/*{w:16,h:10,bpp:2,brev:1}*/
|
||||
0x03, 0xC0, 0x03, 0xC0,
|
||||
0x03, 0xFF, 0xFF, 0xC0,
|
||||
0x00, 0x3F, 0xFC, 0x00,
|
||||
0x00, 0xFF, 0xFF, 0x00,
|
||||
0x3F, 0xFF, 0xFF, 0xFC,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x3F, 0xC0, 0x03, 0xFC,
|
||||
};
|
||||
|
||||
const byte CAR_10_INV[2+4*10] = {
|
||||
4,10,
|
||||
/*{w:16,h:10,bpp:2,brev:1}*/
|
||||
0x02, 0x80, 0x02, 0x80,
|
||||
0x02, 0x95, 0x56, 0x80,
|
||||
0x00, 0x16, 0x94, 0x00,
|
||||
0x00, 0x58, 0x25, 0x00,
|
||||
0x2A, 0x51, 0x45, 0xA8,
|
||||
0x82, 0x6A, 0xA9, 0x82,
|
||||
0xAA, 0x96, 0x96, 0xAA,
|
||||
0xAA, 0x56, 0x95, 0xAA,
|
||||
0xAA, 0x7F, 0xFD, 0xAA,
|
||||
0x2A, 0xC0, 0x03, 0xA8,
|
||||
};
|
||||
|
||||
const byte CAR_10[2+4*10] = {
|
||||
4,10,
|
||||
/*{w:16,h:10,bpp:2,brev:1}*/
|
||||
0x01, 0x40, 0x01, 0x40,
|
||||
0x01, 0x6A, 0xA9, 0x40,
|
||||
0x00, 0x29, 0x68, 0x00,
|
||||
0x02, 0xA7, 0xDA, 0x80,
|
||||
0x15, 0xAC, 0x3A, 0x54,
|
||||
0x7D, 0x95, 0x56, 0x7D,
|
||||
0x55, 0x69, 0x69, 0x55,
|
||||
0x55, 0xA9, 0x6A, 0x55,
|
||||
0x55, 0x80, 0x02, 0x55,
|
||||
0x15, 0x00, 0x00, 0x54,
|
||||
};
|
||||
|
||||
const byte CAR_9[2+4*9] = {
|
||||
4,9,
|
||||
/*{w:16,h:9,bpp:2,brev:1}*/
|
||||
0x00, 0x50, 0x05, 0x00,
|
||||
0x00, 0x5A, 0xA5, 0x00,
|
||||
0x00, 0x29, 0x68, 0x00,
|
||||
0x02, 0xA7, 0xDA, 0x80,
|
||||
0x15, 0xAC, 0x3A, 0x54,
|
||||
0x1D, 0x95, 0x56, 0x7C,
|
||||
0x15, 0x69, 0x69, 0x54,
|
||||
0x15, 0xA9, 0x6A, 0x54,
|
||||
0x15, 0x80, 0x02, 0x54,
|
||||
};
|
||||
|
||||
const byte CAR_8[2+4*8] = {
|
||||
4,8,
|
||||
/*{w:16,h:8,bpp:2,brev:1}*/
|
||||
0x00, 0x14, 0x14, 0x00,
|
||||
0x00, 0x1A, 0xA4, 0x00,
|
||||
0x00, 0x29, 0x68, 0x00,
|
||||
0x02, 0xA7, 0xDA, 0x80,
|
||||
0x05, 0xA0, 0x0A, 0x50,
|
||||
0x0D, 0x55, 0x55, 0x70,
|
||||
0x05, 0xA9, 0x6A, 0x50,
|
||||
0x05, 0x00, 0x00, 0x50,
|
||||
};
|
||||
|
||||
const byte CAR_7[2+4*7] = {
|
||||
4,7,
|
||||
/*{w:16,h:7,bpp:2,brev:1}*/
|
||||
0x00, 0x04, 0x10, 0x00,
|
||||
0x00, 0x06, 0x90, 0x00,
|
||||
0x00, 0x29, 0x68, 0x00,
|
||||
0x00, 0xA7, 0xDA, 0x00,
|
||||
0x03, 0x55, 0x55, 0xC0,
|
||||
0x01, 0x6A, 0xA9, 0x40,
|
||||
0x01, 0x40, 0x01, 0x40,
|
||||
};
|
||||
|
||||
const byte CAR_6[2+4*6] = {
|
||||
2,6,
|
||||
/*{w:8,h:6,bpp:2,brev:1}*/
|
||||
0x04, 0x10,
|
||||
0x06, 0x90,
|
||||
0x0B, 0xE0,
|
||||
0x55, 0x55,
|
||||
0x5A, 0xA5,
|
||||
0x50, 0x05,
|
||||
};
|
||||
|
||||
const byte CAR_5[2+4*5] = {
|
||||
2,5,
|
||||
/*{w:8,h:5,bpp:2,brev:1}*/
|
||||
0x04, 0x10,
|
||||
0x0A, 0xA0,
|
||||
0x05, 0x50,
|
||||
0x16, 0x94,
|
||||
0x14, 0x14,
|
||||
};
|
||||
|
||||
const byte CAR_4[2+4*4] = {
|
||||
2,4,
|
||||
/*{w:8,h:4,bpp:2,brev:1}*/
|
||||
0x01, 0x40,
|
||||
0x0A, 0xA0,
|
||||
0x05, 0x50,
|
||||
0x04, 0x10,
|
||||
};
|
||||
|
||||
const byte CAR_3[2+4*3] = {
|
||||
2,3,
|
||||
/*{w:8,h:3,bpp:2,brev:1}*/
|
||||
0x01, 0x40,
|
||||
0x06, 0x90,
|
||||
0x04, 0x10,
|
||||
};
|
||||
|
||||
const byte CAR_2[2+4*2] = {
|
||||
2,2,
|
||||
/*{w:8,h:2,bpp:2,brev:1}*/
|
||||
0x02, 0x80,
|
||||
0x01, 0x40,
|
||||
};
|
||||
|
||||
const byte* const CAR_PATTERNS[16] = {
|
||||
CAR_10, CAR_10, CAR_10,
|
||||
CAR_9, CAR_9, CAR_8,
|
||||
CAR_7, CAR_6, CAR_5, CAR_4, CAR_3,
|
||||
CAR_2, CAR_2, CAR_2, CAR_2
|
||||
};
|
||||
|
||||
// Z-table -- y = 800/(x*0.5+16)
|
||||
const byte ZTAB[128] = {
|
||||
50,48,47,45,44,43,42,41,40,39,38,37,36,35,34,34,33,32,32,31,30,30,29,29,28,28,27,27,26,26,25,25,25,24,24,23,23,23,22,22,22,21,21,21,21,20,20,20,20,19,19,19,19,18,18,18,18,17,17,17,17,17,17,16,16,16,16,16,16,15,15,15,15,15,15,14,14,14,14,14,14,14,14,13,13,13,13,13,13,13,13,13,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
|
||||
};
|
||||
|
||||
byte get1z(byte x) __z88dk_fastcall {
|
||||
return (x<128) ? ZTAB[x] : (255-x)/16+2;
|
||||
}
|
||||
|
||||
#define PAT_ROAD 0x00
|
||||
#define PAT_SKY 0x55
|
||||
#define PAT_GROUND 0xaa
|
||||
|
||||
byte road_width = 142;
|
||||
byte road_cenx = 80;
|
||||
int road_inc = 0;
|
||||
sbyte road_curve = 0;
|
||||
byte curve_dir = 1;
|
||||
word track_pos = 0;
|
||||
byte speed = 4;
|
||||
byte fill_grass = 0;
|
||||
|
||||
// interrupt handler declarations
|
||||
void inthandler1() __interrupt;
|
||||
void inthandler2() __interrupt;
|
||||
void inthandler3() __interrupt;
|
||||
void inthandler4() __interrupt;
|
||||
void inthandler5() __interrupt;
|
||||
|
||||
// pointers to the interrupt handlers
|
||||
const t_interrupt_handler const intvector1 = &inthandler1;
|
||||
const t_interrupt_handler const intvector2 = &inthandler2;
|
||||
const t_interrupt_handler const intvector3 = &inthandler3;
|
||||
const t_interrupt_handler const intvector4 = &inthandler4;
|
||||
const t_interrupt_handler const intvector5 = &inthandler5;
|
||||
|
||||
// bottom of screen, set sky palette
|
||||
// update track_pos every 1/60 sec
|
||||
void inthandler1() __interrupt {
|
||||
SET_RIGHT_PALETTE(_palette+4);
|
||||
hw_inlin = SKYH*2 - 2;
|
||||
track_pos += speed;
|
||||
CHANGE_INTERRUPT_VECTOR(_intvector2);
|
||||
}
|
||||
// horizon, set ground palette
|
||||
// next split calculated linearly
|
||||
void inthandler2() __interrupt {
|
||||
hw_horcb = 40;
|
||||
hw_inlin = SKYH*2 + 2 + ((track_pos&0xff)>>4);
|
||||
CHANGE_INTERRUPT_VECTOR(_intvector3);
|
||||
}
|
||||
// far split, change road color
|
||||
// next split calculated with Z lookup table
|
||||
void inthandler3() __interrupt {
|
||||
byte y = (SKYH + ZTAB[((~track_pos&0xff)>>1)]) * 2;
|
||||
hw_inlin = y > BOTTOM*2 ? BOTTOM*2 : y;
|
||||
hw_col0l = 2 ^ ((track_pos>>8)&1);
|
||||
CHANGE_INTERRUPT_VECTOR(_intvector4);
|
||||
}
|
||||
// near split, change road color until dash
|
||||
void inthandler4() __interrupt {
|
||||
hw_inlin = (BOTTOM+2)*2;
|
||||
hw_col0l = 3 ^ ((track_pos>>8)&1);
|
||||
CHANGE_INTERRUPT_VECTOR(_intvector5);
|
||||
}
|
||||
// set dash palette until bottom of screen
|
||||
void inthandler5() __interrupt {
|
||||
SET_RIGHT_PALETTE(_dash_palette);
|
||||
hw_horcb = 0;
|
||||
hw_inlin = 106*2;
|
||||
CHANGE_INTERRUPT_VECTOR(_intvector1);
|
||||
}
|
||||
|
||||
// get track position, preventing race condition
|
||||
// if it changes during interrupt
|
||||
word get_track_pos(void) {
|
||||
__asm__("di");
|
||||
__asm__("ld hl,(_track_pos)");
|
||||
__asm__("ei");
|
||||
}
|
||||
|
||||
// car record
|
||||
typedef struct {
|
||||
sbyte x;
|
||||
byte y;
|
||||
const byte* pattern;
|
||||
} Car;
|
||||
|
||||
#define MAX_CARS 2
|
||||
Car cars[MAX_CARS];
|
||||
|
||||
void draw_car(byte x1, const Car* car) {
|
||||
byte x = x1 + car->x;
|
||||
byte* dest = &vmagic[BOTTOM - car->y][x>>2];
|
||||
hw_magic = M_SHIFT(x) | M_OR;
|
||||
// is this pattern 16 pixels wide?
|
||||
if (car->pattern[0] == 4) {
|
||||
// special mask mode for cars near the edge
|
||||
if (car->pattern == CAR_10 && (x < 40 || x > 120)) {
|
||||
hw_magic = M_SHIFT(x) | M_OR;
|
||||
fast_sprite_16(CAR_10_MASK, dest);
|
||||
hw_magic = M_SHIFT(x) | M_XOR;
|
||||
fast_sprite_16(CAR_10_INV, dest);
|
||||
fill_grass = 2; // draw over grass next frame
|
||||
} else {
|
||||
// 16-pixel fast OR with background
|
||||
fast_sprite_16(car->pattern, dest);
|
||||
}
|
||||
} else {
|
||||
// 8-pixel fast OR with background
|
||||
fast_sprite_8(car->pattern, dest);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_cars(byte x1, byte y) {
|
||||
if (y == cars[0].y) {
|
||||
draw_car(x1, &cars[0]);
|
||||
}
|
||||
if (y == cars[1].y) {
|
||||
draw_car(x1, &cars[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_grass(byte* start, byte* end) {
|
||||
hw_magic = 0;
|
||||
while (start < end) {
|
||||
*start++ = PAT_GROUND;
|
||||
}
|
||||
}
|
||||
|
||||
void draw_road() {
|
||||
byte y,x1,x2,w,j;
|
||||
register byte* dest;
|
||||
static byte* line;
|
||||
static word xx;
|
||||
static int inc;
|
||||
static const byte* curb;
|
||||
curb = CURBS;
|
||||
line = &vmagic[BOTTOM][0];
|
||||
inc = road_inc;
|
||||
w = road_width;
|
||||
// 16-bit X coordinate
|
||||
xx = road_cenx << 8;
|
||||
// loop from bottom to top
|
||||
for (y=0; y<GNDH; y++) {
|
||||
x1 = (xx >> 8) - w/2;
|
||||
x2 = x1 + w;
|
||||
// fill in grass?
|
||||
if (fill_grass && y <= PLAYER_Y) {
|
||||
// TODO: calc redundant expr but keeps our register var
|
||||
draw_grass(line, line + x1/4);
|
||||
}
|
||||
// left side of road
|
||||
dest = line + x1/4;
|
||||
hw_magic = M_SHIFT(x1);
|
||||
WASTER = PAT_GROUND; // fill shifter with ground color
|
||||
*dest++ = curb[0];
|
||||
*dest++ = curb[1];
|
||||
// repave road, unroll loop a bit
|
||||
// (causes a little flicker on the right)
|
||||
for (j=0; j<w/8; j++) {
|
||||
*dest++ = PAT_ROAD;
|
||||
*dest++ = PAT_ROAD;
|
||||
}
|
||||
// right side of road
|
||||
dest = line + x2/4;
|
||||
hw_magic = M_SHIFT(x2);
|
||||
*dest++ = curb[2];
|
||||
*dest++ = curb[3];
|
||||
*dest = PAT_GROUND;
|
||||
// fill in grass?
|
||||
if (fill_grass && y <= PLAYER_Y) {
|
||||
draw_grass(dest, line+40);
|
||||
}
|
||||
// draw any cars which start on this line
|
||||
draw_cars(xx>>8, y);
|
||||
// next line up, update variables
|
||||
line -= 40;
|
||||
if ((y&3) == 0) curb += 4;
|
||||
xx += inc;
|
||||
inc += road_curve;
|
||||
w -= 3;
|
||||
}
|
||||
if (fill_grass) fill_grass--;
|
||||
}
|
||||
|
||||
void draw_sky() {
|
||||
SYS_FILL(0x4000+0*40, 44*40, 0x00);
|
||||
SYS_FILL(0x4000+25*40, 10*40, 0x55);
|
||||
SYS_FILL(0x4000+30*40, 5*40, 0xaa);
|
||||
SYS_FILL(0x4000+33*40, 2*40, 0xff);
|
||||
}
|
||||
|
||||
void draw_ground() {
|
||||
SYS_FILL(0x4000+35*40, 44*40, 0xaa);
|
||||
}
|
||||
|
||||
void draw_dash() {
|
||||
SYS_FILL(0x4000+80*40, 16*40, 0x00);
|
||||
SYS_FILL(0x4000+80*40, 5*40, 0xff);
|
||||
}
|
||||
|
||||
void position_cars() {
|
||||
byte x,y,zr;
|
||||
// player car
|
||||
cars[0].x = hw_p1pot/2 - 64;
|
||||
// other cars
|
||||
zr = get1z((get_track_pos() & 0xff) ^ 0xff);
|
||||
y = GNDH - zr;
|
||||
x = zr;
|
||||
cars[1].x = x;
|
||||
cars[1].y = y;
|
||||
cars[1].pattern = CAR_PATTERNS[y/4];
|
||||
if (y < 10) cars[1].y = -1; // TODO: clipping
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
// setup palette
|
||||
set_palette(palette);
|
||||
// set screen height
|
||||
// set horizontal color split (position / 4)
|
||||
// set interrupt status
|
||||
set_interrupt_vector(&intvector1);
|
||||
SYS_SETOUT(96*2, 0, 0x8);
|
||||
// draw initial background
|
||||
draw_sky();
|
||||
draw_ground();
|
||||
draw_dash();
|
||||
// place player car
|
||||
cars[0].y = PLAYER_Y;
|
||||
cars[0].x = 50;
|
||||
cars[0].pattern = CAR_10;
|
||||
// player other car
|
||||
cars[1].y = BOTTOM-60;
|
||||
cars[1].x = 20;
|
||||
cars[1].pattern = CAR_6;
|
||||
// draw score
|
||||
display_string(0, DASH_Y, XPAND_COLORS(1,0), " 00:00");
|
||||
// infinite loop
|
||||
while (1) {
|
||||
position_cars();
|
||||
draw_road();
|
||||
road_curve += curve_dir;
|
||||
if (road_curve >= 21) curve_dir = -1;
|
||||
if (road_curve <= -20) curve_dir = 1;
|
||||
if (hw_p1ctrl & JOY_UP && speed<16) speed++;
|
||||
if (hw_p1ctrl & JOY_DOWN && speed>1) speed--;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma opt_code_speed
|
||||
|
||||
// we have a special interrupt handler that sets
|
||||
// palette colors every 4 lines
|
||||
byte linenum = 0;
|
||||
|
||||
void inthandler(void) __interrupt {
|
||||
byte i = linenum;
|
||||
hw_col0l = i;
|
||||
hw_col1l = i+1;
|
||||
hw_col2l = i+2;
|
||||
hw_col3l = i+3;
|
||||
i += 4;
|
||||
if (i > 200) i = 0;
|
||||
hw_inlin = i;
|
||||
linenum = i;
|
||||
}
|
||||
|
||||
// pointer to the interrupt handler
|
||||
const t_interrupt_handler const intvector = &inthandler;
|
||||
|
||||
// patterns to fill each 4-line scanline group
|
||||
const byte FILLPATS[4] = { 0x00, 0x55, 0xaa, 0xff };
|
||||
|
||||
void main(void) {
|
||||
// fill screen with colors 0-3 every 4 scanlines
|
||||
for (byte i=0; i<89; i++) {
|
||||
memset(&vidmem[i], FILLPATS[i&3], 40);
|
||||
}
|
||||
// set our custom interrupt vector
|
||||
set_interrupt_vector(&intvector);
|
||||
// set screen height
|
||||
// set horizontal color split (position / 4)
|
||||
// set interrupt status (on)
|
||||
SYS_SETOUT(89*2, 20, 0x8);
|
||||
// infinite loop
|
||||
// let the interrupt handler do the work
|
||||
while (1) ;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
//#link "hdr_autostart.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x77, 0xD4, 0x35, 0x01,
|
||||
0x07, 0xD4, 0x35, 0x01,
|
||||
};
|
||||
|
||||
const byte SPRITE[] = {
|
||||
0, 0, // x and y offset
|
||||
1, 4, // width (bytes) and height (lines)
|
||||
/*{w:4,h:4,bpp:2,brev:1}*/
|
||||
0xA0,
|
||||
0xD0,
|
||||
0xC4,
|
||||
0xC1
|
||||
};
|
||||
|
||||
void draw_pattern(byte x) {
|
||||
vmagic[0][x] = SPRITE[4];
|
||||
vmagic[1][x] = SPRITE[5];
|
||||
vmagic[2][x] = SPRITE[6];
|
||||
vmagic[3][x] = SPRITE[7];
|
||||
}
|
||||
|
||||
void draw_pattern_inv(byte x) {
|
||||
vmagic[3][x] = SPRITE[4];
|
||||
vmagic[2][x] = SPRITE[5];
|
||||
vmagic[1][x] = SPRITE[6];
|
||||
vmagic[0][x] = SPRITE[7];
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
// setup palette
|
||||
set_palette(palette);
|
||||
// set screen height
|
||||
// set horizontal color split (position / 4)
|
||||
// set interrupt status
|
||||
SYS_SETOUT(89*2, 23, 0);
|
||||
// clear screen
|
||||
SYS_FILL(0x4000, 89*40, 0);
|
||||
// draw pattern
|
||||
hw_magic = M_ROTATE;
|
||||
draw_pattern(0);
|
||||
draw_pattern(2);
|
||||
// draw pattern flopped
|
||||
hw_magic = M_ROTATE|M_FLOP;
|
||||
draw_pattern(4);
|
||||
draw_pattern(6);
|
||||
// draw pattern
|
||||
hw_magic = M_ROTATE;
|
||||
draw_pattern_inv(8);
|
||||
draw_pattern_inv(10);
|
||||
// draw pattern flopped
|
||||
hw_magic = M_ROTATE|M_FLOP;
|
||||
draw_pattern_inv(12);
|
||||
draw_pattern_inv(14);
|
||||
|
||||
while (1) {
|
||||
}
|
||||
}
|
|
@ -1,8 +1,34 @@
|
|||
|
||||
//#link "acheader.s"
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void main() {
|
||||
memset((void*)0x4000, 0, 0xe00); // clear screen, avoid vars and stack (1e00-1fff)
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x77, 0xD4, 0x35, 0x01,
|
||||
0x07, 0xD4, 0x35, 0x01,
|
||||
};
|
||||
|
||||
void main(void) {
|
||||
// setup palette
|
||||
set_palette(palette);
|
||||
// set screen height
|
||||
// set horizontal color split (position / 4)
|
||||
// set interrupt status
|
||||
SYS_SETOUT(89*2, 23, 0);
|
||||
// clear screen
|
||||
SYS_FILL(0x4000, 89*40, 0);
|
||||
// display standard characters
|
||||
display_string(2, 2, OPT_ON(1), "HELLO, WORLD!!");
|
||||
// infinite loop
|
||||
activate_interrupts();
|
||||
while (1) {
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.c"
|
||||
#include "acextra.h"
|
||||
//#link "acextra.c"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
const byte player_bitmap[] =
|
||||
{3,14,/*{w:12,h:16,bpp:2,brev:1}*/0x00,0x3C,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x04,0x18,0x20,0x0C,0x3C,0x30,0x3C,0x3C,0x3C,0x1F,0xE7,0xF4,0x1F,0x66,0xF4,0x17,0xE7,0xE4,0x17,0xE7,0xE4,0x1C,0x7E,0x34,0x1C,0xFF,0x34,0x3C,0x18,0x3C,0x0C,0x18,0x30,0x04,0x18,0x20};
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x06, 0x62, 0xF1, 0x04,
|
||||
0x07, 0xD4, 0x35, 0x01,
|
||||
};
|
||||
|
||||
void main() {
|
||||
byte x,y;
|
||||
x=10;
|
||||
y=10;
|
||||
set_palette(palette);
|
||||
SYS_SETOUT(102*2, 0, 0);
|
||||
SYS_FILL(0x4000, 89*40, 0);
|
||||
while (1) {
|
||||
render_sprite(player_bitmap, x, y, M_MOVE);
|
||||
erase_sprite(player_bitmap, x, y);
|
||||
x++;
|
||||
y++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
//#resource "astrocade.inc"
|
||||
#include "aclib.h"
|
||||
//#link "aclib.s"
|
||||
#include "acbios.h"
|
||||
//#link "acbios.s"
|
||||
//#link "hdr_autostart.s"
|
||||
|
||||
const byte player_bitmap[] =
|
||||
{0,0, // X, Y offset
|
||||
3,14, // width (bytes) and height (lines)
|
||||
/*{w:12,h:16,bpp:2,brev:1}*/
|
||||
0x00,0x3C,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x04,0x18,0x20,0x0C,0x3C,0x30,0x3C,0x3C,0x3C,0x1F,0xE7,0xF4,0x1F,0x66,0xF4,0x17,0xE7,0xE4,0x17,0xE7,0xE4,0x1C,0x7E,0x34,0x1C,0xFF,0x34,0x3C,0x18,0x3C,0x0C,0x18,0x30,0x04,0x18,0x20};
|
||||
|
||||
/*{pal:"astrocade",layout:"astrocade"}*/
|
||||
const byte palette[8] = {
|
||||
0x07, 0xD4, 0x33, 0x01,
|
||||
0x07, 0xD4, 0x33, 0x01,
|
||||
};
|
||||
|
||||
void main() {
|
||||
byte x,y;
|
||||
x=20;
|
||||
y=20;
|
||||
memset((void*)0x4FCE, 0, 0x5000-0x4FCE);
|
||||
set_palette(palette);
|
||||
SYS_SETOUT(98*2, 0, 0x0);
|
||||
SYS_FILL(0x4000, 98*40, 0); // clear screen
|
||||
activate_interrupts();
|
||||
while (1) {
|
||||
write_relative(x, y, M_MOVE, player_bitmap);
|
||||
write_relative(x, y+20, M_MOVE, player_bitmap);
|
||||
write_relative(x, y+40, M_MOVE|M_FLOP, player_bitmap);
|
||||
// write_relative(x, y+60, M_MOVE, player_bitmap);
|
||||
fast_vsync();
|
||||
x++;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
// define basic types for convenience
|
||||
typedef unsigned char byte; // 8-bit unsigned
|
||||
typedef signed char sbyte; // 8-bit signed
|
||||
typedef unsigned short word; // 16-bit signed
|
||||
typedef enum { false, true } bool; // boolean
|
||||
|
||||
/// MEMORY MAPS
|
||||
|
||||
typedef struct t_TIA {
|
||||
byte _00;
|
||||
byte VBLANK; // input port control
|
||||
byte _02_07[6];
|
||||
byte INPT0; // PADDLE CONTROL INPUT 0 WO
|
||||
byte INPT1; // PADDLE CONTROL INPUT 1 WO
|
||||
byte INPT2; // PADDLE CONTROL INPUT 2 WO
|
||||
byte INPT3; // PADDLE CONTROL INPUT 3 WO
|
||||
byte INPT4; // PLAYER 0 FIRE BUTTON INPUT WO
|
||||
byte INPT5; // PLAYER 1 FIRE BUTTON INPUT WO
|
||||
byte _0e_14[7];
|
||||
byte AUDC0; // AUDIO CONTROL CHANNEL 0 WO
|
||||
byte AUDC1; // AUDIO CONTROL CHANNEL 1 WO
|
||||
byte AUDF0; // AUDIO FREQUENCY CHANNEL 0 WO
|
||||
byte AUDF1; // AUDIO FREQUENCY CHANNEL 1 WO
|
||||
byte AUDV0; // AUDIO VOLUME CHANNEL 0 WO
|
||||
byte AUDV1; // AUDIO VOLUME CHANNEL 1 WO
|
||||
} t_TIA;
|
||||
|
||||
typedef struct t_MARIA {
|
||||
byte BACKGRND ;// X '20' BACKGROUND COLOR R/W
|
||||
byte P0C1 ;// X '21' PALETTE 0 - COLOR 1 R/W
|
||||
byte P0C2 ;// X '22' - COLOR 2 R/W
|
||||
byte P0C3 ;// X '23' - COLOR 3 R/W
|
||||
byte WSYNC ;// X '24' WAIT FOR SYNC STROBE
|
||||
byte P1C1 ;// X '25' PALETTE 1 - COLOR 1 R/W
|
||||
byte P1C2 ;// X '26' - COLOR 2 R/W
|
||||
byte P1C3 ;// X '27' - COLOR 3 R/W
|
||||
byte MSTAT ;// X '28' MARIA STATUS RO
|
||||
byte P2C1 ;// X '29' PALETTE 2 - COLOR 1 R/W
|
||||
byte P2C2 ;// X '2A' - COLOR 2 R/W
|
||||
byte P2C3 ;// X '2B' - COLOR 3 R/W
|
||||
byte DPPH ;// X '2C' DISPLAY LIST LIST POINT HIGH WO
|
||||
byte P3C1 ;// X '2D' PALETTE 3 - COLOR 1 R/W
|
||||
byte P3C2 ;// X '2E' - COLOR 2 R/W
|
||||
byte P3C3 ;// X '2F' - COLOR 3 R/W
|
||||
byte DPPL ;// X '30' DISPLAY LIST LIST POINT LOW WO
|
||||
byte P4C1 ;// X '31' PALETTE 4 - COLOR 1 R/W
|
||||
byte P4C2 ;// X '32' - COLOR 2 R/W
|
||||
byte P4C3 ;// X '33' - COLOR 3 R/W
|
||||
byte CHARBASE ;// X '34' CHARACTER BASE ADDRESS WO
|
||||
byte P5C1 ;// X '35' PALETTE 5 - COLOR 1 R/W
|
||||
byte P5C2 ;// X '36' - COLOR 2 R/W
|
||||
byte P5C3 ;// X '37' - COLOR 3 R/W
|
||||
byte OFFSET ;// X '38' FOR FUTURE EXPANSION -STORE ZERO HERE R/W
|
||||
byte P6C1 ;// X '39' PALETTE 6 - COLOR 1 R/W
|
||||
byte P6C2 ;// X '3A' - COLOR 2 R/W
|
||||
byte P6C3 ;// X '3B' - COLOR 3 R/W
|
||||
byte CTRL ;// X '3C' MARIA CONTROL REGISTER WO
|
||||
byte P7C1 ;// X '3D' PALETTE 7 - COLOR 1 R/W
|
||||
byte P7C2 ;// X '3E' - COLOR 2 R/W
|
||||
byte P7C3 ;// X '3F' - COLOR 3 R/W
|
||||
} t_MARIA;
|
||||
|
||||
typedef struct t_P6532 {
|
||||
byte SWCHA; // P0,P1 JOYSTICK DIRECTIONAL INPUT R/W
|
||||
byte CTLSWA; // CONSOLE SWITCHES RO
|
||||
byte SWCHB; // I/O CONTROL FOR SWCHA R/W
|
||||
byte CTLSWB; // I/O CONTROL FOR SWCHB R/W
|
||||
} t_P6532;
|
||||
|
||||
typedef struct DLLEntry {
|
||||
byte offset_flags;
|
||||
/*
|
||||
unsigned int offset:4;
|
||||
unsigned int _unused:1;
|
||||
unsigned int h8:1;
|
||||
unsigned int h16:1;
|
||||
unsigned int dli:1;
|
||||
*/
|
||||
byte dl_hi;
|
||||
byte dl_lo;
|
||||
} DLLEntry;
|
||||
|
||||
typedef struct DL4Entry {
|
||||
byte data_lo;
|
||||
byte width_pal;
|
||||
/*
|
||||
unsigned int width:5;
|
||||
unsigned int palette:3;
|
||||
*/
|
||||
byte data_hi;
|
||||
byte xpos;
|
||||
} DL4Entry;
|
||||
|
||||
typedef struct DL5Entry {
|
||||
byte data_lo;
|
||||
byte flags;
|
||||
byte data_hi;
|
||||
byte width_pal;
|
||||
/*
|
||||
unsigned int width:5;
|
||||
unsigned int palette:3;
|
||||
*/
|
||||
byte xpos;
|
||||
} DL5Entry;
|
||||
|
||||
/// CONSTANTS
|
||||
|
||||
#define DLL_DLI 0x80 // Display List Interrupt flag
|
||||
#define DLL_H16 0x40 // Holey DMA 4k flag
|
||||
#define DLL_H8 0x20 // Holey DMA 2k flag
|
||||
|
||||
#define DL5_WM 0x80 // Write Mode
|
||||
#define DL5_DIRECT 0x40 // Direct Mode
|
||||
#define DL5_INDIRECT 0x60 // Indirect Mode
|
||||
|
||||
#define DL_WIDTH(x) (32-(x)) // for width_pal
|
||||
#define DL_PAL(x) ((x)<<5) // OR them together
|
||||
#define DL_WP(w,p) (DL_WIDTH(w)|DL_PAL(p))
|
||||
|
||||
#define CTRL_COLORKILL 0x80
|
||||
#define CTRL_DMA_ON 0x40
|
||||
#define CTRL_DMA_OFF 0x60
|
||||
#define CTRL_DBLBYTE 0x10
|
||||
#define CTRL_BLKBORDER 0x08
|
||||
#define CTRL_KANGAROO 0x04
|
||||
#define CTRL_160AB 0x00
|
||||
#define CTRL_320BD 0x02
|
||||
#define CTRL_320AC 0x03
|
||||
|
||||
#define MSTAT_VBLANK 0x80
|
||||
|
||||
/// GLOBALS
|
||||
|
||||
#define TIA (*((t_TIA*) 0x00))
|
||||
#define MARIA (*((t_MARIA*) 0x20))
|
||||
#define P6532 (*((t_P6532*) 0x280))
|
||||
|
||||
/// MACROS
|
||||
|
||||
#define STROBE(addr) __asm__ ("sta %w", addr)
|
||||
#define WSYNC() STROBE(0x24)
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
#include "atari7800.h"
|
||||
|
||||
void main() {
|
||||
byte y1 = 110;
|
||||
byte y2 = 10;
|
||||
byte i;
|
||||
while (1) {
|
||||
while ((MARIA.MSTAT & MSTAT_VBLANK) == 0) ;
|
||||
while ((MARIA.MSTAT & MSTAT_VBLANK) != 0) ;
|
||||
for (i=0; i<y1; i++) {
|
||||
WSYNC();
|
||||
}
|
||||
for (i=0; i<y2; i++) {
|
||||
MARIA.BACKGRND = P6532.SWCHA - i;
|
||||
WSYNC();
|
||||
}
|
||||
MARIA.BACKGRND = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,442 @@
|
|||
; Atari 7800 sprite sample
|
||||
; Written by Daniel Boris (dboris@home.com)
|
||||
;
|
||||
; Assemble with DASM
|
||||
;
|
||||
|
||||
processor 6502
|
||||
|
||||
; ************ Hardware Adresses ***************************
|
||||
|
||||
INPTCTRL equ $01 ;Input control
|
||||
AUDC0 equ $15 ;Audio Control Channel 0
|
||||
AUDC1 equ $16 ;Audio Control Channel 1
|
||||
AUDF0 equ $17 ;Audio Frequency Channel 0
|
||||
AUDF1 equ $18 ;Audio Frequency Channel 1
|
||||
AUDV0 equ $19 ;Audio Volume Channel 0
|
||||
AUDV1 equ $1A ;Audio Volume Channel 1
|
||||
INPT0 equ $08 ;Paddle Control Input 0
|
||||
INPT1 equ $09 ;Paddle Control Input 1
|
||||
INPT2 equ $0A ;Paddle Control Input 2
|
||||
INPT3 equ $0B ;Paddle Control Input 3
|
||||
INPT4 equ $0C ;Player 0 Fire Button Input
|
||||
INPT5 equ $0D ;Player 1 Fire Button Input
|
||||
|
||||
BACKGRND equ $20 ;Background Color
|
||||
P0C1 equ $21 ;Palette 0 - Color 1
|
||||
P0C2 equ $22 ;Palette 0 - Color 2
|
||||
P0C3 equ $23 ;Palette 0 - Color 3
|
||||
WSYNC equ $24 ;Wait For Sync
|
||||
P1C1 equ $25 ;Palette 1 - Color 1
|
||||
P1C2 equ $26 ;Palette 1 - Color 2
|
||||
P1C3 equ $27 ;Palette 1 - Color 3
|
||||
MSTAT equ $28 ;Maria Status
|
||||
P2C1 equ $29 ;Palette 2 - Color 1
|
||||
P2C2 equ $2A ;Palette 2 - Color 2
|
||||
P2C3 equ $2B ;Palette 2 - Color 3
|
||||
DPPH equ $2C ;Display List List Pointer High
|
||||
P3C1 equ $2D ;Palette 3 - Color 1
|
||||
P3C2 equ $2E ;Palette 3 - Color 2
|
||||
P3C3 equ $2F ;Palette 3 - Color 3
|
||||
DPPL equ $30 ;Display List List Pointer Low
|
||||
P4C1 equ $31 ;Palette 4 - Color 1
|
||||
P4C2 equ $32 ;Palette 4 - Color 2
|
||||
P4C3 equ $33 ;Palette 4 - Color 3
|
||||
CHARBASE equ $34 ;Character Base Address
|
||||
P5C1 equ $35 ;Palette 5 - Color 1
|
||||
P5C2 equ $36 ;Palette 5 - Color 2
|
||||
P5C3 equ $37 ;Palette 5 - Color 3
|
||||
OFFSET equ $38 ;Unused - Store zero here
|
||||
P6C1 equ $39 ;Palette 6 - Color 1
|
||||
P6C2 equ $3A ;Palette 6 - Color 2
|
||||
P6C3 equ $3B ;Palette 6 - Color 3
|
||||
CTRL equ $3C ;Maria Control Register
|
||||
P7C1 equ $3D ;Palette 7 - Color 1
|
||||
P7C2 equ $3E ;Palette 7 - Color 2
|
||||
P7C3 equ $3F ;Palette 7 - Color 3
|
||||
|
||||
SWCHA equ $280 ;P0, P1 Joystick Directional Input
|
||||
SWCHB equ $282 ;Console Switches
|
||||
CTLSWA equ $281 ;I/O Control for SCHWA
|
||||
CTLSWB equ $283 ;I/O Control for SCHWB
|
||||
|
||||
SEG.U data
|
||||
|
||||
|
||||
;******* Vairables ********************************
|
||||
|
||||
org $40
|
||||
|
||||
xpos ds.b 1 ;X Position of sprite
|
||||
ypos ds.b 1 ;Y Position of sprite
|
||||
temp ds.b 1
|
||||
dlpnt ds.w 1
|
||||
dlend ds.b 12 ;Index of end of each DL
|
||||
|
||||
|
||||
|
||||
|
||||
;**********************************************************
|
||||
|
||||
SEG code
|
||||
|
||||
org $4000 ;Start of code
|
||||
|
||||
START
|
||||
sei ;Disable interrupts
|
||||
cld ;Clear decimal mode
|
||||
|
||||
|
||||
;******** Atari recommended startup procedure
|
||||
|
||||
lda #$07
|
||||
sta INPTCTRL ;Lock into 7800 mode
|
||||
lda #$7F
|
||||
sta CTRL ;Disable DMA
|
||||
lda #$00
|
||||
sta OFFSET
|
||||
sta INPTCTRL
|
||||
ldx #$FF ;Reset stack pointer
|
||||
txs
|
||||
|
||||
;************** Clear zero page and hardware ******
|
||||
|
||||
ldx #$40
|
||||
lda #$00
|
||||
crloop1
|
||||
sta $00,x ;Clear zero page
|
||||
sta $100,x ;Clear page 1
|
||||
inx
|
||||
bne crloop1
|
||||
|
||||
ldy #$00 ;Clear Ram
|
||||
crloop2
|
||||
sta $1800,y
|
||||
sta $1900,y
|
||||
sta $1a00,y
|
||||
sta $1b00,y
|
||||
sta $1c00,y
|
||||
sta $1d00,y
|
||||
sta $1e00,y
|
||||
sta $1f00,y
|
||||
sta $2200,y
|
||||
sta $2300,y
|
||||
sta $2400,y
|
||||
sta $2500,y
|
||||
sta $2600,y
|
||||
sta $2700,y
|
||||
iny
|
||||
bne crloop2
|
||||
|
||||
ldx #$00
|
||||
crloop5 ;Clear 2100-213F
|
||||
sta $2100,x
|
||||
inx
|
||||
cpx #$40
|
||||
bne crloop5
|
||||
|
||||
;************* Build DLL *******************
|
||||
|
||||
; 20 blank lines
|
||||
|
||||
ldx #$00
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21 ;$2100 = blank DL
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$44 ;4 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
|
||||
; 192 mode lines divided into 12 regions
|
||||
|
||||
ldy #$00
|
||||
DLLloop2
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda DLPOINTH,y
|
||||
sta $1800,x
|
||||
inx
|
||||
lda DLPOINTL,y
|
||||
sta $1800,x
|
||||
inx
|
||||
iny
|
||||
cpy #$0D ;12 DLL entries
|
||||
bne DLLloop2
|
||||
|
||||
|
||||
; 26 blank lines
|
||||
|
||||
lda #$4F ;16 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21 ;$2100 = blank DL
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$4A ;10 lines
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$21
|
||||
sta $1800,x
|
||||
inx
|
||||
lda #$00
|
||||
sta $1800,x
|
||||
|
||||
|
||||
;***************** Setup Maria Registers ****************
|
||||
|
||||
lda #$80
|
||||
sta BACKGRND ;background color
|
||||
lda #$18 ;DLL at $1800
|
||||
sta DPPH
|
||||
lda #$00
|
||||
sta DPPL
|
||||
lda #$18 ;Setup Palette 0
|
||||
sta P0C1
|
||||
lda #$38
|
||||
sta P0C2
|
||||
lda #$58
|
||||
sta P0C3
|
||||
lda #$43 ;Enable DMA
|
||||
sta CTRL
|
||||
lda #$00 ;Setup ports to read mode
|
||||
sta CTLSWA
|
||||
sta CTLSWB
|
||||
|
||||
lda #$40 ;Set initial X position of sprite
|
||||
sta xpos
|
||||
|
||||
mainloop
|
||||
lda MSTAT ;Wait for VBLANK
|
||||
and #$80
|
||||
beq mainloop
|
||||
|
||||
lda SWCHA ;Read stick
|
||||
and #$80 ;Pushed Right?
|
||||
bne skip1
|
||||
ldx xpos ;Move sprite to right
|
||||
inx
|
||||
stx xpos
|
||||
skip1
|
||||
lda SWCHA ;Read stick
|
||||
and #$40 ;Pushed Left?
|
||||
bne skip2
|
||||
ldx xpos ;Move sprite to left
|
||||
dex
|
||||
stx xpos
|
||||
skip2
|
||||
lda SWCHA ;Read stick
|
||||
and #$20 ;Pushed Down?
|
||||
bne skip3
|
||||
ldx ypos ;Move sprite down
|
||||
cpx #176
|
||||
beq skip3 ;Don't move if we are at the bottom
|
||||
inx
|
||||
stx ypos
|
||||
skip3
|
||||
lda SWCHA ;Read stick
|
||||
and #$10 ;Pushed Up?
|
||||
bne skip4
|
||||
ldx ypos ;Move sprite up
|
||||
beq skip4 ;Don't move if we are at the top
|
||||
dex
|
||||
stx ypos
|
||||
skip4
|
||||
|
||||
;********************** reset DL ends ******************
|
||||
|
||||
ldx #$0C
|
||||
lda #$00
|
||||
dlclearloop
|
||||
dex
|
||||
sta dlend,x
|
||||
bne dlclearloop
|
||||
|
||||
|
||||
;******************** build DL entries *********************
|
||||
|
||||
lda ypos ;Get Y position
|
||||
and #$F0
|
||||
lsr ;Divide by 16
|
||||
lsr
|
||||
lsr
|
||||
lsr
|
||||
tax
|
||||
lda DLPOINTL,x ;Get pointer to DL that this sprite starts in
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
|
||||
;Create DL entry for upper part of sprite
|
||||
|
||||
ldy dlend,x ;Get the index to the end of this DL
|
||||
lda #$00
|
||||
sta (dlpnt),y ;Low byte of data address
|
||||
iny
|
||||
lda #$40 ;Mode 320x1
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda ypos
|
||||
and #$0F
|
||||
ora #$a0
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$1F ;Palette 0, 1 byte wide
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda xpos ;Horizontal position
|
||||
sta (dlpnt),y
|
||||
sty dlend,x
|
||||
|
||||
lda ypos
|
||||
and #$0F ;See if sprite is entirely within this region
|
||||
beq doneDL ;branch if it is
|
||||
|
||||
;Create DL entry for lower part of sprite
|
||||
|
||||
inx ;Next region
|
||||
lda DLPOINTL,x ;Get pointer to next DL
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
ldy dlend,x ;Get the index to the end of this DL
|
||||
lda #$00
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$40 ;Mode 320x1
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda ypos
|
||||
and #$0F
|
||||
eor #$0F
|
||||
sta temp
|
||||
lda #$a0
|
||||
clc
|
||||
sbc temp
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda #$1F ;Palette 0, 1 byte wide
|
||||
sta (dlpnt),y
|
||||
iny
|
||||
lda xpos ;Horizontal position
|
||||
sta (dlpnt),y
|
||||
sty dlend,x
|
||||
doneDL
|
||||
|
||||
;************** add DL end entry on each DL *****************************
|
||||
|
||||
ldx #$0C
|
||||
dlendloop
|
||||
dex
|
||||
lda DLPOINTL,x
|
||||
sta dlpnt
|
||||
lda DLPOINTH,x
|
||||
sta dlpnt+1
|
||||
ldy dlend,x
|
||||
iny
|
||||
lda #$00
|
||||
sta (dlpnt),y
|
||||
txa
|
||||
bne dlendloop
|
||||
|
||||
vbloop
|
||||
lda MSTAT ;Wait for VBLANK to end
|
||||
and #$80
|
||||
bne vbloop
|
||||
; test WSYNC
|
||||
ldx #$04
|
||||
sta WSYNC
|
||||
stx BACKGRND
|
||||
dex
|
||||
sta WSYNC
|
||||
stx BACKGRND
|
||||
dex
|
||||
sta WSYNC
|
||||
stx BACKGRND
|
||||
dex
|
||||
sta WSYNC
|
||||
stx BACKGRND
|
||||
|
||||
jmp mainloop ;Loop
|
||||
|
||||
redraw
|
||||
|
||||
|
||||
NMI
|
||||
RTI
|
||||
|
||||
IRQ
|
||||
RTI
|
||||
|
||||
|
||||
;Pointers to the DLs
|
||||
|
||||
DLPOINTH
|
||||
.byte $22,$22,$22,$22,$23,$23,$23,$23,$24,$24,$24,$24
|
||||
DLPOINTL
|
||||
.byte $00,$40,$80,$C0,$00,$40,$80,$C0,$00,$40,$80,$C0
|
||||
|
||||
|
||||
|
||||
|
||||
;************** Graphic Data *****************************
|
||||
;set org and fill character
|
||||
org $a000,0
|
||||
.byte %00111100
|
||||
org $a100
|
||||
.byte %00111100
|
||||
org $a200
|
||||
.byte %01000010
|
||||
org $a300
|
||||
.byte %01000010
|
||||
org $a400
|
||||
.byte %10011001
|
||||
org $a500
|
||||
.byte %10011001
|
||||
org $a600
|
||||
.byte %10100101
|
||||
org $a700
|
||||
.byte %10100101
|
||||
org $a800
|
||||
.byte %10000001
|
||||
org $a900
|
||||
.byte %10000001
|
||||
org $aA00
|
||||
.byte %10100101
|
||||
org $aB00
|
||||
.byte %10100101
|
||||
org $aC00
|
||||
.byte %01000010
|
||||
org $aD00
|
||||
.byte %01000010
|
||||
org $aE00
|
||||
.byte %00111100
|
||||
org $aF00
|
||||
.byte %00111100
|
||||
|
||||
|
||||
;************** Cart reset vector **************************
|
||||
|
||||
org $fff8
|
||||
.byte $FF ;Region verification
|
||||
.byte $87 ;ROM start $4000
|
||||
.word #NMI
|
||||
.word #START
|
||||
.word #IRQ
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cv.h>
|
||||
|
@ -7,9 +7,8 @@
|
|||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#ifdef CV_SMS
|
||||
// for SMS
|
||||
//#link "fonts.s"
|
||||
#endif
|
||||
|
||||
#define XOFS 12 // sprite horiz. offset
|
||||
|
||||
|
@ -592,14 +591,18 @@ void play_scene() {
|
|||
}
|
||||
|
||||
void setup_graphics() {
|
||||
#ifndef CV_MSX
|
||||
cvu_memtovmemcpy(PATTERN, (void *)(font_bitmap_0 - '0'*8), 0x800);
|
||||
#endif
|
||||
cvu_memtovmemcpy(PATTERN+8*64, char_table, sizeof(char_table));
|
||||
cvu_memtovmemcpy(PATTERN+8*128, static_sprite_table, sizeof(static_sprite_table));
|
||||
|
||||
|
||||
#ifndef CV_MSX
|
||||
cvu_vmemset(COLOR, 0x30|BGCOL, 8); // set color for chars 0-63
|
||||
cvu_vmemset(COLOR+8, 0x0|BGCOL, 32-8); // set chars 63-255
|
||||
cvu_vmemset(COLOR+16, 0xb0|BGCOL, 1); // set chars 128-128+8
|
||||
|
||||
#endif
|
||||
|
||||
cvu_memtovmemcpy(SPRITE_PATTERNS, sprite_table, sizeof(sprite_table));
|
||||
flip_sprite_patterns(SPRITE_PATTERNS + 512, (const byte*)sprite_table, sizeof(sprite_table));
|
||||
flip_sprite_patterns(SPRITE_PATTERNS + 384, (const byte*)blimp_sprite_table, sizeof(blimp_sprite_table));
|
||||
|
|
|
@ -34,17 +34,17 @@ word getimageaddr(byte x, byte y) {
|
|||
return IMAGE + y*COLS + x;
|
||||
}
|
||||
|
||||
byte getchar(byte x, byte y) {
|
||||
byte getcharxy(byte x, byte y) {
|
||||
return cvu_vinb(getimageaddr(x,y));
|
||||
}
|
||||
|
||||
void putchar(byte x, byte y, byte attr) {
|
||||
void putcharxy(byte x, byte y, byte attr) {
|
||||
cvu_voutb(attr, getimageaddr(x,y));
|
||||
}
|
||||
|
||||
void putstring(byte x, byte y, const char* string) {
|
||||
void putstringxy(byte x, byte y, const char* string) {
|
||||
while (*string) {
|
||||
putchar(x++, y, CHAR(*string++));
|
||||
putcharxy(x++, y, CHAR(*string++));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ void draw_bcd_word(byte x, byte y, word bcd) {
|
|||
byte j;
|
||||
x += 3;
|
||||
for (j=0; j<4; j++) {
|
||||
putchar(x, y, CHAR('0'+(bcd&0xf)));
|
||||
putcharxy(x, y, CHAR('0'+(bcd&0xf)));
|
||||
x--;
|
||||
bcd >>= 4;
|
||||
}
|
||||
|
@ -123,3 +123,13 @@ void set_shifted_pattern(const byte* src, word dest, byte shift) {
|
|||
dest++;
|
||||
}
|
||||
}
|
||||
|
||||
void copy_default_character_set() {
|
||||
#ifdef CV_MSX
|
||||
static byte __at(0xf91f) CGPNT;
|
||||
static byte* __at(0xf920) CGADDR;
|
||||
cvu_memtovmemcpy(PATTERN, CGADDR, 256*8);
|
||||
#else
|
||||
cvu_memtovmemcpy(PATTERN, (void *)(font_bitmap_0 - '0'*8), 256*8);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -16,17 +16,24 @@
|
|||
#define SPRITE_PATTERNS ((const cv_vmemp)0x3800)
|
||||
#define SPRITES ((const cv_vmemp)0x3c00)
|
||||
|
||||
#ifndef COLS
|
||||
#define COLS 32
|
||||
#endif
|
||||
|
||||
#ifndef ROWS
|
||||
#define ROWS 24
|
||||
#endif
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
|
||||
#ifndef CV_SMS
|
||||
#ifdef CV_CV
|
||||
uintptr_t __at(0x6a) font_bitmap_a;
|
||||
uintptr_t __at(0x6c) font_bitmap_0;
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef CV_SMS
|
||||
extern char font_bitmap_a[];
|
||||
extern char font_bitmap_0[];
|
||||
#endif
|
||||
|
@ -34,8 +41,9 @@ extern char font_bitmap_0[];
|
|||
#define COLOR_FGBG(fg,bg) (((fg)<<4)|(bg))
|
||||
#define COLOR_FG(fg) (((fg)<<4))
|
||||
|
||||
#define LOCHAR 0x20
|
||||
#define HICHAR 0xff
|
||||
#ifndef LOCHAR
|
||||
#define LOCHAR 0x0
|
||||
#endif
|
||||
|
||||
#define CHAR(ch) (ch-LOCHAR)
|
||||
|
||||
|
@ -53,9 +61,9 @@ extern char cursor_y;
|
|||
extern void clrscr();
|
||||
|
||||
extern word getimageaddr(byte x, byte y);
|
||||
extern byte getchar(byte x, byte y);
|
||||
extern void putchar(byte x, byte y, byte attr);
|
||||
extern void putstring(byte x, byte y, const char* string);
|
||||
extern byte getcharxy(byte x, byte y);
|
||||
extern void putcharxy(byte x, byte y, byte attr);
|
||||
extern void putstringxy(byte x, byte y, const char* string);
|
||||
extern void delay(byte i);
|
||||
extern byte rndint(byte a, byte b);
|
||||
|
||||
|
@ -69,4 +77,6 @@ extern word bcd_add(word a, word b);
|
|||
extern void vdp_setup();
|
||||
extern void set_shifted_pattern(const byte* src, word dest, byte shift);
|
||||
|
||||
extern void copy_default_character_set();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,18 +5,15 @@
|
|||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#define IMAGE ((const cv_vmemp)0x1c00)
|
||||
|
||||
#define COLS 40
|
||||
#define ROWS 24
|
||||
|
||||
uintptr_t __at(0x6a) font_bitmap_a;
|
||||
uintptr_t __at(0x6c) font_bitmap_0;
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
void setup_40_column_font() {
|
||||
cv_set_image_table(IMAGE);
|
||||
cvu_memtovmemcpy(0x1800, (void *)(font_bitmap_0 - 0x30*8), 2048);
|
||||
cv_set_character_pattern_t(0x1800);
|
||||
copy_default_character_set();
|
||||
cv_set_character_pattern_t(PATTERN);
|
||||
cv_set_screen_mode(CV_SCREENMODE_TEXT);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,16 +5,7 @@
|
|||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#define PATTERN ((const cv_vmemp)0x0)
|
||||
#define COLOR ((const cv_vmemp)0x2000)
|
||||
#define IMAGE ((const cv_vmemp)0x1800)
|
||||
|
||||
#define COLS 32
|
||||
#define ROWS 24
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
#include "common.h"
|
||||
|
||||
void setup_mode2() {
|
||||
cvu_vmemset(0, 0, 0x4000);
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#define PATTERN 0x0000 // $0000 - $17ff
|
||||
#define IMAGE 0x1800 // $1800 - $1aff
|
||||
#define SPRITES 0x1b00 // not used
|
||||
#define COLOR 0x2000 // $2000 - $37ff
|
||||
#include "common.h"
|
||||
|
||||
/* link in MODE 2 bitmap data */
|
||||
|
||||
|
|
|
@ -5,10 +5,7 @@
|
|||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#define PATTERN 0x0000 // $0000 - $17ff
|
||||
#define IMAGE 0x1800 // $1800 - $1aff
|
||||
#define SPRITES 0x1b00 // not used
|
||||
#define COLOR 0x2000 // $2000 - $37ff
|
||||
#include "common.h"
|
||||
|
||||
/* link in MODE 2 bitmap data */
|
||||
|
||||
|
|
|
@ -1,17 +1,12 @@
|
|||
|
||||
/*
|
||||
64x48 multicolor mode
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#define PATTERN ((const cv_vmemp)0x0000)
|
||||
#define IMAGE ((const cv_vmemp)0x1800)
|
||||
|
||||
#define COLS 64
|
||||
#define ROWS 48
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef signed char sbyte;
|
||||
typedef unsigned short word;
|
||||
#include "common.h"
|
||||
|
||||
void multicolor_fullscreen_image_table(word ofs) {
|
||||
byte x,y;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cv.h>
|
||||
|
@ -10,9 +10,8 @@
|
|||
#include "stars.h"
|
||||
//#link "stars.c"
|
||||
|
||||
#ifdef CV_SMS
|
||||
// for SMS
|
||||
//#link "fonts.s"
|
||||
#endif
|
||||
|
||||
#define NSPRITES 16
|
||||
#define NMISSILES 8
|
||||
|
@ -178,8 +177,8 @@ void copy_sprites() {
|
|||
|
||||
void add_score(word bcd) {
|
||||
player_score = bcd_add(player_score, bcd);
|
||||
draw_bcd_word(0, 1, player_score);
|
||||
putchar(4, 1, CHAR('0'));
|
||||
draw_bcd_word(0, 0, player_score);
|
||||
putcharxy(4, 0, CHAR('0'));
|
||||
}
|
||||
|
||||
void clrobjs() {
|
||||
|
@ -593,7 +592,7 @@ void play_round() {
|
|||
byte end_timer = 255;
|
||||
player_score = 0;
|
||||
add_score(0);
|
||||
putstring(0, 0, "PLAYER 1");
|
||||
//putstringxy(0, 0, "PLAYER 1");
|
||||
setup_formation();
|
||||
clrobjs();
|
||||
formation_direction = 1;
|
||||
|
@ -640,7 +639,7 @@ PATTERN TABLE:
|
|||
|
||||
void setup_graphics() {
|
||||
byte i;
|
||||
cvu_memtovmemcpy(PATTERN, (void *)(font_bitmap_0 - 16*8), 96*8);
|
||||
copy_default_character_set();
|
||||
cvu_memtovmemcpy(SPRITE_PATTERNS, sprite_table, sizeof(sprite_table));
|
||||
cvu_vmemset(COLOR, COLOR_SCORE<<4, 8); // set color for chars 0-63
|
||||
cvu_vmemset(COLOR+8, COLOR_FORMATION<<4, 32-8); // set chars 63-255
|
||||
|
|
|
@ -7,9 +7,8 @@
|
|||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
#ifdef CV_SMS
|
||||
// for SMS
|
||||
//#link "fonts.s"
|
||||
#endif
|
||||
|
||||
////////// GAME DATA
|
||||
|
||||
|
@ -41,26 +40,26 @@ const char BOX_CHARS[8] = {
|
|||
|
||||
void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) {
|
||||
byte x1 = x;
|
||||
putchar(x, y, chars[2]);
|
||||
putchar(x2, y, chars[3]);
|
||||
putchar(x, y2, chars[0]);
|
||||
putchar(x2, y2, chars[1]);
|
||||
putcharxy(x, y, chars[2]);
|
||||
putcharxy(x2, y, chars[3]);
|
||||
putcharxy(x, y2, chars[0]);
|
||||
putcharxy(x2, y2, chars[1]);
|
||||
while (++x < x2) {
|
||||
putchar(x, y, chars[5]);
|
||||
putchar(x, y2, chars[4]);
|
||||
putcharxy(x, y, chars[5]);
|
||||
putcharxy(x, y2, chars[4]);
|
||||
}
|
||||
while (++y < y2) {
|
||||
putchar(x1, y, chars[6]);
|
||||
putchar(x2, y, chars[7]);
|
||||
putcharxy(x1, y, chars[6]);
|
||||
putcharxy(x2, y, chars[7]);
|
||||
}
|
||||
}
|
||||
|
||||
void draw_playfield() {
|
||||
draw_box(0,1,COLS-1,ROWS-1,BOX_CHARS);
|
||||
putstring(0,0,"Plyr1:");
|
||||
putstring(20,0,"Plyr2:");
|
||||
putchar(7,0,CHAR(players[0].score+'0'));
|
||||
putchar(27,0,CHAR(players[1].score+'0'));
|
||||
putstringxy(0,0,"Plyr1:");
|
||||
putstringxy(20,0,"Plyr2:");
|
||||
putcharxy(7,0,CHAR(players[0].score+'0'));
|
||||
putcharxy(27,0,CHAR(players[1].score+'0'));
|
||||
}
|
||||
|
||||
typedef enum { D_RIGHT, D_DOWN, D_LEFT, D_UP } dir_t;
|
||||
|
@ -86,14 +85,14 @@ void reset_players() {
|
|||
}
|
||||
|
||||
void draw_player(Player* p) {
|
||||
putchar(p->x, p->y, p->head_attr);
|
||||
putcharxy(p->x, p->y, p->head_attr);
|
||||
}
|
||||
|
||||
void move_player(Player* p) {
|
||||
putchar(p->x, p->y, p->tail_attr);
|
||||
putcharxy(p->x, p->y, p->tail_attr);
|
||||
p->x += DIR_X[p->dir];
|
||||
p->y += DIR_Y[p->dir];
|
||||
if (getchar(p->x, p->y) != CHAR(' '))
|
||||
if (getcharxy(p->x, p->y) != CHAR(' '))
|
||||
p->collided = 1;
|
||||
draw_player(p);
|
||||
}
|
||||
|
@ -118,7 +117,7 @@ byte ai_try_dir(Player* p, dir_t dir, byte shift) {
|
|||
dir &= 3;
|
||||
x = p->x + (DIR_X[dir] << shift);
|
||||
y = p->y + (DIR_Y[dir] << shift);
|
||||
if (x < 29 && y < 27 && getchar(x, y) == CHAR(' ')) {
|
||||
if (x < 29 && y < 27 && getcharxy(x, y) == CHAR(' ')) {
|
||||
p->dir = dir;
|
||||
return 1;
|
||||
} else {
|
||||
|
@ -179,9 +178,9 @@ void declare_winner(byte winner) {
|
|||
draw_box(i,i,COLS-1-i,ROWS-1-i,BOX_CHARS);
|
||||
delay(1);
|
||||
}
|
||||
putstring(12,10,"WINNER:");
|
||||
putstring(12,13,"PLAYER ");
|
||||
putchar(12+7, 13, CHAR('1')+winner);
|
||||
putstringxy(12,10,"WINNER:");
|
||||
putstringxy(12,13,"PLAYER ");
|
||||
putcharxy(12+7, 13, CHAR('1')+winner);
|
||||
delay(75);
|
||||
gameover = 1;
|
||||
}
|
||||
|
@ -219,8 +218,8 @@ void play_game() {
|
|||
}
|
||||
|
||||
void setup_32_column_font() {
|
||||
copy_default_character_set();
|
||||
cv_set_colors(0, CV_COLOR_BLUE);
|
||||
cvu_memtovmemcpy(PATTERN, (void *)(font_bitmap_0 - 16*8), 96*8);
|
||||
cvu_vmemset(COLOR, COLOR_FG(CV_COLOR_YELLOW), 8); // set color for chars 0-63
|
||||
cvu_vmemset(COLOR+8, COLOR_FG(CV_COLOR_WHITE), 32-8); // set chars 63-255
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ byte starfield_get_tile_xy(byte x, byte y) {
|
|||
}
|
||||
|
||||
void starfield_setup() {
|
||||
// clear star patterns
|
||||
cvu_vmemset(PATTERN+starfield_base_char*8, 0, 16*8);
|
||||
for (byte x=0; x<32; x++) {
|
||||
for (byte y=0; y<28; y++) {
|
||||
putchar(x, y, starfield_get_tile_xy(x, y));
|
||||
putcharxy(x, y, starfield_get_tile_xy(x, y));
|
||||
}
|
||||
cvu_voutb(COLOR_FG(CV_COLOR_WHITE),
|
||||
COLOR+((starfield_base_char+x)>>3));
|
||||
|
|
|
@ -2,18 +2,15 @@
|
|||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#define PATTERN 0x0000
|
||||
#define IMAGE 0x0800
|
||||
|
||||
uintptr_t __at(0x6a) font_bitmap_a;
|
||||
uintptr_t __at(0x6c) font_bitmap_0;
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
void setup_text_mode() {
|
||||
cv_set_screen_mode(CV_SCREENMODE_TEXT);
|
||||
cv_set_image_table(IMAGE);
|
||||
cv_set_character_pattern_t(PATTERN);
|
||||
cvu_vmemset(0, 0, 0x4000);
|
||||
cvu_memtovmemcpy(PATTERN, (void *)(font_bitmap_0 - '0'*8), 256*8);
|
||||
copy_default_character_set();
|
||||
}
|
||||
|
||||
void show_text() {
|
||||
|
|
|
@ -2,14 +2,8 @@
|
|||
#include <cv.h>
|
||||
#include <cvu.h>
|
||||
|
||||
#define PATTERN 0x0000 // 256*8 = 2048 bytes
|
||||
#define IMAGE 0x0800 // 32*24 = 768 bytes
|
||||
#define COLOR 0x0b00 // 32 bytes
|
||||
#define SPRITE_PATTERNS 0x3800 // 32*32 = 1024 bytes
|
||||
#define SPRITES 0x3c00 // 4*32 = 128 bytes
|
||||
|
||||
uintptr_t __at(0x6a) font_bitmap_a;
|
||||
uintptr_t __at(0x6c) font_bitmap_0;
|
||||
#include "common.h"
|
||||
//#link "common.c"
|
||||
|
||||
void setup_32_column_font() {
|
||||
cv_set_screen_mode(CV_SCREENMODE_STANDARD);
|
||||
|
@ -19,7 +13,7 @@ void setup_32_column_font() {
|
|||
cv_set_sprite_pattern_table(SPRITE_PATTERNS);
|
||||
cv_set_sprite_attribute_table(SPRITES);
|
||||
cvu_vmemset(0, 0, 0x4000);
|
||||
cvu_memtovmemcpy(PATTERN, (void *)(font_bitmap_0 - '0'*8), 2048);
|
||||
copy_default_character_set();
|
||||
cvu_vmemset(COLOR, 0x36, 8); // set color for chars 0-63
|
||||
cvu_vmemset(COLOR+8, 0x06, 32-8); // set chars 63-255
|
||||
}
|
||||
|
@ -35,6 +29,6 @@ void main() {
|
|||
setup_32_column_font();
|
||||
show_text();
|
||||
while (1) {
|
||||
cvu_vmemset(COLOR, i++, 8); // set color for chars 0-63
|
||||
cvu_vmemset(COLOR+8, i++, 4); // set color for chars 64-95
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
coleco
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
#include "msxbios.h"
|
||||
//#link "msxbios.c"
|
||||
|
||||
const char* STR = "HELLO WORLD!";
|
||||
|
||||
void main() {
|
||||
int i;
|
||||
FORCLR = COLOR_WHITE;
|
||||
BAKCLR = COLOR_BLUE;
|
||||
BDRCLR = COLOR_GREEN;
|
||||
CHGCLR();
|
||||
DISSCR();
|
||||
ENASCR();
|
||||
POSIT(11+11*256);
|
||||
CHPUT('C');
|
||||
WRTVDP(0x070e); // reg 7, color e
|
||||
WRTVRM(0x1962, '1');
|
||||
SETRD();
|
||||
SETWRT();
|
||||
FILVRM(0x19a2, 33*8, '2');
|
||||
LDIRVM(0x18c2, STR, 12);
|
||||
i = CHGET();
|
||||
CHPUT(i);
|
||||
CLS();
|
||||
CHPUT('.');
|
||||
CHPUT(i);
|
||||
while (1);
|
||||
}
|
|
@ -0,0 +1,367 @@
|
|||
/* eliza.c
|
||||
* ys
|
||||
* original code by Weizenbaum, 1966
|
||||
* this rendition based on Charles Hayden's Java implementation from http://chayden.net/eliza/Eliza.html
|
||||
*
|
||||
* Note: There are certainly far more optimal and elegant ways to code this... we kept this
|
||||
* structure to be faithful to the original. -scaz
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NUMKEYWORDS 37
|
||||
#define MAXLINELEN 40
|
||||
#define NUMSWAPS 14
|
||||
|
||||
#include "msxbios.h"
|
||||
//#link "msxbios.c"
|
||||
|
||||
|
||||
const char *keywords[]= {
|
||||
"CAN YOU","CAN I","YOU ARE","YOURE","I DONT","I FEEL",
|
||||
"WHY DONT YOU","WHY CANT I","ARE YOU","I CANT","I AM","IM ",
|
||||
"YOU ","I WANT","WHAT","HOW","WHO","WHERE",
|
||||
"WHEN","WHY",
|
||||
"NAME","CAUSE","SORRY","DREAM","HELLO","HI ","MAYBE",
|
||||
" NO","YOUR","ALWAYS","THINK","ALIKE","YES","FRIEND",
|
||||
"COMPUTER","CAR","NOKEYFOUND"};
|
||||
|
||||
const char *SWAPS[NUMSWAPS][2] = {
|
||||
{"ARE","AM"},
|
||||
{"WERE", "WAS"},
|
||||
{"YOU","I"},
|
||||
{"YOUR", "MY"},
|
||||
{"IVE", "YOU'VE"},
|
||||
{"IM", "YOU'RE"},
|
||||
{"YOU", "ME"},
|
||||
{"ME", "YOU"},
|
||||
{"AM","ARE"},
|
||||
{"WAS", "WERE"},
|
||||
{"I","YOU"},
|
||||
{"MY", "YOUR"},
|
||||
{"YOUVE", "I'VE"},
|
||||
{"YOURE", "I'M"}
|
||||
};
|
||||
|
||||
int ResponsesPerKeyword[NUMKEYWORDS]= {
|
||||
3,2,4,4,4,3,
|
||||
3,2,3,3,4,4,
|
||||
3,5,9,9,9,9,
|
||||
9,9,
|
||||
2,4,4,4,1,1,5,
|
||||
5,2,4,3,7,3,6,
|
||||
7,5,6};
|
||||
|
||||
const char *responses[NUMKEYWORDS][9] = {
|
||||
{ "DON'T YOU BELIEVE THAT I CAN*",
|
||||
"PERHAPS YOU WOULD LIKE TO BE ABLE TO*",
|
||||
"YOU WANT ME TO BE ABLE TO*"},
|
||||
{ "PERHAPS YOU DON'T WANT TO*",
|
||||
"DO YOU WANT TO BE ABLE TO*"},
|
||||
{ "WHAT MAKES YOU THINK I AM*",
|
||||
"DOES IT PLEASE YOU TO BELIEVE I AM*",
|
||||
"PERHAPS YOU WOULD LIKE TO BE*",
|
||||
"DO YOU SOMETIMES WISH YOU WERE*"},
|
||||
{ "WHAT MAKES YOU THINK I AM*",
|
||||
"DOES IT PLEASE YOU TO BELIEVE I AM*",
|
||||
"PERHAPS YOU WOULD LIKE TO BE*",
|
||||
"DO YOU SOMETIMES WISH YOU WERE*"},
|
||||
{ "DON'T YOU REALLY*",
|
||||
"WHY DON'T YOU*",
|
||||
"DO YOU WISH TO BE ABLE TO*",
|
||||
"DOES THAT TROUBLE YOU?"},
|
||||
{ "TELL ME MORE ABOUT SUCH FEELINGS.",
|
||||
"DO YOU OFTEN FEEL*",
|
||||
"DO YOU ENJOY FEELING*"},
|
||||
{ "DO YOU REALLY BELIEVE I DON'T*",
|
||||
"PERHAPS IN GOOD TIME I WILL*",
|
||||
"DO YOU WANT ME TO*"},
|
||||
{ "DO YOU THINK YOU SHOULD BE ABLE TO*",
|
||||
"WHY CAN'T YOU*"},
|
||||
{ "WHY ARE YOU INTERESTED IN WHETHER OR NOT I AM*",
|
||||
"WOULD YOU PREFER IF I WERE NOT*",
|
||||
"PERHAPS IN YOUR FANTASIES I AM*"},
|
||||
{ "HOW DO YOU KNOW YOU CAN'T*",
|
||||
"HAVE YOU TRIED?",
|
||||
"PERHAPS YOU CAN NOW*"},
|
||||
{ "DID YOU COME TO ME BECAUSE YOU ARE*",
|
||||
"HOW LONG HAVE YOU BEEN*",
|
||||
"DO YOU BELIEVE IT IS NORMAL TO BE*",
|
||||
"DO YOU ENJOY BEING*"},
|
||||
{ "DID YOU COME TO ME BECAUSE YOU ARE*",
|
||||
"HOW LONG HAVE YOU BEEN*",
|
||||
"DO YOU BELIEVE IT IS NORMAL TO BE*",
|
||||
"DO YOU ENJOY BEING*"},
|
||||
{ "WE WERE DISCUSSING YOU-- NOT ME.",
|
||||
"OH, I*",
|
||||
"YOU'RE NOT REALLY TALKING ABOUT ME, ARE YOU?"},
|
||||
{ "WHAT WOULD IT MEAN TO YOU IF YOU GOT*",
|
||||
"WHY DO YOU WANT*",
|
||||
"SUPPOSE YOU SOON GOT*",
|
||||
"WHAT IF YOU NEVER GOT*",
|
||||
"I SOMETIMES ALSO WANT*"},
|
||||
{ "WHY DO YOU ASK?",
|
||||
"DOES THAT QUESTION INTEREST YOU?",
|
||||
"WHAT ANSWER WOULD PLEASE YOU THE MOST?",
|
||||
"WHAT DO YOU THINK?",
|
||||
"ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
|
||||
"WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
|
||||
"HAVE YOU ASKED ANYONE ELSE?",
|
||||
"HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
|
||||
"WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
|
||||
{ "WHY DO YOU ASK?",
|
||||
"DOES THAT QUESTION INTEREST YOU?",
|
||||
"WHAT ANSWER WOULD PLEASE YOU THE MOST?",
|
||||
"WHAT DO YOU THINK?",
|
||||
"ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
|
||||
"WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
|
||||
"HAVE YOU ASKED ANYONE ELSE?",
|
||||
"HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
|
||||
"WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
|
||||
{ "WHY DO YOU ASK?",
|
||||
"DOES THAT QUESTION INTEREST YOU?",
|
||||
"WHAT ANSWER WOULD PLEASE YOU THE MOST?",
|
||||
"WHAT DO YOU THINK?",
|
||||
"ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
|
||||
"WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
|
||||
"HAVE YOU ASKED ANYONE ELSE?",
|
||||
"HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
|
||||
"WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
|
||||
{ "WHY DO YOU ASK?",
|
||||
"DOES THAT QUESTION INTEREST YOU?",
|
||||
"WHAT ANSWER WOULD PLEASE YOU THE MOST?",
|
||||
"WHAT DO YOU THINK?",
|
||||
"ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
|
||||
"WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
|
||||
"HAVE YOU ASKED ANYONE ELSE?",
|
||||
"HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
|
||||
"WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
|
||||
{ "WHY DO YOU ASK?",
|
||||
"DOES THAT QUESTION INTEREST YOU?",
|
||||
"WHAT ANSWER WOULD PLEASE YOU THE MOST?",
|
||||
"WHAT DO YOU THINK?",
|
||||
"ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
|
||||
"WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
|
||||
"HAVE YOU ASKED ANYONE ELSE?",
|
||||
"HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
|
||||
"WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
|
||||
{ "WHY DO YOU ASK?",
|
||||
"DOES THAT QUESTION INTEREST YOU?",
|
||||
"WHAT ANSWER WOULD PLEASE YOU THE MOST?",
|
||||
"WHAT DO YOU THINK?",
|
||||
"ARE SUCH QUESTIONS ON YOUR MIND OFTEN?",
|
||||
"WHAT IS IT THAT YOU REALLY WANT TO KNOW?",
|
||||
"HAVE YOU ASKED ANYONE ELSE?",
|
||||
"HAVE YOU ASKED SUCH QUESTIONS BEFORE?",
|
||||
"WHAT ELSE COMES TO MIND WHEN YOU ASK THAT?"},
|
||||
{ "NAMES DON'T INTEREST ME.",
|
||||
"I DON'T CARE ABOUT NAMES-- PLEASE GO ON."},
|
||||
{ "IS THAT THE REAL REASON?",
|
||||
"DON'T ANY OTHER REASONS COME TO MIND?",
|
||||
"DOES THAT REASON EXPLAIN ANY THING ELSE?",
|
||||
"WHAT OTHER REASONS MIGHT THERE BE?"},
|
||||
{ "PLEASE DON'T APOLOGIZE.",
|
||||
"APOLOGIES ARE NOT NECESSARY.",
|
||||
"WHAT FEELINGS DO YOU HAVE WHEN YOU APOLOGIZE?",
|
||||
"DON'T BE SO DEFENSIVE!"},
|
||||
{ "WHAT DOES THAT DREAM SUGGEST TO YOU?",
|
||||
"DO YOU DREAM OFTEN?",
|
||||
"WHAT PERSONS APPEAR IN YOUR DREAMS?",
|
||||
"ARE YOU DISTURBED BY YOUR DREAMS?"},
|
||||
{ "HOW DO YOU DO--PLEASE STATE YOUR PROBLEM."},
|
||||
{ "HOW DO YOU DO--PLEASE STATE YOUR PROBLEM."},
|
||||
{ "YOU DON'T SEEM QUITE CERTAIN.",
|
||||
"WHY THE UNCERTAIN TONE?",
|
||||
"CAN'T YOU BE MORE POSITIVE?",
|
||||
"YOU AREN'T SURE?",
|
||||
"DON'T YOU KNOW?"},
|
||||
{ "ARE YOU SAYING NO JUST TO BE NEGATIVE?",
|
||||
"YOU ARE BEING A BIT NEGATIVE.",
|
||||
"WHY NOT?",
|
||||
"ARE YOU SURE?",
|
||||
"WHY NO?"},
|
||||
{ "WHY ARE YOU CONCERNED ABOUT MY*",
|
||||
"WHAT ABOUT YOUR OWN*"},
|
||||
{ "CAN YOU THINK OF A SPECIFIC EXAMPLE?",
|
||||
"WHEN?",
|
||||
"WHAT ARE YOU THINKING OF?",
|
||||
"REALLY, ALWAYS?"},
|
||||
{ "DO YOU REALLY THINK SO?",
|
||||
"BUT YOU ARE NOT SURE YOU*",
|
||||
"DO YOU DOUBT YOU*"},
|
||||
{ "IN WHAT WAY?",
|
||||
"WHAT RESEMBLANCE DO YOU SEE?",
|
||||
"WHAT DOES THE SIMILARITY SUGGEST TO YOU?",
|
||||
"WHAT OTHER CONNECTIONS DO YOU SEE?",
|
||||
"COULD THERE REALLY BE SOME CONNECTION?",
|
||||
"HOW?"},
|
||||
{ "YOU SEEM QUITE POSITIVE.",
|
||||
"ARE YOU SURE?",
|
||||
"I SEE.",
|
||||
"I UNDERSTAND."},
|
||||
{ "WHY DO YOU BRING UP THE TOPIC OF FRIENDS?",
|
||||
"DO YOUR FRIENDS WORRY YOU?",
|
||||
"DO YOUR FRIENDS PICK ON YOU?",
|
||||
"ARE YOU SURE YOU HAVE ANY FRIENDS?",
|
||||
"DO YOU IMPOSE ON YOUR FRIENDS?",
|
||||
"PERHAPS YOUR LOVE FOR FRIENDS WORRIES YOU?"},
|
||||
{ "DO COMPUTERS WORRY YOU?",
|
||||
"ARE YOU TALKING ABOUT ME IN PARTICULAR?",
|
||||
"ARE YOU FRIGHTENED BY MACHINES?",
|
||||
"WHY DO YOU MENTION COMPUTERS?",
|
||||
"WHAT DO YOU THINK MACHINES HAVE TO DO WITH YOUR PROBLEM?",
|
||||
"DON'T YOU THINK COMPUTERS CAN HELP PEOPLE?",
|
||||
"WHAT IS IT ABOUT MACHINES THAT WORRIES YOU?"},
|
||||
{ "OH, DO YOU LIKE CARS?",
|
||||
"MY FAVORITE CAR IS A LAMBORGINI COUNTACH. WHAT IS YOUR FAVORITE CAR?",
|
||||
"MY FAVORITE CAR COMPANY IS FERRARI. WHAT IS YOURS?",
|
||||
"DO YOU LIKE PORSCHES?",
|
||||
"DO YOU LIKE PORSCHE TURBO CARRERAS?"},
|
||||
{ "SAY, DO YOU HAVE ANY PSYCHOLOGICAL PROBLEMS?",
|
||||
"WHAT DOES THAT SUGGEST TO YOU?",
|
||||
"I SEE.",
|
||||
"I'M NOT SURE I UNDERSTAND YOU FULLY.",
|
||||
"COME, COME ELUCIDATE YOUR THOUGHTS.",
|
||||
"CAN YOU ELABORATE ON THAT?",
|
||||
"THAT IS QUITE INTERESTING."}
|
||||
|
||||
|
||||
};
|
||||
|
||||
void print_center(const char *msg) {
|
||||
int numspaces=(MAXLINELEN-strlen(msg))/2;
|
||||
int i;
|
||||
for(i=0;i<numspaces;i++)
|
||||
printf(" ");
|
||||
printf("%s\n", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
void print_title () {
|
||||
printf("\n\n");
|
||||
print_center("*** ELIZA ***");
|
||||
print_center("Original code by Weizenbaum, 1966");
|
||||
print_center("To stop Eliza, type 'bye'");
|
||||
printf("\n\n");
|
||||
printf("HI! I'M ELIZA. WHAT'S YOUR PROBLEM?\n");
|
||||
}
|
||||
|
||||
void readline(char *instr) {
|
||||
char c;
|
||||
int slen=0;
|
||||
|
||||
c=getchar();
|
||||
while (c != '\n')
|
||||
{
|
||||
// removes punctuation and sets to uppercase
|
||||
if(isalpha(c) || isspace(c))
|
||||
instr[slen++]=toupper(c);
|
||||
if(slen>MAXLINELEN-1)
|
||||
{
|
||||
printf("Exceeded Max Line Length\n");
|
||||
}
|
||||
c=getchar();
|
||||
}
|
||||
instr[slen]='\0';
|
||||
}
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
int k,baseLength;
|
||||
int whichReply[NUMKEYWORDS];
|
||||
char lastinput[MAXLINELEN];
|
||||
char reply[MAXLINELEN];
|
||||
char *baseResponse, *token;
|
||||
const char separator[2]=" ";
|
||||
char inputstr[MAXLINELEN];
|
||||
int x,s;
|
||||
char *location;
|
||||
|
||||
// use the first reply for each keyword match the first time you see that keyword
|
||||
for (x=0;x<NUMKEYWORDS; x++) {
|
||||
whichReply[x] = 0;
|
||||
}
|
||||
|
||||
// print a nice centered title screen
|
||||
INITXT();
|
||||
SCNCNT = 1; // set keyboard scan counter
|
||||
print_title();
|
||||
|
||||
lastinput[0]='\0';
|
||||
|
||||
while (1) {
|
||||
printf(">");
|
||||
readline(inputstr);
|
||||
printf("\n");
|
||||
|
||||
// check for termination
|
||||
if (strcmp(inputstr,"BYE")==0)
|
||||
break;
|
||||
|
||||
// check for repeated entries
|
||||
if (strcmp(lastinput,inputstr)==0)
|
||||
{
|
||||
printf("PLEASE DON'T REPEAT YOURSELF!\n");
|
||||
continue;
|
||||
}
|
||||
strncpy(lastinput,inputstr,strlen(inputstr)+1);
|
||||
|
||||
// see if any of the keywords is contained in the input
|
||||
// if not, we use the last element of keywords as our default responses
|
||||
strcpy(reply,"");
|
||||
for(k=0;k<NUMKEYWORDS-1;k++)
|
||||
{
|
||||
location=strstr(inputstr, keywords[k]);
|
||||
if(location != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
// Build Eliza's response
|
||||
// start with Eliza's canned response, based on the keyword match
|
||||
baseResponse = (char *) responses[k][whichReply[k]];
|
||||
baseLength = strlen(baseResponse);
|
||||
|
||||
if(baseResponse[baseLength-1] != '*')
|
||||
{
|
||||
// if we have a baseResponse without an asterix, just use it as-is
|
||||
strcat(reply, baseResponse);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we do have an asterix, fill in the remaining with the user input
|
||||
// use all but the last character of the base response
|
||||
strncat(reply, baseResponse, baseLength-1);
|
||||
|
||||
// now add in the rest of the user's input, starting at <location>
|
||||
// but skip over the keyword itself
|
||||
location+=strlen(keywords[k]);
|
||||
// take them one word at a time, so that we can substitute pronouns
|
||||
token = strtok(location, separator);
|
||||
while(token != NULL)
|
||||
{
|
||||
for(s=0;s<NUMSWAPS;s++)
|
||||
{
|
||||
if(strcmp(SWAPS[s][0], token) == 0)
|
||||
{
|
||||
token = (char *) SWAPS[s][1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
strcat(reply," ");
|
||||
strcat(reply, token);
|
||||
token=strtok(NULL, separator);
|
||||
};
|
||||
strcat(reply, "?");
|
||||
}
|
||||
printf("%s\n", reply);
|
||||
|
||||
// next time, use the next appropriate reply for that keyword
|
||||
whichReply[k]++;
|
||||
if ( whichReply[k] >= ResponsesPerKeyword[k])
|
||||
whichReply[k] = 0;
|
||||
}
|
||||
printf( "GOODBYE! THANKS FOR VISITING WITH ME...\n");
|
||||
}
|
|
@ -1,13 +1,10 @@
|
|||
|
||||
|
||||
; Hello World example
|
||||
|
||||
; ROM routine for character output
|
||||
CHPUT: equ $00A2
|
||||
|
||||
; waste space @ 0x0000 - 0x3fff
|
||||
org 0x0000
|
||||
db 0
|
||||
ds 0x3fff
|
||||
org 0x4000
|
||||
|
||||
; MSX cartridge header @ 0x4000 - 0x400f
|
||||
dw 0x4241
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
; Hello World example
|
||||
|
||||
; ROM routine for character output
|
||||
CHGET = #0x009F
|
||||
CHPUT = #0x00A2
|
||||
|
||||
; Bank 1
|
||||
.area _CODE
|
||||
; MSX cartridge header @ 0x4000 - 0x400f
|
||||
.dw 0x4241
|
||||
.dw Init
|
||||
.dw Init
|
||||
.dw 0
|
||||
.dw 0
|
||||
.dw 0
|
||||
.dw 0
|
||||
.dw 0
|
||||
|
||||
; initialize and print message
|
||||
Init:
|
||||
ld hl,#msg
|
||||
call puts
|
||||
jp Init ; loop forever
|
||||
puts: ; print 0-terminated string in HL
|
||||
ld a,(hl)
|
||||
or a
|
||||
ret z
|
||||
call CHPUT ; displays one character in A
|
||||
inc hl
|
||||
jr puts
|
||||
|
||||
; ASCII message + CR LF
|
||||
msg: .ascii "Hello, world!\n\r\0"
|
|
@ -0,0 +1,339 @@
|
|||
|
||||
/*
|
||||
http://map.grauw.nl/resources/msxbios.php
|
||||
http://map.grauw.nl/resources/msxsystemvars.php
|
||||
https://www.msx.org/wiki/System_variables_and_work_area
|
||||
*/
|
||||
|
||||
#include "msxbios.h"
|
||||
|
||||
#define MSXUSR_LOAD_A() __asm__("ld a,l");
|
||||
#define MSXUSR_LOAD_E() __asm__("ld e,h");
|
||||
#define MSXUSR_RTN_A() __asm__("ld l,a");
|
||||
#define MSXUSR_RTN_Z()\
|
||||
__asm__("ld l,#0");\
|
||||
__asm__("ret nz");\
|
||||
__asm__("inc l");
|
||||
#define MSXUSR_RTN_C()\
|
||||
__asm__("ld l,#0");\
|
||||
__asm__("ret nc");\
|
||||
__asm__("inc l");
|
||||
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint16_t iy,ix,de,bc,af,hl;
|
||||
} w;
|
||||
struct {
|
||||
uint8_t iyl,iyh,ixl,ixh,e,d,c,b,f,a,l,h;
|
||||
} b;
|
||||
} REGS;
|
||||
|
||||
void LOAD_REGS() {
|
||||
__asm__("ld de,(_REGS+4)");
|
||||
__asm__("ld bc,(_REGS+6)");
|
||||
__asm__("ld a,(_REGS+9)");
|
||||
__asm__("ld hl,(_REGS+10)");
|
||||
// TODO: load other regs?
|
||||
}
|
||||
|
||||
#define MSXUSR_LOAD_REGS(bioscall)\
|
||||
LOAD_REGS();\
|
||||
MSXUSR(bioscall);
|
||||
|
||||
void RDSLT(uint8_t slot, uint16_t addr) {
|
||||
REGS.b.a = slot;
|
||||
REGS.w.hl = addr;
|
||||
MSXUSR_LOAD_REGS(0x000c);
|
||||
}
|
||||
|
||||
void WRSLT(uint8_t slot, uint16_t addr, uint8_t value) {
|
||||
REGS.b.a = slot;
|
||||
REGS.w.hl = addr;
|
||||
REGS.b.e = value;
|
||||
MSXUSR_LOAD_REGS(0x0014);
|
||||
}
|
||||
|
||||
void DISSCR() __z88dk_fastcall {
|
||||
MSXUSR(0x0041);
|
||||
}
|
||||
|
||||
void ENASCR() __z88dk_fastcall {
|
||||
MSXUSR(0x0044);
|
||||
}
|
||||
|
||||
void WRTVDP(uint16_t reg_data) __z88dk_fastcall {
|
||||
reg_data;
|
||||
__asm__("ld b,l");
|
||||
__asm__("ld c,h");
|
||||
MSXUSR(0x0047);
|
||||
}
|
||||
|
||||
uint8_t RDVRM(uint16_t addr) __z88dk_fastcall {
|
||||
addr;
|
||||
MSXUSR(0x004a);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
void WRTVRM(uint16_t addr, uint8_t data) {
|
||||
REGS.w.hl = addr;
|
||||
REGS.b.a = data;
|
||||
MSXUSR_LOAD_REGS(0x004d);
|
||||
}
|
||||
|
||||
void SETRD() {
|
||||
MSXUSR(0x0050);
|
||||
}
|
||||
|
||||
void SETWRT() {
|
||||
MSXUSR(0x0053);
|
||||
}
|
||||
|
||||
void FILVRM(uint16_t start, uint16_t len, uint8_t data) {
|
||||
REGS.w.hl = start;
|
||||
REGS.w.bc = len;
|
||||
REGS.b.a = data;
|
||||
MSXUSR_LOAD_REGS(0x0056);
|
||||
}
|
||||
|
||||
void LDIRMV(uint8_t* mdest, uint16_t vsrc, uint16_t count) {
|
||||
REGS.w.de = (uint16_t)mdest;
|
||||
REGS.w.hl = vsrc;
|
||||
REGS.w.bc = count;
|
||||
MSXUSR_LOAD_REGS(0x0059);
|
||||
}
|
||||
|
||||
void LDIRVM(uint16_t vdest, const uint8_t* msrc, uint16_t count) {
|
||||
REGS.w.de = vdest;
|
||||
REGS.w.hl = (uint16_t)msrc;
|
||||
REGS.w.bc = count;
|
||||
MSXUSR_LOAD_REGS(0x005c);
|
||||
}
|
||||
|
||||
void CHGMOD(uint8_t mode) __z88dk_fastcall {
|
||||
mode;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x005f);
|
||||
}
|
||||
|
||||
void CHGCLR() __z88dk_fastcall {
|
||||
// TODO
|
||||
MSXUSR(0x0062);
|
||||
}
|
||||
|
||||
void CLRSPR() __z88dk_fastcall {
|
||||
MSXUSR(0x0069);
|
||||
}
|
||||
|
||||
void INITXT() __z88dk_fastcall {
|
||||
MSXUSR(0x006c);
|
||||
}
|
||||
|
||||
void INIT32() __z88dk_fastcall {
|
||||
MSXUSR(0x006f);
|
||||
}
|
||||
|
||||
void INIGRP() __z88dk_fastcall {
|
||||
MSXUSR(0x0072);
|
||||
}
|
||||
|
||||
void INIMLT() __z88dk_fastcall {
|
||||
MSXUSR(0x0075);
|
||||
}
|
||||
|
||||
uint16_t CALPAT() __z88dk_fastcall {
|
||||
MSXUSR(0x0084);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
uint16_t CALATR() __z88dk_fastcall {
|
||||
MSXUSR(0x0087);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
uint16_t GSPSIZ() __z88dk_fastcall {
|
||||
MSXUSR(0x008a);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
uint16_t GRPPRT(char ch) __z88dk_fastcall {
|
||||
ch;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x008d);
|
||||
}
|
||||
|
||||
uint16_t GICINI() __z88dk_fastcall {
|
||||
MSXUSR(0x0090);
|
||||
}
|
||||
|
||||
uint16_t WRTPSG(uint16_t reg_data) __z88dk_fastcall {
|
||||
reg_data;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR_LOAD_E();
|
||||
MSXUSR(0x0096);
|
||||
}
|
||||
|
||||
uint8_t CHSNS() __z88dk_fastcall {
|
||||
MSXUSR(0x009c);
|
||||
MSXUSR_RTN_Z();
|
||||
}
|
||||
|
||||
char CHGET() __z88dk_fastcall {
|
||||
MSXUSR(0x009f);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
void CHPUT(char ch) __z88dk_fastcall {
|
||||
ch;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x00a2);
|
||||
}
|
||||
|
||||
void LPTOUT(char ch) __z88dk_fastcall {
|
||||
ch;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x00a5);
|
||||
}
|
||||
|
||||
void BEEP() __z88dk_fastcall {
|
||||
MSXUSR(0x00c0);
|
||||
}
|
||||
|
||||
void CLS() __z88dk_fastcall {
|
||||
__asm__("xor a");
|
||||
MSXUSR(0x00c3);
|
||||
}
|
||||
|
||||
void POSIT(uint16_t yx) __z88dk_fastcall {
|
||||
yx;
|
||||
MSXUSR(0x00c6);
|
||||
}
|
||||
|
||||
void TOTEXT() __z88dk_fastcall {
|
||||
MSXUSR(0x00d2);
|
||||
}
|
||||
|
||||
uint8_t GTSTCK(uint8_t index) __z88dk_fastcall {
|
||||
index;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x00d5);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
uint8_t GTTRIG(uint8_t index) __z88dk_fastcall {
|
||||
index;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x00d8);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
uint8_t GTPAD(uint8_t index) __z88dk_fastcall {
|
||||
index;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x00db);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
uint8_t GTPDL(uint8_t index) __z88dk_fastcall {
|
||||
index;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x00de);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
/*
|
||||
void RIGHTC() __z88dk_fastcall {
|
||||
MSXUSR(0x00fc);
|
||||
}
|
||||
|
||||
void LEFTC() __z88dk_fastcall {
|
||||
MSXUSR(0x00ff);
|
||||
}
|
||||
|
||||
void UPC() __z88dk_fastcall {
|
||||
MSXUSR(0x0102);
|
||||
}
|
||||
|
||||
uint8_t TUPC() __z88dk_fastcall {
|
||||
MSXUSR(0x0105);
|
||||
MSXUSR_RTN_C();
|
||||
}
|
||||
|
||||
void DOWNC() __z88dk_fastcall {
|
||||
MSXUSR(0x0108);
|
||||
}
|
||||
|
||||
uint8_t TDOWNC() __z88dk_fastcall {
|
||||
MSXUSR(0x010b);
|
||||
MSXUSR_RTN_C();
|
||||
}
|
||||
|
||||
void SCALXY() __z88dk_fastcall {
|
||||
MSXUSR(0x010e);
|
||||
}
|
||||
*/
|
||||
|
||||
void MAPXY() __z88dk_fastcall {
|
||||
MSXUSR(0x0111);
|
||||
}
|
||||
|
||||
uint16_t FETCHC_ADDR() __z88dk_fastcall {
|
||||
MSXUSR(0x0114);
|
||||
}
|
||||
|
||||
/*
|
||||
void STOREC(uint16_t addr, uint8_t mask) {
|
||||
REGS.w.hl = addr;
|
||||
REGS.b.a = mask;
|
||||
MSXUSR_LOAD_REGS(0x0117);
|
||||
}
|
||||
|
||||
void SETATR(uint8_t attr) __z88dk_fastcall {
|
||||
attr;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x011a);
|
||||
}
|
||||
|
||||
uint8_t READC() __z88dk_fastcall {
|
||||
MSXUSR(0x011d);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
void SETC() __z88dk_fastcall {
|
||||
MSXUSR(0x0120);
|
||||
}
|
||||
|
||||
void NSETCX(uint16_t fillcount) __z88dk_fastcall {
|
||||
fillcount;
|
||||
MSXUSR(0x0123);
|
||||
}
|
||||
*/
|
||||
|
||||
uint8_t RDVDP() __z88dk_fastcall {
|
||||
MSXUSR(0x013e);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
uint8_t SNSMAT(uint8_t row) __z88dk_fastcall {
|
||||
row;
|
||||
MSXUSR_LOAD_A();
|
||||
MSXUSR(0x0141);
|
||||
MSXUSR_RTN_A();
|
||||
}
|
||||
|
||||
void KILBUF() __z88dk_fastcall {
|
||||
MSXUSR(0x0156);
|
||||
}
|
||||
|
||||
// for stdio.h
|
||||
int putchar(int ch) {
|
||||
CHPUT(ch);
|
||||
if (ch == '\n') CHPUT('\r'); // convert CR to CRLF
|
||||
return ch;
|
||||
}
|
||||
char getchar() {
|
||||
char ch = CHGET();
|
||||
putchar(ch); // echo
|
||||
if (ch == '\r') ch = '\n';
|
||||
return ch;
|
||||
}
|
|
@ -0,0 +1,231 @@
|
|||
#ifndef _MSXBIOS_H
|
||||
#define _MSXBIOS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MSXUSR(pc) __asm__("call "#pc);
|
||||
|
||||
/// VARIABLES
|
||||
|
||||
const uint8_t* __at(0x0004) MSX_charset;
|
||||
const uint8_t __at(0x0006) MSX_vdp_port_read;
|
||||
const uint8_t __at(0x0007) MSX_vdp_port_write;
|
||||
const uint8_t __at(0x002d) MSX_version;
|
||||
|
||||
// F3AE: # of positions on a line in SCREEN 0 (ini:39)
|
||||
uint8_t __at(0xf3ae) LINL40;
|
||||
// F3AF: # of positions on a line in SCREEN 1 (ini:29)
|
||||
uint8_t __at(0xf3af) LINL32;
|
||||
// F3B0: # of actually used positions in the current screenmodus (ini:39)
|
||||
uint8_t __at(0xf3b0) LINLEN;
|
||||
// F3B1: # of used lines on screen (ini:24)
|
||||
uint8_t __at(0xf3b1) CRTCNT;
|
||||
// F3B2: # of positions within a tabulator-column (ini:14)
|
||||
uint8_t __at(0xf3b1) CLMLST;
|
||||
|
||||
typedef struct {
|
||||
uint16_t name;
|
||||
uint16_t color;
|
||||
uint16_t pattern;
|
||||
uint16_t sprite_attribute;
|
||||
uint16_t sprite_pattern;
|
||||
} MSXVDPModeData;
|
||||
|
||||
MSXVDPModeData __at(0xf3b3) MSX_modedata_screen0;
|
||||
MSXVDPModeData __at(0xf3bd) MSX_modedata_screen1;
|
||||
MSXVDPModeData __at(0xf3c7) MSX_modedata_screen2;
|
||||
MSXVDPModeData __at(0xf3d1) MSX_modedata_screen3;
|
||||
|
||||
// F3DC: line where the cursor is located
|
||||
uint8_t __at(0xf3dc) CSRY;
|
||||
// F3DD: column where the cursor is located
|
||||
uint8_t __at(0xf3dd) CSRX;
|
||||
// F3DE: function key definition shown: 0: no, -1: yes
|
||||
uint8_t __at(0xf3de) CNSDFG;
|
||||
// F3DF-D3E6: storage for the last written value towards VDP registers 0 till 7
|
||||
uint8_t __at(0xf3df) MSX_vdp_regs[8];
|
||||
// F3E7: last read value of VDP register 8
|
||||
uint8_t __at(0xf3e7) STATFL;
|
||||
// F3E8: information about the joystick and space bar
|
||||
// 7 6 5 4 3 2 1 0
|
||||
// | | | | +-- Space bar, trig(0) (0 = pressed)
|
||||
// | | | +---------- Stick 1, Trigger 1 (0 = pressed)
|
||||
// | | +------------ Stick 1, Trigger 2 (0 = pressed)
|
||||
// | +-------------- Stick 2, Trigger 1 (0 = pressed)
|
||||
// +---------------- Stick 2, Trigger 2 (0 = pressed)
|
||||
uint8_t __at(0xf3e8) TRGFLG;
|
||||
|
||||
// F3E9: code for the standard foreground color (ini:15)
|
||||
uint8_t __at(0xf3e9) FORCLR;
|
||||
// F3EA: code for the standard background color (ini:4)
|
||||
uint8_t __at(0xf3ea) BAKCLR;
|
||||
// F3EB: code for the standard border color (ini:7)
|
||||
uint8_t __at(0xf3eb) BDRCLR;
|
||||
|
||||
//Pixel lcocation
|
||||
uint16_t __at(0xf92a) CLOC;
|
||||
//Pixel mask
|
||||
uint8_t __at(0xf92c) CMASK;
|
||||
//Attribute byte for SETC
|
||||
uint8_t __at(0xf3f2) ATRBYT;
|
||||
//Key scan timing
|
||||
uint8_t __at(0xf3f6) SCNCNT;
|
||||
//Key repeat timer
|
||||
uint8_t __at(0xf3f7) REPCNT;
|
||||
//Address in the keyboard buffer where a character will be written
|
||||
uint8_t* __at(0xf3f8) PUTPNT;
|
||||
//Address in the keyboard buffer where the next character is read
|
||||
uint8_t* __at(0xf3fa) GETPNT;
|
||||
|
||||
/// FUNCTIONS
|
||||
|
||||
// Reads the value of an address in another slot
|
||||
void RDSLT(uint8_t slot, uint16_t addr);
|
||||
// Writes a value to an address in another slot.
|
||||
void WRSLT(uint8_t slot, uint16_t addr, uint8_t value);
|
||||
// inhibits the screen display
|
||||
void DISSCR() __z88dk_fastcall;
|
||||
// displays the screen
|
||||
void ENASCR() __z88dk_fastcall;
|
||||
// write data in the VDP-register
|
||||
void WRTVDP(uint16_t reg_data) __z88dk_fastcall;
|
||||
// Reads the content of VRAM
|
||||
uint8_t RDVRM(uint16_t addr) __z88dk_fastcall;
|
||||
// Writes data in VRAM
|
||||
void WRTVRM(uint16_t addr, uint8_t data);
|
||||
// Enable VDP to read
|
||||
void SETRD();
|
||||
// Enable VDP to write
|
||||
void SETWRT();
|
||||
// fill VRAM with value
|
||||
void FILVRM(uint16_t start, uint16_t len, uint8_t data);
|
||||
// Block transfer to memory from VRAM
|
||||
void LDIRMV(uint8_t* mdest, uint16_t vsrc, uint16_t count);
|
||||
// Block transfer to VRAM from memory
|
||||
void LDIRVM(uint16_t vdest, const uint8_t* msrc, uint16_t count);
|
||||
// Switches to given screenmode
|
||||
void CHGMOD(uint8_t mode) __z88dk_fastcall;
|
||||
// Changes the screencolors
|
||||
void CHGCLR() __z88dk_fastcall;
|
||||
// Initialises all sprites
|
||||
void CLRSPR() __z88dk_fastcall;
|
||||
// Switches to SCREEN 0 (40x24 text mode)
|
||||
void INITXT() __z88dk_fastcall;
|
||||
// Switches to SCREEN 1 (text screen with 32*24 characters)
|
||||
void INIT32() __z88dk_fastcall;
|
||||
// Switches to SCREEN 2 (high resolution screen with 256*192 pixels)
|
||||
void INIGRP() __z88dk_fastcall;
|
||||
// Switches to SCREEN 3 (multi-color screen 64*48 pixels)
|
||||
void INIMLT() __z88dk_fastcall;
|
||||
// Returns the address of the sprite pattern table
|
||||
uint16_t CALPAT() __z88dk_fastcall;
|
||||
// Returns the address of the sprite attribute table
|
||||
uint16_t CALATR() __z88dk_fastcall;
|
||||
// Returns current sprite size
|
||||
uint16_t GSPSIZ() __z88dk_fastcall;
|
||||
// Displays a character on the graphic screen
|
||||
uint16_t GRPPRT(char ch) __z88dk_fastcall;
|
||||
// Initialises PSG and sets initial value for the PLAY statement
|
||||
uint16_t GICINI() __z88dk_fastcall;
|
||||
// Writes data to PSG-register
|
||||
uint16_t WRTPSG(uint16_t reg_data) __z88dk_fastcall;
|
||||
// Tests the status of the keyboard buffer
|
||||
uint8_t CHSNS() __z88dk_fastcall;
|
||||
// One character input (waiting)
|
||||
char CHGET() __z88dk_fastcall;
|
||||
// Displays one character
|
||||
void CHPUT(char ch) __z88dk_fastcall;
|
||||
// Sends one character to printer
|
||||
void LPTOUT(char ch) __z88dk_fastcall;
|
||||
// Beeps
|
||||
void BEEP() __z88dk_fastcall;
|
||||
// Clears the screen
|
||||
void CLS() __z88dk_fastcall;
|
||||
// Sets cursor X/Y position
|
||||
void POSIT(uint16_t yx) __z88dk_fastcall;
|
||||
// Forces the screen to be in the text mode
|
||||
void TOTEXT() __z88dk_fastcall;
|
||||
// Returns the joystick status
|
||||
uint8_t GTSTCK(uint8_t index) __z88dk_fastcall;
|
||||
// Returns current trigger status
|
||||
uint8_t GTTRIG(uint8_t index) __z88dk_fastcall;
|
||||
// Returns current touch pad status
|
||||
uint8_t GTPAD(uint8_t index) __z88dk_fastcall;
|
||||
// Returns currenct value of paddle
|
||||
uint8_t GTPDL(uint8_t index) __z88dk_fastcall;
|
||||
|
||||
/*
|
||||
void RIGHTC() __z88dk_fastcall;
|
||||
void LEFTC() __z88dk_fastcall;
|
||||
void UPC() __z88dk_fastcall;
|
||||
uint8_t TUPC() __z88dk_fastcall;
|
||||
void DOWNC() __z88dk_fastcall;
|
||||
uint8_t TDOWNC() __z88dk_fastcall;
|
||||
void SCALXY() __z88dk_fastcall;
|
||||
*/
|
||||
void MAPXY() __z88dk_fastcall;
|
||||
uint16_t FETCHC_ADDR() __z88dk_fastcall;
|
||||
/*
|
||||
void STOREC(uint16_t addr, uint8_t mask);
|
||||
void SETATR(uint8_t attr) __z88dk_fastcall;
|
||||
uint8_t READC() __z88dk_fastcall;
|
||||
void SETC() __z88dk_fastcall;
|
||||
void NSETCX(uint16_t fillcount) __z88dk_fastcall;
|
||||
*/
|
||||
uint8_t RDVDP() __z88dk_fastcall;
|
||||
uint8_t SNSMAT(uint8_t row) __z88dk_fastcall;
|
||||
void KILBUF() __z88dk_fastcall;
|
||||
|
||||
// VDP colors for TMS9918A
|
||||
|
||||
enum MSX1_Color {
|
||||
COLOR_TRANSPARENT = 0x0,
|
||||
COLOR_BLACK = 0x1,
|
||||
COLOR_GREEN = 0x2,
|
||||
COLOR_LIGHT_GREEN = 0x3,
|
||||
COLOR_BLUE = 0x4,
|
||||
COLOR_LIGHT_BLUE = 0x5,
|
||||
COLOR_DARK_RED = 0x6,
|
||||
COLOR_CYAN = 0x7,
|
||||
COLOR_RED = 0x8,
|
||||
COLOR_LIGHT_RED = 0x9,
|
||||
COLOR_YELLOW = 0xa,
|
||||
COLOR_LIGHT_YELLOW = 0xb,
|
||||
COLOR_DARK_GREEN = 0xc,
|
||||
COLOR_MAGENTA = 0xd,
|
||||
COLOR_GRAY = 0xe,
|
||||
COLOR_WHITE = 0xf
|
||||
};
|
||||
|
||||
// joystick positions for GTSTCK
|
||||
typedef enum GTSTCK_Direction {
|
||||
STCK_none = 0,
|
||||
STCK_N,
|
||||
STCK_NE,
|
||||
STCK_E,
|
||||
STCK_SE,
|
||||
STCK_S,
|
||||
STCK_SW,
|
||||
STCK_W,
|
||||
STCK_NW
|
||||
};
|
||||
|
||||
// parameter for GTSTCK
|
||||
typedef enum GTSTCK_Param {
|
||||
STCK_Cursors,
|
||||
STCK_Joy1,
|
||||
STCK_Joy2
|
||||
};
|
||||
|
||||
// parameter for GTTRIG
|
||||
typedef enum GTTRIG_Param {
|
||||
TRIG_Spacebar,
|
||||
TRIG_Joy1_A,
|
||||
TRIG_Joy2_A,
|
||||
TRIG_Joy1_B,
|
||||
TRIG_Joy2_B
|
||||
};
|
||||
|
||||
#define VSYNC() __asm__("HALT");
|
||||
|
||||
#endif
|
|
@ -0,0 +1,166 @@
|
|||
ORG 04000H
|
||||
; LOAD 04000H
|
||||
; MSX cartridge header @ 0x4000 - 0x400f
|
||||
dw 0x4241
|
||||
dw Start
|
||||
dw Start
|
||||
dw 0,0,0,0,0
|
||||
|
||||
; ******************************
|
||||
; * BIOS STANDARD ROUTINES *
|
||||
; ******************************
|
||||
|
||||
RDSLT: EQU 000CH
|
||||
CNVCHR: EQU 00ABH
|
||||
MAPXYC: EQU 0111H
|
||||
SETC: EQU 0120H
|
||||
|
||||
; ******************************
|
||||
; * WORKSPACE VARIABLES *
|
||||
; ******************************
|
||||
|
||||
FORCLR: EQU 0F3E9H
|
||||
ATRBYT: EQU 0F3F2H
|
||||
CGPNT: EQU 0F91FH
|
||||
PATWRK: EQU 0FC40H
|
||||
SCRMOD: EQU 0FCAFH
|
||||
GRPACX: EQU 0FCB7H
|
||||
GRPACY: EQU 0FCB9H
|
||||
|
||||
; ******************************
|
||||
; * CONTROL CHARACTERS *
|
||||
; ******************************
|
||||
|
||||
CR: EQU 13
|
||||
|
||||
Start:
|
||||
GFORTY: CP 3 ; String type?
|
||||
RET NZ ;
|
||||
LD A,(SCRMOD) ; Mode
|
||||
CP 2 ; Graphics?
|
||||
RET NZ ;
|
||||
EX DE,HL ; HL->Descriptor
|
||||
LD B,(HL) ; B=String len
|
||||
INC HL ;
|
||||
LD E,(HL) ; Address LSB
|
||||
INC HL ;
|
||||
LD D,(HL) ; DE->String
|
||||
INC B ;
|
||||
GF2: DEC B ; Finished?
|
||||
RET Z ;
|
||||
LD A,(DE) ; A=Chr from string
|
||||
CALL GPRINT ; Print it
|
||||
INC DE ;
|
||||
JR GF2 ; Next chr
|
||||
GPRINT: PUSH AF ;
|
||||
PUSH BC ;
|
||||
PUSH DE ;
|
||||
PUSH HL ;
|
||||
PUSH IY ;
|
||||
LD BC,(GRPACX) ; BC=X coord
|
||||
LD DE,(GRPACY) ; DE=Y coord
|
||||
CALL GDC ; Decode chr
|
||||
LD (GRPACX),BC ; New X coord
|
||||
LD (GRPACY),DE ; New Y coord
|
||||
POP IY ;
|
||||
POP HL ;
|
||||
POP DE ;
|
||||
POP BC ;
|
||||
POP AF ;
|
||||
RET ;
|
||||
|
||||
GDC: CALL CNVCHR ; Check graphic
|
||||
RET NC ; NC=Header
|
||||
JR NZ,GD2 ; NZ=Converted
|
||||
CP CR ; Carriage Return?
|
||||
JR Z,GCRLF ;
|
||||
CP 20H ; Other control?
|
||||
RET C ; Ignore
|
||||
GD2: LD L,A ;
|
||||
LD H,0 ; HL=Chr code
|
||||
ADD HL,HL ;
|
||||
ADD HL,HL ;
|
||||
ADD HL,HL ; HL=Chr*8
|
||||
PUSH BC ; X coord
|
||||
PUSH DE ; Y coord
|
||||
LD DE,(CGPNT+1) ; Character set
|
||||
ADD HL,DE ; HL->Pattern
|
||||
LD DE,PATWRK ; DE->Buffer
|
||||
LD B,8 ; Eight byte pattern
|
||||
GD3: PUSH BC ;
|
||||
PUSH DE ;
|
||||
LD A,(CGPNT) ; Slot ID
|
||||
CALL RDSLT ; Get pattern
|
||||
EI ;
|
||||
POP DE ;
|
||||
POP BC ;
|
||||
LD (DE),A ; Put in buffer
|
||||
INC DE ;
|
||||
INC HL ;
|
||||
DJNZ GD3 ; Next
|
||||
POP DE ;
|
||||
POP BC ;
|
||||
LD A,(FORCLR) ; Current colour
|
||||
LD (ATRBYT),A ; Set ink
|
||||
LD IY,PATWRK ; IY->Patterns
|
||||
PUSH DE ;
|
||||
LD H,8 ; Max dot rows
|
||||
GD4: BIT 7,D ; Pos Y coord?
|
||||
JR NZ,GD8 ;
|
||||
CALL BMDROW ; Bottom most row?
|
||||
JR C,GD9 ; C=Y too large
|
||||
PUSH BC ;
|
||||
LD L,6 ; Max dot cols
|
||||
LD A,(IY+0) ; A=Pattern row
|
||||
GD5: BIT 7,B ; Pos X coord
|
||||
JR NZ,GD6 ;
|
||||
CALL RMDCOL ; Rightmost col?
|
||||
JR C,GD7 ; C=X too large
|
||||
BIT 7,A ; Pattern bit
|
||||
JR Z,GD6 ; Z=0 Pixel
|
||||
PUSH AF ;
|
||||
PUSH DE ;
|
||||
PUSH HL ;
|
||||
CALL MAPXYC ; Map coords
|
||||
CALL SETC ; Set pixel
|
||||
POP HL ;
|
||||
POP DE ;
|
||||
POP AF ;
|
||||
GD6: RLCA ; Shift pattern
|
||||
INC BC ; X=X+1
|
||||
DEC L ; Finished dot cols?
|
||||
JR NZ,GD5 ;
|
||||
GD7: POP BC ; Initial X coord
|
||||
GD8: INC IY ; Next pattern byte
|
||||
INC DE ; Y=Y+1
|
||||
DEC H ; Finished dot rows?
|
||||
JR NZ,GD4 ;
|
||||
GD9: POP DE ; Initial Y coord
|
||||
LD HL,6 ; Step
|
||||
ADD HL,BC ; X=X+6
|
||||
LD B,H ;
|
||||
LD C,L ; BC=New X coord
|
||||
CALL RMDCOL ; Rightmost col?
|
||||
RET NC ;
|
||||
|
||||
GCRLF: LD BC,0 ; X=0
|
||||
LD HL,8 ;
|
||||
ADD HL,DE ;
|
||||
EX DE,HL ; Y=Y+8
|
||||
RET ;
|
||||
|
||||
BMDROW: PUSH HL ;
|
||||
LD HL,191 ; Bottom dot row
|
||||
OR A ;
|
||||
SBC HL,DE ; Check Y coord
|
||||
POP HL ;
|
||||
RET ; C=Below screen
|
||||
|
||||
RMDCOL: PUSH HL ;
|
||||
LD HL,239 ; Rightmost dot col
|
||||
OR A ;
|
||||
SBC HL,BC ; Check X coord
|
||||
POP HL ;
|
||||
RET ; C=Beyond right
|
||||
|
||||
END
|