Merge branch 'master' into improved-readme

This commit is contained in:
Steven Hugg 2019-08-21 15:29:06 -04:00 committed by GitHub
commit b72f974a3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
271 changed files with 18706 additions and 42391 deletions

4
.github/FUNDING.yml vendored Normal file
View File

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

1
.gitignore vendored
View File

@ -5,3 +5,4 @@ local
release
gen
test/output
.DS_Store

9
.gitmodules vendored
View File

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

View File

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

View File

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

6
bootstrap/js/bootbox.all.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
cc65/.gitignore vendored
View File

@ -1,4 +0,0 @@
*.nes
*.o
*.s
*.lzg

View File

@ -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,"' > $@

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

265
doc/platforms.md Normal file
View File

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

View File

@ -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 +0,0 @@
Subproject commit 7a9227d43057b6ab6271a2577ecce47fa3360134

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

BIN
images/book_nes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

View File

@ -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>
&nbsp;
<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"/>
&nbsp;&nbsp;<b>Making Games For The Atari 2600</b>
&nbsp;&nbsp;<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"/>
&nbsp;&nbsp;<b>Making 8-bit Arcade Games in C</b>
&nbsp;&nbsp;<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"/>
&nbsp;&nbsp;<b>Designing Video Game Hardware in Verilog</b>
&nbsp;&nbsp;<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"/>
&nbsp;&nbsp;<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">&#x2190;&#x2191;&#x2193;&#x2192;</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">&#x2190;&#x2191;&#x2193;&#x2192;</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">&#x2190;&#x2191;&#x2193;&#x2192;</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">&#x2190;&#x2191;&#x2193;&#x2192;</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">&#x2190;&nbsp;&#x2192;</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">&#x2190;&#x2191;&#x2193;&#x2192;</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">&#x2190;&#x2191;&#x2193;&#x2192;</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/&nbsp;<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>-->

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
nanoasm Submodule

@ -0,0 +1 @@
Subproject commit 53470410c34d2738a9f52e65bf8ffe1eabbef19b

159
package-lock.json generated
View File

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

View File

@ -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"
},

116
presets/LICENSE Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

148
presets/astrocade/acbios.h Normal file
View File

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

148
presets/astrocade/acbios.s Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

37
presets/astrocade/aclib.s Normal file
View File

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

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

107
presets/astrocade/hello.c Normal file
View File

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

View File

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

49
presets/astrocade/lines.c Normal file
View File

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

97
presets/astrocade/music.c Normal file

File diff suppressed because one or more lines are too long

458
presets/astrocade/racing.c Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

40
presets/astrocade/vsync.c Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

1
presets/msx-libcv Symbolic link
View File

@ -0,0 +1 @@
coleco

29
presets/msx/biostest.c Normal file
View File

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

367
presets/msx/eliza.c Normal file
View File

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

View File

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

34
presets/msx/helloworld.s Normal file
View File

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

339
presets/msx/msxbios.c Normal file
View File

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

231
presets/msx/msxbios.h Normal file
View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More