From b29f11a1cc243ce8d570a3a3170a3256f8008557 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Tue, 14 Aug 2018 16:28:29 -0400 Subject: [PATCH] new neslib2.lib (from clbr/neslib) using extrafiles parameter, local .h, disasm uses symbols --- editstorage.html | 1 + presets/nes/crypto.c | 51 ++- presets/nes/neslib.h | 292 ++++++++++++++ presets/nes/neslib1.c | 11 +- presets/nes/neslib2.c | 12 +- presets/nes/neslib3.c | 36 +- presets/nes/neslib4.c | 12 +- presets/nes/neslib5.c | 13 +- presets/nes/shoot2.c | 808 ++++++++++++++++++++++++++++++++++++++ presets/nes/siegegame.c | 159 ++++++-- presets/nes/skeleton.dasm | 46 +++ presets/vicdual/asmtest.s | 135 +++++++ src/pixed/pixeleditor.ts | 1 + src/platform/nes.js | 1 + src/project.ts | 3 +- src/views.ts | 14 +- src/worker/lib/nes/crt0.o | Bin 0 -> 57756 bytes src/worker/workermain.js | 31 +- 18 files changed, 1540 insertions(+), 86 deletions(-) create mode 100644 presets/nes/neslib.h create mode 100644 presets/nes/shoot2.c create mode 100644 presets/nes/skeleton.dasm create mode 100644 presets/vicdual/asmtest.s create mode 100644 src/worker/lib/nes/crt0.o diff --git a/editstorage.html b/editstorage.html index 6558bfe8..0474a9ec 100644 --- a/editstorage.html +++ b/editstorage.html @@ -60,6 +60,7 @@ $("#deleteitem").click(function(e) { })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-54497476-9', 'auto'); + ga('set', 'anonymizeIp', true); ga('send', 'pageview'); diff --git a/presets/nes/crypto.c b/presets/nes/crypto.c index a2c08b9d..0dd719a9 100644 --- a/presets/nes/crypto.c +++ b/presets/nes/crypto.c @@ -1,6 +1,9 @@ - + #include "neslib.h" +#pragma data-name (push,"CHARS") +#pragma data-name (pop) + //#define DEBUG #define HAS_DEBUGGER @@ -34,6 +37,8 @@ static const unsigned char paused_palette[]={ #pragma bss-name(push,"ZEROPAGE") #pragma data-name(push,"ZEROPAGE") +unsigned char oam_off; + static unsigned char i, j; static unsigned char player_dir[2]; @@ -2632,14 +2637,20 @@ void __fastcall__ init(void){ bank_spr(0); bank_bg(1); - unrle_vram(bg_top_left, NAMETABLE_A); - unrle_vram(bg_top_right, NAMETABLE_B); - unrle_vram(bg_bottom_left, NAMETABLE_C); - unrle_vram(bg_bottom_right, NAMETABLE_D); + vram_adr(NAMETABLE_A); + vram_unrle(bg_top_left); + vram_adr(NAMETABLE_B); + vram_unrle(bg_top_right); + vram_adr(NAMETABLE_C); + vram_unrle(bg_bottom_left); + vram_adr(NAMETABLE_D); + vram_unrle(bg_bottom_right); // copy tilesets - vram_write((unsigned char*)0x0000, 0x0, 0x2000); - vram_write((unsigned char*)0x2000, 0x0, 0x2000); + vram_adr(0x0); + vram_write((unsigned char*)0x0000, 0x2000); + vram_adr(0x2000); + vram_write((unsigned char*)0x2000, 0x2000); ppu_on_all(); @@ -2823,20 +2834,21 @@ void main(void){ while(1){ pal_all(paused_palette); scroll(0, 0); - ppu_waitnmi(); + ppu_wait_nmi(); ppu_off(); - unrle_vram(bg_menu, NAMETABLE_A); + vram_adr(NAMETABLE_A); + vram_unrle(bg_menu); ppu_on_all(); pal_all(palette); - ppu_waitnmi(); + ppu_wait_nmi(); - ppu_waitnmi(); + ppu_wait_nmi(); while(1){ - ppu_waitnmi(); + ppu_wait_nmi(); spr=0; oam_clear(); frame++; @@ -2894,20 +2906,21 @@ void main(void){ oam_clear(); pal_all(paused_palette); - ppu_waitnmi(); + ppu_wait_nmi(); ppu_off(); - unrle_vram(bg_top_left, NAMETABLE_A); + vram_adr(NAMETABLE_A); + vram_unrle(bg_top_left); ppu_on_all(); - ppu_waitnmi(); + ppu_wait_nmi(); difficulty = 0; next_level = 1; while(1){ - ppu_waitnmi(); + ppu_wait_nmi(); spr=0; oam_clear(); @@ -2941,7 +2954,7 @@ void main(void){ frame = 0; while(1) { - ppu_waitnmi(); + ppu_wait_nmi(); frame++; if((frame > 100) && (frame == 255 || ((pad_trigger(0)|pad_trigger(1))&(PAD_A|PAD_B|PAD_START)))) { @@ -2981,7 +2994,7 @@ void main(void){ frame = 0; while(1) { - ppu_waitnmi(); + ppu_wait_nmi(); frame++; if(frame == 255) { @@ -3014,7 +3027,7 @@ void main(void){ while(!(pad_trigger(0) & PAD_START)) { - ppu_waitnmi(); + ppu_wait_nmi(); } pal_all(palette); diff --git a/presets/nes/neslib.h b/presets/nes/neslib.h new file mode 100644 index 00000000..e9f9355e --- /dev/null +++ b/presets/nes/neslib.h @@ -0,0 +1,292 @@ +/* + (C) 2015 Alex Semenov (Shiru) + (C) 2016 Lauri Kasanen + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +// NES hardware-dependent functions by Shiru (shiru@mail.ru) +// Feel free to do anything you want with this code, consider it Public Domain + +// Versions history: +// 280215 - fixed palette glitch caused with the active DMC DMA glitch +// 030914 - minor fixes in the vram update system +// 310814 - added vram_flush_update +// 120414 - removed adr argument from vram_write and vram_read, +// unrle_vram renamed to vram_unrle, with adr argument removed +// 060414 - many fixes and improvements, including sequental VRAM updates +// previous versions were created since mid-2011, there were many updates + + + + + +// 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 both for sprites and background, 0 is black, 4 is normal, 8 is white +void __fastcall__ pal_bright(unsigned char bright); + +// set virtual bright for sprites only +void __fastcall__ pal_spr_bright(unsigned char bright); + +// set virtual bright for sprites background only +void __fastcall__ pal_bg_bright(unsigned char bright); + + + +// wait actual TV frame, 50hz for PAL, 60hz for NTSC +void __fastcall__ ppu_wait_nmi(void); + +// wait virtual frame, it is always 50hz, frame-to-frame in PAL, frameskip in NTSC +void __fastcall__ ppu_wait_frame(void); + +// turn off rendering, nmi still enabled when rendering is disabled +void __fastcall__ ppu_off(void); + +// turn on bg, spr +void __fastcall__ ppu_on_all(void); + +// turn on bg only +void __fastcall__ ppu_on_bg(void); + +// turn on spr only +void __fastcall__ ppu_on_spr(void); + +// set PPU_MASK directly +void __fastcall__ ppu_mask(unsigned char mask); + +// get current video system, 0 for PAL, not 0 for NTSC +unsigned char __fastcall__ ppu_system(void); + +// Return an 8-bit counter incremented at each vblank +unsigned char __fastcall__ nesclock(void); + +// get/set the internal ppu ctrl cache var for manual writing +unsigned char __fastcall__ get_ppu_ctrl_var(void); +void __fastcall__ set_ppu_ctrl_var(unsigned char var); + + +// clear OAM buffer, all the sprites are hidden +void __fastcall__ oam_clear(void); + +// set sprite display mode, 0 for 8x8 sprites, 1 for 8x16 sprites +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 remaining sprites from given offset +void __fastcall__ oam_hide_rest(unsigned char sprid); + + + +// play a music in FamiTone format +void __fastcall__ music_play(unsigned char song); + +// 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); + +// play a DPCM sample, 1..63 +void __fastcall__ sample_play(unsigned char sample); + + + +// 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 rhe top bits +// it is always applied at beginning of a TV frame, not at the function call +void __fastcall__ scroll(unsigned int x, unsigned int y); + +// set scroll after screen split invoked by the sprite 0 hit +// warning: all CPU time between the function call and the actual split point will be wasted! +// warning: the program loop has to fit into the frame time, ppu_wait_frame should not be used +// otherwise empty frames without split will be inserted, resulting in jumpy screen +// warning: only X scroll could be changed in this version +void __fastcall__ split(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); + + + +// get 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); + + + +// when display is enabled, vram access could only be done with this vram update system +// the function sets a pointer to the update buffer that contains data and addresses +// in a special format. It allows to write non-sequental bytes, as well as horizontal or +// vertical nametable sequences. +// buffer pointer could be changed during rendering, but it only takes effect on a new frame +// number of transferred bytes is limited by vblank time +// to disable updates, call this function with NULL pointer + +// the update data format: +// MSB, LSB, byte for a non-sequental write +// MSB|NT_UPD_HORZ, LSB, LEN, [bytes] for a horizontal sequence +// MSB|NT_UPD_VERT, LSB, LEN, [bytes] for a vertical sequence +// NT_UPD_EOF to mark end of the buffer + +// length of this data should be under 256 bytes + +void __fastcall__ set_vram_update(unsigned char *buf); + +// all following vram functions only work when display is disabled + +// do a series of VRAM writes, the same format as for set_vram_update, but writes done right away +void __fastcall__ flush_vram_update(unsigned char *buf); + +// set vram pointer to write operations if you need to write some data to vram +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 current address of vram, works only when rendering is turned off +void __fastcall__ vram_read(unsigned char *dst, unsigned int size); + +// write a block to current address of vram, works only when rendering is turned off +void __fastcall__ vram_write(const unsigned char *src, unsigned int size); + + +// unpack RLE data to current address of vram, mostly used for nametables +void __fastcall__ vram_unrle(const unsigned char *data); + +// unpack LZ4 data to this address +void __fastcall__ vram_unlz4(const unsigned char *in, unsigned char *out, + const unsigned uncompressed_size); +/* + Rough speeds for a full 1024 nametable: + - rle takes 0.5 frames + - uncompressed takes 1.3 frames + - lz4 takes 2.8 frames +*/ + + +// 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); + +// display.sinc functions +void __fastcall__ oam_clear_fast(void); +void __fastcall__ oam_meta_spr_pal(unsigned char x,unsigned char y,unsigned char pal,const unsigned char *metasprite); +void __fastcall__ oam_meta_spr_clip(signed int x,unsigned char y,const unsigned char *metasprite); + + + +#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 NAMETABLE_A 0x2000 +#define NAMETABLE_B 0x2400 +#define NAMETABLE_C 0x2800 +#define NAMETABLE_D 0x2c00 + +#define NULL 0 +#define TRUE 1 +#define FALSE 0 + +#define NT_UPD_HORZ 0x40 +#define NT_UPD_VERT 0x80 +#define NT_UPD_EOF 0xff + +// macro to calculate nametable address from X,Y in compile time + +#define NTADR_A(x,y) (NAMETABLE_A|(((y)<<5)|(x))) +#define NTADR_B(x,y) (NAMETABLE_B|(((y)<<5)|(x))) +#define NTADR_C(x,y) (NAMETABLE_C|(((y)<<5)|(x))) +#define NTADR_D(x,y) (NAMETABLE_D|(((y)<<5)|(x))) + +// macro to get MSB and LSB + +#define MSB(x) (((x)>>8)) +#define LSB(x) (((x)&0xff)) diff --git a/presets/nes/neslib1.c b/presets/nes/neslib1.c index 6201b3f3..740e6815 100644 --- a/presets/nes/neslib1.c +++ b/presets/nes/neslib1.c @@ -3,7 +3,11 @@ #include "neslib.h" -// tileset data +#pragma bss-name (push,"ZEROPAGE") +unsigned char oam_off; +#pragma bss-name (pop) + +#pragma data-name (push,"CHARS") 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, @@ -12,6 +16,8 @@ const unsigned char TILESET[8*128] = {/*{w:8,h:8,bpp:1,count:128,brev:1}*/ 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, }; +#pragma data-name(pop) + //this macro is used remove need of calculation of the nametable address in runtime #define NTADR(x,y) ((0x2000|((y)<<5)|x)) @@ -32,7 +38,8 @@ void put_str(unsigned int adr,const char *str) void main(void) { //copy tileset to RAM - vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET)); + vram_adr(0x0); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); //rendering is disabled at the startup, and palette is all black pal_col(1,0x30);//set while color diff --git a/presets/nes/neslib2.c b/presets/nes/neslib2.c index 5a8b5959..63180aad 100644 --- a/presets/nes/neslib2.c +++ b/presets/nes/neslib2.c @@ -4,6 +4,13 @@ #include "neslib.h" +#pragma bss-name (push,"ZEROPAGE") +unsigned char oam_off; +#pragma bss-name (pop) + +#pragma data-name (push,"CHARS") +#pragma data-name(pop) + //#link "tileset1.c" // palette for balls, there are four sets for different ball colors @@ -35,7 +42,8 @@ static unsigned char ball_dy[BALLS_MAX]; void main(void) { //copy tileset to RAM - vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET)); + vram_adr(0x0); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); pal_spr(palSprites);//set palette for sprites oam_size(1); @@ -69,7 +77,7 @@ void main(void) while(1) { - ppu_waitnmi();//wait for next TV frame + ppu_wait_nmi();//wait for next TV frame spr=0; diff --git a/presets/nes/neslib3.c b/presets/nes/neslib3.c index a38c50b2..e869c72f 100644 --- a/presets/nes/neslib3.c +++ b/presets/nes/neslib3.c @@ -2,8 +2,17 @@ //this example shows how to set up a palette and use 8x8 HW sprites //also shows how fast (or slow) C code is +#include + #include "neslib.h" +#pragma bss-name (push,"ZEROPAGE") +unsigned char oam_off; +#pragma bss-name (pop) + +#pragma data-name (push,"CHARS") +#pragma data-name(pop) + //#link "tileset1.c" // tile set, two planes for 4 colors @@ -13,9 +22,6 @@ extern unsigned char TILESET[8*256]; //and how to use nametable update system that allows to modify nametable //while rendering is enabled -#include "neslib.h" - - //these macro are needed to simplify defining update list constants #define NTADR(x,y) ((0x2000|((y)<<5)|x)) @@ -35,27 +41,27 @@ static unsigned char list[6*3]; //init data for the update list, it contains MSB and LSB of a tile address //in the nametable, then the tile number -const unsigned char list_init[6*3]={ - MSB(NTADR(2,2)),LSB(NTADR(2,2)),0, - MSB(NTADR(3,2)),LSB(NTADR(3,2)),0, - MSB(NTADR(4,2)),LSB(NTADR(4,2)),0, - MSB(NTADR(6,2)),LSB(NTADR(6,2)),0, - MSB(NTADR(7,2)),LSB(NTADR(7,2)),0, - MSB(NTADR(8,2)),LSB(NTADR(8,2)),0 +const unsigned char list_init[6*3+1]={ + MSB(NTADR(2,2)),LSB(NTADR(2,2)),0, + MSB(NTADR(3,2)),LSB(NTADR(3,2)),0, + MSB(NTADR(4,2)),LSB(NTADR(4,2)),0, + MSB(NTADR(6,2)),LSB(NTADR(6,2)),0, + MSB(NTADR(7,2)),LSB(NTADR(7,2)),0, + MSB(NTADR(8,2)),LSB(NTADR(8,2)),0, + NT_UPD_EOF }; - - void main(void) { //copy tileset to RAM - vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET)); + vram_adr(0x0); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); pal_col(1,0x21);//blue color for text pal_col(17,0x30);//white color for sprite memcpy(list,list_init,sizeof(list_init)); - set_vram_update(6,list); + set_vram_update(list); ppu_on_all();//enable rendering @@ -66,7 +72,7 @@ void main(void) while(1) { - ppu_waitnmi();//wait for next TV frame + ppu_wait_nmi();//wait for next TV frame oam_spr(x,y,0x41,0,0);//put sprite diff --git a/presets/nes/neslib4.c b/presets/nes/neslib4.c index c4e43e99..72429f89 100644 --- a/presets/nes/neslib4.c +++ b/presets/nes/neslib4.c @@ -1,6 +1,13 @@ #include "neslib.h" +#pragma bss-name (push,"ZEROPAGE") +unsigned char oam_off; +#pragma bss-name (pop) + +#pragma data-name (push,"CHARS") +#pragma data-name(pop) + //#link "tileset1.c" // tile set, two planes for 4 colors @@ -54,7 +61,8 @@ const unsigned char metaCat2[]={ void main(void) { //copy tileset to RAM - vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET)); + vram_adr(0x0); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); ppu_on_all();//enable rendering @@ -74,7 +82,7 @@ void main(void) while(1) { - ppu_waitnmi();//wait for next TV frame + ppu_wait_nmi();//wait for next TV frame //flashing color for touch diff --git a/presets/nes/neslib5.c b/presets/nes/neslib5.c index 063429fd..9baabc4d 100644 --- a/presets/nes/neslib5.c +++ b/presets/nes/neslib5.c @@ -4,6 +4,13 @@ #include "neslib.h" +#pragma bss-name (push,"ZEROPAGE") +unsigned char oam_off; +#pragma bss-name (pop) + +#pragma data-name (push,"CHARS") +#pragma data-name(pop) + const unsigned char test[308]={ 0x01,0x00,0x01,0xa3,0x10,0x01,0x04,0x00,0x10,0x01,0x04,0x00,0x10,0x01,0x04,0x00, 0x10,0x01,0x04,0x00,0x01,0x0a,0x10,0x00,0x01,0x02,0x10,0x00,0x01,0x04,0x10,0x00, @@ -41,10 +48,12 @@ void main(void) pal_bg(palette);//set background palette from an array //copy tileset to RAM - vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET)); + vram_adr(0x0); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); //unpack nametable into the VRAM - unrle_vram(test,0x2000); + vram_adr(0x2000); + vram_unrle(test); //enable rendering ppu_on_all(); diff --git a/presets/nes/shoot2.c b/presets/nes/shoot2.c new file mode 100644 index 00000000..fed7441f --- /dev/null +++ b/presets/nes/shoot2.c @@ -0,0 +1,808 @@ + +#include +#include +#include +#include + +#include "neslib.h" + +#pragma bss-name (push,"ZEROPAGE") +unsigned char oam_off; +#pragma bss-name (pop) + +#pragma data-name (push,"CHARS") +#pragma data-name(pop) + +#pragma static-locals (1); + +#define COLS 32 +#define ROWS 28 + +typedef unsigned char byte; +typedef signed char sbyte; +typedef unsigned short word; + +/// + +const char PALETTE[32] = { + 0x0f, + + 0x11,0x24,0x3c, 0, + 0x01,0x15,0x25, 0, + 0x01,0x10,0x20, 0, + 0x06,0x16,0x26, 0, + + 0x11,0x24,0x3c, 0, + 0x01,0x15,0x25, 0, + 0x31,0x35,0x3c, 0, + 0x01,0x17,0x30 +}; + +#define COLOR_PLAYER 3 +#define COLOR_FORMATION 1 +#define COLOR_ATTACKER 1 +#define COLOR_MISSILE 3 +#define COLOR_BOMB 2 +#define COLOR_SCORE 2 +#define COLOR_EXPLOSION 3 + +const char TILESET[128*8*2] = {/*{w:8,h:8,bpp:1,count:128,brev:1,np:2,pofs:8,remap:[0,1,2,4,5,6,7,8,9,10,11,12]}*/ +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, + +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, +// formation enemy (66) +0x0C,0x13,0x03,0x03,0x03,0x01,0x01,0x00,0x0C,0x10,0x01,0x0C,0x30,0x02,0x04,0x18, +0x18,0x64,0xE0,0xE0,0xE0,0xC0,0xC0,0x80,0x18,0x04,0x40,0x18,0x06,0x20,0x10,0x0C, +// attackers (68) +0x00,0x00,0x04,0x08,0x04,0x00,0x01,0x0C,0x00,0x00,0x04,0x08,0x04,0x03,0x03,0x03, +0x03,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x30,0x02,0x04,0x18,0x00,0x00,0x00,0x00, +0x00,0x00,0x10,0x08,0x10,0x60,0xE0,0xE0,0x00,0x00,0x10,0x08,0x10,0x00,0x40,0x18, +0xE0,0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,0x06,0x20,0x10,0x0C,0x00,0x00,0x00,0x00, + +0x00,0x00,0x02,0x04,0x04,0x03,0x03,0x03,0x00,0x00,0x02,0x04,0x04,0x20,0x11,0x0C, +0x03,0x07,0x03,0x03,0x02,0x00,0x00,0x00,0x00,0x20,0x1C,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x08,0x08,0x10,0xE0,0xE0,0x00,0x00,0x00,0x08,0x08,0x10,0x00,0x40, +0xE0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x10,0x0C,0x02,0x20,0x10,0x0C,0x00,0x00, + +0x00,0x00,0x0C,0x04,0x02,0x03,0x07,0x27,0x00,0x00,0x0C,0x04,0x00,0x00,0x01,0x20, +0x3F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x04,0x08,0x10,0x01,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0x00,0x00,0x00,0x20,0x40,0x84,0x08,0x10, +0xE0,0xF0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x00,0x00,0x00, + +0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x07,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0x21,0x44,0x08,0x08,0x00,0x00, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x20,0x40,0x80,0x98,0x20,0x00, +0xE0,0xFC,0xC4,0x80,0x80,0x80,0xC0,0x00,0x40,0x0C,0x04,0x00,0x00,0x80,0xC0,0x00, + +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x02,0x11,0x08,0x04, +0x03,0x03,0x07,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x30,0x20,0x60,0xF0,0xFC,0x00,0x00,0x00,0x30,0x20,0x00,0x40,0x04, +0xFC,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x2C,0x00,0x20,0x18,0x80,0x40,0x60,0x00, + +0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x07,0x00,0x00,0x00,0x10,0x10,0x08,0x04,0x00, +0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x02,0x02,0x00,0x00, +0x00,0x00,0x00,0x08,0x34,0xE0,0xE0,0xF0,0x00,0x80,0x80,0x88,0x94,0x00,0x40,0x00, +0xFA,0xE4,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x04,0x80,0x40,0x20,0x00,0x00,0x00, + +0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x00,0x00,0x01,0x09,0x08,0x04,0x02,0x00, +0x0F,0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x08,0x09,0x01,0x00, +0x00,0x00,0x00,0x00,0x08,0x14,0xE0,0xE0,0x00,0x00,0x00,0x00,0x88,0x94,0x00,0x40, +0xC0,0xE0,0xE0,0x14,0x08,0x00,0x00,0x00,0x00,0x40,0x00,0x94,0x88,0x00,0x00,0x00, + +0x01,0x01,0x01,0x00,0x00,0x01,0x11,0x11,0x01,0x01,0x02,0x07,0x01,0x21,0x21,0x2B, +0x11,0x16,0x1E,0x15,0x10,0x10,0x10,0x10,0x3F,0x3F,0x3F,0x3D,0x3B,0x3C,0x28,0x28, +0x40,0x40,0xC0,0x00,0x00,0x40,0x44,0x44,0xC0,0xC0,0x20,0xF0,0xC0,0xC2,0xC2,0xEA, +0x44,0x34,0x3C,0x54,0x04,0x04,0x04,0x04,0xFE,0xFE,0xFE,0xDE,0xEE,0x1E,0x0A,0x0A, + +0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x08,0x18,0x08,0x18,0x08,0x18,0x18,0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, +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,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, +// explosions +0x00,0x00,0x00,0x08,0x04,0x03,0x06,0x05,0x00,0x00,0x00,0x0C,0x06,0x04,0x00,0x18, +0x05,0x06,0x07,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x08,0x09,0x00,0x00,0x00,0x00, +0x00,0x00,0x00,0x08,0x90,0xE0,0x90,0xD0,0x00,0x00,0x00,0x18,0x30,0x10,0x00,0x0C, +0xF0,0x20,0xE0,0x80,0x00,0x00,0x00,0x00,0x0C,0x10,0x18,0xC8,0x00,0x00,0x00,0x00, + +0x00,0x04,0x12,0x0C,0x42,0x30,0x00,0x19,0x00,0x00,0x00,0x0A,0x00,0x06,0x08,0x00, +0x11,0x04,0x0C,0x00,0x21,0x46,0x00,0x00,0x04,0x10,0x02,0x0C,0x00,0x00,0x00,0x00, +0x00,0x40,0x08,0x91,0xA2,0x04,0x80,0xCC,0x00,0x00,0x00,0x20,0x00,0x30,0x08,0x00, +0xC4,0x10,0x1A,0x80,0x20,0x10,0x00,0x00,0x10,0x04,0xA0,0x98,0x80,0x00,0x00,0x00, + +0x61,0x20,0x00,0x04,0x00,0xC4,0x08,0x10,0x00,0x00,0x04,0x06,0x09,0x02,0x10,0x14, +0x10,0x00,0x42,0xC8,0x80,0x00,0x10,0x30,0x34,0x10,0x11,0x02,0x00,0x00,0x00,0x00, +0x86,0xC4,0x00,0x10,0x01,0x10,0x08,0x04,0x00,0x00,0x10,0x30,0x48,0x20,0x04,0x14, +0x04,0x00,0x20,0x89,0x00,0x84,0xC6,0x43,0x16,0x04,0x44,0xA0,0x00,0x00,0x00,0x00, + +0x00,0x00,0x02,0x08,0x00,0x06,0x02,0x00,0x00,0x00,0x08,0x01,0x11,0x15,0x00,0x38, +0x30,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x10,0x00,0x00,0x00,0x00,0x00, +0x00,0x00,0x20,0x08,0x00,0x30,0x20,0x00,0x00,0x00,0x08,0x40,0x44,0x54,0x00,0x0E, +0x06,0x20,0x80,0x80,0x00,0x00,0x00,0x00,0x0C,0x80,0x04,0x80,0x00,0x00,0x00,0x00, +}; + +#define CHAR(x) ((x)-' ') +#define BLANK 0 + +// VRAM UPDATE BUFFER + +#define VBUFSIZE 64 +byte updbuf[VBUFSIZE]; +byte updptr = 0; + +void cendbuf() { + updbuf[updptr] = NT_UPD_EOF; +} + +void cflushnow() { + cendbuf(); + ppu_wait_nmi(); + flush_vram_update(updbuf); + updptr = 0; + cendbuf(); + vram_adr(0x0); +} + +void vdelay(byte count) { + while (count--) cflushnow(); +} + +void putchar(byte x, byte y, char ch) { + word addr = NTADR_A(x,y); + if (updptr >= VBUFSIZE-4) cflushnow(); + updbuf[updptr++] = addr >> 8; + updbuf[updptr++] = addr & 0xff; + updbuf[updptr++] = ch; + cendbuf(); +} + +void putbytes(byte x, byte y, char* str, byte len) { + word addr = NTADR_A(x,y); + if (updptr >= VBUFSIZE-4-len) cflushnow(); + updbuf[updptr++] = (addr >> 8) | NT_UPD_HORZ; + updbuf[updptr++] = addr & 0xff; + updbuf[updptr++] = len; + while (len--) { + updbuf[updptr++] = *str++; + } + cendbuf(); +} + +void putstring(byte x, byte y, char* str) { + putbytes(x, y, str, strlen(str)); +} + +void clrscr() { + updptr = 0; + cendbuf(); + ppu_off(); + vram_adr(0x2000); + vram_fill(BLANK, 32*28); + vram_adr(0x0); + ppu_on_all(); +} + +///// + +char in_rect(byte x, byte y, byte x0, byte y0, byte w, byte h) { + return ((byte)(x-x0) < w && (byte)(y-y0) < h); // unsigned +} + +void draw_bcd_word(byte col, byte row, word bcd) { + byte j; + static char buf[5]; + buf[4] = CHAR('0'); + for (j=3; j<0x80; j--) { + buf[j] = CHAR('0'+(bcd&0xf)); + bcd >>= 4; + } + putbytes(col, row, buf, 5); +} + +word bcd_add(word a, word b) { + word result = 0; + byte c = 0; + byte shift = 0; + while (shift < 16) { + byte d = (a & 0xf) + (b & 0xf) + c; + c = 0; + while (d >= 10) { + c++; + d -= 10; + } + result |= d << shift; + shift += 4; + a >>= 4; + b >>= 4; + } + return result; +} + +// GAME CODE + +#define NSPRITES 16 +#define NMISSILES 8 +#define YOFFSCREEN 239 + +#define SPRI_SHIP 96 +#define SPRI_MISSILE 100 +#define SPRI_BOMB 104 +#define SPRI_EXPLODE 112 +#define SPRI_ENEMY 68 + +#define SSRC_FORM1 66 +#define SDST_FORM1 128 + +typedef struct { + byte shape; +} FormationEnemy; + +// should be power of 2 length +typedef struct { + byte findex; + byte shape; + word x; + word y; + byte dir; + byte returning; +} AttackingEnemy; + +typedef struct { + signed char dx; + byte xpos; + signed char dy; + byte ypos; +} Missile; + +typedef struct { + byte name; + byte tag; + byte x; + byte y; +} Sprite; + +#define ENEMIES_PER_ROW 8 +#define ENEMY_ROWS 4 +#define MAX_IN_FORMATION (ENEMIES_PER_ROW*ENEMY_ROWS) +#define MAX_ATTACKERS 6 + +FormationEnemy formation[MAX_IN_FORMATION]; +AttackingEnemy attackers[MAX_ATTACKERS]; +Missile missiles[NMISSILES]; +Sprite vsprites[NSPRITES]; + +byte formation_offset_x; +signed char formation_direction; +byte current_row; +byte player_x; +const byte player_y = 190; +byte player_exploding; +byte enemy_exploding; +byte enemies_left; +word player_score; +byte framecount; + +void copy_sprites() { + byte i; + byte oamid = 0; + for (i=0; iy != YOFFSCREEN) { + byte y = spr->y; + byte x = spr->x; + byte chr = spr->name; + byte attr = spr->tag; + if (attr & 0x40) chr += 2; // horiz flip, swap tiles + oamid = oam_spr(x, y, chr, attr, oamid); + oamid = oam_spr(x+8, y, chr^2, attr, oamid); + } + } + // copy all "shadow missiles" to video memory + for (i=0; iypos != YOFFSCREEN) { + oamid = oam_spr(mis->xpos, mis->ypos, SPRI_MISSILE, + (i==7)?COLOR_MISSILE:COLOR_BOMB, + oamid); + } + } + oam_hide_rest(oamid); +} + +void add_score(word bcd) { + player_score = bcd_add(player_score, bcd); + draw_bcd_word(1, 1, player_score); +} + +void clrobjs() { + byte i; + memset(vsprites, 0, sizeof(vsprites)); + for (i=0; ifindex) { + byte code = DIR_TO_CODE[(a->dir)&31]; + vsprites[i].name = SPRI_ENEMY + (code&7)*4; // tile + vsprites[i].tag = code & 0xc0; // flip h/v + vsprites[i].x = a->x >> 8; + vsprites[i].y = a->y >> 8; + } else { + vsprites[i].y = YOFFSCREEN; + } +} + +void draw_attackers() { + byte i; + for (i=0; ifindex-1; + byte destx = get_attacker_x(fi); + byte desty = get_attacker_y(fi); + byte ydist = desty - (a->y >> 8); + // are we close to our formation slot? + if (ydist == 0) { + // convert back to formation enemy + formation[fi].shape = a->shape; + a->findex = 0; + } else { + a->dir = (ydist + 16) & 31; + a->x = destx << 8; + a->y += 128; + } +} + +void fly_attacker(AttackingEnemy* a) { + a->x += isin(a->dir) * 2; + a->y += icos(a->dir) * 2; + if ((a->y >> 8) == 0) { + a->returning = 1; + } +} + +void move_attackers() { + byte i; + for (i=0; ifindex) { + if (a->returning) + return_attacker(a); + else + fly_attacker(a); + } + } +} + +void think_attackers() { + byte i; + for (i=0; ifindex) { + // rotate? + byte x = a->x >> 8; + byte y = a->y >> 8; + // don't shoot missiles after player exploded + if (y < 112 || player_exploding) { + if (x < 128) { + a->dir++; + } else { + a->dir--; + } + } else { + // lower half of screen + // shoot a missile? + if (missiles[i].ypos == YOFFSCREEN) { + missiles[i].ypos = y+16; + missiles[i].xpos = x; + missiles[i].dy = 2; + } + } + } + } +} + +void formation_to_attacker(byte formation_index) { + byte i; + // out of bounds? return + if (formation_index >= MAX_IN_FORMATION) + return; + // nobody in formation? return + if (!formation[formation_index].shape) + return; + // find an empty attacker slot + for (i=0; ifindex == 0) { + a->x = get_attacker_x(formation_index) << 8; + a->y = get_attacker_y(formation_index) << 8; + a->shape = formation[formation_index].shape; + a->findex = formation_index+1; + a->dir = 0; + a->returning = 0; + formation[formation_index].shape = 0; + break; + } + } +} + +void draw_player() { + vsprites[7].x = player_x; + vsprites[7].y = player_y; + vsprites[7].name = SPRI_SHIP; + vsprites[7].tag = COLOR_PLAYER; +} + +void move_player() { + byte joy = joy_read(JOY_1); + // move left/right? + if ((joy & JOY_LEFT_MASK) && player_x > 16) player_x--; + if ((joy & JOY_RIGHT_MASK) && player_x < 224) player_x++; + // shoot missile? + if ((joy & JOY_BTN_A_MASK) && missiles[7].ypos == YOFFSCREEN) { + missiles[7].ypos = player_y-8; // must be multiple of missile speed + missiles[7].xpos = player_x; // player X position + missiles[7].dy = -4; // player missile speed + } + vsprites[7].x = player_x; +} + +void move_missiles() { + byte i; + for (i=0; i<8; i++) { + if (missiles[i].ypos != YOFFSCREEN) { + // hit the bottom or top? + if ((byte)(missiles[i].ypos += missiles[i].dy) > YOFFSCREEN) { + missiles[i].ypos = YOFFSCREEN; + } + } + } +} + +void blowup_at(byte x, byte y) { + vsprites[6].tag = COLOR_EXPLOSION; + vsprites[6].name = SPRI_EXPLODE; // TODO + vsprites[6].x = x; + vsprites[6].y = y; + enemy_exploding = 1; +} + +void animate_enemy_explosion() { + if (enemy_exploding) { + // animate next frame + if (enemy_exploding >= 8) { + enemy_exploding = 0; // hide explosion after 4 frames + vsprites[6].y = YOFFSCREEN; + } else { + vsprites[6].name = SPRI_EXPLODE + (enemy_exploding += 4); // TODO + } + } +} + +void animate_player_explosion() { + byte z = player_exploding; + if (z <= 3) { + if (z == 3) { + vsprites[7].y = YOFFSCREEN; + } else { + vsprites[7].name = SPRI_EXPLODE + z*4; + } + } +} + +void hide_player_missile() { + missiles[7].ypos = YOFFSCREEN; +} + +void does_player_shoot_formation() { + byte mx = missiles[7].xpos + 8; + byte my = missiles[7].ypos; + signed char row = (my - FORMATION_Y0) / FORMATION_YSPACE; + if (row >= 0 && row < ENEMY_ROWS) { + // ok if unsigned (in fact, must be due to range) + byte xoffset = mx - FORMATION_X0 - formation_offset_x; + byte column = xoffset / FORMATION_XSPACE; + byte localx = xoffset - column * FORMATION_XSPACE; + if (column < ENEMIES_PER_ROW && localx < 16) { + char index = column + row * ENEMIES_PER_ROW; + if (formation[index].shape) { + formation[index].shape = 0; + enemies_left--; + blowup_at(get_attacker_x(index), get_attacker_y(index)); + hide_player_missile(); + add_score(2); + } + } + } +} + +void does_player_shoot_attacker() { + byte mx = missiles[7].xpos + 8; + byte my = missiles[7].ypos; + byte i; + for (i=0; ifindex && in_rect(mx, my, a->x >> 8, a->y >> 8, 16, 16)) { + blowup_at(a->x >> 8, a->y >> 8); + a->findex = 0; + enemies_left--; + hide_player_missile(); + add_score(5); + break; + } + } +} + +void does_missile_hit_player() { + byte i; + if (player_exploding) + return; + for (i=0; i> 8; + if (y >= 0x80) { + cv_set_frequency(CV_SOUNDCHANNEL_2, 4000+y*8); + cv_set_attenuation(CV_SOUNDCHANNEL_2, 28); + break; + } + } + } + */ +} + +void wait_for_frame() { + ppu_wait_nmi(); +} + +void play_round() { + byte end_timer = 255; + player_score = 0; + add_score(0); + putstring(0, 0, "PLAYER 1"); + setup_formation(); + clrobjs(); + formation_direction = 1; + framecount = 0; + new_player_ship(); + while (end_timer) { + if (player_exploding) { + if ((framecount & 7) == 1) { + animate_player_explosion(); + if (++player_exploding > 32 && enemies_left) { + new_player_ship(); + } + } + } else { + if ((framecount & 0x7f) == 0 || enemies_left < 8) { + new_attack_wave(); + } + move_player(); + does_missile_hit_player(); + } + if ((framecount & 3) == 2) animate_enemy_explosion(); + move_attackers(); + move_missiles(); + if (framecount & 1) + does_player_shoot_formation(); + else + does_player_shoot_attacker(); + draw_next_row(); + draw_attackers(); + if ((framecount & 0xf) == 0) think_attackers(); + set_sounds(); + framecount++; + if (!enemies_left) end_timer--; + cflushnow(); + copy_sprites(); + } +} + +void set_shifted_pattern(const byte* src, word dest, byte shift) { + static byte buf[16*3]; + byte y; + for (y=0; y<16; y++) { + byte a = src[y]; + byte b = src[y+16]; + buf[y] = a>>shift; + buf[y+16] = b>>shift | a<<(8-shift); + buf[y+32] = b<<(8-shift); + } + vram_adr(dest); + vram_write(buf, sizeof(buf)); +} + +void setup_tileset() { + byte i; + word src; + word dest; + // copy background + vram_adr(0x0); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); + // copy sprites + vram_adr(0x1000); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); + // write shifted versions of formation ships + src = SSRC_FORM1*16; + dest = SDST_FORM1*16; + for (i=0; i<8; i++) { + set_shifted_pattern(&TILESET[src], dest, i); + dest += 3*16; + } +} + +void main() { + joy_install (joy_static_stddrv); + setup_tileset(); + pal_all(PALETTE); + oam_clear(); + oam_size(1); // 8x16 sprites + clrscr(); + play_round(); + main(); +} + diff --git a/presets/nes/siegegame.c b/presets/nes/siegegame.c index 7d5d8a46..a0cd6a6e 100644 --- a/presets/nes/siegegame.c +++ b/presets/nes/siegegame.c @@ -1,21 +1,28 @@ #include #include -#include #include #include #include "neslib.h" +#pragma bss-name (push,"ZEROPAGE") +unsigned char oam_off; +#pragma bss-name (pop) + +#pragma data-name (push,"CHARS") +#pragma data-name(pop) + //#link "tileset1.c" extern unsigned char palSprites[16]; extern unsigned char TILESET[8*256]; - #define COLS 32 #define ROWS 28 +#define NTADR(x,y) ((0x2000|((y)<<5)|(x))) + typedef unsigned char byte; typedef signed char sbyte; typedef unsigned short word; @@ -27,25 +34,68 @@ typedef unsigned short word; // back to the start of the frame. byte getchar(byte x, byte y) { // compute VRAM read address - word addr = 0x2020+x+y*32; + word addr = NTADR(x,y); byte rd; // wait for VBLANK to start waitvsync(); - // set VRAM read address in PPU - PPU.vram.address = addr>>8; - PPU.vram.address = addr&0xff; - // read the char from PPUDATA - rd = PPU.vram.data; // discard - rd = PPU.vram.data; // keep this one - // reset the VRAM address to start of frame - PPU.vram.address = 0x00; - PPU.vram.address = 0x00; - // return result - return rd; + vram_adr(addr); + vram_read(&rd, 1); + vram_adr(0x0); + return rd + 0x20; +} + +// VRAM UPDATE BUFFER + +byte updbuf[64]; +byte updptr = 0; + +void cendbuf() { + updbuf[updptr] = NT_UPD_EOF; +} + +void cflushnow() { + cendbuf(); + waitvsync(); + flush_vram_update(updbuf); + updptr = 0; + cendbuf(); + vram_adr(0x0); } void vdelay(byte count) { - while (count--) waitvsync(); + while (count--) cflushnow(); +} + +void cputcxy(byte x, byte y, char ch) { + word addr = NTADR(x,y); + if (updptr >= 60) cflushnow(); + updbuf[updptr++] = addr >> 8; + updbuf[updptr++] = addr & 0xff; + updbuf[updptr++] = ch - 0x20; + cendbuf(); +} + +void cputsxy(byte x, byte y, char* str) { + word addr = NTADR(x,y); + byte len = strlen(str); + if (updptr >= 60 - len) cflushnow(); + updbuf[updptr++] = (addr >> 8) | NT_UPD_HORZ; + updbuf[updptr++] = addr & 0xff; + updbuf[updptr++] = len; + while (len--) { + updbuf[updptr++] = *str++ - 0x20; + } + cendbuf(); +} + +void clrscr() { + updptr = 0; + cendbuf(); + ppu_off(); + vram_adr(0x2000); + vram_fill(0, 32*28); + vram_adr(0x0); + ppu_on_bg(); } ////////// GAME DATA @@ -63,7 +113,8 @@ typedef struct { Player players[2]; -byte credits = 0; +byte attract; +byte gameover; byte frames_per_move; #define START_SPEED 12 @@ -72,7 +123,7 @@ byte frames_per_move; /////////// -const char BOX_CHARS[8] = { 17, 8, 20, 18, 11, 11, 14, 14 }; +const char BOX_CHARS[8] = { '+','+','+','+','-','-','!','!' }; void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) { byte x1 = x; @@ -91,11 +142,15 @@ void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) { } void draw_playfield() { - draw_box(0,1,COLS-1,ROWS-1,BOX_CHARS); - cputsxy(0,0,"Plyr1:"); - cputsxy(20,0,"Plyr2:"); - cputcxy(7,0,players[0].score+'0'); - cputcxy(27,0,players[1].score+'0'); + draw_box(1,2,COLS-2,ROWS-1,BOX_CHARS); + cputcxy(9,1,players[0].score+'0'); + cputcxy(28,1,players[1].score+'0'); + if (attract) { + cputsxy(5,ROWS-1,"ATTRACT MODE - PRESS 1"); + } else { + cputsxy(1,1,"PLYR1:"); + cputsxy(20,1,"PLYR2:"); + } } typedef enum { D_RIGHT, D_DOWN, D_LEFT, D_UP } dir_t; @@ -106,8 +161,8 @@ void init_game() { memset(players, 0, sizeof(players)); players[0].head_attr = '1'; players[1].head_attr = '2'; - players[0].tail_attr = 1; - players[1].tail_attr = 9; + players[0].tail_attr = '#'; + players[1].tail_attr = '*'; frames_per_move = START_SPEED; } @@ -136,8 +191,12 @@ void move_player(Player* p) { void human_control(Player* p) { byte dir = 0xff; byte joy; - if (!p->human) return; joy = joy_read (JOY_1); + // start game if attract mode + if (attract && (joy & JOY_START_MASK)) + gameover = 1; + // do not allow movement unless human player + if (!p->human) return; if (joy & JOY_LEFT_MASK) dir = D_LEFT; if (joy & JOY_RIGHT_MASK) dir = D_RIGHT; if (joy & JOY_UP_MASK) dir = D_UP; @@ -175,8 +234,6 @@ void ai_control(Player* p) { } } -byte gameover; - void flash_colliders() { byte i; // flash players that collided @@ -219,13 +276,13 @@ void declare_winner(byte winner) { gameover = 1; } -#define AE(a,b,c,d) (((a)<<0)|((b)<<2)|((c)<<4)|((d)<<6)) +#define AE(tl,tr,bl,br) (((tl)<<0)|((tr)<<2)|((bl)<<4)|((br)<<6)) // this is attribute table data, // each 2 bits defines a color palette // for a 16x16 box const unsigned char Attrib_Table[0x40]={ -AE(3,3,1,1),AE(3,3,1,1),AE(3,3,1,1),AE(3,3,1,1), AE(2,2,1,1),AE(2,2,1,1),AE(2,2,1,1),AE(2,2,1,1), +AE(3,3,1,0),AE(3,3,0,0),AE(3,3,0,0),AE(3,3,0,0), AE(2,2,0,0),AE(2,2,0,0),AE(2,2,0,0),AE(2,2,0,1), AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,1,0,1), AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,1,0,1), AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,1,0,1), @@ -235,24 +292,37 @@ AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0, AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1), AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1), }; +// this is palette data +const unsigned char Palette_Table[16]={ + 0x02, + 0x31,0x31,0x31,0x00, + 0x34,0x34,0x34,0x00, + 0x39,0x39,0x39,0x00, +}; + // put 8x8 grid of palette entries into the PPU void setup_attrib_table() { - byte index; - waitvsync(); // wait for VBLANK - PPU.vram.address = 0x23; - PPU.vram.address = 0xc0; - for( index = 0; index < 0x40; ++index ){ - PPU.vram.data = Attrib_Table[index]; - } + vram_adr(0x23c0); + vram_write(Attrib_Table, 0x40); +} + +void setup_palette() { + int i; + // only set palette entries 0-15 (background only) + for (i=0; i<15; i++) + pal_col(i, Palette_Table[i] ^ attract); } void play_round() { - reset_players(); - clrscr(); + ppu_off(); setup_attrib_table(); + setup_palette(); + clrscr(); draw_playfield(); + reset_players(); while (1) { make_move(); + if (gameover) return; // attract mode -> start if (players[0].collided || players[1].collided) break; } flash_colliders(); @@ -273,14 +343,21 @@ void play_round() { void play_game() { gameover = 0; init_game(); - players[0].human = 1; + if (!attract) + players[0].human = 1; while (!gameover) { play_round(); } } void main() { - vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET)); + vram_adr(0x0); + vram_write((unsigned char*)TILESET, sizeof(TILESET)); joy_install (joy_static_stddrv); - play_game(); + while (1) { + attract = 1; + play_game(); + attract = 0; + play_game(); + } } diff --git a/presets/nes/skeleton.dasm b/presets/nes/skeleton.dasm new file mode 100644 index 00000000..09f6d651 --- /dev/null +++ b/presets/nes/skeleton.dasm @@ -0,0 +1,46 @@ + + include "nesdefs.asm" + +;;;;; VARIABLES + + seg.u RAM + org $0 + +;;;;; NES CARTRIDGE HEADER + + NES_HEADER 0,2,1,0 ; mapper 0, 2 PRGs, 1 CHR, vertical + +;;;;; START OF CODE + +Start: + NES_INIT ; set up stack pointer, turn off PPU + jsr WaitSync ; wait for VSYNC + jsr ClearRAM ; clear RAM + jsr WaitSync ; wait for VSYNC (and PPU warmup) + + lda #$3f ; $3F -> A register + ldy #$00 ; $00 -> Y register + sta PPU_ADDR ; write high byte first + sty PPU_ADDR ; $3F00 -> PPU address + lda #$1c ; $1C = light blue color + sta PPU_DATA ; $1C -> PPU data + lda #CTRL_NMI + sta PPU_CTRL ; enable NMI + lda #MASK_COLOR + sta PPU_MASK ; enable rendering +.endless + jmp .endless ; endless loop + +;;;;; COMMON SUBROUTINES + + include "nesppu.asm" + +;;;;; INTERRUPT HANDLERS + +NMIHandler: + rti + +;;;;; CPU VECTORS + + NES_VECTORS + diff --git a/presets/vicdual/asmtest.s b/presets/vicdual/asmtest.s new file mode 100644 index 00000000..e9b5233f --- /dev/null +++ b/presets/vicdual/asmtest.s @@ -0,0 +1,135 @@ +.area _HOME +.area _CODE +.area _INITIALIZER +.area _DATA +.area _INITIALIZED +.area _BSEG +.area _BSS +.area _HEAP +;-------------------------------------------------------- +; File Created by SDCC : free open source ANSI-C Compiler +; Version 3.6.5 # (UNIX) +;-------------------------------------------------------- + .module minimal + .optsdcc -mz80 + +;-------------------------------------------------------- +; Public variables in this module +;-------------------------------------------------------- + .globl _start + .globl _tileram + .globl _cellram + .globl _main +;-------------------------------------------------------- +; special function registers +;-------------------------------------------------------- +_palette = 0x0040 +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _DATA +_cellram = 0xe000 +_tileram = 0xe800 +;-------------------------------------------------------- +; ram data +;-------------------------------------------------------- + .area _INITIALIZED +;-------------------------------------------------------- +; absolute external ram data +;-------------------------------------------------------- + .area _DABS (ABS) +;-------------------------------------------------------- +; global & static initialisations +;-------------------------------------------------------- + .area _HOME + .area _GSINIT + .area _GSFINAL + .area _GSINIT +;-------------------------------------------------------- +; Home +;-------------------------------------------------------- + .area _HOME + .area _HOME +;-------------------------------------------------------- +; code +;-------------------------------------------------------- + .area _CODE +;:15: +; --------------------------------- +; Function start +; --------------------------------- +_start:: +;:19: + LD SP,#0xE800 ; set up stack pointer + DI ; disable interrupts +;:20: + jp _main +;:23: +; --------------------------------- +; Function main +; --------------------------------- +_main:: +;:26: + ld a,#0x01 + out (_palette),a +;:27: + ld hl,#_tileram + ld (hl), #0xfe + ld e, l + ld d, h + inc de + ld bc, #0x07ff + ldir +;:28: + ld hl,#_cellram + ld (hl), #0x00 + ld e, l + ld d, h + inc de + ld bc, #0x07ff + ldir +;:29: + ld c,#0x00 +;:30: +00112$: + ld a,c + rlca + rlca + rlca + and a,#0xf8 + ld e,a + ld d,#0x00 +00106$: +;:31: + ld l,d + ld h,#0x00 + add hl, hl + add hl, hl + add hl, hl + add hl, hl + add hl, hl + ld a,#<(_cellram) + add a, l + ld l,a + ld a,#>(_cellram) + adc a, h + ld h,a + ld b,#0x00 + add hl, bc + ld (hl),e +;:30: + inc d + ld a,d + sub a, #0x20 + jr C,00106$ +;:29: + inc c + ld a,c + sub a, #0x20 + jr C,00112$ +;:34: +00104$: + jr 00104$ + .area _CODE + .area _INITIALIZER + .area _CABS (ABS) diff --git a/src/pixed/pixeleditor.ts b/src/pixed/pixeleditor.ts index 147f0f71..e6508923 100644 --- a/src/pixed/pixeleditor.ts +++ b/src/pixed/pixeleditor.ts @@ -332,6 +332,7 @@ function convertBytesToImages(bytes, fmt) { } function convertImagesToBytes(images, fmt) { + if (fmt.destfmt) fmt = fmt.destfmt; var width = fmt.w; var height = fmt.h; var count = fmt.count || 1; diff --git a/src/platform/nes.js b/src/platform/nes.js index 12685e15..54d77cbb 100644 --- a/src/platform/nes.js +++ b/src/platform/nes.js @@ -12,6 +12,7 @@ var JSNES_PRESETS = [ {id:'neslib4.c', name:'Metasprites'}, {id:'neslib5.c', name:'RLE Unpack'}, {id:'siegegame.c', name:'Siege Game'}, + {id:'shoot2.c', name:'Solarian Game'}, ]; var NES_NESLIB_PRESETS = [ diff --git a/src/project.ts b/src/project.ts index 4ad43f23..c8b0ac07 100644 --- a/src/project.ts +++ b/src/project.ts @@ -92,9 +92,10 @@ export class CodeProject { var linkfiles = this.parseLinkDependencies(text); var allfiles = includes.concat(linkfiles); this.loadFiles(allfiles, (err:string, result?:Dependency[]) => { + // set 'link' property on files that are link dependencies (must match filename) if (result) for (var dep of result) - dep.link = linkfiles.indexOf(dep.filename) >= 0; + dep.link = linkfiles.indexOf(dep.filename) >= 0 || linkfiles.indexOf('local/'+dep.filename) >= 0; //TODO!!! callback(err, result); }); } diff --git a/src/views.ts b/src/views.ts index 0127f221..8bff2d03 100644 --- a/src/views.ts +++ b/src/views.ts @@ -184,6 +184,7 @@ export class SourceEditor implements ProjectView { var insnstr = info.insns.length > 9 ? ("...") : info.insns; this.setGutter("gutter-bytes", info.line-1, insnstr); if (info.iscode) { + // TODO: labels trick this part? var opcode = parseInt(info.insns.split(" ")[0], 16); if (platform.getOpcodeMetadata) { var meta = platform.getOpcodeMetadata(opcode, info.offset); @@ -415,7 +416,18 @@ export class DisassemblerView implements ProjectView { bytes += hex(platform.readAddress(a+i)); while (bytes.length < 14) bytes += ' '; - var dline = hex(parseInt(a)) + "\t" + bytes + "\t" + disasm.line + "\n"; + var dstr = disasm.line; + if (addr2symbol) { + dstr = dstr.replace(/([^#])[$]([0-9A-F]+)/, (substr:string, ...args:any[]):string => { + var addr = parseInt(args[1], 16); + var sym = addr2symbol[addr]; + if (sym) return (args[0] + sym); + sym = addr2symbol[addr+1]; + if (sym) return (args[0] + sym + "+1"); + return substr; + }); + } + var dline = hex(parseInt(a)) + "\t" + bytes + "\t" + dstr + "\n"; s += dline; if (a == pc) selline = curline; curline++; diff --git a/src/worker/lib/nes/crt0.o b/src/worker/lib/nes/crt0.o new file mode 100644 index 0000000000000000000000000000000000000000..7e8c327fbea5e4cb953755f703ce70e3ec1b9672 GIT binary patch literal 57756 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 BBO(9* literal 0 HcmV?d00001 diff --git a/src/worker/workermain.js b/src/worker/workermain.js index 25d8ab66..a01935e0 100644 --- a/src/worker/workermain.js +++ b/src/worker/workermain.js @@ -105,7 +105,13 @@ var PLATFORM_PARAMS = { 'nes': { //TODO define: '__NES__', cfgfile: 'neslib.cfg', - libargs: ['neslib.lib', 'nes.lib'], + libargs: ['crt0.o', 'nes.lib', + '-D', 'NES_MAPPER=0', + '-D', 'NES_PRG_BANKS=2', + '-D', 'NES_CHR_BANKS=0', // TODO: >0 doesn't seem to work + '-D', 'NES_MIRRORING=0', + ], + extrafiles: ['crt0.o'], }, 'nes-conio': { cfgfile: 'nes.cfg', @@ -247,6 +253,28 @@ function populateFiles(step, fs, options) { } } +function populateExtraFiles(step, fs) { + // TODO: cache extra files + var extrafiles = step.params.extrafiles; + if (extrafiles) { + for (var i=0; i